/// <summary>
        /// Stop the server
        /// </summary>
        public async Task Stop()
        {
            BotServices.GetService <IBotLogger>().LogInformation($"Websocket server stopping all clients...");
            WebSocketClients.ForEach(async delegate(WebSocketClient client)
            {
                await client.CloseAsync();
            });
            await WebSocketServer.StopAsync();

            BotServices.GetService <IBotLogger>().LogInformation($"Websocket server stopped");
        }
        // --- [Javascripting ] ---

        private JavaScriptValue JSPushMessage(JavaScriptValue callee, bool isConstructCall, JavaScriptValue[] arguments, ushort argumentCount, IntPtr callbackData)
        {
            if (arguments.Length < 3)
            {
                JSThrowException("not enough arguments");
                return(JavaScriptValue.Invalid);
            }

            string socketId = arguments[1].ToString();
            string message  = arguments[2].ToString();

            // #todo make this async?
            WebSocketClients.SendMessageAsync(socketId, message);

            return(JavaScriptValue.Invalid);
        }
 /// <summary>
 /// Get unique identifiers of all open clients
 /// </summary>
 /// <returns></returns>
 public List <Guid> GetClientIds()
 {
     return(WebSocketClients.Select(x => x.GetId()).ToList());
 }
        public virtual async void ProcessWebSocketRequest(HttpListenerContext context)
        {
            WebSocketContext webSocketContext = null;

            try
            {
                // When calling `AcceptWebSocketAsync` the negotiated subprotocol must be specified. For simplicity now we assumes that no subprotocol
                // was requested.
                webSocketContext = await context.AcceptWebSocketAsync(null);

                if (_websocketConnectionCount == int.MaxValue)
                {
                    Log("[VERBOSE] Websocket reset connection count");
                    _websocketConnectionCount = 0;
                }
                Interlocked.Increment(ref _websocketConnectionCount);
                Log(string.Format("[VERBOSE] Websocket #{0}", _websocketConnectionCount));
            }
            catch (Exception ex)
            {
                // The upgrade process failed somehow. For simplicity lets assume it was a failure on the part of the server and indicate this using 500.
                context.Response.StatusCode = 500;
                context.Response.Close();
                Log(string.Format("[ERROR] {0}", ex.Message));
                return;
            }

            WebSocket webSocket = webSocketContext.WebSocket;
            string    clientId  = WebSocketClients.AddSocket(webSocket);

            try
            {
                Log("[VERBOSE] Websocket is receiving");

                //### Receiving
                // Define a receive buffer to hold data received on the WebSocket connection. The buffer will be reused as we only need to hold on to the data
                // long enough to send it back to the sender.
                ArraySegment <byte> receiveBuffer = new ArraySegment <byte>(new byte[1024]);  // 8192;
                MemoryStream        msText        = null;
                MemoryStream        msBin         = null;

                // While the WebSocket connection remains open run a simple loop that receives data and sends it back.
                while (webSocket.State == WebSocketState.Open)
                {
                    // The first step is to begin a receive operation on the WebSocket. `ReceiveAsync` takes two parameters:
                    //
                    // * An `ArraySegment` to write the received data to.
                    // * A cancellation token. In this example we are not using any timeouts so we use `CancellationToken.None`.
                    //
                    // `ReceiveAsync` returns a `Task<WebSocketReceiveResult>`. The `WebSocketReceiveResult` provides information on the receive operation that was just
                    // completed, such as:
                    //
                    // * `WebSocketReceiveResult.MessageType` - What type of data was received and written to the provided buffer. Was it binary, utf8, or a close message?
                    // * `WebSocketReceiveResult.Count` - How many bytes were read?
                    // * `WebSocketReceiveResult.EndOfMessage` - Have we finished reading the data for this message or is there more coming?
                    WebSocketReceiveResult receiveResult = await webSocket.ReceiveAsync(receiveBuffer, CancellationToken.None);

                    if (receiveResult.MessageType == WebSocketMessageType.Close)
                    {
                        // The WebSocket protocol defines a close handshake that allows a party to send a close frame when they wish to gracefully shut down the connection.
                        // The party on the other end can complete the close handshake by sending back a close frame.
                        //
                        // If we received a close frame then lets participate in the handshake by sending a close frame back. This is achieved by calling `CloseAsync`.
                        // `CloseAsync` will also terminate the underlying TCP connection once the close handshake is complete.
                        //
                        // The WebSocket protocol defines different status codes that can be sent as part of a close frame and also allows a close message to be sent.
                        // If we are just responding to the client's request to close we can just use `WebSocketCloseStatus.NormalClosure` and omit the close message.

                        Log(string.Format("[VERBOSE] Websocket for client {0} graceful close", clientId));
                        await WebSocketClients.RemoveSocket(clientId);
                    }
                    else if (receiveResult.MessageType == WebSocketMessageType.Text)
                    {
                        // We received text!

                        if (msText == null)
                        {
                            Log("[VERBOSE] Websocket text frame");
                            msText = new MemoryStream();
                        }
                        else
                        {
                            Log("[VERBOSE] Websocket text frame (append)");
                        }

                        msText.Write(receiveBuffer.Array, receiveBuffer.Offset, receiveResult.Count);

                        if (receiveResult.EndOfMessage)
                        {
                            msText.Seek(0, SeekOrigin.Begin);
                            using (var reader = new StreamReader(msText, Encoding.UTF8))
                            {
                                string receiveText = reader.ReadToEnd();
                                string sendText    = ProcessWebSocketTextRequest(clientId, receiveText);
                                byte[] encoded     = Encoding.UTF8.GetBytes(sendText);
                                var    sendBuffer  = new ArraySegment <byte>(encoded, 0, encoded.Length);
                                await webSocket.SendAsync(sendBuffer, WebSocketMessageType.Text, true, CancellationToken.None);
                            }

                            msText.Close();
                            msText.Dispose();
                            msText = null;
                        }
                    }
                    else
                    {
                        // We received binary data!

                        if (msBin == null)
                        {
                            Log("[VERBOSE] Websocket bin frame");
                            msBin = new MemoryStream();
                        }
                        else
                        {
                            Log("[VERBOSE] Websocket bin frame (append)");
                        }

                        msBin.Write(receiveBuffer.Array, receiveBuffer.Offset, receiveResult.Count);

                        if (receiveResult.EndOfMessage)
                        {
                            msBin.Seek(0, SeekOrigin.Begin);
                            Stream sendStream = ProcessWebSocketBinaryRequest(clientId, msBin);
                            sendStream.Seek(0, SeekOrigin.Begin);
                            byte[] sendBytes = new byte[sendStream.Length];
                            sendStream.Read(sendBytes, 0, (int)sendStream.Length);
                            var sendBuffer = new ArraySegment <byte>(sendBytes, 0, sendBytes.Length);
                            await webSocket.SendAsync(sendBuffer, WebSocketMessageType.Binary, true, CancellationToken.None);

                            msBin.Close();
                            msBin.Dispose();
                            msBin = null;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Log(string.Format("[ERROR] {0}", ex.Message));
            }
            finally
            {
                // Clean up by disposing the WebSocket once it is closed/aborted.
                if (webSocket != null)
                {
                    Log(string.Format("[VERBOSE] Websocket for client {0} is being disposed", clientId));
                    webSocket.Dispose();
                }
            }
        }