private void Dispose(bool disposing) { if (disposing) { OrderSentUnsubscriber?.Dispose(); ServerWebSocketConnection?.Dispose(); (DataRepository as IDisposable)?.Dispose(); } }
public async Task Get() { try { var context = ControllerContext.HttpContext; var isSocketRequest = context.WebSockets.IsWebSocketRequest; if (!isSocketRequest) { _logger.LogWarning("A non-websocket request was received."); context.Response.StatusCode = 400; return; } int counter = 0; using (WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync()) using (var serverConnection = new ServerWebSocketConnection(webSocket)) { while (true) { counter++; if (counter >= 4) { _logger.LogInformation("Disconnecting..."); await serverConnection.Disconnect(); return; } var packet = await serverConnection.Receive(); if (packet == null) { return; } var message = Encoding.UTF8.GetString(packet.Body); _logger.LogInformation(message); await serverConnection.Send(packet.Body, packet.Type); } } } catch (Exception ex) { _logger.LogError(ex, "Unhandled exception in the WebSocketController."); return; } }
public async Task IsRunning_SingleCycle_ReturnsValidStatus() { using ServerWebSocketConnection server = WebSocketServer.CreateServer(TEST_CONNECTION_PORT); Assert.IsFalse(server.IsRunning); Task serverTask = Task.Run(server.RunServerLoop); // ReSharper disable once AccessToDisposedClosure Assert.IsTrue(SpinWait.SpinUntil(() => server.IsRunning, TEST_TIMEOUT)); await server.DisconnectAsync(); Assert.IsTrue(serverTask.Wait(TEST_TIMEOUT)); Assert.IsFalse(server.IsRunning); }
public async Task RunServer() { if (!await DataRepository.OpenRepository(RepositoryParam)) { Console.WriteLine("Failed to open the data repository!"); return; } ServerWebSocketConnection.OnClientConnected += ServerWebSocketConnection_OnClientConnected; ServerWebSocketConnection.OnMessage += (e, a) => OnMessage(a.Connection, a.Message); ServerWebSocketConnection.OnError += (e, a) => OnError(a.Connection, a.Exception); ServerWebSocketConnection.OnClose += (e, a) => OnClose(a.Connection); await ServerWebSocketConnection.RunServerLoop(); }
public async Task TwoWayCommunication_MessagesReceivedAndValid() { const string MSG1 = "abcd", MSG2 = "ASDF123", MSG3 = "qwerty", MSG4 = "¹³œæÊÓÆŒ¥£"; ConcurrentQueue <string> serverMessages = new ConcurrentQueue <string>(), clientMessages = new ConcurrentQueue <string>(); using AutoResetEvent serverMsgEvent = new AutoResetEvent(false), clientConnEvent = new AutoResetEvent(false), clientMsgEvent = new AutoResetEvent(false); using ServerWebSocketConnection server = WebSocketServer.CreateServer(TEST_CONNECTION_PORT); server.OnMessage += (o, a) => { serverMessages.Enqueue(a.Message); serverMsgEvent.Set(); }; server.OnClientConnected += (o, a) => clientConnEvent.Set(); _ = Task.Run(server.RunServerLoop); using WebSocketConnection client = await WebSocketClient.ConnectAsync(TEST_CONNECTION_URI); client.OnMessage += (o, a) => { clientMessages.Enqueue(a.Message); clientMsgEvent.Set(); }; Assert.IsTrue(clientConnEvent.WaitOne(TEST_TIMEOUT)); await client.SendAsync(MSG1); Assert.IsTrue(serverMsgEvent.WaitOne(TEST_TIMEOUT)); await client.SendAsync(MSG2); Assert.IsTrue(serverMsgEvent.WaitOne(TEST_TIMEOUT)); await server.SendAsync(MSG3); Assert.IsTrue(clientMsgEvent.WaitOne(TEST_TIMEOUT)); await server.SendAsync(MSG4); Assert.IsTrue(clientMsgEvent.WaitOne(TEST_TIMEOUT)); Assert.AreEqual(2, serverMessages.Count); Assert.AreEqual(2, clientMessages.Count); Assert.IsTrue(serverMessages.TryDequeue(out string msg)); Assert.AreEqual(MSG1, msg); Assert.IsTrue(serverMessages.TryDequeue(out msg)); Assert.AreEqual(MSG2, msg); Assert.IsTrue(clientMessages.TryDequeue(out msg)); Assert.AreEqual(MSG3, msg); Assert.IsTrue(clientMessages.TryDequeue(out msg)); Assert.AreEqual(MSG4, msg); }
public async Task ConnectDisconnect_ValidStatusAndInvokesConnectionEvents() { using ServerWebSocketConnection server = WebSocketServer.CreateServer(TEST_CONNECTION_PORT); bool connected = false; bool serverSideDisconnected = false, clientSideDisconnected = false; server.OnClientConnected += (o, a) => connected = true; server.OnClose += (o, a) => serverSideDisconnected = true; _ = Task.Run(server.RunServerLoop); using WebSocketConnection client = await WebSocketClient.ConnectAsync(TEST_CONNECTION_URI); client.OnClose += (o, a) => clientSideDisconnected = true; Assert.IsTrue(connected); Assert.IsFalse(serverSideDisconnected); Assert.IsFalse(clientSideDisconnected); await client.DisconnectAsync(); Assert.IsTrue(serverSideDisconnected); Assert.IsTrue(clientSideDisconnected); }
private static async Task ServerLoop(Uri _uri, Action <WebSocketConnection> onConnection) { HttpListener _server = new HttpListener(); _server.Prefixes.Add(_uri.ToString()); _server.Start(); while (true) { HttpListenerContext _hc = await _server.GetContextAsync(); if (!_hc.Request.IsWebSocketRequest) { _hc.Response.StatusCode = 400; _hc.Response.Close(); } HttpListenerWebSocketContext _context = await _hc.AcceptWebSocketAsync(null); WebSocketConnection ws = new ServerWebSocketConnection(_context.WebSocket, _hc.Request.RemoteEndPoint); onConnection?.Invoke(ws); } }
public async Task MultipleClients_MessagesDistributedProperly() { const string MSG = "123"; List <WebSocketConnection> serverSideClients = new List <WebSocketConnection>(); uint serverMessages = 0U, c1Messages = 0U, c2Messages = 0U, c3Messages = 0U; using AutoResetEvent serverMsgEvent = new AutoResetEvent(false), clientConnEvent = new AutoResetEvent(false), client1MsgEvent = new AutoResetEvent(false), client2MsgEvent = new AutoResetEvent(false), client3MsgEvent = new AutoResetEvent(false); using (ServerWebSocketConnection server = WebSocketServer.CreateServer(TEST_CONNECTION_PORT)) { _ = Task.Run(server.RunServerLoop); server.OnMessage += (o, a) => { ++serverMessages; serverMsgEvent.Set(); }; server.OnClientConnected += (o, a) => { serverSideClients.Add(a.ClientConnection); clientConnEvent.Set(); }; using WebSocketConnection client1 = await WebSocketClient.ConnectAsync(TEST_CONNECTION_URI); client1.OnMessage += (o, a) => { ++c1Messages; client1MsgEvent.Set(); }; Assert.IsTrue(clientConnEvent.WaitOne(TEST_TIMEOUT)); using WebSocketConnection client2 = await WebSocketClient.ConnectAsync(TEST_CONNECTION_URI); client2.OnMessage += (o, a) => { ++c2Messages; client2MsgEvent.Set(); }; Assert.IsTrue(clientConnEvent.WaitOne(TEST_TIMEOUT)); using WebSocketConnection client3 = await WebSocketClient.ConnectAsync(TEST_CONNECTION_URI); client3.OnMessage += (o, a) => { ++c3Messages; client3MsgEvent.Set(); }; Assert.IsTrue(clientConnEvent.WaitOne(TEST_TIMEOUT)); await serverSideClients[0].SendAsync(MSG); Assert.IsTrue(client1MsgEvent.WaitOne(TEST_TIMEOUT)); await serverSideClients[1].SendAsync(MSG); Assert.IsTrue(client2MsgEvent.WaitOne(TEST_TIMEOUT)); await serverSideClients[2].SendAsync(MSG); Assert.IsTrue(client3MsgEvent.WaitOne(TEST_TIMEOUT)); await server.SendAsync(MSG); Assert.IsTrue(client1MsgEvent.WaitOne(TEST_TIMEOUT)); Assert.IsTrue(client2MsgEvent.WaitOne(TEST_TIMEOUT)); Assert.IsTrue(client3MsgEvent.WaitOne(TEST_TIMEOUT)); await client1.SendAsync(MSG); Assert.IsTrue(serverMsgEvent.WaitOne(TEST_TIMEOUT)); await client2.SendAsync(MSG); Assert.IsTrue(serverMsgEvent.WaitOne(TEST_TIMEOUT)); await client3.SendAsync(MSG); Assert.IsTrue(serverMsgEvent.WaitOne(TEST_TIMEOUT)); } Assert.AreEqual(3U, serverMessages); Assert.AreEqual(2U, c1Messages); Assert.AreEqual(2U, c2Messages); Assert.AreEqual(2U, c3Messages); }
private async Task ProcessClientMessage(WebSocketConnection connection, string message) { Console.WriteLine($"{connection}> {message}"); if (WebSerializer.TryParseRequest(message, out WebSimpleMessageType msgType)) { switch (msgType) { case WebSimpleMessageType.GetAllClients: { string response = WebSerializer.SerializeWebMessage(WebMessageType.ProvideAllClients, new HashSet <ClientDTO>( (await DataRepository.GetAllClients()) .Select(c => new ClientDTO(c)))); await connection.SendAsync(response); break; } case WebSimpleMessageType.GetAllProducts: { string response = WebSerializer.SerializeWebMessage(WebMessageType.ProvideAllProducts, new HashSet <ProductDTO>( (await DataRepository.GetAllProducts()) .Select(p => new ProductDTO(p)))); await connection.SendAsync(response); break; } case WebSimpleMessageType.GetAllOrders: { string response = WebSerializer.SerializeWebMessage(WebMessageType.ProvideAllOrders, new HashSet <OrderDTO>( (await DataRepository.GetAllOrders()) .Select(o => new OrderDTO(o)))); await connection.SendAsync(response); break; } } } else { try { WebMessageDTO <object> msgDto = WebSerializer.DeserializeWebMessage(message); switch (msgDto.MessageType) { case WebMessageType.AddClient: { if (msgDto.Data is ClientDTO clt) { IClient client = await DataRepository.CreateClient( clt.Username, clt.FirstName, clt.LastName, clt.Street, clt.StreetNumber, clt.PhoneNumber); if (client == null) { await connection.SendAsync(WebSimpleMessageType.Failure.ToString()); } else { ClientDTO newDto = new ClientDTO(client); await connection.SendAsync( WebSerializer.SerializeWebMessage(WebMessageType.ProvideClient, newDto)); await ServerWebSocketConnection.SendAsync( WebSerializer.SerializeWebMessage(WebMessageType.AddClient, newDto)); } } else { await connection.SendAsync(WebSimpleMessageType.Failure.ToString()); } break; } case WebMessageType.UpdateClient: { bool result = false; if (msgDto.Data is ClientDTO clt) { try { result = await DataRepository.Update(clt.ToIClient()); } catch (Exception e) { await connection.SendAsync( WebSerializer.SerializeWebMessage(WebMessageType.Error, e.ToString())); } } await connection.SendAsync(result ?WebSimpleMessageType.Success.ToString() : WebSimpleMessageType.Failure.ToString()); if (result) { await ServerWebSocketConnection.SendAsync( WebSerializer.SerializeWebMessage(WebMessageType.UpdateClient, msgDto.Data)); } break; } case WebMessageType.RemoveClient: { bool result = false; if (msgDto.Data is ClientDTO clt) { try { result = await DataRepository.RemoveClient(clt.ToIClient()); } catch (Exception e) { await connection.SendAsync( WebSerializer.SerializeWebMessage(WebMessageType.Error, e.ToString())); } } await connection.SendAsync(result ?WebSimpleMessageType.Success.ToString() : WebSimpleMessageType.Failure.ToString()); if (result) { await ServerWebSocketConnection.SendAsync( WebSerializer.SerializeWebMessage(WebMessageType.RemoveClient, msgDto.Data)); } break; } case WebMessageType.AddProduct: { if (msgDto.Data is ProductDTO prd) { IProduct product = await DataRepository.CreateProduct( prd.Name, prd.Price, prd.ProductType); if (product == null) { await connection.SendAsync(WebSimpleMessageType.Failure.ToString()); } else { ProductDTO newDto = new ProductDTO(product); await connection.SendAsync( WebSerializer.SerializeWebMessage(WebMessageType.ProvideProduct, newDto)); await ServerWebSocketConnection.SendAsync( WebSerializer.SerializeWebMessage(WebMessageType.AddProduct, newDto)); } } else { await connection.SendAsync(WebSimpleMessageType.Failure.ToString()); } break; } case WebMessageType.UpdateProduct: { bool result = false; if (msgDto.Data is ProductDTO prd) { try { result = await DataRepository.Update(prd.ToIProduct()); } catch (Exception e) { await connection.SendAsync( WebSerializer.SerializeWebMessage(WebMessageType.Error, e.ToString())); } } await connection.SendAsync(result ?WebSimpleMessageType.Success.ToString() : WebSimpleMessageType.Failure.ToString()); if (result) { await ServerWebSocketConnection.SendAsync( WebSerializer.SerializeWebMessage(WebMessageType.UpdateProduct, msgDto.Data)); } break; } case WebMessageType.RemoveProduct: { bool result = false; if (msgDto.Data is ProductDTO prd) { try { result = await DataRepository.RemoveProduct(prd.ToIProduct()); } catch (Exception e) { await connection.SendAsync( WebSerializer.SerializeWebMessage(WebMessageType.Error, e.ToString())); } } await connection.SendAsync(result ?WebSimpleMessageType.Success.ToString() : WebSimpleMessageType.Failure.ToString()); if (result) { await ServerWebSocketConnection.SendAsync( WebSerializer.SerializeWebMessage(WebMessageType.RemoveProduct, msgDto.Data)); } break; } case WebMessageType.AddOrder: { if (msgDto.Data is OrderDTO ord) { IOrder order = await DataRepository.CreateOrder( ord.ClientUsername, ord.OrderDate, ord.ProductIdQuantityMap, ord.DeliveryDate); if (order == null) { await connection.SendAsync(WebSimpleMessageType.Failure.ToString()); } else { OrderDTO newDto = new OrderDTO(order); await connection.SendAsync( WebSerializer.SerializeWebMessage(WebMessageType.ProvideOrder, newDto)); await ServerWebSocketConnection.SendAsync( WebSerializer.SerializeWebMessage(WebMessageType.AddOrder, newDto)); } } else { await connection.SendAsync(WebSimpleMessageType.Failure.ToString()); } break; } case WebMessageType.UpdateOrder: { bool result = false; if (msgDto.Data is OrderDTO ord) { try { result = await DataRepository.Update(ord.ToIOrder()); } catch (Exception e) { await connection.SendAsync( WebSerializer.SerializeWebMessage(WebMessageType.Error, e.ToString())); } } await connection.SendAsync(result ?WebSimpleMessageType.Success.ToString() : WebSimpleMessageType.Failure.ToString()); if (result) { await ServerWebSocketConnection.SendAsync( WebSerializer.SerializeWebMessage(WebMessageType.UpdateOrder, msgDto.Data)); } break; } case WebMessageType.RemoveOrder: { bool result = false; if (msgDto.Data is OrderDTO ord) { try { result = await DataRepository.RemoveOrder(ord.ToIOrder()); } catch (Exception e) { await connection.SendAsync( WebSerializer.SerializeWebMessage(WebMessageType.Error, e.ToString())); } } await connection.SendAsync(result ?WebSimpleMessageType.Success.ToString() : WebSimpleMessageType.Failure.ToString()); if (result) { await ServerWebSocketConnection.SendAsync( WebSerializer.SerializeWebMessage(WebMessageType.RemoveOrder, msgDto.Data)); } break; } case WebMessageType.GetClient: { if (!(msgDto.Data is string username)) { await connection.SendAsync(WebSimpleMessageType.Failure.ToString()); break; } IClient client = await DataRepository.GetClient(username); if (client == null) { await connection.SendAsync(WebSimpleMessageType.Failure.ToString()); break; } string response = WebSerializer.SerializeWebMessage(WebMessageType.ProvideClient, new ClientDTO(client)); await connection.SendAsync(response); break; } case WebMessageType.GetProduct: { if (!(msgDto.Data is uint id)) { await connection.SendAsync(WebSimpleMessageType.Failure.ToString()); break; } IProduct product = await DataRepository.GetProduct(id); if (product == null) { await connection.SendAsync(WebSimpleMessageType.Failure.ToString()); break; } string response = WebSerializer.SerializeWebMessage(WebMessageType.ProvideProduct, new ProductDTO(product)); await connection.SendAsync(response); break; } case WebMessageType.GetOrder: { if (!(msgDto.Data is uint id)) { await connection.SendAsync(WebSimpleMessageType.Failure.ToString()); break; } IOrder order = await DataRepository.GetOrder(id); if (order == null) { await connection.SendAsync(WebSimpleMessageType.Failure.ToString()); break; } string response = WebSerializer.SerializeWebMessage(WebMessageType.ProvideOrder, new OrderDTO(order)); await connection.SendAsync(response); break; } } } catch (Exception e) { Console.WriteLine($"Failed to parse message '{message}' from a client! {e}"); } } }
public void OnNext(OrderSent value) { string msg = WebSerializer.SerializeWebMessage(WebMessageType.OrderSent, new OrderDTO(value.Order)); Task.Run(() => ServerWebSocketConnection.SendAsync(msg)); }