diff --git a/AuthHost/AuthHost.csproj b/AuthHost/AuthHost.csproj
index 73babaf0..d4eb627c 100644
--- a/AuthHost/AuthHost.csproj
+++ b/AuthHost/AuthHost.csproj
@@ -36,6 +36,15 @@
4
false
+
+ bin\UnityRelease\
+ TRACE
+ true
+ pdbonly
+ AnyCPU
+ prompt
+ MinimumRecommendedRules.ruleset
+
..\packages\Nancy.1.4.4\lib\net40\Nancy.dll
diff --git a/ExampleApplication/ExampleApplication.csproj b/ExampleApplication/ExampleApplication.csproj
index bc246543..cd4f0cd1 100644
--- a/ExampleApplication/ExampleApplication.csproj
+++ b/ExampleApplication/ExampleApplication.csproj
@@ -36,6 +36,15 @@
4
false
+
+ bin\UnityRelease\
+ TRACE
+ true
+ pdbonly
+ AnyCPU
+ prompt
+ MinimumRecommendedRules.ruleset
+
..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll
diff --git a/PusherClient.Tests.Utilities/PusherClient.Tests.Utilities.csproj b/PusherClient.Tests.Utilities/PusherClient.Tests.Utilities.csproj
index 33c0446b..efa2a3bd 100644
--- a/PusherClient.Tests.Utilities/PusherClient.Tests.Utilities.csproj
+++ b/PusherClient.Tests.Utilities/PusherClient.Tests.Utilities.csproj
@@ -32,6 +32,15 @@
prompt
4
+
+ bin\UnityRelease\
+ TRACE
+ true
+ pdbonly
+ AnyCPU
+ prompt
+ MinimumRecommendedRules.ruleset
+
..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll
diff --git a/PusherClient.Tests/AcceptanceTests/EventEmitter.cs b/PusherClient.Tests/AcceptanceTests/EventEmitter.cs
index 7a016996..fd633a1a 100644
--- a/PusherClient.Tests/AcceptanceTests/EventEmitter.cs
+++ b/PusherClient.Tests/AcceptanceTests/EventEmitter.cs
@@ -17,7 +17,7 @@ public void EventEmitterShouldEmitAnEventToARegisteredListener()
var myAction = new Action(o => emittedEvent = o);
- var emitter = new PusherClient.EventEmitter();
+ var emitter = new PusherClient.EventEmitter(new NewtonsoftJsonSerializer());
emitter.Bind("listener event", myAction);
// Act
@@ -36,7 +36,7 @@ public void EventEmitterShouldEmitAnEventToARegisteredRawListener()
var myAction = new Action(o => emittedEvent = o);
- var emitter = new PusherClient.EventEmitter();
+ var emitter = new PusherClient.EventEmitter(new NewtonsoftJsonSerializer());
emitter.Bind("raw listener event", myAction);
// Act
@@ -55,7 +55,7 @@ public void EventEmitterShouldEmitAnEventToARegisteredPusherEventListener()
var myAction = new Action(o => emittedEvent = o);
- var emitter = new PusherClient.EventEmitter();
+ var emitter = new PusherClient.EventEmitter(new NewtonsoftJsonSerializer());
emitter.Bind("pusher event listener event", myAction);
// Act
@@ -75,7 +75,7 @@ public void EventEmitterShouldEmitAnEventToARegisteredGeneralListener()
var myAction = new Action((e, o) => emittedEvent = new Tuple(e, o));
- var emitter = new PusherClient.EventEmitter();
+ var emitter = new PusherClient.EventEmitter(new NewtonsoftJsonSerializer());
emitter.BindAll(myAction);
// Act
@@ -95,7 +95,7 @@ public void EventEmitterShouldEmitAnEventToARegisteredRawGeneralListener()
var myAction = new Action((e, o) => emittedEvent = new Tuple(e, o));
- var emitter = new PusherClient.EventEmitter();
+ var emitter = new PusherClient.EventEmitter(new NewtonsoftJsonSerializer());
emitter.BindAll(myAction);
// Act
@@ -115,7 +115,7 @@ public void EventEmitterShouldEmitAnEventToARegisteredPusherEventGeneralListener
var myAction = new Action((e, o) => emittedEvent = new Tuple(e, o));
- var emitter = new PusherClient.EventEmitter();
+ var emitter = new PusherClient.EventEmitter(new NewtonsoftJsonSerializer());
emitter.BindAll(myAction);
// Act
@@ -137,7 +137,7 @@ public void EventEmitterShouldNotEmitAnEventToAnUnregisteredListener()
var myAction = new Action(o => emittedEvent = o);
var myAction2 = new Action(o => emittedEvent2 = o);
- var emitter = new PusherClient.EventEmitter();
+ var emitter = new PusherClient.EventEmitter(new NewtonsoftJsonSerializer());
emitter.Bind("listener event", myAction);
emitter.Bind("listener event", myAction2);
emitter.Unbind("listener event", myAction);
@@ -160,7 +160,7 @@ public void EventEmitterShouldNotEmitAnEventToAnUnregisteredRawListener()
var myAction = new Action(o => emittedEvent = o);
var myAction2 = new Action(o => emittedEvent2 = o);
- var emitter = new PusherClient.EventEmitter();
+ var emitter = new PusherClient.EventEmitter(new NewtonsoftJsonSerializer());
emitter.Bind("raw listener event", myAction);
emitter.Bind("raw listener event", myAction2);
emitter.Unbind("raw listener event", myAction);
@@ -183,7 +183,7 @@ public void EventEmitterShouldNotEmitAnEventToAnUnregisteredPusherEventListener(
var myAction = new Action(o => emittedEvent = o);
var myAction2 = new Action(o => emittedEvent2 = o);
- var emitter = new PusherClient.EventEmitter();
+ var emitter = new PusherClient.EventEmitter(new NewtonsoftJsonSerializer());
emitter.Bind("pusher event listener event", myAction);
emitter.Bind("pusher event listener event", myAction2);
emitter.Unbind("pusher event listener event", myAction);
@@ -206,7 +206,7 @@ public void EventEmitterShouldNotEmitAnEventToAnUnregisteredEventName()
var myAction = new Action(o => emittedEvent = o);
var myAction2 = new Action(o => emittedEvent2 = o);
- var emitter = new PusherClient.EventEmitter();
+ var emitter = new PusherClient.EventEmitter(new NewtonsoftJsonSerializer());
emitter.Bind("listener event", myAction);
emitter.Bind("listener event", myAction2);
emitter.Unbind("listener event");
@@ -229,7 +229,7 @@ public void EventEmitterShouldNotEmitAnEventToAnUnregisteredRawEventName()
var myAction = new Action(o => emittedEvent = o);
var myAction2 = new Action(o => emittedEvent2 = o);
- var emitter = new PusherClient.EventEmitter();
+ var emitter = new PusherClient.EventEmitter(new NewtonsoftJsonSerializer());
emitter.Bind("raw listener event", myAction);
emitter.Bind("raw listener event", myAction2);
emitter.Unbind("raw listener event");
@@ -252,7 +252,7 @@ public void EventEmitterShouldNotEmitAnEventToAnUnregisteredPusherEventEventName
var myAction = new Action(o => emittedEvent = o);
var myAction2 = new Action(o => emittedEvent2 = o);
- var emitter = new PusherClient.EventEmitter();
+ var emitter = new PusherClient.EventEmitter(new NewtonsoftJsonSerializer());
emitter.Bind("pusher event listener event", myAction);
emitter.Bind("pusher event listener event", myAction2);
emitter.Unbind("pusher event listener event");
@@ -273,7 +273,7 @@ public void EventEmitterShouldNotEmitAnEventToAnUnregisteredGeneralListener()
var myAction = new Action((e, o) => emittedEvent = new Tuple(e, o));
- var emitter = new PusherClient.EventEmitter();
+ var emitter = new PusherClient.EventEmitter(new NewtonsoftJsonSerializer());
emitter.BindAll(myAction);
emitter.UnbindAll();
@@ -292,7 +292,7 @@ public void EventEmitterShouldNotEmitAnEventToAnUnregisteredRawGeneralListener()
var myAction = new Action((e, o) => emittedEvent = new Tuple(e, o));
- var emitter = new PusherClient.EventEmitter();
+ var emitter = new PusherClient.EventEmitter(new NewtonsoftJsonSerializer());
emitter.BindAll(myAction);
emitter.UnbindAll();
@@ -311,7 +311,7 @@ public void EventEmitterShouldNotEmitAnEventToAnUnregisteredPusherEventGeneralLi
var myAction = new Action((e, o) => emittedEvent = new Tuple(e, o));
- var emitter = new PusherClient.EventEmitter();
+ var emitter = new PusherClient.EventEmitter(new NewtonsoftJsonSerializer());
emitter.BindAll(myAction);
emitter.UnbindAll();
diff --git a/PusherClient.Tests/PusherClient.Tests.csproj b/PusherClient.Tests/PusherClient.Tests.csproj
index 6f0d8862..b9857344 100644
--- a/PusherClient.Tests/PusherClient.Tests.csproj
+++ b/PusherClient.Tests/PusherClient.Tests.csproj
@@ -34,6 +34,15 @@
prompt
4
+
+ bin\UnityRelease\
+ TRACE
+ true
+ pdbonly
+ AnyCPU
+ prompt
+ MinimumRecommendedRules.ruleset
+
..\packages\Castle.Core.4.2.1\lib\net45\Castle.Core.dll
diff --git a/PusherClient/Channel.cs b/PusherClient/Channel.cs
index f9bcc764..0578da15 100644
--- a/PusherClient/Channel.cs
+++ b/PusherClient/Channel.cs
@@ -32,6 +32,8 @@ internal Channel(string channelName, ITriggerChannels pusher)
{
_pusher = pusher;
Name = channelName;
+
+ JsonSerializer = pusher.JsonSerializer;
}
internal virtual void SubscriptionSucceeded(string data)
diff --git a/PusherClient/Connection.cs b/PusherClient/Connection.cs
index c24102a7..cfd70857 100644
--- a/PusherClient/Connection.cs
+++ b/PusherClient/Connection.cs
@@ -3,15 +3,15 @@
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using WebSocket4Net;
+using WebSocketSharp;
+using PusherClient.Messages;
namespace PusherClient
{
internal class Connection
{
private WebSocket _websocket;
+ private Timer _pingTimer;
private readonly string _url;
private readonly IPusher _pusher;
@@ -54,18 +54,14 @@ internal Task Connect()
ChangeState(ConnectionState.Initialized);
_allowReconnect = true;
- _websocket = new WebSocket(_url)
- {
- EnableAutoSendPing = true,
- AutoSendPingInterval = 1
- };
+ _websocket = new WebSocket(_url);
- _websocket.Opened += websocket_Opened;
- _websocket.Error += websocket_Error;
- _websocket.Closed += websocket_Closed;
- _websocket.MessageReceived += websocket_MessageReceived;
+ _websocket.OnOpen += websocket_Opened;
+ _websocket.OnError += websocket_Error;
+ _websocket.OnClose += websocket_Closed;
+ _websocket.OnMessage += websocket_MessageReceived;
- _websocket.Open();
+ _websocket.ConnectAsync();
return completionSource.Task;
}
@@ -110,11 +106,11 @@ internal async Task Send(string message)
return false;
}
- private void websocket_MessageReceived(object sender, MessageReceivedEventArgs e)
+ private void websocket_MessageReceived(object sender, MessageEventArgs e)
{
- Pusher.Trace.TraceEvent(TraceEventType.Information, 0, "Websocket message received: " + e.Message);
+ Pusher.Trace.TraceEvent(TraceEventType.Information, 0, "Websocket message received: " + e.Data);
- Debug.WriteLine(e.Message);
+ Debug.WriteLine(e.Data);
// DeserializeAnonymousType will throw and error when an error comes back from pusher
// It stems from the fact that the data object is a string normally except when an error is sent back
@@ -123,64 +119,52 @@ private void websocket_MessageReceived(object sender, MessageReceivedEventArgs e
// bad: "{\"event\":\"pusher:error\",\"data\":{\"code\":4201,\"message\":\"Pong reply not received\"}}"
// good: "{\"event\":\"pusher:error\",\"data\":\"{\\\"code\\\":4201,\\\"message\\\":\\\"Pong reply not received\\\"}\"}";
- var jObject = JObject.Parse(e.Message);
-
- if (jObject["data"] != null && jObject["data"].Type != JTokenType.String)
- jObject["data"] = jObject["data"].ToString(Formatting.None);
-
- var jsonMessage = jObject.ToString(Formatting.None);
- var template = new { @event = string.Empty, data = string.Empty, channel = string.Empty };
-
- var message = JsonConvert.DeserializeAnonymousType(jsonMessage, template);
-
- var eventData = JsonConvert.DeserializeObject>(jsonMessage);
-
- if (jObject["data"] != null)
- eventData["data"] = jObject["data"].ToString(Formatting.None); // undo any kind of deserialisation of the data property
+ var jsonMessage = _pusher.JsonSerializer.GetJsonWithStringProperty(e.Data, "data");
+ var eventData = _pusher.JsonSerializer.Deserialize>(jsonMessage);
var receivedEvent = new PusherEvent(eventData, jsonMessage);
- _pusher.EmitPusherEvent(message.@event, receivedEvent);
+ _pusher.EmitPusherEvent(receivedEvent.EventName, receivedEvent);
- if (message.@event.StartsWith(Constants.PUSHER_MESSAGE_PREFIX))
+ if (receivedEvent.EventName.StartsWith(Constants.PUSHER_MESSAGE_PREFIX))
{
// Assume Pusher event
- switch (message.@event)
+ switch (receivedEvent.EventName)
{
// TODO - Need to handle Error on subscribing to a channel
case Constants.ERROR:
- ParseError(message.data);
+ ParseError(receivedEvent.Data);
break;
case Constants.CONNECTION_ESTABLISHED:
- ParseConnectionEstablished(message.data);
+ ParseConnectionEstablished(receivedEvent.Data);
break;
case Constants.CHANNEL_SUBSCRIPTION_SUCCEEDED:
- _pusher.SubscriptionSuceeded(message.channel, message.data);
+ _pusher.SubscriptionSuceeded(receivedEvent.ChannelName, receivedEvent.Data);
break;
case Constants.CHANNEL_SUBSCRIPTION_ERROR:
- RaiseError(new PusherException("Error received on channel subscriptions: " + e.Message, ErrorCodes.SubscriptionError));
+ RaiseError(new PusherException("Error received on channel subscriptions: " + e.Data, ErrorCodes.SubscriptionError));
break;
case Constants.CHANNEL_MEMBER_ADDED:
- _pusher.AddMember(message.channel, message.data);
+ _pusher.AddMember(receivedEvent.ChannelName, receivedEvent.Data);
- Pusher.Trace.TraceEvent(TraceEventType.Warning, 0, "Received a presence event on channel '" + message.channel + "', however there is no presence channel which matches.");
+ Pusher.Trace.TraceEvent(TraceEventType.Warning, 0, "Received a presence event on channel '" + receivedEvent.ChannelName + "', however there is no presence channel which matches.");
break;
case Constants.CHANNEL_MEMBER_REMOVED:
- _pusher.RemoveMember(message.channel, message.data);
+ _pusher.RemoveMember(receivedEvent.ChannelName, receivedEvent.Data);
- Pusher.Trace.TraceEvent(TraceEventType.Warning, 0, "Received a presence event on channel '" + message.channel + "', however there is no presence channel which matches.");
+ Pusher.Trace.TraceEvent(TraceEventType.Warning, 0, "Received a presence event on channel '" + receivedEvent.ChannelName + "', however there is no presence channel which matches.");
break;
}
}
else // Assume channel event
{
- _pusher.EmitChannelEvent(message.channel, message.@event, receivedEvent);
+ _pusher.EmitChannelEvent(receivedEvent.ChannelName, receivedEvent.EventName, receivedEvent);
}
}
@@ -189,20 +173,34 @@ private void websocket_Opened(object sender, EventArgs e)
Pusher.Trace.TraceEvent(TraceEventType.Information, 0, "Websocket opened OK.");
_connectionTaskComplete.SetResult(ConnectionState.Connected);
_connectionTaskComplete = null;
+
+ // We need to manually ping, otherwise the server will time out the connection.
+ _pingTimer = new Timer(DoPing, _websocket, 60000, 60000);
}
- private void websocket_Closed(object sender, EventArgs e)
+ private void DoPing(object state)
+ {
+ var socket = state as WebSocket;
+ if (socket == null || !socket.IsAlive || socket.ReadyState != WebSocketState.Open)
+ return;
+
+ socket.Ping();
+ }
+
+ private void websocket_Closed(object sender, CloseEventArgs e)
{
Pusher.Trace.TraceEvent(TraceEventType.Warning, 0, "Websocket connection has been closed");
- _websocket.Opened -= websocket_Opened;
- _websocket.Error -= websocket_Error;
- _websocket.Closed -= websocket_Closed;
- _websocket.MessageReceived -= websocket_MessageReceived;
+ _websocket.OnOpen -= websocket_Opened;
+ _websocket.OnError -= websocket_Error;
+ _websocket.OnClose -= websocket_Closed;
+ _websocket.OnMessage -= websocket_MessageReceived;
+
+ _pingTimer.Dispose();
if (_websocket != null)
{
- _websocket.Dispose();
+ ((IDisposable)_websocket).Dispose();
_websocket = null;
}
@@ -224,7 +222,7 @@ private void websocket_Closed(object sender, EventArgs e)
}
}
- private void websocket_Error(object sender, SuperSocket.ClientEngine.ErrorEventArgs e)
+ private void websocket_Error(object sender, ErrorEventArgs e)
{
Pusher.Trace.TraceEvent(TraceEventType.Error, 0, "Error: " + e.Exception);
@@ -241,17 +239,17 @@ private void websocket_Error(object sender, SuperSocket.ClientEngine.ErrorEventA
private void ParseConnectionEstablished(string data)
{
- var template = new { socket_id = string.Empty };
- var message = JsonConvert.DeserializeAnonymousType(data, template);
+ var message = _pusher.JsonSerializer.Deserialize(data);
SocketId = message.socket_id;
ChangeState(ConnectionState.Connected);
}
+
+
private void ParseError(string data)
{
- var template = new { message = string.Empty, code = (int?) null };
- var parsed = JsonConvert.DeserializeAnonymousType(data, template);
+ var parsed = _pusher.JsonSerializer.Deserialize(data);
ErrorCodes error = ErrorCodes.Unkown;
diff --git a/PusherClient/ErrorConstants.cs b/PusherClient/ErrorConstants.cs
index 40d73e3e..ff0e4317 100644
--- a/PusherClient/ErrorConstants.cs
+++ b/PusherClient/ErrorConstants.cs
@@ -4,5 +4,6 @@ class ErrorConstants
{
public const string ApplicationKeyNotSet = "The application key cannot be null or whitespace";
public const string ConnectionAlreadyConnected = "Attempt to connect when another connection has already started. New attempt has been ignored.";
+ public const string JsonSerializerNotProvided = "The options used for initialization must contain a value for JsonSerializer.";
}
}
diff --git a/PusherClient/EventEmitter.cs b/PusherClient/EventEmitter.cs
index 71cf079f..38e328b9 100644
--- a/PusherClient/EventEmitter.cs
+++ b/PusherClient/EventEmitter.cs
@@ -1,14 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using Newtonsoft.Json;
namespace PusherClient
{
///
/// Class used to Bind and unbind from events
///
- public class EventEmitter
+ public class EventEmitter : IRequiresJsonSerializer
{
private readonly Dictionary>> _eventListeners = new Dictionary>>();
private readonly List> _generalListeners = new List>();
@@ -19,6 +18,18 @@ public class EventEmitter
private readonly Dictionary>> _pusherEventEventListeners = new Dictionary>>();
private readonly List> _pusherEventGeneralListeners = new List>();
+ public IJsonSerializer JsonSerializer { get; protected set; }
+
+ public EventEmitter()
+ {
+
+ }
+
+ internal EventEmitter(IJsonSerializer serializer)
+ {
+ JsonSerializer = serializer;
+ }
+
///
/// Binds to a given event name
///
@@ -189,7 +200,7 @@ internal void EmitDynamicEvent(string eventName, string data)
{
if (_generalListeners.Count > 0 || _eventListeners.Count > 0)
{
- var dynamicData = JsonConvert.DeserializeObject(data);
+ var dynamicData = JsonSerializer.Deserialize(data);
ActionData(_generalListeners, _eventListeners, eventName, dynamicData);
}
}
diff --git a/PusherClient/GenericPresenceChannel.cs b/PusherClient/GenericPresenceChannel.cs
index 19fba036..ab73c6ca 100644
--- a/PusherClient/GenericPresenceChannel.cs
+++ b/PusherClient/GenericPresenceChannel.cs
@@ -1,6 +1,5 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
-using Newtonsoft.Json;
namespace PusherClient
{
@@ -75,7 +74,7 @@ private ConcurrentDictionary ParseMembersList(string data)
{
ConcurrentDictionary members = new ConcurrentDictionary();
- var dataAsObj = JsonConvert.DeserializeObject(data);
+ var dataAsObj = JsonSerializer.Deserialize(data);
for (int i = 0; i < (int)dataAsObj.presence.count; i++)
{
@@ -95,7 +94,7 @@ private class MemberData
private KeyValuePair ParseMember(string data)
{
- var dataAsObj = JsonConvert.DeserializeObject(data);
+ var dataAsObj = JsonSerializer.Deserialize(data);
var id = dataAsObj.user_id;
var val = dataAsObj.user_info;
diff --git a/PusherClient/IJsonSerializer.cs b/PusherClient/IJsonSerializer.cs
new file mode 100644
index 00000000..076eae62
--- /dev/null
+++ b/PusherClient/IJsonSerializer.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PusherClient
+{
+ public interface IJsonSerializer
+ {
+ string Serialize(T obj);
+ T Deserialize(string json);
+
+ string GetJsonWithStringProperty(string json, string property);
+ }
+}
diff --git a/PusherClient/IPusher.cs b/PusherClient/IPusher.cs
index 6d1650da..bb211563 100644
--- a/PusherClient/IPusher.cs
+++ b/PusherClient/IPusher.cs
@@ -1,8 +1,6 @@
-using System.Collections.Generic;
-
-namespace PusherClient
+namespace PusherClient
{
- internal interface IPusher
+ internal interface IPusher : IRequiresJsonSerializer
{
void ConnectionStateChanged(ConnectionState state);
void ErrorOccured(PusherException pusherException);
diff --git a/PusherClient/IRequiresJsonSerializer.cs b/PusherClient/IRequiresJsonSerializer.cs
new file mode 100644
index 00000000..11958a98
--- /dev/null
+++ b/PusherClient/IRequiresJsonSerializer.cs
@@ -0,0 +1,7 @@
+namespace PusherClient
+{
+ public interface IRequiresJsonSerializer
+ {
+ IJsonSerializer JsonSerializer { get; }
+ }
+}
diff --git a/PusherClient/ITriggerChannels.cs b/PusherClient/ITriggerChannels.cs
index 2348767e..6f4b1418 100644
--- a/PusherClient/ITriggerChannels.cs
+++ b/PusherClient/ITriggerChannels.cs
@@ -2,7 +2,7 @@
namespace PusherClient
{
- internal interface ITriggerChannels
+ internal interface ITriggerChannels : IRequiresJsonSerializer
{
Task Trigger(string channelName, string eventName, object obj);
diff --git a/PusherClient/Messages/AuthMessage.cs b/PusherClient/Messages/AuthMessage.cs
new file mode 100644
index 00000000..3aede424
--- /dev/null
+++ b/PusherClient/Messages/AuthMessage.cs
@@ -0,0 +1,11 @@
+namespace PusherClient.Messages
+{
+ [Preserve]
+ public class AuthMessage
+ {
+ [Preserve]
+ public string auth { get; set; }
+ [Preserve]
+ public string channel_data { get; set; }
+ }
+}
diff --git a/PusherClient/Messages/ConnectionEstablishedMessage.cs b/PusherClient/Messages/ConnectionEstablishedMessage.cs
new file mode 100644
index 00000000..67cb90dd
--- /dev/null
+++ b/PusherClient/Messages/ConnectionEstablishedMessage.cs
@@ -0,0 +1,9 @@
+namespace PusherClient.Messages
+{
+ [Preserve]
+ public class ConnectionEstablishedMessage
+ {
+ [Preserve]
+ public string socket_id { get; set; }
+ }
+}
diff --git a/PusherClient/Messages/ErrorMessage.cs b/PusherClient/Messages/ErrorMessage.cs
new file mode 100644
index 00000000..7b5a7a7f
--- /dev/null
+++ b/PusherClient/Messages/ErrorMessage.cs
@@ -0,0 +1,11 @@
+namespace PusherClient.Messages
+{
+ [Preserve]
+ public class ErrorMessage
+ {
+ [Preserve]
+ public string message { get; set; }
+ [Preserve]
+ public int? code { get; set; }
+ }
+}
diff --git a/PusherClient/NewtonsoftJsonSerializer.cs b/PusherClient/NewtonsoftJsonSerializer.cs
new file mode 100644
index 00000000..db969d40
--- /dev/null
+++ b/PusherClient/NewtonsoftJsonSerializer.cs
@@ -0,0 +1,30 @@
+#if !NO_NEWTONSOFT_JSON
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+
+namespace PusherClient
+{
+ internal class NewtonsoftJsonSerializer : IJsonSerializer
+ {
+ public T Deserialize(string json)
+ {
+ return JsonConvert.DeserializeObject(json);
+ }
+
+ public string Serialize(T obj)
+ {
+ return JsonConvert.SerializeObject(obj);
+ }
+
+ public string GetJsonWithStringProperty(string json, string property)
+ {
+ var jObject = JObject.Parse(json);
+
+ if (jObject[property] != null && jObject[property].Type != JTokenType.String)
+ jObject[property] = jObject[property].ToString();
+
+ return jObject.ToString(Formatting.None);
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/PusherClient/PresenceChannel.cs b/PusherClient/PresenceChannel.cs
index c6a31d86..450f8177 100644
--- a/PusherClient/PresenceChannel.cs
+++ b/PusherClient/PresenceChannel.cs
@@ -1,5 +1,4 @@
using System.Collections.Generic;
-using Newtonsoft.Json;
namespace PusherClient
{
diff --git a/PusherClient/PreserveAttribute.cs b/PusherClient/PreserveAttribute.cs
new file mode 100644
index 00000000..24cd1a42
--- /dev/null
+++ b/PusherClient/PreserveAttribute.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace PusherClient
+{
+ // This attribute is required to prevent il2cpp from stripping models used for serialization
+ [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)]
+ public class PreserveAttribute : Attribute
+ {
+ }
+}
diff --git a/PusherClient/Pusher.cs b/PusherClient/Pusher.cs
index 9545ca2b..589b5b99 100644
--- a/PusherClient/Pusher.cs
+++ b/PusherClient/Pusher.cs
@@ -4,7 +4,7 @@
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
-using Newtonsoft.Json;
+using PusherClient.Messages;
namespace PusherClient
{
@@ -98,6 +98,19 @@ public Pusher(string applicationKey, PusherOptions options = null)
_applicationKey = applicationKey;
_options = options ?? new PusherOptions { Encrypted = false };
+
+ if (options.JsonSerializer == null)
+ {
+#if NO_NEWTONSOFT_JSON
+ throw new ArgumentException(ErrorConstants.JsonSerializerNotProvided, nameof(options));
+#else
+ JsonSerializer = new NewtonsoftJsonSerializer();
+#endif
+ }
+ else
+ {
+ JsonSerializer = options.JsonSerializer;
+ }
}
void IPusher.ConnectionStateChanged(ConnectionState state)
@@ -309,15 +322,14 @@ private async Task SubscribeToChannel(string channelName)
{
var jsonAuth = _options.Authorizer.Authorize(channelName, _connection.SocketId);
- var template = new { auth = string.Empty, channel_data = string.Empty };
- var message = JsonConvert.DeserializeAnonymousType(jsonAuth, template);
+ var message = JsonSerializer.Deserialize(jsonAuth);
- await _connection.Send(JsonConvert.SerializeObject(new { @event = Constants.CHANNEL_SUBSCRIBE, data = new { channel = channelName, auth = message.auth, channel_data = message.channel_data } }));
+ await _connection.Send(JsonSerializer.Serialize(new { @event = Constants.CHANNEL_SUBSCRIBE, data = new { channel = channelName, auth = message.auth, channel_data = message.channel_data } }));
}
else
{
// No need for auth details. Just send subscribe event
- await _connection.Send(JsonConvert.SerializeObject(new { @event = Constants.CHANNEL_SUBSCRIBE, data = new { channel = channelName } }));
+ await _connection.Send(JsonSerializer.Serialize(new { @event = Constants.CHANNEL_SUBSCRIBE, data = new { channel = channelName } }));
}
}
@@ -377,14 +389,14 @@ private void AuthEndpointCheck()
async Task ITriggerChannels.Trigger(string channelName, string eventName, object obj)
{
- await _connection.Send(JsonConvert.SerializeObject(new { @event = eventName, channel = channelName, data = obj }));
+ await _connection.Send(JsonSerializer.Serialize(new { @event = eventName, channel = channelName, data = obj }));
}
async Task ITriggerChannels.Unsubscribe(string channelName)
{
if (_connection.IsConnected)
{
- await _connection.Send(JsonConvert.SerializeObject(new
+ await _connection.Send(JsonSerializer.Serialize(new
{
@event = Constants.CHANNEL_UNSUBSCRIBE,
data = new {channel = channelName}
diff --git a/PusherClient/PusherClient.csproj b/PusherClient/PusherClient.csproj
index be35c4a8..6383ebe6 100644
--- a/PusherClient/PusherClient.csproj
+++ b/PusherClient/PusherClient.csproj
@@ -1,13 +1,14 @@
- net45;net46;netstandard1.6
+ net45;net46
+ Debug;Release;UnityRelease
PusherClient
Pusher .NET Client Library
- 1.1.0
+ 1.1.1
false
pusher realtime websocket
https://github.com/pusher/pusher-websocket-dotnet/blob/master/LICENSE.txt
@@ -17,20 +18,31 @@
https://pusher.com/static_logos/64x64.png
+
+ NO_NEWTONSOFT_JSON
+
+
-
-
+
+
+ 11.0.2
+
+
+
4.3.0
+
+ 1.0.4
+
@@ -39,4 +51,10 @@
+
+
+ 1.0.4
+
+
+
diff --git a/PusherClient/PusherOptions.cs b/PusherClient/PusherOptions.cs
index 7ff9df97..faf7a3fb 100644
--- a/PusherClient/PusherOptions.cs
+++ b/PusherClient/PusherOptions.cs
@@ -21,5 +21,10 @@ public class PusherOptions
public string Cluster { get; set; } = "mt1";
internal string Host => $"ws-{Cluster}.pusher.com";
+
+ ///
+ /// Interface used for internal JSON serialization
+ ///
+ public IJsonSerializer JsonSerializer { get; set; }
}
}
\ No newline at end of file
diff --git a/pusher-dotnet-client.sln b/pusher-dotnet-client.sln
index 1b5bf80f..d461a258 100644
--- a/pusher-dotnet-client.sln
+++ b/pusher-dotnet-client.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27703.2042
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.28917.181
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleApplication", "ExampleApplication\ExampleApplication.csproj", "{D6D38D9A-EF72-4C0D-A4A9-C325775E5CA3}"
EndProject
@@ -24,28 +24,39 @@ Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
+ UnityRelease|Any CPU = UnityRelease|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D6D38D9A-EF72-4C0D-A4A9-C325775E5CA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D6D38D9A-EF72-4C0D-A4A9-C325775E5CA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D6D38D9A-EF72-4C0D-A4A9-C325775E5CA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D6D38D9A-EF72-4C0D-A4A9-C325775E5CA3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D6D38D9A-EF72-4C0D-A4A9-C325775E5CA3}.UnityRelease|Any CPU.ActiveCfg = UnityRelease|Any CPU
+ {D6D38D9A-EF72-4C0D-A4A9-C325775E5CA3}.UnityRelease|Any CPU.Build.0 = UnityRelease|Any CPU
{218EE921-5E27-4E15-9382-42DD2F40857C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{218EE921-5E27-4E15-9382-42DD2F40857C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{218EE921-5E27-4E15-9382-42DD2F40857C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{218EE921-5E27-4E15-9382-42DD2F40857C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {218EE921-5E27-4E15-9382-42DD2F40857C}.UnityRelease|Any CPU.ActiveCfg = UnityRelease|Any CPU
+ {218EE921-5E27-4E15-9382-42DD2F40857C}.UnityRelease|Any CPU.Build.0 = UnityRelease|Any CPU
{F016BFD6-1BD2-4E30-A2C2-1A02A85C0478}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F016BFD6-1BD2-4E30-A2C2-1A02A85C0478}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F016BFD6-1BD2-4E30-A2C2-1A02A85C0478}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F016BFD6-1BD2-4E30-A2C2-1A02A85C0478}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F016BFD6-1BD2-4E30-A2C2-1A02A85C0478}.UnityRelease|Any CPU.ActiveCfg = UnityRelease|Any CPU
+ {F016BFD6-1BD2-4E30-A2C2-1A02A85C0478}.UnityRelease|Any CPU.Build.0 = UnityRelease|Any CPU
{00F1F3BE-1210-4D06-89CA-F1E17898384C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{00F1F3BE-1210-4D06-89CA-F1E17898384C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{00F1F3BE-1210-4D06-89CA-F1E17898384C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{00F1F3BE-1210-4D06-89CA-F1E17898384C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {00F1F3BE-1210-4D06-89CA-F1E17898384C}.UnityRelease|Any CPU.ActiveCfg = UnityRelease|Any CPU
+ {00F1F3BE-1210-4D06-89CA-F1E17898384C}.UnityRelease|Any CPU.Build.0 = UnityRelease|Any CPU
{A325BB9F-6476-4422-AEF4-C22FA53890DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A325BB9F-6476-4422-AEF4-C22FA53890DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A325BB9F-6476-4422-AEF4-C22FA53890DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A325BB9F-6476-4422-AEF4-C22FA53890DD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A325BB9F-6476-4422-AEF4-C22FA53890DD}.UnityRelease|Any CPU.ActiveCfg = UnityRelease|Any CPU
+ {A325BB9F-6476-4422-AEF4-C22FA53890DD}.UnityRelease|Any CPU.Build.0 = UnityRelease|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE