Пример #1
0
        internal ConnectionManager(SemaphoreSlim stateLock, Logger logger, int connectionTimeout,
                                   Func <Task> onConnecting, Func <Exception, Task> onDisconnecting, Action <Func <Exception, Task> > clientDisconnectHandler)
        {
            _stateLock         = stateLock;
            _logger            = logger;
            _connectionTimeout = connectionTimeout;
            _onConnecting      = onConnecting;
            _onDisconnecting   = onDisconnecting;

            clientDisconnectHandler(ex =>
            {
                if (ex != null)
                {
                    WebSocketClosedException ex2 = ex as WebSocketClosedException;
                    if (ex2?.CloseCode == 4006)
                    {
                        CriticalError(new Exception("WebSocket session expired", ex));
                    }
                    else if (ex2?.CloseCode == 4014)
                    {
                        CriticalError(new Exception("WebSocket connection was closed, some intents defined are not allowed by the bot app.", ex));
                    }
                    else
                    {
                        Error(new Exception("WebSocket connection was closed", ex));
                    }
                }
                else
                {
                    Error(new Exception("WebSocket connection was closed"));
                }
                return(Task.Delay(0));
            });
        }
Пример #2
0
        private void OnClosed(object sender, CloseEventArgs e)
        {
            if (e.WasClean)
            {
                this.Closed?.Invoke(null).GetAwaiter().GetResult();
                return;
            }

            var ex = new WebSocketClosedException(e.Code, e.Reason);

            this.Closed?.Invoke(ex).GetAwaiter().GetResult();
        }
Пример #3
0
        private async Task Receive(Func <Stream, Task> handleMessage, CancellationToken ct)
        {
            Exception closingException = null;

            while (!ct.IsCancellationRequested && _clientWebSocket.State == WebSocketState.Open)
            {
                try
                {
                    ArraySegment <byte> buffer = new ArraySegment <byte>(new byte[1024 * 4]);

                    using (var stream = _clientWebSocket.GetReadStream())
                    {
                        // Wait for data
                        await stream.WaitForDataAsync(ct);

                        var             receiveIterator  = _middleware.GetEnumerator();
                        RecieveDelegate receiveDelegator = null;
                        receiveDelegator = async transformedMessage =>
                        {
                            if (receiveIterator.MoveNext())
                            {
                                using (_logger?.Tracer($"Middleware[{receiveIterator.Current.GetType()}].RecieveAsync(...)"))
                                {
                                    await receiveIterator.Current.RecieveAsync(new ConnectionContext(_clientWebSocket, transformedMessage.Stream), receiveDelegator).ConfigureAwait(false);
                                }
                            }
                            else
                            {
                                using (_logger?.Tracer("Connection.InternalReceive(...)"))
                                {
                                    await handleMessage(transformedMessage.Stream).ConfigureAwait(false);
                                }
                            }
                        };

                        await receiveDelegator(new ConnectionContext(_clientWebSocket, stream))
                        .ContinueWith(task =>
                        {
                            // Dispose of our middleware iterator before we handle possible exceptions
                            receiveIterator.Dispose();

                            // Unwrap and allow the outer catch to handle if we have an exception
                            task.WaitAndUnwrapException();
                        })
                        .ConfigureAwait(false);
                    }
                }
                catch (WebSocketException e) when(e.Message == "The remote party closed the WebSocket connection without completing the close handshake.")
                {
                    _logger.LogWarning("Observed WebSocketException - likely server closing our connection");

                    // Eat the exception because we're closing
                    closingException = new WebSocketClosedException("Observed WebSocketException - likely server closing our connection", e);

                    try
                    {
                        if (_clientWebSocket.State == WebSocketState.CloseReceived)
                        {
                            // Attempt to be "good" and close
                            await _clientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, null, ct);
                        }
                        else
                        {
                            _clientWebSocket.Abort();
                        }
                    }
                    catch (Exception) { }

                    // Fire the closing event
                    FireClosed(e);

                    // But we cancel out because the socket is closed
                    break;
                }
                catch (WebSocketClosedException e)
                {
                    _logger.LogWarning("Observed WebSocketClosedException - likely OK");

                    // Eat the exception because we're closing
                    closingException = e;

                    try
                    {
                        if (_clientWebSocket.State == WebSocketState.CloseReceived)
                        {
                            // Attempt to be "good" and close
                            await _clientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, null, ct);
                        }
                    }
                    catch (Exception) { }

                    // Fire the closing event
                    FireClosed(e);

                    // But we cancel out because the socket is closed
                    break;
                }
                catch (Exception e)
                {
                    _logger.LogError(new EventId(), e, $"Observed {e.GetType()}!");

                    Error?.Invoke(e);
                }
            }

            // We're closing so we need to unblock any pending TaskCompletionSources
            InvocationRequest[] calls;

            lock (_pendingCallsLock)
            {
                calls = _pendingCalls.Values.ToArray();
                _pendingCalls.Clear();
            }

            foreach (var request in calls)
            {
                request.Registration.Dispose();
                request.Completion.TrySetException(closingException ?? new WebSocketClosedException("The WebSocket has been closed!"));
            }
        }