diff --git a/PubNubUnity/Assets/PubNub/Runtime/Plugins/PubnubApiUnity.dll b/PubNubUnity/Assets/PubNub/Runtime/Plugins/PubnubApiUnity.dll index 4e7d6ff6..d84d615a 100644 Binary files a/PubNubUnity/Assets/PubNub/Runtime/Plugins/PubnubApiUnity.dll and b/PubNubUnity/Assets/PubNub/Runtime/Plugins/PubnubApiUnity.dll differ diff --git a/PubNubUnity/Assets/PubNub/Runtime/Util/NewtonsoftJsonUnity.cs b/PubNubUnity/Assets/PubNub/Runtime/Util/NewtonsoftJsonUnity.cs new file mode 100644 index 00000000..5be4e152 --- /dev/null +++ b/PubNubUnity/Assets/PubNub/Runtime/Util/NewtonsoftJsonUnity.cs @@ -0,0 +1,570 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace PubnubApi.Unity.PubNub.Runtime.Util { + public class NewtonsoftJsonUnity : IJsonPluggableLibrary { + private readonly PNConfiguration config; + private readonly IPubnubLog pubnubLog; + private readonly JsonSerializerSettings defaultJsonSerializerSettings; + + public NewtonsoftJsonUnity(PNConfiguration pubnubConfig, IPubnubLog log) { + this.config = pubnubConfig; + this.pubnubLog = log; + defaultJsonSerializerSettings = new JsonSerializerSettings { MaxDepth = 64 }; + } + + #region IJsonPlugableLibrary methods implementation + + private static bool IsValidJson(string jsonString, PNOperationType operationType) { + bool ret = false; + try { + if (operationType == PNOperationType.PNPublishOperation + || operationType == PNOperationType.PNHistoryOperation + || operationType == PNOperationType.PNTimeOperation + || operationType == PNOperationType.PNPublishFileMessageOperation) { + JArray.Parse(jsonString); + } else { + JObject.Parse(jsonString); + } + + ret = true; + } catch { + try { + if (operationType == PNOperationType.PNPublishOperation + || operationType == PNOperationType.PNHistoryOperation + || operationType == PNOperationType.PNTimeOperation + || operationType == PNOperationType.PNPublishFileMessageOperation) { + JObject.Parse(jsonString); + ret = true; + } + } catch { + /* igonore */ + } + } + + return ret; + } + + public object BuildJsonObject(string jsonString) { + object ret = null; + + try { + var token = JToken.Parse(jsonString); + ret = token; + } catch { + /* ignore */ + } + + return ret; + } + + public bool IsDictionaryCompatible(string jsonString, PNOperationType operationType) { + bool ret = false; + if (JsonFastCheck(jsonString) && IsValidJson(jsonString, operationType)) { + try { + using (StringReader strReader = new StringReader(jsonString)) { + using (JsonTextReader jsonTxtreader = new JsonTextReader(strReader)) { + while (jsonTxtreader.Read()) { + if (jsonTxtreader.LineNumber == 1 && jsonTxtreader.LinePosition == 1 && + jsonTxtreader.TokenType == JsonToken.StartObject) { + ret = true; + break; + } else { + break; + } + } + + jsonTxtreader.Close(); + } +#if (NET35 || NET40 || NET45 || NET461 || NET48) + strReader.Close(); +#endif + } + } catch { + /* ignore */ + } + } + + return ret; + } + + public string SerializeToJsonString(object objectToSerialize) { + return JsonConvert.SerializeObject(objectToSerialize, defaultJsonSerializerSettings); + } + + public List DeserializeToListOfObject(string jsonString) { + List result = + JsonConvert.DeserializeObject>(jsonString, defaultJsonSerializerSettings); + + return result; + } + + public object DeserializeToObject(string jsonString) { + object result = JsonConvert.DeserializeObject(jsonString, + new JsonSerializerSettings { DateParseHandling = DateParseHandling.None, MaxDepth = 64 }); + if (result.GetType().ToString() == "Newtonsoft.Json.Linq.JArray") { + JArray jarrayResult = result as JArray; + List objectContainer = jarrayResult.ToObject>(); + if (objectContainer != null && objectContainer.Count > 0) { + for (int index = 0; index < objectContainer.Count; index++) { + if (objectContainer[index].GetType().ToString() == "Newtonsoft.Json.Linq.JArray") { + JArray internalItem = objectContainer[index] as JArray; + objectContainer[index] = internalItem.Select(item => (object)item).ToArray(); + } + } + + result = objectContainer; + } + } + + return result; + } + + public object DeserializeToObject(object rawObject, Type type) + { + try + { + if (rawObject is JObject jObject) + { + return jObject.ToObject(type); + } + else + { + return rawObject; + } + } + catch (Exception e) + { + LoggingMethod.WriteToLog(pubnubLog, e.ToString(), config.LogVerbosity); + return rawObject; + } + } + + public void PopulateObject(string value, object target) { + JsonConvert.PopulateObject(value, target, defaultJsonSerializerSettings); + } + + public virtual T DeserializeToObject(string jsonString) { + T ret = default(T); + + try { + ret = JsonConvert.DeserializeObject(jsonString, + new JsonSerializerSettings { DateParseHandling = DateParseHandling.None, MaxDepth = 64 }); + } catch { + /* ignore */ + } + + return ret; + } + + private bool IsGenericTypeForMessage() { + bool ret = false; + +#if (NET35 || NET40 || NET45 || NET461 || NET48) + if (typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(PNMessageResult<>)) + { + ret = true; + } + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, NET35/40 IsGenericTypeForMessage = {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ret.ToString()), config.LogVerbosity); +#elif (NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 || NETSTANDARD13 || NETSTANDARD14 || NETSTANDARD20 || NET60 || UAP || NETFX_CORE || WINDOWS_UWP) + if (typeof(T).GetTypeInfo().IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(PNMessageResult<>)) + { + ret = true; + } + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, typeof(T).GetTypeInfo().IsGenericType = {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), typeof(T).GetTypeInfo().IsGenericType.ToString()), config.LogVerbosity); + if (typeof(T).GetTypeInfo().IsGenericType) + { + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, typeof(T).GetGenericTypeDefinition() = {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), typeof(T).GetGenericTypeDefinition().ToString()), config.LogVerbosity); + } + LoggingMethod.WriteToLog(pubnubLog, string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, PCL/CORE IsGenericTypeForMessage = {1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), ret.ToString()), config.LogVerbosity); +#endif + LoggingMethod.WriteToLog(pubnubLog, + string.Format(CultureInfo.InvariantCulture, "DateTime: {0}, IsGenericTypeForMessage = {1}", + DateTime.Now.ToString(CultureInfo.InvariantCulture), ret.ToString()), config.LogVerbosity); + return ret; + } + + private T DeserializeMessageToObjectBasedOnPlatform(List listObject) { + T ret = default(T); + +#if NET35 || NET40 || NET45 || NET461 || NET48 + Type dataType = typeof(T).GetGenericArguments()[0]; + Type generic = typeof(PNMessageResult<>); + Type specific = generic.MakeGenericType(dataType); + + ConstructorInfo ci = specific.GetConstructors().FirstOrDefault(); + if (ci != null) + { + object message = ci.Invoke(new object[] { }); + + //Set data + PropertyInfo dataProp = specific.GetProperty("Message"); + + object userMessage = null; + if (listObject[0].GetType() == typeof(Newtonsoft.Json.Linq.JValue)) + { + JValue jsonValue = listObject[0] as JValue; + userMessage = jsonValue.Value; + userMessage = ConvertToDataType(dataType, userMessage); + + dataProp.SetValue(message, userMessage, null); + } + else if (listObject[0].GetType() == typeof(Newtonsoft.Json.Linq.JObject) || listObject[0].GetType() == typeof(Newtonsoft.Json.Linq.JArray)) + { + JToken token = listObject[0] as JToken; + if (dataProp.PropertyType == typeof(string)) + { + userMessage = JsonConvert.SerializeObject(token, defaultJsonSerializerSettings); + } + else + { + userMessage = token.ToObject(dataProp.PropertyType, JsonSerializer.Create()); + } + + dataProp.SetValue(message, userMessage, null); + } + else if (listObject[0].GetType() == typeof(System.String)) + { + userMessage = listObject[0] as string; + dataProp.SetValue(message, userMessage, null); + } + + //Set Time + PropertyInfo timeProp = specific.GetProperty("Timetoken"); + long timetoken; + var _ = Int64.TryParse(listObject[2].ToString(), out timetoken); + timeProp.SetValue(message, timetoken, null); + + //Set Publisher + PropertyInfo publisherProp = specific.GetProperty("Publisher"); + string publisherValue = (listObject[3] != null) ? listObject[3].ToString() : ""; + publisherProp.SetValue(message, publisherValue, null); + + // Set ChannelName + PropertyInfo channelNameProp = specific.GetProperty("Channel"); + channelNameProp.SetValue(message, (listObject.Count == 6) ? listObject[5].ToString() : listObject[4].ToString(), null); + + // Set ChannelGroup + if (listObject.Count == 6) + { + PropertyInfo subsciptionProp = specific.GetProperty("Subscription"); + subsciptionProp.SetValue(message, listObject[4].ToString(), null); + } + + //Set Metadata list second position, index=1 + if (listObject[1] != null) + { + PropertyInfo userMetadataProp = specific.GetProperty("UserMetadata"); + userMetadataProp.SetValue(message, listObject[1], null); + } + + ret = (T)Convert.ChangeType(message, specific, CultureInfo.InvariantCulture); + } +#elif NETSTANDARD10 || NETSTANDARD11 || NETSTANDARD12 || NETSTANDARD13 || NETSTANDARD14 || NETSTANDARD20 || NET60 || UAP || NETFX_CORE || WINDOWS_UWP + Type dataType = typeof(T).GetTypeInfo().GenericTypeArguments[0]; + Type generic = typeof(PNMessageResult<>); + Type specific = generic.MakeGenericType(dataType); + + ConstructorInfo ci = specific.GetTypeInfo().DeclaredConstructors.FirstOrDefault(); + if (ci != null) + { + object message = ci.Invoke(new object[] { }); + + //Set data + PropertyInfo dataProp = specific.GetRuntimeProperty("Message"); + + object userMessage = null; + if (listObject[0].GetType() == typeof(Newtonsoft.Json.Linq.JValue)) + { + JValue jsonValue = listObject[0] as JValue; + userMessage = jsonValue.Value; + userMessage = ConvertToDataType(dataType, userMessage); + + dataProp.SetValue(message, userMessage, null); + } + else if (listObject[0].GetType() == typeof(Newtonsoft.Json.Linq.JObject) || listObject[0].GetType() == typeof(Newtonsoft.Json.Linq.JArray)) + { + JToken token = listObject[0] as JToken; + if (dataProp.PropertyType == typeof(string)) + { + userMessage = JsonConvert.SerializeObject(token, defaultJsonSerializerSettings); + } + else + { + userMessage = token.ToObject(dataProp.PropertyType, JsonSerializer.Create()); + } + + dataProp.SetValue(message, userMessage, null); + } + else if (listObject[0].GetType() == typeof(System.String)) + { + userMessage = listObject[0] as string; + dataProp.SetValue(message, userMessage, null); + } + + //Set Time + PropertyInfo timeProp = specific.GetRuntimeProperty("Timetoken"); + long timetoken; + Int64.TryParse(listObject[2].ToString(), out timetoken); + timeProp.SetValue(message, timetoken, null); + + //Set Publisher + PropertyInfo publisherProp = specific.GetRuntimeProperty("Publisher"); + string publisherValue = (listObject[3] != null) ? listObject[3].ToString() : ""; + publisherProp.SetValue(message, publisherValue, null); + + // Set ChannelName + PropertyInfo channelNameProp = specific.GetRuntimeProperty("Channel"); + channelNameProp.SetValue(message, (listObject.Count == 6) ? listObject[5].ToString() : listObject[4].ToString(), null); + + // Set ChannelGroup + if (listObject.Count == 6) + { + PropertyInfo subsciptionProp = specific.GetRuntimeProperty("Subscription"); + subsciptionProp.SetValue(message, listObject[4].ToString(), null); + } + + //Set Metadata list second position, index=1 + if (listObject[1] != null) + { + PropertyInfo userMetadataProp = specific.GetRuntimeProperty("UserMetadata"); + userMetadataProp.SetValue(message, listObject[1], null); + } + + ret = (T)Convert.ChangeType(message, specific, CultureInfo.InvariantCulture); + } +#endif + + return ret; + } + + public virtual T DeserializeToObject(List listObject) { + T ret = default(T); + + if (listObject == null) { + return ret; + } + + if (IsGenericTypeForMessage()) { + #region "Subscribe Message<>" + + return DeserializeMessageToObjectBasedOnPlatform(listObject); + + #endregion + } else { + return DeserializeToInternalObjectUtility.DeserializeToInternalObject(this, listObject); + } + } + + public Dictionary DeserializeToDictionaryOfObject(string jsonString) { + Dictionary result = null; + try { + if (JsonFastCheck(jsonString)) { + result = JsonConvert.DeserializeObject>(jsonString, + defaultJsonSerializerSettings); + } + } catch { + //ignore + } + + return result; + } + + public Dictionary ConvertToDictionaryObject(object localContainer) { + Dictionary ret = null; + + try { + if (localContainer != null) { + if (localContainer.GetType().ToString() == "Newtonsoft.Json.Linq.JObject") { + ret = new Dictionary(); + + IDictionary jsonDictionary = localContainer as JObject; + if (jsonDictionary != null) { + foreach (KeyValuePair pair in jsonDictionary) { + JToken token = pair.Value; + ret.Add(pair.Key, ConvertJTokenToObject(token)); + } + } + } else if (localContainer.GetType().ToString() == + "System.Collections.Generic.Dictionary`2[System.String,System.Object]") { + ret = new Dictionary(); + Dictionary dictionary = localContainer as Dictionary; + foreach (string key in dictionary.Keys) { + ret.Add(key, dictionary[key]); + } + } else if (localContainer.GetType().ToString() == "Newtonsoft.Json.Linq.JProperty") { + ret = new Dictionary(); + + JProperty jsonProp = localContainer as JProperty; + if (jsonProp != null) { + string propName = jsonProp.Name; + ret.Add(propName, ConvertJTokenToObject(jsonProp.Value)); + } + } else if (localContainer.GetType().ToString() == + "System.Collections.Generic.List`1[System.Object]") { + List localList = localContainer as List; + if (localList != null) { + if (localList.Count > 0 && localList[0].GetType() == typeof(KeyValuePair)) { + ret = new Dictionary(); + foreach (object item in localList) { + if (item is KeyValuePair kvpItem) { + ret.Add(kvpItem.Key, kvpItem.Value); + } else { + ret = null; + break; + } + } + } else if (localList.Count == 1 && + localList[0].GetType() == typeof(Dictionary)) { + ret = new Dictionary(); + + Dictionary localDic = localList[0] as Dictionary; + foreach (object item in localDic) { + if (item is KeyValuePair kvpItem) { + ret.Add(kvpItem.Key, kvpItem.Value); + } else { + ret = null; + break; + } + } + } + } + } + } + } catch { + /* ignore */ + } + + return ret; + } + + public object[] ConvertToObjectArray(object localContainer) { + object[] ret = null; + + try { + if (localContainer.GetType().ToString() == "Newtonsoft.Json.Linq.JArray") { + JArray jarrayResult = localContainer as JArray; + List objectContainer = jarrayResult.ToObject>(); + if (objectContainer != null && objectContainer.Count > 0) { + for (int index = 0; index < objectContainer.Count; index++) { + if (objectContainer[index].GetType().ToString() == "Newtonsoft.Json.Linq.JArray") { + JArray internalItem = objectContainer[index] as JArray; + objectContainer[index] = internalItem.Select(item => (object)item).ToArray(); + } + } + + ret = objectContainer.ToArray(); + } + } else if (localContainer.GetType().ToString() == "System.Collections.Generic.List`1[System.Object]") { + List listResult = localContainer as List; + ret = listResult.ToArray(); + } + } catch { + /* ignore */ + } + + return ret; + } + + public static bool JsonFastCheck(string rawJson) { + var c = rawJson.TrimStart()[0]; + return c == '[' || c == '{'; + } + + private static object ConvertJTokenToObject(JToken token) { + if (token == null) { + return null; + } + + var jsonValue = token as JValue; + if (jsonValue != null) { + return jsonValue.Value; + } + + var jsonContainer = token as JArray; + if (jsonContainer != null) { + List jsonList = new List(); + foreach (JToken arrayItem in jsonContainer) { + jsonList.Add(ConvertJTokenToObject(arrayItem)); + } + + return jsonList; + } + + IDictionary jsonObject = token as JObject; + if (jsonObject != null) { + var jsonDict = new Dictionary(); + List propertyList = (from childToken in token + where childToken is JProperty + select childToken as JProperty).ToList(); + foreach (JProperty property in propertyList) { + jsonDict.Add(property.Name, ConvertJTokenToObject(property.Value)); + } + + return jsonDict; + } + + return null; + } + + private static object ConvertToDataType(Type dataType, object inputValue) { + if (dataType == inputValue.GetType()) { + return inputValue; + } + + object userMessage = inputValue; + switch (dataType.FullName) { + case "System.Int32": + userMessage = Convert.ChangeType(inputValue, typeof(System.Int32), CultureInfo.InvariantCulture); + break; + case "System.Int16": + userMessage = Convert.ChangeType(inputValue, typeof(System.Int16), CultureInfo.InvariantCulture); + break; + case "System.UInt64": + userMessage = Convert.ChangeType(inputValue, typeof(System.UInt64), CultureInfo.InvariantCulture); + break; + case "System.UInt32": + userMessage = Convert.ChangeType(inputValue, typeof(System.UInt32), CultureInfo.InvariantCulture); + break; + case "System.UInt16": + userMessage = Convert.ChangeType(inputValue, typeof(System.UInt16), CultureInfo.InvariantCulture); + break; + case "System.Byte": + userMessage = Convert.ChangeType(inputValue, typeof(System.Byte), CultureInfo.InvariantCulture); + break; + case "System.SByte": + userMessage = Convert.ChangeType(inputValue, typeof(System.SByte), CultureInfo.InvariantCulture); + break; + case "System.Decimal": + userMessage = Convert.ChangeType(inputValue, typeof(System.Decimal), CultureInfo.InvariantCulture); + break; + case "System.Boolean": + userMessage = Convert.ChangeType(inputValue, typeof(System.Boolean), CultureInfo.InvariantCulture); + break; + case "System.Double": + userMessage = Convert.ChangeType(inputValue, typeof(System.Double), CultureInfo.InvariantCulture); + break; + case "System.Char": + userMessage = Convert.ChangeType(inputValue, typeof(System.Char), CultureInfo.InvariantCulture); + break; + case "System.String": + userMessage = Convert.ChangeType(inputValue, typeof(System.String), CultureInfo.InvariantCulture); + break; + case "System.Object": + userMessage = Convert.ChangeType(inputValue, typeof(System.Object), CultureInfo.InvariantCulture); + break; + default: + break; + } + + return userMessage; + } + + #endregion + } +} \ No newline at end of file diff --git a/PubNubUnity/Assets/PubNub/Runtime/Util/NewtonsoftJsonUnity.cs.meta b/PubNubUnity/Assets/PubNub/Runtime/Util/NewtonsoftJsonUnity.cs.meta new file mode 100644 index 00000000..0137ba9c --- /dev/null +++ b/PubNubUnity/Assets/PubNub/Runtime/Util/NewtonsoftJsonUnity.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2b8bd38fe64c4d1682527467510ac874 +timeCreated: 1713964809 \ No newline at end of file diff --git a/PubNubUnity/Assets/PubNub/Runtime/Util/PNManagerBehaviour.cs b/PubNubUnity/Assets/PubNub/Runtime/Util/PNManagerBehaviour.cs index 9fbc2964..ff4c3997 100644 --- a/PubNubUnity/Assets/PubNub/Runtime/Util/PNManagerBehaviour.cs +++ b/PubNubUnity/Assets/PubNub/Runtime/Util/PNManagerBehaviour.cs @@ -1,3 +1,4 @@ +using PubnubApi.Unity.PubNub.Runtime.Util; using UnityEngine; namespace PubnubApi.Unity { @@ -36,6 +37,7 @@ public Pubnub Initialize(string userId) { pnConfiguration.UserId = userId; pubnub = new Pubnub(pnConfiguration); + pubnub.SetJsonPluggableLibrary(new NewtonsoftJsonUnity(pnConfiguration, ((PNConfiguration)pnConfiguration).PubnubLog)); pubnub.AddListener(listener); return pubnub;