Beispiel #1
0
 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;
            }
        }
Beispiel #3
0
        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);
        }
Beispiel #4
0
        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();
        }
Beispiel #5
0
        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);
        }
Beispiel #6
0
        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);
            }
        }
Beispiel #8
0
        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);
        }
Beispiel #9
0
        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}");
                }
            }
        }
Beispiel #10
0
        public void OnNext(OrderSent value)
        {
            string msg = WebSerializer.SerializeWebMessage(WebMessageType.OrderSent, new OrderDTO(value.Order));

            Task.Run(() => ServerWebSocketConnection.SendAsync(msg));
        }