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(); } } 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; }
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 NET_4_6 || UNITY_WSA 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 NET_4_6 || UNITY_WSA 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); }
internal async Task ProcessWebSocketRequestAsync(WebSocketContext webSocketContext, Func <Task <WebSocketMessage> > messageRetriever) { bool cleanClose = true; try { // first, set primitives and initialize the object WebSocketContext = webSocketContext; OnOpen(); // dispatch incoming messages while (true) { WebSocketMessage incomingMessage = await messageRetriever(); switch (incomingMessage.MessageType) { case WebSocketMessageType.Binary: OnMessage((byte[])incomingMessage.Data); break; case WebSocketMessageType.Text: OnMessage((string)incomingMessage.Data); break; default: // 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)) .ContinueWith(_ => { }, TaskContinuationOptions.ExecuteSynchronously); // swallow exceptions occurring from sending the CLOSE return; } } } catch (Exception ex) { if (IsFatalException(ex)) { Error = ex; OnError(); cleanClose = false; } } finally { try { OnClose(cleanClose); } finally { // call Dispose if it exists IDisposable disposable = this as IDisposable; if (disposable != null) { disposable.Dispose(); } } } }
internal async Task ProcessWebSocketRequestAsync(WebSocket webSocket, CancellationToken disconnectToken, Func <object, Task <WebSocketMessage> > messageRetriever, object state) { bool cleanClose = true; try { _isClosed = false; // first, set primitives and initialize the object WebSocket = webSocket; OnOpen(); // dispatch incoming messages while (!disconnectToken.IsCancellationRequested) { WebSocketMessage incomingMessage = await messageRetriever(state); switch (incomingMessage.MessageType) { case WebSocketMessageType.Binary: OnMessage((byte[])incomingMessage.Data); break; case WebSocketMessageType.Text: OnMessage((string)incomingMessage.Data); break; default: // 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)) .ContinueWith(_ => { }, TaskContinuationOptions.ExecuteSynchronously); // swallow exceptions occurring from sending the CLOSE return; } } } catch (OperationCanceledException ex) { // ex.CancellationToken never has the token that was actually cancelled if (!disconnectToken.IsCancellationRequested) { Error = ex; OnError(); cleanClose = false; } } catch (Exception ex) { if (IsFatalException(ex)) { Error = ex; OnError(); cleanClose = false; } } finally { try { Close(); } finally { OnClose(cleanClose); } } }