Example #1
0
        public BroadcastingChat(ConnectionManager connectionManager, string welcomeMessage)
        {
            this.connectionManager = connectionManager;
            this.welcomeMessage = welcomeMessage;

            connectionManager.ClientConnected += ClientConnected;
            connectionManager.ClientDisconnected += ClientDisconnected;
            connectionManager.IncomingMessage += IncomingMessage;
        }
Example #2
0
        private static void StartServer(Options options)
        {
            logger.Info("==========================");
            logger.Info("Starting server...");

            var cancellationSource = new CancellationTokenSource();
            var cancellation = cancellationSource.Token;

            Console.CancelKeyPress += (sender, e) =>
            {
                e.Cancel = true;
                logger.Info("Gracefully stopping server...");
                cancellationSource.Cancel();
            };

            var threadPool = new Core.ThreadPool(10, cancellation);
            IClientAcceptor acceptor = new TcpClientAcceptor(options.Port);
            var connectionManager = new ConnectionManager(acceptor, cancellation);
            var broadcastingChat = new BroadcastingChat(connectionManager, options.WelcomeMessage);
            var commandShell = new CommandShell("cmd", command => $"/c {command}");

            Func<ClientConnection, string, Task> processCommand = async (client, command) =>
            {
                Message reply;
                if (command.StartsWith("/c "))
                {
                    var task = commandShell.TryStartExecuting(command.Substring(3), TimeSpan.FromSeconds(10));
                    if (task == null)
                        reply = new Message { Sender = "<server-shell>", Text = "Another command is already running." };
                    else
                    {
                        await broadcastingChat.ReplyTo(client, new Message { Sender = "<server-shell>", Text = $"Running `{command}`..." });

                        try { reply = new Message { Sender = "<server-shell>", Text = $"Execution result: {Environment.NewLine}{await task}" }; }
                        catch (OperationCanceledException) { reply = new Message { Sender = "<server-shell>", Text = $"Execution timed out." }; }
                    }
                }
                else
                    reply = new Message { Sender = "<server>", Text = $"Invalid command '{command}'" };

                await broadcastingChat.ReplyTo(client, reply);
            };

            broadcastingChat.IncomingMessageStrategy = incoming =>
            {
                var message = incoming.Message.Text.TrimStart();
                if (message.StartsWith("/"))
                    return processCommand(incoming.Sender, message);
                else
                    return broadcastingChat.BroadcastToAll(incoming.Message);
            };

            var tcs = new TaskCompletionSource<bool>();
            threadPool.Post(async () =>
            {
                logger.Info($"Start accepting clients at port {options.Port}");
                try
                {
                    await acceptor.Listen(cancellation);
                    logger.Info("Finish accepting clients");
                    tcs.TrySetResult(true);
                }
                catch (OperationCanceledException)
                {
                    tcs.SetCanceled();
                }
                catch (Exception ex)
                {
                    logger.Error(ex, "Error accepting clients");
                    tcs.SetException(ex);
                }
            });

            try
            {
                tcs.Task.Wait();
            }
            catch (AggregateException ex)
            {
                try { ex.Handle(exc => exc is OperationCanceledException); }
                catch (Exception innerEx) { logger.Error(innerEx); }
            }
            logger.Info("Server stopped");
        }