public void ConnectToServer(IPAddress ip, int port) { if (_webSocketConnection != null) return; _webSocketConnection = new WebSocket($"ws://{ip}:{port}"); _webSocketConnection.OnOpen += (sender, args) => { Connected?.Invoke(); }; _webSocketConnection.OnClose += (sender, args) => { Disconnected?.Invoke(); }; _webSocketConnection.OnMessage += (sender, args) => { if (args.IsText) { ReceivedTextMessage?.Invoke(args.Data); } else if (args.IsBinary) { ReceivedByteArrayMessage?.Invoke(args.RawData); } }; _webSocketConnection.OnError += (sender, args) => { ReceivedError?.Invoke(); }; _webSocketConnection.Connect(); }
private async Task ReceiveLoop(WebSocket webSocket, CancellationToken cancellationToken) { var buffer = new byte[MaxMessageSize]; while (true) { var result = await webSocket.ReceiveAsync(new ArraySegment <byte>(buffer), cancellationToken); if (result == null) { break; } if (result.MessageType == WebSocketMessageType.Close) { break; } var data = await ReadFrames(result, webSocket, buffer); if (data.Count == 0) { break; } try { Received?.Invoke(data); } catch (Exception e) { ReceivedError?.Invoke(e); } } }
// send message to client using socket connection or throws exception public async void Send(int connectionId, ArraySegment <byte> segment) { // find the connection if (clients.TryGetValue(connectionId, out WebSocket client)) { try { await client.SendAsync(segment, WebSocketMessageType.Binary, true, cancellation.Token); } catch (ObjectDisposedException) { // connection has been closed, swallow exception Disconnect(connectionId); } catch (Exception exception) { if (clients.ContainsKey(connectionId)) { // paul: If someone unplugs their internet // we can potentially get hundreds of errors here all at once // because all the WriteAsync wake up at once and throw exceptions // by hiding inside this if, I ensure that we only report the first error // all other errors are swallowed. // this prevents a log storm that freezes the server for several seconds ReceivedError?.Invoke(connectionId, exception); } Disconnect(connectionId); } } else { ReceivedError?.Invoke(connectionId, new SocketException((int)SocketError.NotConnected)); } }
public async void Connect(System.Uri uri) { var clientFactory = new WebSocketClientFactory(); cancellation = new CancellationTokenSource(); Connecting = true; try { using (WebSocket = await clientFactory.ConnectAsync(uri, ClientOptions, cancellation.Token)) { Connecting = false; ConnectionActive = true; Connected?.Invoke(); await Receive(WebSocket, cancellation.Token); } } catch (System.ObjectDisposedException) { // client closed Debug.Log("closed connection"); } catch (System.Exception ex) { Debug.LogError(ex); ReceivedError?.Invoke(ex); } finally { Disconnect(); } }
private async Task <ArraySegment <byte> > ReadFrames(WebSocketReceiveResult result, WebSocket webSocket, byte[] buffer) { var count = result.Count; while (!result.EndOfMessage) { if (count >= MaxMessageSize) { var closeMessage = $"Maximum message size {MaxMessageSize} bytes reached."; await webSocket.CloseAsync(WebSocketCloseStatus.MessageTooBig, closeMessage, CancellationToken.None); ReceivedError?.Invoke(new WebSocketException(WebSocketError.HeaderError)); return(new ArraySegment <byte>()); } result = await webSocket.ReceiveAsync(new ArraySegment <byte>(buffer, count, MaxMessageSize - count), CancellationToken.None); count += result.Count; } return(new ArraySegment <byte>(buffer, 0, count)); }
public async Task Listen(int port) { try { cancellation = new CancellationTokenSource(); listener = TcpListener.Create(port); listener.Server.NoDelay = this.NoDelay; listener.Start(); Debug.Log($"Websocket server started listening on port {port}"); while (true) { TcpClient tcpClient = await listener.AcceptTcpClientAsync(); _ = ProcessTcpClient(tcpClient, cancellation.Token); } } catch (ObjectDisposedException) { // do nothing. This will be thrown if the Listener has been stopped } catch (Exception ex) { ReceivedError?.Invoke(0, ex); } }
/// <inheritdoc cref="ISocketAdapter.Connect"/> public void Connect(Uri uri, int timeout) { // TODO will need to use window.setTimeout to implement timeouts on DOM WebSocket. if (Ref > -1) { ReceivedError?.Invoke(new SocketException((int)SocketError.IsConnected)); return; } _uri = uri; IsConnecting = true; Action open = () => { IsConnected = true; IsConnecting = false; Connected?.Invoke(); }; Action <int, string> close = (code, reason) => { IsConnected = false; IsConnecting = false; Ref = -1; Closed?.Invoke(); }; Action <string> error = reason => { IsConnected = false; Ref = -1; ReceivedError?.Invoke(new Exception(reason)); }; Action <string> handler = message => { Received?.Invoke(new ArraySegment <byte>(Encoding.UTF8.GetBytes(message))); }; Ref = UnityWebGLSocketBridge.Instance.CreateSocket(uri.AbsoluteUri, open, close, error, handler); }
async Task ReceiveLoop(WebSocket webSocket, CancellationToken token) { byte[] buffer = new byte[MaxMessageSize]; while (true) { WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment <byte>(buffer), token); if (result == null) { break; } if (result.MessageType == WebSocketMessageType.Close) { break; } // we got a text or binary message, need the full message ArraySegment <byte> data = await ReadFrames(result, webSocket, buffer); if (data.Count == 0) { break; } try { ReceivedData?.Invoke(data); } catch (Exception exception) { ReceivedError?.Invoke(exception); } } }
/// <summary> /// A new socket with server connection and adapter options. /// </summary> /// <param name="scheme">The protocol scheme. Must be "ws" or "wss".</param> /// <param name="host">The host address of the server.</param> /// <param name="port">The port number of the server.</param> /// <param name="adapter">The adapter for use with the socket.</param> public Socket(string scheme, string host, int port, ISocketAdapter adapter) { Logger = NullLogger.Instance; _adapter = adapter; _baseUri = new UriBuilder(scheme, host, port).Uri; _responses = new ConcurrentDictionary <string, TaskCompletionSource <WebSocketMessageEnvelope> >(); _adapter.Connected += () => Connected?.Invoke(); _adapter.Closed += () => { foreach (var response in _responses) { response.Value.TrySetCanceled(); } _responses.Clear(); Closed?.Invoke(); }; _adapter.ReceivedError += e => { if (!_adapter.IsConnected) { foreach (var response in _responses) { response.Value.TrySetCanceled(); } _responses.Clear(); } ReceivedError?.Invoke(e); }; _adapter.Received += ReceivedMessage; }
async Task ProcessTcpClient(TcpClient tcpClient, CancellationToken token) { try { // this worker thread stays alive until either of the following happens: // Client sends a close conection request OR // An unhandled exception is thrown OR // The server is disposed // get a secure or insecure stream Stream stream = tcpClient.GetStream(); if (_secure) { SslStream sslStream = new SslStream(stream, false, CertVerificationCallback); sslStream.AuthenticateAsServer(_sslConfig.Certificate, _sslConfig.ClientCertificateRequired, _sslConfig.EnabledSslProtocols, _sslConfig.CheckCertificateRevocation); stream = sslStream; } WebSocketHttpContext context = await webSocketServerFactory.ReadHttpHeaderFromStreamAsync(tcpClient, stream, token); if (context.IsWebSocketRequest) { WebSocketServerOptions options = new WebSocketServerOptions() { KeepAliveInterval = TimeSpan.FromSeconds(30), SubProtocol = "binary" }; WebSocket webSocket = await webSocketServerFactory.AcceptWebSocketAsync(context, options); await ReceiveLoopAsync(webSocket, token); } else { Debug.Log("Http header contains no web socket upgrade request. Ignoring"); } } catch (IOException) { // do nothing. This will be thrown if the transport is closed } catch (ObjectDisposedException) { // do nothing. This will be thrown if the Listener has been stopped } catch (Exception ex) { ReceivedError?.Invoke(0, ex); } finally { try { tcpClient.Client.Close(); tcpClient.Close(); } catch (Exception ex) { ReceivedError?.Invoke(0, ex); } } }
private async Task ReceiveLoop(TcpClient client) { using (Stream networkStream = client.GetStream()) { while (true) { byte[] data = await ReadMessageAsync(networkStream); if (data == null) { break; } try { // we received some data, raise event ReceivedData?.Invoke(data); } catch (Exception exception) { ReceivedError?.Invoke(exception); } } } }
async Task ReceiveLoopAsync(WebSocket webSocket, CancellationToken token) { int connectionId = NextConnectionId(); clients.Add(connectionId, webSocket); byte[] buffer = new byte[MaxMessageSize]; try { // someone connected, raise event Connected?.Invoke(connectionId); while (true) { WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment <byte>(buffer), token); if (!enabled) { await WaitForEnabledAsync(); } if (result.MessageType == WebSocketMessageType.Close) { Debug.Log($"Client initiated close. Status: {result.CloseStatus} Description: {result.CloseStatusDescription}"); break; } ArraySegment <byte> data = await ReadFrames(connectionId, result, webSocket, buffer, token); if (data.Count == 0) { break; } try { // we received some data, raise event ReceivedData?.Invoke(connectionId, data); } catch (Exception exception) { ReceivedError?.Invoke(connectionId, exception); } } } catch (Exception exception) { ReceivedError?.Invoke(connectionId, exception); } finally { clients.Remove(connectionId); Disconnected?.Invoke(connectionId); } }
private async Task ReceiveLoop(WebSocket webSocket, CancellationToken canceller) { canceller.ThrowIfCancellationRequested(); var buffer = new byte[_maxMessageReadSize]; var bufferReadCount = 0; try { do { var bufferSegment = new ArraySegment <byte>(buffer, bufferReadCount, _maxMessageReadSize - bufferReadCount); var result = await webSocket.ReceiveAsync(bufferSegment, canceller).ConfigureAwait(false); if (result == null) { break; } if (result.MessageType == WebSocketMessageType.Close) { break; } bufferReadCount += result.Count; if (!result.EndOfMessage) { continue; } try { Received?.Invoke(new ArraySegment <byte>(buffer, 0, bufferReadCount)); } catch (Exception e) { ReceivedError?.Invoke(e); } bufferReadCount = 0; } while (_webSocket.State == WebSocketState.Open && !canceller.IsCancellationRequested); } catch (Exception e) { ReceivedError?.Invoke(e); } finally { IsConnecting = false; IsConnected = false; Closed?.Invoke(); } }
/// <inheritdoc cref="ISocketAdapter.Send"/> public void Send(ArraySegment <byte> buffer, CancellationToken cancellationToken, bool reliable = true) { if (Ref == -1) { ReceivedError?.Invoke(new SocketException((int)SocketError.NotConnected)); return; } var payload = Encoding.UTF8.GetString(buffer.Array, buffer.Offset, buffer.Count); UnityWebGLSocketBridge.Instance.Send(Ref, payload); }
public async void Connect(Uri uri) { // not if already started if (webSocket != null) { // paul: exceptions are better than silence ReceivedError?.Invoke(new Exception("Client already connected")); return; } this.uri = uri; // We are connecting from now until Connect succeeds or fails Connecting = true; var options = new WebSocketClientOptions() { NoDelay = true, KeepAliveInterval = TimeSpan.Zero, SecWebSocketProtocol = "binary" }; cancellation = new CancellationTokenSource(); var clientFactory = new WebSocketClientFactory(); try { using (webSocket = await clientFactory.ConnectAsync(uri, options, cancellation.Token)) { var token = cancellation.Token; IsConnected = true; Connecting = false; Connected?.Invoke(); await ReceiveLoop(webSocket, token); } } catch (ObjectDisposedException) { // No error, the client got closed } catch (Exception ex) { ReceivedError?.Invoke(ex); } finally { Disconnect(); Disconnected?.Invoke(); } }
public async void Connect(string host, int port) { // not if already started if (client != null) { // paul: exceptions are better than silence ReceivedError?.Invoke(new Exception("Client already connected")); return; } // We are connecting from now until Connect succeeds or fails Connecting = true; try { // TcpClient can only be used once. need to create a new one each // time. client = new TcpClient(AddressFamily.InterNetworkV6); // works with IPv6 and IPv4 client.Client.DualMode = true; // NoDelay disables nagle algorithm. lowers CPU% and latency // but increases bandwidth client.NoDelay = this.NoDelay; await client.ConnectAsync(host, port); // now we are connected: IsConnected = true; Connecting = false; Connected?.Invoke(); await ReceiveLoop(client); } catch (ObjectDisposedException) { // No error, the client got closed } catch (Exception ex) { ReceivedError?.Invoke(ex); } finally { Disconnect(); Disconnected?.Invoke(); } }
public void Send() { if (Client.ConnectionActive == false) { ReceivedError?.Invoke(new System.Net.Sockets.SocketException((int)System.Net.Sockets.SocketError.NotConnected)); return; } if (EnqueuedMessagesToSend.Count > 0) { SendEnqueuedMessages(EnqueuedMessagesToSend); EnqueuedMessagesToSend = new List <DetourMessage>(); } }
// the listener thread's listen function public async Task ListenAsync(int port) { // absolutely must wrap with try/catch, otherwise thread // exceptions are silent try { if (listener != null) { ReceivedError?.Invoke(0, new Exception("Already listening")); return; } // start listener listener = TcpListener.Create(port); // NoDelay disables nagle algorithm. lowers CPU% and latency // but increases bandwidth listener.Server.NoDelay = this.NoDelay; listener.Start(); Debug.Log($"Tcp server started listening on port {port}"); // keep accepting new clients while (true) { // wait for a tcp client; TcpClient tcpClient = await listener.AcceptTcpClientAsync(); // non blocking receive loop // must be on main thread Task receive = ReceiveLoop(tcpClient); } } catch (ObjectDisposedException) { Debug.Log("Server dispossed"); } catch (Exception exception) { ReceivedError?.Invoke(0, exception); } finally { listener = null; } }
/// <inheritdoc cref="ISocketAdapter.Connect"/> public async void Connect(Uri uri, int timeout) { if (_webSocket != null) { ReceivedError?.Invoke(new SocketException((int)SocketError.IsConnected)); return; } _cancellationSource = new CancellationTokenSource(); _uri = uri; IsConnecting = true; var clientFactory = new WebSocketClientFactory(); try { var cts = new CancellationTokenSource(TimeSpan.FromSeconds(timeout)); var lcts = CancellationTokenSource.CreateLinkedTokenSource(_cancellationSource.Token, cts.Token); using (_webSocket = await clientFactory.ConnectAsync(_uri, _options, lcts.Token)) { IsConnected = true; IsConnecting = false; Connected?.Invoke(); await ReceiveLoop(_webSocket, _cancellationSource.Token); } } catch (TaskCanceledException) { // No error, the socket got closed via the cancellation signal. } catch (ObjectDisposedException) { // No error, the socket got closed. } catch (Exception e) { ReceivedError?.Invoke(e); } finally { Close(); Closed?.Invoke(); } }
// send the data or throw exception public async Task SendAsync(ArraySegment <byte> data) { if (client == null) { ReceivedError?.Invoke(new SocketException((int)SocketError.NotConnected)); return; } try { await SendMessage(client.GetStream(), data); } catch (Exception ex) { Disconnect(); ReceivedError?.Invoke(ex); } }
// send the data or throw exception public async void Send(byte[] data) { if (webSocket == null) { ReceivedError?.Invoke(new SocketException((int)SocketError.NotConnected)); return; } try { await webSocket.SendAsync(new ArraySegment <byte>(data), WebSocketMessageType.Binary, true, cancellation.Token); } catch (Exception ex) { Disconnect(); ReceivedError?.Invoke(ex); } }
private async Task ReceiveLoop(TcpClient tcpClient) { int connectionId = NextConnectionId(); clients.Add(connectionId, tcpClient); try { // someone connected, raise event Connected?.Invoke(connectionId); using (Stream networkStream = tcpClient.GetStream()) { while (true) { byte[] data = await ReadMessageAsync(networkStream); if (data == null) { break; } try { // we received some data, raise event ReceivedData?.Invoke(connectionId, data); } catch (Exception exception) { ReceivedError?.Invoke(connectionId, exception); } } } } catch (Exception exception) { ReceivedError?.Invoke(connectionId, exception); } finally { clients.Remove(connectionId); Disconnected?.Invoke(connectionId); } }
/// <summary> /// A new socket with server connection and adapter options. /// </summary> /// <param name="scheme">The protocol scheme. Must be "ws" or "wss".</param> /// <param name="host">The host address of the server.</param> /// <param name="port">The port number of the server.</param> /// <param name="adapter">The adapter for use with the socket.</param> /// <param name="sendTimeoutSec">The maximum time allowed for a message to be sent.</param> public Socket(string scheme, string host, int port, ISocketAdapter adapter, int sendTimeoutSec = DefaultSendTimeout) { Logger = NullLogger.Instance; _adapter = adapter; _baseUri = new UriBuilder(scheme, host, port).Uri; _responses = new Dictionary <string, TaskCompletionSource <WebSocketMessageEnvelope> >(); _sendTimeoutSec = TimeSpan.FromSeconds(sendTimeoutSec); _adapter.Connected += () => Connected?.Invoke(); _adapter.Closed += () => { lock (_responsesLock) { foreach (var response in _responses) { response.Value.TrySetCanceled(); } _responses.Clear(); } Closed?.Invoke(); }; _adapter.ReceivedError += e => { if (!_adapter.IsConnected) { lock (_responsesLock) { foreach (var response in _responses) { response.Value.TrySetCanceled(); } _responses.Clear(); } } ReceivedError?.Invoke(e); }; _adapter.Received += ProcessMessage; }
/// <inheritdoc cref="ISocketAdapter.Send"/> public async void Send(ArraySegment <byte> buffer, CancellationToken cancellationToken, bool reliable = true) { if (_webSocket == null) { ReceivedError?.Invoke(new SocketException((int)SocketError.NotConnected)); return; } try { await _webSocket.SendAsync(buffer, WebSocketMessageType.Text, true, cancellationToken); } catch (Exception e) { Close(); ReceivedError?.Invoke(e); } }
// a message might come splitted in multiple frames // collect all frames private async Task <byte[]> ReadFrames(WebSocketReceiveResult result, WebSocket webSocket, byte[] buffer) { int count = result.Count; while (!result.EndOfMessage) { if (count >= MaxMessageSize) { string closeMessage = string.Format("Maximum message size: {0} bytes.", MaxMessageSize); await webSocket.CloseAsync(WebSocketCloseStatus.MessageTooBig, closeMessage, CancellationToken.None); ReceivedError?.Invoke(new WebSocketException(WebSocketError.HeaderError)); return(null); } result = await webSocket.ReceiveAsync(new ArraySegment <byte>(buffer, count, MaxMessageSize - count), CancellationToken.None); count += result.Count; } return(new ArraySegment <byte>(buffer, 0, count).ToArray()); }
private void SendEnqueuedMessages(List <DetourMessage> enqueuedMessagesToSend) { foreach (var item in enqueuedMessagesToSend) { if (ConnectionActive) { try { JSONBuffer = JsonConvert.SerializeObject(item, JSONSettings); MessageBuffer = Encoding.UTF8.GetBytes(JSONBuffer); Client.Send(MessageBuffer); } catch (System.Exception ex) { Debug.LogError(ex); Client.Disconnect(); ReceivedError?.Invoke(ex); } } } }
// send message to client using socket connection or throws exception private async Task SendAsync(int connectionId, MemoryStream data) { // find the connection if (clients.TryGetValue(connectionId, out TcpClient client)) { try { NetworkStream stream = client.GetStream(); await SendMessage(stream, data); } catch (ObjectDisposedException) { // connection has been closed, swallow exception Disconnect(connectionId); } catch (Exception exception) { if (clients.ContainsKey(connectionId)) { // paul: If someone unplugs their internet // we can potentially get hundreds of errors here all at once // because all the WriteAsync wake up at once and throw exceptions // by hiding inside this if, I ensure that we only report the first error // all other errors are swallowed. // this prevents a log storm that freezes the server for several seconds ReceivedError?.Invoke(connectionId, exception); } Disconnect(connectionId); } } else { ReceivedError?.Invoke(connectionId, new SocketException((int)SocketError.NotConnected)); } // we are done with the buffer return it bufferPool.PutObject(data); }
public void ConnectToServer(string address, int port, bool isUsingSecureConnection) { if (_webSocketConnection != null) { return; } var urlPrefix = isUsingSecureConnection ? "wss" : "ws"; _webSocketConnection = new WebSocket($"{urlPrefix}://{address}:{port}/Listener"); _webSocketConnection.OnOpen += (sender, args) => { Connected?.Invoke(); }; _webSocketConnection.OnClose += (sender, args) => { Disconnected?.Invoke(); }; _webSocketConnection.OnMessage += (sender, args) => { if (args.IsBinary) { ReceivedByteArrayMessage?.Invoke(args.RawData); } }; _webSocketConnection.OnError += (sender, args) => { ReceivedError?.Invoke(); }; _webSocketConnection.Connect(); ConfigureNoDelay(); }
private void ReceivedMessage(ArraySegment <byte> buffer) { var contents = System.Text.Encoding.UTF8.GetString(buffer.Array, buffer.Offset, buffer.Count); Logger?.DebugFormat("Received JSON over web socket: {0}", contents); var envelope = contents.FromJson <WebSocketMessageEnvelope>(); try { if (!string.IsNullOrEmpty(envelope.Cid)) { lock (_lockObj) { // Handle message response. if (_responses.ContainsKey(envelope.Cid)) { TaskCompletionSource <WebSocketMessageEnvelope> completer = _responses[envelope.Cid]; _responses.Remove(envelope.Cid); if (envelope.Error != null) { completer.SetException(new WebSocketException(WebSocketError.InvalidState, envelope.Error.Message)); } else { completer.SetResult(envelope); } } else { Logger?.ErrorFormat("No completer for message cid: {0}", envelope.Cid); } } } else if (envelope.Error != null) { ReceivedError?.Invoke(new WebSocketException(WebSocketError.InvalidState, envelope.Error.Message)); } else if (envelope.ChannelMessage != null) { ReceivedChannelMessage?.Invoke(envelope.ChannelMessage); } else if (envelope.ChannelPresenceEvent != null) { ReceivedChannelPresence?.Invoke(envelope.ChannelPresenceEvent); } else if (envelope.MatchmakerMatched != null) { ReceivedMatchmakerMatched?.Invoke(envelope.MatchmakerMatched); } else if (envelope.MatchPresenceEvent != null) { ReceivedMatchPresence?.Invoke(envelope.MatchPresenceEvent); } else if (envelope.MatchState != null) { ReceivedMatchState?.Invoke(envelope.MatchState); } else if (envelope.NotificationList != null) { foreach (var notification in envelope.NotificationList.Notifications) { ReceivedNotification?.Invoke(notification); } } else if (envelope.StatusPresenceEvent != null) { ReceivedStatusPresence?.Invoke(envelope.StatusPresenceEvent); } else if (envelope.StreamPresenceEvent != null) { ReceivedStreamPresence?.Invoke(envelope.StreamPresenceEvent); } else if (envelope.StreamState != null) { ReceivedStreamState?.Invoke(envelope.StreamState); } else if (envelope.Party != null) { ReceivedParty?.Invoke(envelope.Party); } else if (envelope.PartyClose != null) { ReceivedPartyClose?.Invoke(envelope.PartyClose); } else if (envelope.PartyData != null) { ReceivedPartyData?.Invoke(envelope.PartyData); } else if (envelope.PartyJoinRequest != null) { ReceivedPartyJoinRequest?.Invoke(envelope.PartyJoinRequest); } else if (envelope.PartyLeader != null) { ReceivedPartyLeader?.Invoke(envelope.PartyLeader); } else if (envelope.PartyMatchmakerTicket != null) { ReceivedPartyMatchmakerTicket?.Invoke(envelope.PartyMatchmakerTicket); } else if (envelope.PartyPresenceEvent != null) { ReceivedPartyPresence?.Invoke(envelope.PartyPresenceEvent); } else { Logger?.ErrorFormat("Received unrecognised message: '{0}'", contents); } } catch (Exception e) { ReceivedError?.Invoke(e); } }
private void ReceivedMessage(ArraySegment <byte> buffer) { var contents = System.Text.Encoding.UTF8.GetString(buffer.Array, buffer.Offset, buffer.Count); var envelope = contents.FromJson <WebSocketMessageEnvelope>(); try { if (!string.IsNullOrEmpty(envelope.Cid)) { // Handle message response. TaskCompletionSource <WebSocketMessageEnvelope> completer; var cid = envelope.Cid; _responses.TryRemove(cid, out completer); if (completer == null) { Logger?.ErrorFormat("No completer for message cid: {0}", envelope.Cid); return; } if (envelope.Error != null) { completer.SetException(new WebSocketException(WebSocketError.InvalidState, envelope.Error.Message)); } else { completer.SetResult(envelope); } } else if (envelope.Error != null) { ReceivedError?.Invoke(new WebSocketException(WebSocketError.InvalidState, envelope.Error.Message)); } else if (envelope.ChannelMessage != null) { ReceivedChannelMessage?.Invoke(envelope.ChannelMessage); } else if (envelope.ChannelPresenceEvent != null) { ReceivedChannelPresence?.Invoke(envelope.ChannelPresenceEvent); } else if (envelope.MatchmakerMatched != null) { ReceivedMatchmakerMatched?.Invoke(envelope.MatchmakerMatched); } else if (envelope.MatchPresenceEvent != null) { ReceivedMatchPresence?.Invoke(envelope.MatchPresenceEvent); } else if (envelope.MatchState != null) { ReceivedMatchState?.Invoke(envelope.MatchState); } else if (envelope.NotificationList != null) { foreach (var notification in envelope.NotificationList.Notifications) { ReceivedNotification?.Invoke(notification); } } else if (envelope.StatusPresenceEvent != null) { ReceivedStatusPresence?.Invoke(envelope.StatusPresenceEvent); } else if (envelope.StreamPresenceEvent != null) { ReceivedStreamPresence?.Invoke(envelope.StreamPresenceEvent); } else if (envelope.StreamState != null) { ReceivedStreamState?.Invoke(envelope.StreamState); } else { Logger?.ErrorFormat("Received unrecognised message: '{0}'", contents); } } catch (Exception e) { ReceivedError?.Invoke(e); } }