internal async Task ProcessWebSocketRequestAsync(WebSocket webSocket, CancellationToken disconnectToken, Func <object, Task <WebSocketMessage> > messageRetriever, object state) { bool closedReceived = false; try { // first, set primitives and initialize the object WebSocket = webSocket; OnOpen(); // dispatch incoming messages while (!disconnectToken.IsCancellationRequested && !closedReceived) { WebSocketMessage incomingMessage = await messageRetriever(state).PreserveCulture(); switch (incomingMessage.MessageType) { case WebSocketMessageType.Binary: OnMessage((byte[])incomingMessage.Data); break; case WebSocketMessageType.Text: OnMessage((string)incomingMessage.Data); break; default: closedReceived = true; // If we received an incoming CLOSE message, we'll queue a CLOSE frame to be sent. // We'll give the queued frame some amount of time to go out on the wire, and if a // timeout occurs we'll give up and abort the connection. await Task.WhenAny(CloseAsync(), Task.Delay(_closeTimeout)).PreserveCulture(); break; } } } catch (OperationCanceledException ex) { // ex.CancellationToken never has the token that was actually cancelled if (!disconnectToken.IsCancellationRequested) { Error = ex; OnError(); } } catch (ObjectDisposedException) { // If the websocket was disposed while we were reading then noop } catch (Exception ex) { if (IsFatalException(ex)) { Error = ex; OnError(); } } try { #if CLIENT var webSocketState = GetWebSocketState(WebSocket); if (webSocketState == WebSocketState.Closed || webSocketState == WebSocketState.Aborted) { // No-op if the socket is already closed or aborted } else { // Initiate the WebSocket closing handshake. Only the client should ever do this. await WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None).PreserveCulture(); } #endif } finally { #if CLIENT WebSocket.Dispose(); #endif OnClose(); } }
private static bool TryGetMessage(WebSocketReceiveResult receiveResult, byte[] buffer, out WebSocketMessage message) { message = null; if (receiveResult.MessageType == WebSocketMessageType.Close) { message = WebSocketMessage.CloseMessage; } else if (receiveResult.EndOfMessage) { // we anticipate that single-fragment messages will be common, so we optimize for them switch (receiveResult.MessageType) { case WebSocketMessageType.Binary: if (buffer == null) { message = WebSocketMessage.EmptyBinaryMessage; } else { message = new WebSocketMessage(BufferSliceToByteArray(buffer, receiveResult.Count), WebSocketMessageType.Binary); } break; case WebSocketMessageType.Text: if (buffer == null) { message = WebSocketMessage.EmptyTextMessage; } else { message = new WebSocketMessage(BufferSliceToString(buffer, receiveResult.Count), WebSocketMessageType.Text); } break; default: throw new InvalidOperationException("Unknown message type"); } } return(message != null); }