/// <summary> /// Begins a Real Time Messaging API session and connects via a websocket. /// Will reconnect automatically. /// </summary> /// <param name="manualPresenceSubscription">Only deliver presence events when requested by subscription.</param> /// <param name="batchPresenceAware">Group presence change notices in <see cref="PresenceChange"/> events when possible.</param> /// <param name="cancellationToken"></param> public async Task <ConnectResponse> Connect(bool batchPresenceAware = false, bool manualPresenceSubscription = false, CancellationToken?cancellationToken = null) { if (Connected) { throw new InvalidOperationException("Already connecting or connected"); } var connectResponse = await _client.Rtm.Connect(manualPresenceSubscription, batchPresenceAware, cancellationToken).ConfigureAwait(false); _webSocket?.Dispose(); _webSocket = _webSocketFactory.Create(connectResponse.Url); var openedTask = _webSocket.Opened .Merge(_webSocket.Errors.SelectMany(Observable.Throw <Unit>)) .FirstAsync() .ToTask(cancellationToken); _webSocket.Open(); await openedTask.ConfigureAwait(false); _eventSubscription?.Dispose(); _eventSubscription = _webSocket.Messages .Select(m => JsonConvert.DeserializeObject <Event>(m, _jsonSettings.SerializerSettings)) .Subscribe(_rawEvents); _reconnection?.Dispose(); _reconnection = _webSocket.Closed .SelectMany(_ => Observable.FromAsync(() => Connect(batchPresenceAware, manualPresenceSubscription, cancellationToken), _scheduler) .RetryWithDelay(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5), TimeSpan.FromMinutes(5), _scheduler)) .Subscribe(); return(connectResponse); }
/// <summary> /// Releases unmanaged and - optionally - managed resources. /// </summary> /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> protected virtual void Dispose(bool dispose) { if (dispose) { _socket.Dispose(); } }
/// <inheritdoc /> public virtual async Task Connect() { if (Socket != null) { throw new JsonRpcAlreadyConnectedException(); } Socket?.Dispose(); RequestMgr.Reset(); ReceiveCancellationTokenSource = new CancellationTokenSource(); if (Logger?.IsEnabled(LogEventLevel.Information) ?? false) { Logger.Information("Connecting to {Host}", ServerUri); } Socket = WebSocketFactory.Create(); try { await Socket.ConnectAsync(ServerUri, CancellationToken.None).ConfigureAwait(false); } catch (Exception ex) { Logger?.Error(ex, "Exception during ConnectAsync"); Socket.Dispose(); Socket = null; throw; } InternalOnConnected(); }
private static void RunOrderBookWebSocket(Dictionary <string, string> dict) { RequireArgs(dict, "exchangeName"); var api = ExchangeAPI.GetExchangeAPI(dict["exchangeName"]); if (api == null) { throw new ArgumentException("Cannot find exchange with name {0}", dict["exchangeName"]); } var apiSymbols = api.GetSymbols(); string[] symbols = dict["symbols"].Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); foreach (string symbol in symbols) { if (!apiSymbols.Contains(symbol)) { throw new ArgumentException(string.Format("Symbol {0} does not exist in API {1}, valid symbols: {2}", symbol, api.Name, string.Join(",", apiSymbols.OrderBy(s => s)))); } } IWebSocket socket = api.GetOrderBookWebSocket(message => { //print the top bid and ask with amount var topBid = message.Bids.FirstOrDefault(); var topAsk = message.Asks.FirstOrDefault(); Console.WriteLine($"[{message.Symbol}:{message.SequenceId}] {topBid.Value.Price} ({topBid.Value.Amount}) | {topAsk.Value.Price} ({topAsk.Value.Amount})"); }, symbols: symbols); Console.WriteLine("Press any key to quit."); SetWebSocketEvents(socket); Console.ReadKey(); socket.Dispose(); }
/// <summary> /// Releases unmanaged and - optionally - managed resources. /// </summary> /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> protected virtual void Dispose(bool dispose) { if (dispose) { _cancellationTokenSource.Dispose(); _socket.Dispose(); } }
public void TestDisposeWebSocket() { WebSocketJetConnection webSocketJetConnection = new WebSocketJetConnection("ws://172.19.191.179:8081"); IWebSocket webSocket = A.Fake <IWebSocket>(); webSocketJetConnection.SetWebSocket(webSocket); webSocketJetConnection.Dispose(); A.CallTo(() => webSocket.Dispose()).MustHaveHappened(Repeated.Exactly.Once); }
//public List<IWebSocket> this[string metadata] //{ // get // { // if (clientsByMetadata.ContainsKey(metadata)) // { // return clientsByMetadata[metadata]; // } // return new List<IWebSocket>(); // } //} private void OnHandShaken(IWebSocket webSocket, ClientHandshake clientHandshake) { var handler = handlerFactory.Create(clientHandshake.ResourceName); if (handler != null) { webSocket.Received = handler.Received; webSocket.Disconnected = sender => { var found = clientsByMetadata.FirstOrDefault(kv => kv.Value.Exists(ws => ws == sender)); if (found.Value != null) { found.Value.Remove((WebSocket)sender); if (!found.Value.Any()) { clientsByMetadata.Remove(found.Key); } // A web socket with the metaData has been disconnected from the server handler.Disconnected(found.Key); } }; webSocket.Error = handler.Error; var metadata = GetMetadata(clientHandshake, webSocket); // A web socket with the metaData has been connected to the server handler.Connected(metadata); if (!clientsByMetadata.ContainsKey(metadata)) { clientsByMetadata.Add(metadata, new List <IWebSocket> { webSocket }); } else { //clientsByMetaData[metaData].Dispose(); clientsByMetadata[metadata].Add(webSocket); } // Begin receiving data from the client webSocket.ReceiveAsync(); } else { if (Log.IsDebugEnabled) { Log.Debug("There was no handler found for the resource name"); } // If nothing is handling client connections // the client connection should be closed webSocket.Dispose(); } }
#pragma warning disable S3241 // Methods should not return values that are never used private async Task StartListening(CancellationToken cancellationToken = default) #pragma warning restore S3241 // Methods should not return values that are never used { try { while (webSocket.State == WebSocketState.Open) { logger?.LogDebug("Waiting for new message"); var message = await ReadNextMessage(cancellationToken); logger?.LogDebug("Received new message from websocket"); logger?.LogTrace("Received: '{message}'", message); string eventString = null; int? channelId = null; if (!string.IsNullOrEmpty(message)) { var token = JToken.Parse(message); switch (token) { case JObject _: var messageObj = JObject.Parse(message); eventString = (string)messageObj.GetValue("event"); break; case JArray arrayToken: // Data / private messages if (int.TryParse(arrayToken.First.ToString(), out var localChannelId)) { channelId = localChannelId; } eventString = channelId != null ? "data" : "private"; break; } InvokeDataReceived(new KrakenMessageEventArgs(eventString, message, channelId)); } } } catch (Exception ex) { logger?.LogError(ex, "Error while listening or reading new messages from WebSocket"); // TODO: Disconnected-Event throw; } finally { logger?.LogInformation("Closing WebSocket"); webSocket.Dispose(); } }
public void TestDisposeClosesWebSocketIfConnected() { WebSocketJetConnection webSocketJetConnection = new WebSocketJetConnection("ws://172.19.191.179:8081"); IWebSocket webSocket = WebSocketFakesFactory.CreateWebSocketThatConnectsAndClosesSuccessful(); webSocketJetConnection.SetWebSocket(webSocket); webSocketJetConnection.Connect(A.Dummy <Action <bool> >(), 1000.0); webSocketJetConnection.Dispose(); A.CallTo(() => webSocket.Close(CloseStatusCode.Away)).MustHaveHappened(Repeated.Exactly.Once).Then( A.CallTo(() => webSocket.Dispose()).MustHaveHappened(Repeated.Exactly.Once)); }
public void Dispose() { if (!_disposed) { _disposed = true; _webSocket.Dispose(); foreach (ISubscription subscription in _subscriptions.Values) { subscription.Dispose(); } _subscriptions.Clear(); } }
// This may be triggered remotely by the server or locally by Close/Dispose() private void Closed(IWebSocket sender, WebSocketClosedEventArgs args) { if (sender != null) { sender.Dispose(); // Distroy keepalive timer before close connection if (_timer != null) { _timer.Cancel(); _timer = null; } CoreApplication.Properties.Remove("connected"); CoreApplication.Properties.Remove("clientSocket"); } }
protected async Task RunWebSocket(string exchangeName, Func <IExchangeAPI, Task <IWebSocket> > getWebSocket) { using var api = ExchangeAPI.GetExchangeAPI(exchangeName); Console.WriteLine("Connecting web socket to {0}...", api.Name); IWebSocket socket = null; var tcs = new TaskCompletionSource <bool>(); // ReSharper disable once AccessToModifiedClosure var disposable = KeepSessionAlive(() => { socket?.Dispose(); tcs.TrySetResult(true); }); try { socket = await getWebSocket(api); socket.Connected += _ => { Console.WriteLine("Web socket connected."); return(Task.CompletedTask); }; socket.Disconnected += _ => { Console.WriteLine("Web socket disconnected."); // ReSharper disable once AccessToDisposedClosure disposable.Dispose(); return(Task.CompletedTask); }; await tcs.Task; } catch { disposable.Dispose(); throw; } }
/// <summary> /// Implement <see cref="IDisposable"/> pattern for inheritable classes. /// </summary> /// <param name="disposing">If <c>true</c> - dispose managed objects.</param> protected virtual void Dispose( Boolean disposing) { if (!disposing || _webSocket == null) { return; } _webSocket.Opened -= OnOpened; _webSocket.Closed -= OnClosed; _webSocket.MessageReceived -= OnMessageReceived; _webSocket.DataReceived -= OnDataReceived; _webSocket.Error -= HandleError; _webSocket.Dispose(); }
private static void RunTradesWebSocket(Dictionary <string, string> dict) { RequireArgs(dict, "exchangeName"); var api = ExchangeAPI.GetExchangeAPI(dict["exchangeName"]); if (api == null) { throw new ArgumentException("Cannot find exchange with name {0}", dict["exchangeName"]); } string[] symbols = dict["symbols"].Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); IWebSocket socket = api.GetTradesWebSocket(message => { Console.WriteLine($"{message.Key}: {message.Value}"); }, symbols: symbols); Console.WriteLine("Press any key to quit."); SetWebSocketEvents(socket); Console.ReadKey(); socket.Dispose(); }
#pragma warning disable S3241 // Methods should not return values that are never used private async Task StartListening(CancellationToken cancellationToken = default) #pragma warning restore S3241 // Methods should not return values that are never used { try { while (webSocket.State == WebSocketState.Open) { logger?.LogDebug("Waiting for new message"); var message = await ReadNextMessage(cancellationToken); logger?.LogDebug("Received new message from websocket"); logger?.LogTrace("Received: '{message}'", message); string eventString = null; int? channelId = null; if (!string.IsNullOrEmpty(message)) { var token = JToken.Parse(message); switch (token) { case JObject _: var messageObj = JObject.Parse(message); eventString = (string)messageObj.GetValue("event"); break; case JArray arrayToken: // Data / private messages if (int.TryParse(arrayToken.First.ToString(), out var localChannelId)) { channelId = localChannelId; } eventString = channelId != null ? "data" : "private"; break; } InvokeDataReceived(new KrakenMessageEventArgs(eventString, message, channelId)); } } } catch (Exception ex) { logger?.LogError(ex, "Error while listening or reading new messages from WebSocket"); } finally { logger?.LogInformation("Closing WebSocket"); webSocket.Dispose(); } #if false //reconnect while (true) { logger?.LogInformation("Attempting reconnect.."); await Task.Delay(1 * 1000); webSocket = new DefaultWebSocket(new ClientWebSocket()); try { await ConnectAsync(); await Task.Delay(1 * 1000); var ev = ReConnected; if (ev != null) { InvokeAllHandlers(ev.GetInvocationList(), null); } return; } catch { try { webSocket.Dispose(); } catch { } await Task.Delay(20 * 1000); } await Task.Delay(10 * 1000); } #endif }