private void SocketOnClose(CoinExStream stream) { log.Write(LogVerbosity.Debug, $"Socket {stream.StreamResult.StreamId} closed event"); if (stream.TryReconnect) { log.Write(LogVerbosity.Info, $"Socket {stream.StreamResult.StreamId} Connection lost, going to try to reconnect"); Task.Run(() => { Thread.Sleep(reconnectInterval); if (!stream.Socket.Connect().Result) { log.Write(LogVerbosity.Debug, $"Socket {stream.StreamResult.StreamId} failed to reconnect"); return; // Connect() should result in a SocketClosed event so we end up here again } log.Write(LogVerbosity.Info, $"Socket {stream.StreamResult.StreamId} Reconnected"); if (stream.Request != null) { var resubResult = Subscribe(stream, stream.Request, true).Result; if (!resubResult.Success) { log.Write(LogVerbosity.Info, $"Socket {stream.StreamResult.StreamId} failed to resubscribe, closing socket and trying again"); stream.Close(true).Wait(); } else { log.Write(LogVerbosity.Info, $"Socket {stream.StreamResult.StreamId} resubscribed reconnected socket"); } } }); } else { log.Write(LogVerbosity.Info, $"Socket {stream.StreamResult.StreamId} closed"); lock (subscriptions) if (subscriptions.Contains(stream.Subscription)) { subscriptions.Remove(stream.Subscription); } stream.StreamResult.InvokeClosed(); stream.Socket.Dispose(); lock (sockets) sockets.Remove(stream); } }
private async Task <CallResult <CoinExStreamSubscription> > Subscribe(CoinExStream stream, CoinExSocketRequest request, bool resubscribing) { if (stream.Authenticated) { var auth = await Authenticate(stream).ConfigureAwait(false); if (!auth.Success) { return(new CallResult <CoinExStreamSubscription>(null, auth.Error)); } } if (!resubscribing) // Only add the message handler once, is already done if resubscribing { stream.Socket.OnMessage += (msg) => OnMessage(stream.StreamResult.StreamId, msg); } var subConfirm = await Query <CoinExSocketRequestResponseMessage>(stream, request).ConfigureAwait(false); if (subConfirm.Success) { stream.Request = request; stream.Subscription.StreamId = stream.StreamResult.StreamId; stream.TryReconnect = true; lock (subscriptions) if (!subscriptions.Contains(stream.Subscription)) { subscriptions.Add(stream.Subscription); } log.Write(LogVerbosity.Info, $"Subscription {stream.Subscription.StreamId} successful"); } else { log.Write(LogVerbosity.Info, $"Failed to subscribe {stream.Subscription.StreamId}: {subConfirm.Error}"); if (!resubscribing) // If we're just trying to initialy subscribe we dont need to reconnect if we failed subbing, so close it here { await stream.Close().ConfigureAwait(false); } } return(new CallResult <CoinExStreamSubscription>(stream.StreamResult, subConfirm.Error)); }
private CallResult <CoinExStream> ConnectNewSocket() { var socket = SocketFactory.CreateWebsocket(log, baseAddress); log.Write(LogVerbosity.Debug, "Created new socket"); var id = NextStreamId(); var stream = new CoinExStream() { Socket = socket, StreamResult = new CoinExStreamSubscription() { StreamId = id } }; if (apiProxy != null) { socket.SetProxy(apiProxy.Host, apiProxy.Port); } socket.SetEnabledSslProtocols(protocols); socket.OnClose += () => SocketOnClose(stream); socket.OnError += SocketOnError; socket.OnError += stream.StreamResult.InvokeError; socket.OnOpen += SocketOnOpen; if (socket.Connect().Result) { lock (sockets) sockets.Add(stream); return(new CallResult <CoinExStream>(stream, null)); } socket.Dispose(); return(new CallResult <CoinExStream>(null, new CantConnectError())); }
private async Task <CallResult <bool> > Authenticate(CoinExStream stream) { if (authProvider == null) { return(new CallResult <bool>(false, new NoApiCredentialsError())); } var result = await Query <CoinExSocketRequestResponseMessage>(stream, new CoinExSocketRequest(ServerSubject, AuthenticateAction, GetAuthParameters())).ConfigureAwait(false); if (!result.Success) { log.Write(LogVerbosity.Debug, "Failed to authenticate: " + result.Error); return(new CallResult <bool>(false, result.Error)); } if (result.Data.Status != SuccessString) { log.Write(LogVerbosity.Debug, "Failed to authenticate: " + result.Data.Status); return(new CallResult <bool>(false, new ServerError(result.Data.Status))); } log.Write(LogVerbosity.Debug, "Successfully authenticated"); return(new CallResult <bool>(true, null)); }
private async Task <CallResult <T> > Query <T>(CoinExStream stream, CoinExSocketRequest request) { return(await Task.Run(() => { log.Write(LogVerbosity.Debug, $"Querying socket {stream.Subscription.StreamId} for {request.Method}"); ManualResetEvent evnt = new ManualResetEvent(false); CallResult <CoinExSocketRequestResponse <T> > result = null; request.Id = NextRequestId(); var onMessageAction = new Action <string>((msg) => { log.Write(LogVerbosity.Debug, "Socket received query response: " + msg); var token = JToken.Parse(msg); if ((int?)token["id"] != request.Id) { return; } if (token["error"].Type == JTokenType.Null) { result = Deserialize <CoinExSocketRequestResponse <T> >(msg); } else { var errorResult = Deserialize <CoinExSocketError>(token["error"].ToString()); if (!errorResult.Success) { result = new CallResult <CoinExSocketRequestResponse <T> >(null, new ServerError("Unknown error: " + token["error"])); } else { result = new CallResult <CoinExSocketRequestResponse <T> >(null, new ServerError(errorResult.Data.Code, errorResult.Data.Message)); } } evnt?.Set(); }); stream.Socket.OnMessage += onMessageAction; var data = JsonConvert.SerializeObject(request); log.Write(LogVerbosity.Debug, "Sending data: " + data); stream.Socket.Send(data); evnt.WaitOne(subResponseTimeout); stream.Socket.OnMessage -= onMessageAction; evnt.Dispose(); evnt = null; if (result == null) { return new CallResult <T>(default(T), new ServerError("No response from server")); } if (!result.Success) { return new CallResult <T>(default(T), result.Error); } if (result.Data.Error != null) { return new CallResult <T>(default(T), new ServerError(result.Data.Error.Code, result.Data.Error.Message)); } return new CallResult <T>(result.Data.Result, null); }).ConfigureAwait(false)); }