/// <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(); } } }