diff --git a/CryptoExchange.Net/BaseClient.cs b/CryptoExchange.Net/BaseClient.cs index 6f4132c..0fc9953 100644 --- a/CryptoExchange.Net/BaseClient.cs +++ b/CryptoExchange.Net/BaseClient.cs @@ -21,6 +21,7 @@ namespace CryptoExchange.Net protected static int lastId; protected static object idLock = new object(); + public static int LastId { get => lastId; } private static readonly JsonSerializer defaultSerializer = JsonSerializer.Create(new JsonSerializerSettings() { @@ -59,13 +60,13 @@ namespace CryptoExchange.Net authProvider = authentictationProvider; } - protected CallResult Deserialize(string data, bool checkObject = true, JsonSerializer serializer = null) where T : class + protected CallResult Deserialize(string data, bool checkObject = true, JsonSerializer serializer = null) { var obj = JToken.Parse(data); return Deserialize(obj, checkObject, serializer); } - protected CallResult Deserialize(JToken obj, bool checkObject = true, JsonSerializer serializer = null) where T : class + protected CallResult Deserialize(JToken obj, bool checkObject = true, JsonSerializer serializer = null) { if (serializer == null) serializer = defaultSerializer; @@ -99,19 +100,19 @@ namespace CryptoExchange.Net { var info = $"Deserialize JsonReaderException: {jre.Message}, Path: {jre.Path}, LineNumber: {jre.LineNumber}, LinePosition: {jre.LinePosition}. Received data: {obj.ToString()}"; log.Write(LogVerbosity.Error, info); - return new CallResult(null, new DeserializeError(info)); + return new CallResult(default(T), new DeserializeError(info)); } catch (JsonSerializationException jse) { var info = $"Deserialize JsonSerializationException: {jse.Message}. Received data: {obj.ToString()}"; log.Write(LogVerbosity.Error, info); - return new CallResult(null, new DeserializeError(info)); + return new CallResult(default(T), new DeserializeError(info)); } catch (Exception ex) { var info = $"Deserialize Unknown Exception: {ex.Message}. Received data: {obj.ToString()}"; log.Write(LogVerbosity.Error, info); - return new CallResult(null, new DeserializeError(info)); + return new CallResult(default(T), new DeserializeError(info)); } } diff --git a/CryptoExchange.Net/SocketClient.cs b/CryptoExchange.Net/SocketClient.cs index c200c5f..487bb14 100644 --- a/CryptoExchange.Net/SocketClient.cs +++ b/CryptoExchange.Net/SocketClient.cs @@ -63,8 +63,6 @@ namespace CryptoExchange.Net socket.DataInterpreter = dataInterpreter; socket.OnClose += () => { - if(socket.DisconnectTime == null) - socket.DisconnectTime = DateTime.UtcNow; SocketOnClose(socket); }; socket.OnError += (e) => @@ -110,7 +108,7 @@ namespace CryptoExchange.Net { if (socket.ShouldReconnect) { - log.Write(LogVerbosity.Info, $"Socket {socket.Id} Connection lost, going to try to reconnect"); + log.Write(LogVerbosity.Info, $"Socket {socket.Id} Connection lost, will try to reconnect"); Task.Run(() => { Thread.Sleep(reconnectInterval); @@ -119,16 +117,22 @@ namespace CryptoExchange.Net log.Write(LogVerbosity.Debug, $"Socket {socket.Id} failed to reconnect"); return; // Connect() should result in a SocketClosed event so we end up here again } + var time = socket.DisconnectTime; + socket.DisconnectTime = null; + if (time == null) + return; - log.Write(LogVerbosity.Info, $"Socket {socket.Id} reconnected after {DateTime.UtcNow - socket.DisconnectTime.Value}"); + log.Write(LogVerbosity.Info, $"Socket {socket.Id} reconnected after {DateTime.UtcNow - time}"); SocketSubscription subscription; - lock(sockets) + lock (sockets) subscription = sockets.Single(s => s.Socket == socket); - if (!SocketReconnect(subscription, DateTime.UtcNow - socket.DisconnectTime.Value)) + if (!SocketReconnect(subscription, DateTime.UtcNow - time.Value)) socket.Close().Wait(); // Close so we end up reconnecting again - socket.DisconnectTime = null; + + + log.Write(LogVerbosity.Info, $"Socket {socket.Id} successfully resubscribed"); return; }); } diff --git a/CryptoExchange.Net/Sockets/SocketEvent.cs b/CryptoExchange.Net/Sockets/SocketEvent.cs index 3585cd0..eb8a650 100644 --- a/CryptoExchange.Net/Sockets/SocketEvent.cs +++ b/CryptoExchange.Net/Sockets/SocketEvent.cs @@ -6,7 +6,6 @@ namespace CryptoExchange.Net.Sockets public class SocketEvent { public string Name { get; set; } - public int Id { get; set; } private CallResult result; private ManualResetEvent setEvnt; diff --git a/CryptoExchange.Net/Sockets/SocketSubscription.cs b/CryptoExchange.Net/Sockets/SocketSubscription.cs index de80738..747f42c 100644 --- a/CryptoExchange.Net/Sockets/SocketSubscription.cs +++ b/CryptoExchange.Net/Sockets/SocketSubscription.cs @@ -20,11 +20,14 @@ namespace CryptoExchange.Net.Sockets public object Request { get; set; } private bool lostTriggered; + private Dictionary waitingForIds; + public SocketSubscription(IWebsocket socket) { Socket = socket; Events = new List(); + waitingForIds = new Dictionary(); DataHandlers = new List>(); @@ -33,6 +36,7 @@ namespace CryptoExchange.Net.Sockets if (lostTriggered) return; + Socket.DisconnectTime = DateTime.UtcNow; lostTriggered = true; foreach (var events in Events) @@ -43,9 +47,11 @@ namespace CryptoExchange.Net.Sockets }; Socket.OnOpen += () => { - lostTriggered = false; - if (Socket.DisconnectTime != null) + if (lostTriggered) + { + lostTriggered = false; ConnectionRestored?.Invoke(DateTime.UtcNow - Socket.DisconnectTime.Value); + } }; } @@ -59,16 +65,37 @@ namespace CryptoExchange.Net.Sockets Events.SingleOrDefault(e => e.Name == name)?.Set(success, error); } - public CallResult WaitForEvent(string name) + public void SetEvent(int id, bool success, Error error) { - return Events.Single(e => e.Name == name).Wait(); + if (waitingForIds.ContainsKey(id)) + { + waitingForIds[id].Set(success, error); + waitingForIds.Remove(id); + } } - public CallResult WaitForEvent(string name, int id) + public (int, SocketEvent) GetWaitingEvent(string name) { - var evnt = Events.Single(e => e.Name == name); - evnt.Id = id; - return evnt.Wait(); + var result = waitingForIds.SingleOrDefault(w => w.Value.Name == name); + if (result.Equals(default(KeyValuePair))) + return (0, null); + + return (result.Key, result.Value); + } + + public CallResult WaitForEvent(string name, int timeout) + { + return Events.Single(e => e.Name == name).Wait(timeout); + } + + public Task> WaitForEvent(string name, int id, int timeout) + { + return Task.Run(() => + { + var evnt = Events.Single(e => e.Name == name); + waitingForIds.Add(id, evnt); + return evnt.Wait(timeout); + }); } public async Task Close()