예제 #1
0
        public async Task CloseAsync(
            string message,
            SocketCloseStatus closeStatus,
            CancellationToken cancellationToken)
        {
            try
            {
                WebSocket?webSocket = _webSocket;

                if (_disposed || Closed || webSocket is null)
                {
                    return;
                }

                await webSocket.CloseOutputAsync(
                    MapCloseStatus(closeStatus),
                    message,
                    cancellationToken);

                Dispose();
            }
            catch
            {
                // we do not throw here ...
            }
        }
예제 #2
0
        internal static ServerEventsStatus CalculateServerEventsStatus(bool enabled, WebSocket?socket)
        {
            if (!enabled)
            {
                return(ServerEventsStatus.Disabled);
            }

            return(socket == null ? ServerEventsStatus.Connecting : ServerEventsStatus.Enabled);
        }
예제 #3
0
        public Task ConnectAsync(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options)
        {
            cancellationToken.ThrowIfCancellationRequested();

            var ws = new BrowserWebSocket();

            WebSocket = ws;
            return(ws.ConnectAsync(uri, options.RequestedSubProtocols, cancellationToken));
        }
예제 #4
0
 /// <summary>
 /// Attaches an WebSocket instance to the payment processing delegate event
 /// </summary>
 /// <param name="webSocket">the WebSocket instance to attach to</param>
 public void ListeningPaymentProcessing(WebSocket webSocket)
 {
     _webSocket = webSocket;
     if (_paymentProcessing.HasPaymentProcessingEventMethod)
     {
         return;
     }
     _logger.LogInformation("Assigned to payment websocket event");
     _paymentProcessing.PaymentProcessingEvent += PaymentProcessingOnPaymentProcessingEvent;
 }
예제 #5
0
        public async Task <TaskCompletionSource <bool> > GetSocketCompletion(WebSocket socket)
        {
            await DiscardSocket();

            _serverEventsSocket = socket;
            _completion         = new TaskCompletionSource <bool>();
            await FlushIfPending();

            return(_completion);
        }
예제 #6
0
        private async Task DiscardSocket()
        {
            if (_serverEventsSocket != null)
            {
                _completion?.SetResult(true);
                await PostEventHandler.CloseSocket(_serverEventsSocket);

                _serverEventsSocket = null;
            }
        }
 protected virtual void Dispose(bool disposing)
 {
     if (disposing)
     {
         if (WebSocket != null)
         {
             WebSocket.Dispose();
             WebSocket = null;
         }
     }
 }
예제 #8
0
 protected virtual void Dispose(bool disposing)
 {
     if (!_disposed)
     {
         if (disposing)
         {
             Subscriptions.Dispose();
             _webSocket?.Dispose();
             _webSocket = null;
         }
         _disposed = true;
     }
 }
예제 #9
0
        public async Task ReceiveAsync(
            PipeWriter writer,
            CancellationToken cancellationToken)
        {
            WebSocket?webSocket = _webSocket;

            if (_disposed || webSocket == null)
            {
                return;
            }

            try
            {
                WebSocketReceiveResult?socketResult = null;
                do
                {
                    Memory <byte> memory  = writer.GetMemory(_maxMessageSize);
                    bool          success = MemoryMarshal.TryGetArray(memory, out ArraySegment <byte> buffer);

                    if (success)
                    {
                        try
                        {
                            socketResult = await webSocket.ReceiveAsync(buffer, cancellationToken);

                            if (socketResult.Count == 0)
                            {
                                break;
                            }

                            writer.Advance(socketResult.Count);
                        }
                        catch
                        {
                            break;
                        }

                        FlushResult result = await writer.FlushAsync(cancellationToken);

                        if (result.IsCompleted)
                        {
                            break;
                        }
                    }
                } while (socketResult == null || !socketResult.EndOfMessage);
            }
            catch (ObjectDisposedException)
            {
                // we will just stop receiving
            }
        }
예제 #10
0
 private void CloseConnectionIfItsNotNull()
 {
     if (_socketConnection != null)
     {
         _logger.LogDebug("Closing existing connection");
         using (_socketConnection)
         {
             _socketConnection.MessageReceived -= SocketConnectionOnMessageReceived;
             _socketConnection.Closed          -= SocketConnectionOnClosed;
             _socketConnection.Error           -= SocketConnectionOnError;
             _welcomeReceived.Reset();
             _socketConnection.Close();
             _socketConnection = null;
         }
     }
 }
예제 #11
0
        public Task SendAsync(
            byte[] message,
            CancellationToken cancellationToken)
        {
            WebSocket?webSocket = _webSocket;

            if (_disposed || webSocket == null)
            {
                return(Task.CompletedTask);
            }

            return(webSocket.SendAsync(
                       new ArraySegment <byte>(message),
                       WebSocketMessageType.Text,
                       true, cancellationToken));
        }
예제 #12
0
        protected override async Task InternalConnectAsync(CancellationToken token)
        {
            int roomId = _Options.RoomId;
            DanmakuServerInfo server = await _CredentialProvider.GetDanmakuServerInfoAsync(token);

            ClientWebSocket client = new ClientWebSocket();

            client.Options.KeepAliveInterval = Timeout.InfiniteTimeSpan;
            token.Register(client.Dispose);
            DanmakuServerHostInfo serverHost = server.Hosts[(int)(Stopwatch.GetTimestamp() % server.Hosts.Length)];
            await client.ConnectAsync(new Uri($"wss://{serverHost.Host}:{serverHost.WssPort}/sub"), token);

            await SendJoinRoomAsync(client, roomId, 0, server.Token, token);

            _Client = client;
        }
예제 #13
0
        public async Task ReadWebSocket(WebSocket socket)
        {
            if (WebSocket != null)
            {
                try {
                    Task ignored = WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
                }
                catch (Exception) { }
            }

            WebSocket = socket;

            const int maxMessageSize = 1024;

            byte[] receiveBuffer = new byte[maxMessageSize];

            while (!closed)
            {
                try {
                    WebSocketReceiveResult receiveResult = await socket.ReceiveAsync(new ArraySegment <byte>(receiveBuffer), CancellationToken.None);

                    if (receiveResult.MessageType == WebSocketMessageType.Close)
                    {
                        await Close();

                        return;
                    }
                    if (receiveResult.Count == 2 && receiveBuffer[0] == (byte)'O' && receiveBuffer[1] == (byte)'K')
                    {
                        eventAcked = true;
                    }
                    lastActivity = Timestamp.Now;
                }
                catch (Exception) {
                    try {
                        Task ignored = socket.CloseAsync(WebSocketCloseStatus.ProtocolError, string.Empty, CancellationToken.None);
                    }
                    catch (Exception) { }
                    if (socket == WebSocket)
                    {
                        WebSocket = null;
                    }
                    return;
                }
            }
        }
예제 #14
0
        public async Task ConnectAsync(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options)
        {
            try
            {
                cancellationToken.ThrowIfCancellationRequested();  // avoid allocating a WebSocket object if cancellation was requested before connect
                CancellationTokenSource?linkedCancellation;
                CancellationTokenSource externalAndAbortCancellation;
                if (cancellationToken.CanBeCanceled) // avoid allocating linked source if external token is not cancelable
                {
                    linkedCancellation =
                        externalAndAbortCancellation =
                            CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _abortSource.Token);
                }
                else
                {
                    linkedCancellation           = null;
                    externalAndAbortCancellation = _abortSource;
                }

                using (linkedCancellation)
                {
                    WebSocket = new BrowserWebSocket();
                    await((BrowserWebSocket)WebSocket).ConnectAsyncJavaScript(uri, externalAndAbortCancellation.Token, options.RequestedSubProtocols).ConfigureAwait(continueOnCapturedContext: true);
                    externalAndAbortCancellation.Token.ThrowIfCancellationRequested();
                }
            }
            catch (Exception exc)
            {
                if (_state < WebSocketState.Closed)
                {
                    _state = WebSocketState.Closed;
                }

                Abort();

                switch (exc)
                {
                case WebSocketException:
                case OperationCanceledException _ when cancellationToken.IsCancellationRequested:
                    throw;

                default:
                    throw new WebSocketException(SR.net_webstatus_ConnectFailure, exc);
                }
            }
        }
예제 #15
0
    public async Task ReceiveAsync(
        PipeWriter writer,
        CancellationToken cancellationToken)
    {
        WebSocket?webSocket = _webSocket;

        if (_disposed || webSocket == null)
        {
            return;
        }

        try
        {
            ValueWebSocketReceiveResult socketResult;
            do
            {
                if (webSocket.State != WebSocketState.Open)
                {
                    break;
                }

                Memory <byte> memory = writer.GetMemory(_maxMessageSize);
                socketResult = await webSocket.ReceiveAsync(memory, cancellationToken);

                if (socketResult.Count == 0)
                {
                    break;
                }

                writer.Advance(socketResult.Count);

                FlushResult result = await writer.FlushAsync(cancellationToken);

                if (result.IsCompleted)
                {
                    break;
                }
            } while (!socketResult.EndOfMessage);
        }
        catch
        {
            // swallow exception, there's nothing we can reasonably do
        }
    }
예제 #16
0
        public bool Connect()
        {
            CloseConnectionIfItsNotNull();
            _socketConnection = new WebSocket($"wss://{Environments.Values[_bitmexEnvironment]}/realtime")
            {
                EnableAutoSendPing = true, AutoSendPingInterval = 2
            };
            BitmexWelcomeMessage welcomeData = null;
            EventHandler <MessageReceivedEventArgs> welcomeMessageReceived = (sender, e) =>
            {
                _logger.LogDebug($"Welcome Data Received {e.Message}");
                welcomeData = BitmexJsonSerializer.Deserialize <BitmexWelcomeMessage>(e.Message);
                _welcomeReceived.Set();
            };

            _socketConnection.MessageReceived += welcomeMessageReceived;
            _socketConnection.Open();
            var waitResult = _welcomeReceived.WaitOne(SocketMessageResponseTimeout);

            _socketConnection.MessageReceived -= welcomeMessageReceived;
            if (waitResult && (welcomeData?.Limit?.Remaining ?? 0) == 0)
            {
                _logger.LogError("Bitmex connection limit reached");
                throw new BitmexWebSocketLimitReachedException();
            }

            if (!waitResult)
            {
                _logger.LogError("Open connection timeout. Welcome message is not received");
                return(false);
            }

            if (IsAlive)
            {
                _logger.LogInformation("Bitmex web socket connection opened");
                _socketConnection.MessageReceived += SocketConnectionOnMessageReceived;
                _socketConnection.Closed          += SocketConnectionOnClosed;
                _socketConnection.Error           += SocketConnectionOnError;
            }

            return(IsAlive);
        }
예제 #17
0
        internal async Task Close()
        {
            if (closed)
            {
                return;
            }

            closed = true;

            if (WebSocket != null)
            {
                var socket = WebSocket;
                WebSocket = null;
                try {
                    await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
                }
                catch (Exception) { }
            }

            if (currentView != null)
            {
                try {
                    await currentView.OnDeactivate();
                }
                catch (Exception) { }
                currentView = null;
            }

            foreach (ViewBase view in views.Values)
            {
                try {
                    await view.OnDestroy();
                }
                catch (Exception) { }
            }

            await connection.Close();
        }
예제 #18
0
        public async Task <bool> TryOpenAsync()
        {
            if (_disposed)
            {
                throw new ObjectDisposedException(nameof(WebSocketConnection));
            }

            _webSocket = await WebSockets.AcceptWebSocketAsync(_protocol);

            if (_webSocket.SubProtocol is not null &&
                WebSockets.WebSocketRequestedProtocols.Contains(_webSocket.SubProtocol))
            {
                return(true);
            }

            await _webSocket.CloseOutputAsync(
                WebSocketCloseStatus.ProtocolError,
                "Expected graphql-ws protocol.",
                CancellationToken.None);

            _webSocket.Dispose();
            _webSocket = null;
            return(false);
        }
        public async Task ConnectAsync(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options)
        {
            HttpResponseMessage?response = null;
            SocketsHttpHandler? handler  = null;
            bool disposeHandler          = true;

            try
            {
                var request = new HttpRequestMessage(HttpMethod.Get, uri);
                if (options._requestHeaders?.Count > 0) // use field to avoid lazily initializing the collection
                {
                    foreach (string key in options.RequestHeaders)
                    {
                        request.Headers.TryAddWithoutValidation(key, options.RequestHeaders[key]);
                    }
                }

                // Create the security key and expected response, then build all of the request headers
                KeyValuePair <string, string> secKeyAndSecWebSocketAccept = CreateSecKeyAndSecWebSocketAccept();
                AddWebSocketHeaders(request, secKeyAndSecWebSocketAccept.Key, options);

                // Create the handler for this request and populate it with all of the options.
                // Try to use a shared handler rather than creating a new one just for this request, if
                // the options are compatible.
                if (options.Credentials == null &&
                    !options.UseDefaultCredentials &&
                    options.Proxy == null &&
                    options.Cookies == null &&
                    options.RemoteCertificateValidationCallback == null &&
                    options._clientCertificates?.Count == 0)
                {
                    disposeHandler = false;
                    handler        = s_defaultHandler;
                    if (handler == null)
                    {
                        handler = new SocketsHttpHandler()
                        {
                            PooledConnectionLifetime = TimeSpan.Zero,
                            UseProxy   = false,
                            UseCookies = false,
                        };
                        if (Interlocked.CompareExchange(ref s_defaultHandler, handler, null) != null)
                        {
                            handler.Dispose();
                            handler = s_defaultHandler;
                        }
                    }
                }
                else
                {
                    handler = new SocketsHttpHandler();
                    handler.PooledConnectionLifetime = TimeSpan.Zero;
                    handler.CookieContainer          = options.Cookies;
                    handler.UseCookies = options.Cookies != null;
                    handler.SslOptions.RemoteCertificateValidationCallback = options.RemoteCertificateValidationCallback;

                    if (options.UseDefaultCredentials)
                    {
                        handler.Credentials = CredentialCache.DefaultCredentials;
                    }
                    else
                    {
                        handler.Credentials = options.Credentials;
                    }

                    if (options.Proxy == null)
                    {
                        handler.UseProxy = false;
                    }
                    else if (options.Proxy != DefaultWebProxy.Instance)
                    {
                        handler.Proxy = options.Proxy;
                    }

                    if (options._clientCertificates?.Count > 0) // use field to avoid lazily initializing the collection
                    {
                        Debug.Assert(handler.SslOptions.ClientCertificates == null);
                        handler.SslOptions.ClientCertificates = new X509Certificate2Collection();
                        handler.SslOptions.ClientCertificates.AddRange(options.ClientCertificates);
                    }
                }

                // Issue the request.  The response must be status code 101.
                CancellationTokenSource?linkedCancellation;
                CancellationTokenSource externalAndAbortCancellation;
                if (cancellationToken.CanBeCanceled) // avoid allocating linked source if external token is not cancelable
                {
                    linkedCancellation =
                        externalAndAbortCancellation =
                            CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _abortSource.Token);
                }
                else
                {
                    linkedCancellation           = null;
                    externalAndAbortCancellation = _abortSource;
                }

                using (linkedCancellation)
                {
                    response = await new HttpMessageInvoker(handler).SendAsync(request, externalAndAbortCancellation.Token).ConfigureAwait(false);
                    externalAndAbortCancellation.Token.ThrowIfCancellationRequested(); // poll in case sends/receives in request/response didn't observe cancellation
                }

                if (response.StatusCode != HttpStatusCode.SwitchingProtocols)
                {
                    throw new WebSocketException(WebSocketError.NotAWebSocket, SR.Format(SR.net_WebSockets_Connect101Expected, (int)response.StatusCode));
                }

                // The Connection, Upgrade, and SecWebSocketAccept headers are required and with specific values.
                ValidateHeader(response.Headers, HttpKnownHeaderNames.Connection, "Upgrade");
                ValidateHeader(response.Headers, HttpKnownHeaderNames.Upgrade, "websocket");
                ValidateHeader(response.Headers, HttpKnownHeaderNames.SecWebSocketAccept, secKeyAndSecWebSocketAccept.Value);

                // The SecWebSocketProtocol header is optional.  We should only get it with a non-empty value if we requested subprotocols,
                // and then it must only be one of the ones we requested.  If we got a subprotocol other than one we requested (or if we
                // already got one in a previous header), fail. Otherwise, track which one we got.
                string?subprotocol = null;
                if (response.Headers.TryGetValues(HttpKnownHeaderNames.SecWebSocketProtocol, out IEnumerable <string>?subprotocolEnumerableValues))
                {
                    Debug.Assert(subprotocolEnumerableValues is string[]);
                    string[] subprotocolArray = (string[])subprotocolEnumerableValues;
                    if (subprotocolArray.Length > 0 && !string.IsNullOrEmpty(subprotocolArray[0]))
                    {
                        subprotocol = options.RequestedSubProtocols.Find(requested => string.Equals(requested, subprotocolArray[0], StringComparison.OrdinalIgnoreCase));
                        if (subprotocol == null)
                        {
                            throw new WebSocketException(
                                      WebSocketError.UnsupportedProtocol,
                                      SR.Format(SR.net_WebSockets_AcceptUnsupportedProtocol, string.Join(", ", options.RequestedSubProtocols), string.Join(", ", subprotocolArray)));
                        }
                    }
                }

                if (response.Content is null)
                {
                    throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely);
                }

                // Get the response stream and wrap it in a web socket.
                Stream connectedStream = response.Content.ReadAsStream();
                Debug.Assert(connectedStream.CanWrite);
                Debug.Assert(connectedStream.CanRead);
                WebSocket = WebSocket.CreateFromStream(
                    connectedStream,
                    isServer: false,
                    subprotocol,
                    options.KeepAliveInterval);
            }
            catch (Exception exc)
            {
                if (_state < WebSocketState.Closed)
                {
                    _state = WebSocketState.Closed;
                }

                Abort();
                response?.Dispose();

                if (exc is WebSocketException ||
                    (exc is OperationCanceledException && cancellationToken.IsCancellationRequested))
                {
                    throw;
                }

                throw new WebSocketException(WebSocketError.Faulted, SR.net_webstatus_ConnectFailure, exc);
            }
            finally
            {
                // Disposing the handler will not affect any active stream wrapped in the WebSocket.
                if (disposeHandler)
                {
                    handler?.Dispose();
                }
            }
        }
 public StandardWebSocket(WebSocket webSocket, HttpContext context)
 {
     this.Context   = context;
     this.WebSocket = webSocket ?? throw new ArgumentNullException(nameof(webSocket));
 }
예제 #21
0
        public override async Task KeepConnectionOpen(CancellationToken cancellationToken)
        {
            if (_websocket != null)
            {
                throw new Exception("WebSocket has already been accepted");
            }

            try
            {
                _websocket = await _httpContext.WebSockets.AcceptWebSocketAsync();

                var buffer = ArrayPool <byte> .Shared.Rent(4096);

                while (!cancellationToken.IsCancellationRequested && _websocket.State is WebSocketState.Connecting or WebSocketState.Open)
                {
                    WebSocketReceiveResult message;
                    try
                    {
                        message = await _websocket.ReceiveAsync(new ArraySegment <byte>(buffer), cancellationToken);
                    }
                    catch (OperationCanceledException)
                    {
                        break;
                    }
                    catch (WebSocketException)
                    {
                        break;
                    }
                    catch (IOException)
                    {
                        break;
                    }

                    if (message.MessageType == WebSocketMessageType.Close)
                    {
                        break;
                    }

                    if (message.EndOfMessage && message.MessageType == WebSocketMessageType.Text)
                    {
                        try
                        {
                            var parsed = JsonSerializer.Deserialize <Message>(buffer);
                            if (parsed != null)
                            {
                                OnMessageReceived(parsed);
                            }
                        }
                        catch (JsonException)
                        {
                        }
                    }
                }
            }
            catch (Exception)
            {
            }
            finally
            {
                OnDisconnected();
            }
        }
 public WebSocketAdapter(ClientWebSocket?client = null, WebSocket?server = null)
 {
     Assert.True(client is null ^ server is null);
     _client = client;
     _server = server;
 }