Skip to content

Commit

Permalink
Fix for hard-coded nu-get Newtonsoft usage in C# SDK causing Unity IL…
Browse files Browse the repository at this point in the history
…2CPP builds to crash (#219)

* fix: expose way to deserialize to internal object from external IJsonPluggableLibrary implementations, remove duplicate/non-IJsonPluggableLibrary-based deserialization logic

* fix: remove direct Newtonsoft usage from EmitMessagesHandler

* fix: handling error status in subscribe

* PubNub SDK v6.20.1.0 release.

---------

Co-authored-by: Mohit Tejani <[email protected]>
Co-authored-by: PubNub Release Bot <[email protected]>
  • Loading branch information
3 people authored May 9, 2024
1 parent 325cae0 commit 3718f01
Show file tree
Hide file tree
Showing 39 changed files with 1,295 additions and 1,357 deletions.
19 changes: 12 additions & 7 deletions .pubnub.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
name: c-sharp
version: "6.20.0"
version: "6.20.1"
schema: 1
scm: github.com/pubnub/c-sharp
changelog:
- date: 2024-05-09
version: v6.20.1
changes:
- type: bug
text: "Fixes issue of Unity SDK not being able to have a fully independent IJsonPluggableLibrary implementation because of direct nu-get Newtonsoft usage in C# SDK (Unity has it's own version that works with IL2CPP builds)."
- date: 2024-04-18
version: v6.20.0
changes:
Expand Down Expand Up @@ -783,7 +788,7 @@ features:
- QUERY-PARAM
supported-platforms:
-
version: Pubnub 'C#' 6.20.0
version: Pubnub 'C#' 6.20.1
platforms:
- Windows 10 and up
- Windows Server 2008 and up
Expand All @@ -793,7 +798,7 @@ supported-platforms:
- .Net Framework 4.5
- .Net Framework 4.6.1+
-
version: PubnubPCL 'C#' 6.20.0
version: PubnubPCL 'C#' 6.20.1
platforms:
- Xamarin.Android
- Xamarin.iOS
Expand All @@ -813,7 +818,7 @@ supported-platforms:
- .Net Core
- .Net 6.0
-
version: PubnubUWP 'C#' 6.20.0
version: PubnubUWP 'C#' 6.20.1
platforms:
- Windows Phone 10
- Universal Windows Apps
Expand All @@ -837,7 +842,7 @@ sdks:
distribution-type: source
distribution-repository: GitHub
package-name: Pubnub
location: https://github.com/pubnub/c-sharp/releases/tag/v6.20.0.0
location: https://github.com/pubnub/c-sharp/releases/tag/v6.20.1.0
requires:
-
name: ".Net"
Expand Down Expand Up @@ -1120,7 +1125,7 @@ sdks:
distribution-type: source
distribution-repository: GitHub
package-name: PubNubPCL
location: https://github.com/pubnub/c-sharp/releases/tag/v6.20.0.0
location: https://github.com/pubnub/c-sharp/releases/tag/v6.20.1.0
requires:
-
name: ".Net Core"
Expand Down Expand Up @@ -1479,7 +1484,7 @@ sdks:
distribution-type: source
distribution-repository: GitHub
package-name: PubnubUWP
location: https://github.com/pubnub/c-sharp/releases/tag/v6.20.0.0
location: https://github.com/pubnub/c-sharp/releases/tag/v6.20.1.0
requires:
-
name: "Universal Windows Platform Development"
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
v6.20.1 - May 09 2024
-----------------------------
- Fixed: fixes issue of Unity SDK not being able to have a fully independent IJsonPluggableLibrary implementation because of direct nu-get Newtonsoft usage in C# SDK (Unity has it's own version that works with IL2CPP builds).

v6.20.0 - April 18 2024
-----------------------------
- Added: added event engine implementation for subscribe and presence operation.
Expand Down
2 changes: 1 addition & 1 deletion src/Api/PubnubApi/EndPoint/PubSub/SubscribeEndpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ private void Subscribe(string[] channels, string[] channelGroups, SubscriptionCu
} else {
var subscribeManager = new SubscribeManager2(config, jsonLibrary, unit, pubnubLog, pubnubTelemetryMgr, pubnubTokenMgr, PubnubInstance);
var eventEmitter = new EventEmitter(config, SubscribeListenerList, jsonLibrary, pubnubTokenMgr, pubnubLog, PubnubInstance);
subscribeEventEngine = subscribeEventEngineFactory.InitializeEventEngine(instanceId, PubnubInstance, config, subscribeManager, eventEmitter, StatusEmitter);
subscribeEventEngine = subscribeEventEngineFactory.InitializeEventEngine(instanceId, PubnubInstance, config, subscribeManager, eventEmitter, jsonLibrary, StatusEmitter);
subscribeEventEngine.OnStateTransition += SubscribeEventEngine_OnStateTransition;
subscribeEventEngine.OnEventQueued += SubscribeEventEngine_OnEventQueued;
subscribeEventEngine.OnEffectDispatch += SubscribeEventEngine_OnEffectDispatch;
Expand Down
8 changes: 6 additions & 2 deletions src/Api/PubnubApi/EndPoint/PubSub/SubscribeManager2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public async Task<Tuple<HandshakeResponse, PNStatus>> HandshakeRequest(PNOperati
if (!string.IsNullOrEmpty(responseTuple.Item1) && responseTuple.Item2 == null)
{
PNStatus status = new PNStatus(null, PNOperationType.PNSubscribeOperation, PNStatusCategory.PNConnectedCategory, channels, channelGroups);
HandshakeResponse handshakeResponse = JsonConvert.DeserializeObject<HandshakeResponse>(responseTuple.Item1);
HandshakeResponse handshakeResponse = jsonLibrary.DeserializeToObject<HandshakeResponse>(responseTuple.Item1);
return new Tuple<HandshakeResponse, PNStatus>(handshakeResponse, status);
}

Expand Down Expand Up @@ -170,7 +170,7 @@ internal async Task<Tuple<ReceivingResponse<object>, PNStatus>> ReceiveRequest<T
if (!string.IsNullOrEmpty(responseTuple.Item1) && responseTuple.Item2 == null)
{
PNStatus status = new PNStatus(null, PNOperationType.PNSubscribeOperation, PNStatusCategory.PNConnectedCategory, channels, channelGroups);
ReceivingResponse<object> receiveResponse = JsonConvert.DeserializeObject<ReceivingResponse<object>>(responseTuple.Item1);
ReceivingResponse<object> receiveResponse = jsonLibrary.DeserializeToObject<ReceivingResponse<object>>(responseTuple.Item1);
return new Tuple<ReceivingResponse<object>, PNStatus>(receiveResponse, status);
}
else if (responseTuple.Item2 != null)
Expand Down Expand Up @@ -550,6 +550,10 @@ private PNStatus GetStatusIfError<T>(RequestState<T> asyncRequestState, string j
status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse<T>(type, category, asyncRequestState, statusCode, new PNException(jsonString));
}
}
else if (deserializeStatus.ContainsKey("message") && statusCode != 200) {
PNStatusCategory category = PNStatusCategoryHelper.GetPNStatusCategory(statusCode, deserializeStatus["message"].ToString());
status = new StatusBuilder(config, jsonLibrary).CreateStatusResponse<T>(type, category, asyncRequestState, statusCode, new PNException(jsonString));
}

}
else if (jsonString.ToLowerInvariant().TrimStart().IndexOf("<head", StringComparison.CurrentCultureIgnoreCase) == 0
Expand Down
4 changes: 2 additions & 2 deletions src/Api/PubnubApi/EventEngine/Common/EventEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,13 @@ public void EmitEvent<T>(object e)
Timetoken = pnFileResult.Timetoken,
Publisher = pnFileResult.Publisher,
};
Dictionary<string, object> pnMsgObjDic = JsonDataParseInternalUtil.ConvertToDictionaryObject(pnFileResult.Message);
Dictionary<string, object> pnMsgObjDic = jsonLibrary.ConvertToDictionaryObject(pnFileResult.Message);
if (pnMsgObjDic != null && pnMsgObjDic.Count > 0) {
if (pnMsgObjDic.ContainsKey("message") && pnMsgObjDic["message"] != null) {
fileMessage.Message = pnMsgObjDic["message"];
}
if (pnMsgObjDic.ContainsKey("file")) {
Dictionary<string, object> fileObjDic = JsonDataParseInternalUtil.ConvertToDictionaryObject(pnMsgObjDic["file"]);
Dictionary<string, object> fileObjDic = jsonLibrary.ConvertToDictionaryObject(pnMsgObjDic["file"]);
if (fileObjDic != null && fileObjDic.ContainsKey("id") && fileObjDic.ContainsKey("name")) {
fileMessage.File = new PNFile { Id = fileObjDic["id"].ToString(), Name = fileObjDic["name"].ToString() };

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PubnubApi.EventEngine.Common;
using PubnubApi.EventEngine.Core;
using PubnubApi.EventEngine.Subscribe.Invocations;
Expand All @@ -14,18 +12,18 @@ public class EmitMessagesHandler : EffectHandler<EmitMessagesInvocation>
{
private readonly Dictionary<string, Type> channelTypeMap;
private readonly Dictionary<string, Type> channelGroupTypeMap;
private readonly JsonSerializer serializer;
private readonly IJsonPluggableLibrary jsonPluggableLibrary;
private readonly EventEmitter eventEmitter;

public EmitMessagesHandler(EventEmitter eventEmitter,
JsonSerializer serializer,
IJsonPluggableLibrary jsonPluggableLibrary,
Dictionary<string, Type> channelTypeMap = null,
Dictionary<string, Type> channelGroupTypeMap = null)
{
this.eventEmitter = eventEmitter;
this.channelTypeMap = channelTypeMap;
this.channelGroupTypeMap = channelGroupTypeMap;
this.serializer = serializer;
this.jsonPluggableLibrary = jsonPluggableLibrary;
}

public async override Task Run(EmitMessagesInvocation invocation)
Expand All @@ -45,17 +43,14 @@ public async override Task Run(EmitMessagesInvocation invocation)
private object DeserializePayload(string key, object rawMessage)
{
try {
if (rawMessage is JObject message) {
Type t;
if ((channelTypeMap is not null && channelTypeMap.TryGetValue(key, out t) ||
channelGroupTypeMap is not null && channelGroupTypeMap.TryGetValue(key, out t)) &&
t != typeof(string)) {
return message.ToObject(t, serializer);
} else {
return message.ToString(Formatting.None);
}
Type t;
if ((channelTypeMap is not null && channelTypeMap.TryGetValue(key, out t) ||
channelGroupTypeMap is not null && channelGroupTypeMap.TryGetValue(key, out t)) &&
t != typeof(string))
{
return jsonPluggableLibrary.DeserializeToObject(rawMessage, t);
} else {
return rawMessage;
return rawMessage.ToString();
}
} catch (Exception) {
return rawMessage;
Expand Down
12 changes: 4 additions & 8 deletions src/Api/PubnubApi/EventEngine/Subscribe/SubscribeEventEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
using System.Collections.Generic;
using System.Linq;
using PubnubApi.EventEngine.Subscribe.Common;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using PubnubApi.EventEngine.Subscribe.Events;
using PubnubApi.EventEngine.Common;
Expand All @@ -17,11 +15,7 @@ public class SubscribeEventEngine : Engine
private SubscribeManager2 subscribeManager;
private readonly Dictionary<string, Type> channelTypeMap = new Dictionary<string, Type>();
private readonly Dictionary<string, Type> channelGroupTypeMap = new Dictionary<string, Type>();

private static readonly JsonSerializerSettings SerializerSettings = new JsonSerializerSettings()
{ Formatting = Formatting.None, DateParseHandling = DateParseHandling.None };
private static readonly JsonSerializer Serializer = JsonSerializer.Create(SerializerSettings);

private readonly IJsonPluggableLibrary jsonPluggableLibrary;

public string[] Channels { get; set; } = new string[] {};
public string[] Channelgroups { get; set; } = new string[] {};
Expand All @@ -30,9 +24,11 @@ internal SubscribeEventEngine(Pubnub pubnubInstance,
PNConfiguration pubnubConfiguration,
SubscribeManager2 subscribeManager,
EventEmitter eventEmitter,
IJsonPluggableLibrary jsonPluggableLibrary,
Action<Pubnub, PNStatus> statusListener = null)
{
this.subscribeManager = subscribeManager;
this.jsonPluggableLibrary = jsonPluggableLibrary;
var handshakeHandler = new Effects.HandshakeEffectHandler(subscribeManager, EventQueue);
var handshakeReconnectHandler = new Effects.HandshakeReconnectEffectHandler(pubnubConfiguration, EventQueue, handshakeHandler);

Expand All @@ -49,7 +45,7 @@ internal SubscribeEventEngine(Pubnub pubnubInstance,
dispatcher.Register<Invocations.ReceiveReconnectInvocation, Effects.ReceivingReconnectEffectHandler>(receiveReconnectHandler);
dispatcher.Register<Invocations.CancelReceiveReconnectInvocation, Effects.ReceivingReconnectEffectHandler>(receiveReconnectHandler);

var emitMessageHandler = new Effects.EmitMessagesHandler(eventEmitter, Serializer, channelTypeMap, channelGroupTypeMap);
var emitMessageHandler = new Effects.EmitMessagesHandler(eventEmitter, jsonPluggableLibrary, channelTypeMap, channelGroupTypeMap);
dispatcher.Register<Invocations.EmitMessagesInvocation, Effects.EmitMessagesHandler>(emitMessageHandler);

var emitStatusHandler = new Effects.EmitStatusEffectHandler(pubnubInstance, statusListener);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@ internal SubscribeEventEngine InitializeEventEngine(string instanceId,
PNConfiguration pubnubConfiguration,
SubscribeManager2 subscribeManager,
EventEmitter eventEmitter,
IJsonPluggableLibrary jsonPluggableLibrary,
Action<Pubnub, PNStatus> statusListener = null)
{

var subscribeEventEngine = new SubscribeEventEngine(pubnubInstance, pubnubConfiguration: pubnubConfiguration, subscribeManager,eventEmitter, statusListener);
var subscribeEventEngine = new SubscribeEventEngine(pubnubInstance, pubnubConfiguration: pubnubConfiguration, subscribeManager,eventEmitter, jsonPluggableLibrary, statusListener);
if (engineInstances.TryAdd(instanceId, subscribeEventEngine)) {
return subscribeEventEngine;
}
Expand Down
8 changes: 6 additions & 2 deletions src/Api/PubnubApi/Interface/IJsonPluggableLibrary.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;

namespace PubnubApi
{
Expand All @@ -17,7 +19,9 @@ public interface IJsonPluggableLibrary
T DeserializeToObject<T>(string jsonString);

T DeserializeToObject<T>(List<object> listObject);


object DeserializeToObject(object rawObject, Type type);

Dictionary<string, object> DeserializeToDictionaryOfObject(string jsonString);

Dictionary<string, object> ConvertToDictionaryObject(object localContainer);
Expand Down
Loading

0 comments on commit 3718f01

Please sign in to comment.