/// <summary>
        /// Builds an <see cref="IBlipClient" /> with the configured parameters
        /// </summary>
        public IBlipClient Build()
        {
            var channelBuilder = ClientChannelBuilder
                                 .Create(() => _transportFactory.Create(EndPoint), EndPoint)
                                 .WithSendTimeout(SendTimeout)
                                 .WithEnvelopeBufferSize(100)
                                 .AddCommandModule(c => new ReplyPingChannelModule(c))
                                 .AddBuiltHandler(
                (c, t) =>
            {
                if (Throughput > 0)
                {
                    ThroughputControlChannelModule.CreateAndRegister(c, Throughput);
                }
                return(Task.CompletedTask);
            });

            var establishedClientChannelBuilder = new EstablishedClientChannelBuilder(channelBuilder)
                                                  .WithIdentity(Identity)
                                                  .WithAuthentication(GetAuthenticationScheme())
                                                  .WithCompression(Compression)
                                                  .WithEncryption(Encryption)
                                                  .AddEstablishedHandler(SetPresenceAsync)
                                                  .AddEstablishedHandler(SetReceiptAsync);

            if (Instance != null)
            {
                establishedClientChannelBuilder = establishedClientChannelBuilder.WithInstance(Instance);
            }

            var onDemandClientChannel = CreateOnDemandClientChannel(establishedClientChannelBuilder);

            return(new BlipClient(onDemandClientChannel, _logger));
        }
Exemple #2
0
 static async Task <TResponse> Send <TRequest, TResponse>(TRequest request)
 {
     using (var channelFactory = ClientChannelBuilder.GetChannelFactory <TRequest, TResponse>(serverUrl))
         using (var client = channelFactory.CreateChannel())
         {
             return(await client.SendRequest(request)
                    .ConfigureAwait(false));
         }
 }
        /// <summary>
        /// Builds a <see cref="IMessagingHubConnection">connection</see> with the configured parameters
        /// </summary>
        /// <returns>An inactive connection with the Messaging Hub. Call <see cref="IMessagingHubConnection.ConnectAsync"/> to activate it</returns>
        public IMessagingHubConnection Build()
        {
            var channelBuilder = ClientChannelBuilder.Create(() => _transportFactory.Create(EndPoint), EndPoint)
                                 .WithSendTimeout(SendTimeout)
                                 .WithEnvelopeBufferSize(ChannelBuffer)
                                 .AddCommandModule(c => new ReplyPingChannelModule(c));

            channelBuilder =
                channelBuilder
                .AddBuiltHandler(
                    (c, t) =>
            {
                if (Throughput > 0)
                {
                    ThroughputControlChannelModule.CreateAndRegister(c, Throughput);
                }

                return(Task.CompletedTask);
            })
                .AddBuiltHandler(
                    (c, t) =>
            {
                if (ChannelCount > 1)
                {
                    FillEnvelopeRecipientsChannelModule.CreateAndRegister(c);
                }

                return(Task.CompletedTask);
            });


            var establishedClientChannelBuilder = new EstablishedClientChannelBuilder(channelBuilder)
                                                  .WithIdentity(Identity)
                                                  .WithAuthentication(GetAuthenticationScheme())
                                                  .WithCompression(Compression)
                                                  .AddEstablishedHandler(SetPresenceAsync)
                                                  .AddEstablishedHandler(SetReceiptAsync)
                                                  .WithEncryption(Encryption);

            if (Instance != null)
            {
                establishedClientChannelBuilder = establishedClientChannelBuilder.WithInstance(Instance);
            }

            var onDemandClientChannelFactory = new OnDemandClientChannelFactory(establishedClientChannelBuilder);

            return(new MessagingHubConnection(SendTimeout, MaxConnectionRetries, onDemandClientChannelFactory, ChannelCount));
        }
Exemple #4
0
        static async Task MainAsync(string[] args)
        {
            Console.Write("Host name (ENTER for default): ");

            var hostName = Console.ReadLine();

            if (string.IsNullOrWhiteSpace(hostName))
            {
                hostName = Dns.GetHostName();
            }

            Console.Write("Port number (ENTER for default): ");

            int portNumber;

            if (!int.TryParse(Console.ReadLine(), out portNumber))
            {
                portNumber = 55321;
            }

            Console.Write("Identity (name@domain - ENTER for none): ");

            Identity identity;

            if (!Identity.TryParse(Console.ReadLine(), out identity))
            {
                identity = null;
            }

            string password = null;

            if (identity != null)
            {
                Console.Write("Password: "******"net.tcp://{hostName}:{portNumber}");
            var transport = new TcpTransport(traceWriter: new DebugTraceWriter());

            // Creates a new client channel
            var builder = ClientChannelBuilder
                          .Create(transport, serverUri)
                          .AddBuiltHandler((channel, token) =>
            {
                channel.CommandModules.Add(new ReplyPingChannelModule(channel));
                return(TaskUtil.CompletedTask);
            })
                          .CreateEstablishedClientChannelBuilder()
                          .AddEstablishedHandler(async(c, t) =>
                                                 await c.SetResourceAsync(
                                                     new LimeUri(UriTemplates.PRESENCE),
                                                     new Presence()
            {
                Status = PresenceStatus.Available
            },
                                                     t))
                          .AddEstablishedHandler(async(c, t) =>
                                                 await c.SetResourceAsync(
                                                     new LimeUri(UriTemplates.RECEIPT),
                                                     new Receipt()
            {
                Events = new[] { Event.Received, Event.Dispatched }
            },
                                                     t));

            if (identity == null)
            {
                builder = builder.WithAuthentication <GuestAuthentication>();
            }
            else
            {
                builder = builder
                          .WithIdentity(identity)
                          .WithPlainAuthentication(password);
            }

            var onDemandChannel = new OnDemandClientChannel(builder);
            var running         = true;

            onDemandChannel.ChannelCreationFailedHandlers.Add(information =>
            {
                Console.Write("Could not establish the session: {0}", information.Exception.Message);
                Console.WriteLine();
                running = false;
                return(TaskUtil.FalseCompletedTask);
            });


            var channelListener = new ChannelListener(message =>
            {
                Console.ForegroundColor = ConsoleColor.DarkRed;
                Console.WriteLine("Message with id '{0}' received from '{1}': {2}", message.Id, message.GetSender(),
                                  message.Content);
                Console.ResetColor();
                return(TaskUtil.TrueCompletedTask);
            },
                                                      notification =>
            {
                Console.ForegroundColor = ConsoleColor.DarkBlue;
                Console.WriteLine("Notification with id {0} received from '{1}' - Event: {2}",
                                  notification.Id, notification.GetSender(), notification.Event);
                Console.ResetColor();
                return(TaskUtil.TrueCompletedTask);
            },
                                                      command =>
            {
                Console.ForegroundColor = ConsoleColor.DarkGreen;
                Console.WriteLine("Command with id '{0}' received from '{1}' - Method: {2} - URI: {3}", command.Id,
                                  command.GetSender(), command.Method, command.Uri);
                Console.ResetColor();
                return(TaskUtil.TrueCompletedTask);
            });

            channelListener.Start(onDemandChannel);

            while (running)
            {
                Console.Write("Destination node (Type EXIT to quit): ");
                var toInput = Console.ReadLine();
                if (toInput != null &&
                    toInput.Equals("exit", StringComparison.InvariantCultureIgnoreCase))
                {
                    break;
                }

                Node to = null;
                if (string.IsNullOrEmpty(toInput) || Node.TryParse(toInput, out to))
                {
                    Console.Write("Message text: ");
                    var message = new Message
                    {
                        To      = to,
                        Content = new PlainText
                        {
                            Text = Console.ReadLine()
                        }
                    };

                    await onDemandChannel.SendMessageAsync(message, CancellationToken.None);
                }
            }

            channelListener.Stop();
            await Task.WhenAll(
                channelListener.MessageListenerTask,
                channelListener.NotificationListenerTask,
                channelListener.CommandListenerTask);

            await onDemandChannel.FinishAsync(CancellationToken.None);

            Console.WriteLine("Press any key to exit.");
            Console.Read();
        }
        static async Task Main(string[] args)
        {
            Console.Write("Server URI (ENTER for default): ");

            var serverUriValue = Console.ReadLine();

            if (string.IsNullOrWhiteSpace(serverUriValue))
            {
                serverUriValue = $"net.tcp://{Dns.GetHostName()}:{55321}";
            }

            Console.Write("Identity (name@domain - ENTER for none): ");
            if (!Identity.TryParse(Console.ReadLine(), out var identity))
            {
                identity = null;
            }

            string password = null;

            if (identity != null)
            {
                Console.Write("Password: "******"Number of channels (ENTER for 1): ");
            if (!int.TryParse(Console.ReadLine(), out var channelCount))
            {
                channelCount = 1;
            }

            var setPresence = false;
            var setReceipts = false;

            // Creates a new transport and connect to the server
            var serverUri = new Uri(serverUriValue);
            Func <ITransport> transportFactory = () => CreateTransportForUri(serverUri);

            // Creates a new client channel
            var builder = ClientChannelBuilder
                          .Create(transportFactory, serverUri)
                          .AddBuiltHandler((channel, token) =>
            {
                channel.CommandModules.Add(new ReplyPingChannelModule(channel));
                return(TaskUtil.CompletedTask);
            })
                          .CreateEstablishedClientChannelBuilder()
                          .WithEncryption(SessionEncryption.None)
                          .AddEstablishedHandler(async(c, t) =>
            {
                if (setPresence)
                {
                    await c.SetResourceAsync(
                        new LimeUri(UriTemplates.PRESENCE),
                        new Presence()
                    {
                        Status      = PresenceStatus.Available,
                        RoutingRule = RoutingRule.Identity,
                        RoundRobin  = true
                    },
                        t);
                }
            })
                          .AddEstablishedHandler(async(c, t) =>
            {
                if (setReceipts)
                {
                    await c.SetResourceAsync(
                        new LimeUri(UriTemplates.RECEIPT),
                        new Receipt()
                    {
                        Events = new[] { Event.Received, Event.Consumed }
                    },
                        t);
                }
            });

            if (identity == null)
            {
                builder = builder.WithAuthentication <GuestAuthentication>();
            }
            else
            {
                builder = builder
                          .WithIdentity(identity)
                          .WithPlainAuthentication(password);
            }

            IOnDemandClientChannel onDemandClientChannel;

            if (channelCount == 1)
            {
                onDemandClientChannel = new OnDemandClientChannel(builder);
            }
            else
            {
                onDemandClientChannel = new MultiplexerClientChannel(builder);
            }

            var running = true;

            onDemandClientChannel.ChannelCreationFailedHandlers.Add(information =>
            {
                Console.Write("Could not establish the session: {0}", information.Exception.Message);
                Console.WriteLine();
                running = false;
                return(TaskUtil.FalseCompletedTask);
            });

            var channelListener = new ChannelListener(message =>
            {
                Console.ForegroundColor = ConsoleColor.DarkRed;
                Console.WriteLine("Message with id '{0}' received from '{1}': {2}", message.Id, message.GetSender(),
                                  message.Content);
                Console.ResetColor();
                return(TaskUtil.TrueCompletedTask);
            },
                                                      notification =>
            {
                Console.ForegroundColor = ConsoleColor.DarkBlue;
                Console.WriteLine("Notification with id {0} received from '{1}' - Event: {2}",
                                  notification.Id, notification.GetSender(), notification.Event);
                Console.ResetColor();
                return(TaskUtil.TrueCompletedTask);
            },
                                                      command =>
            {
                Console.ForegroundColor = ConsoleColor.DarkGreen;
                Console.WriteLine("Command with id '{0}' received from '{1}' - Method: {2} - URI: {3}", command.Id,
                                  command.GetSender(), command.Method, command.Uri);
                Console.ResetColor();
                return(TaskUtil.TrueCompletedTask);
            });


            await onDemandClientChannel.EstablishAsync(CancellationToken.None);

            channelListener.Start(onDemandClientChannel);

            while (running)
            {
                Console.Write("Destination node (Type EXIT to quit): ");
                var toInput = Console.ReadLine();
                if (toInput != null &&
                    toInput.Equals("exit", StringComparison.OrdinalIgnoreCase))
                {
                    break;
                }

                Node to = null;
                if (string.IsNullOrEmpty(toInput) || Node.TryParse(toInput, out to))
                {
                    Console.Write("Message text: ");
                    var text = Console.ReadLine();

                    var stopwatch = Stopwatch.StartNew();

                    Console.Write("Number of times to send (ENTER to 1): ");
                    int count;
                    if (!int.TryParse(Console.ReadLine(), out count))
                    {
                        count = 1;
                    }

                    await Task.WhenAll(
                        Enumerable
                        .Range(0, count)
                        .Select(async i =>
                    {
                        var message = new Message
                        {
                            Id      = i.ToString(),
                            To      = to,
                            Content = new PlainText
                            {
                                Text = text
                            }
                        };

                        await onDemandClientChannel.SendMessageAsync(message, CancellationToken.None);
                    }));

                    stopwatch.Stop();
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    Console.WriteLine("Elapsed: {0} ms", stopwatch.ElapsedMilliseconds);
                    Console.ResetColor();
                }
            }

            channelListener.Stop();
            await Task.WhenAll(
                channelListener.MessageListenerTask,
                channelListener.NotificationListenerTask,
                channelListener.CommandListenerTask);

            await onDemandClientChannel.FinishAsync(CancellationToken.None);

            Console.WriteLine("Press any key to exit.");
            Console.Read();
        }
Exemple #6
0
 private ClientChannelBuilder GetTarget()
 {
     return(ClientChannelBuilder.Create(_transport.Object, _serverUri));
 }
Exemple #7
0
        private static async Task <IOnDemandClientChannel> EstablishChannelAsync(ConnectionInformation connectionInformation, CancellationToken cancellationToken)
        {
            ITransport transportFactory() => CreateTransportForUri(connectionInformation.ServerUri);

            // Creates a new client channel
            var builder = ClientChannelBuilder
                          .Create(transportFactory, connectionInformation.ServerUri)
                          .AddBuiltHandler((channel, handlerCancellationToken) =>
            {
                channel.CommandModules.Add(new ReplyPingChannelModule(channel));
                return(Task.CompletedTask);
            })
                          .CreateEstablishedClientChannelBuilder()
                          .WithEncryption(SessionEncryption.None)
                          .WithInstance(connectionInformation.Instance)
                          .AddEstablishedHandler(async(channel, handlerCancellationToken) =>
            {
                await channel.SetResourceAsync(
                    new LimeUri(UriTemplates.PRESENCE),
                    connectionInformation.Presence,
                    handlerCancellationToken);
            })
                          .AddEstablishedHandler(async(channel, handlerCancellationToken) =>
            {
                await channel.SetResourceAsync(
                    new LimeUri(UriTemplates.RECEIPT),
                    connectionInformation.Receipt,
                    handlerCancellationToken);
            });

            if (connectionInformation.Identity == null)
            {
                builder = builder.WithAuthentication <GuestAuthentication>();
            }
            else
            {
                builder = builder
                          .WithIdentity(connectionInformation.Identity)
                          .WithPlainAuthentication(connectionInformation.Password);
            }

            var clientChannel = new OnDemandClientChannel(builder);

            clientChannel.ChannelCreationFailedHandlers.Add(information =>
            {
                WriteError("Could not establish the session: {0}", information.Exception.Message);
                return(TaskUtil.FalseCompletedTask);
            });

            var channelListener = new ChannelListener(message =>
            {
                WriteInfo("Message with id '{0}' received from '{1}': {2}", message.Id, message.GetSender(), message.Content);
                return(TaskUtil.TrueCompletedTask);
            },
                                                      notification =>
            {
                WriteInfo("Notification with id {0} received from '{1}' - Event: {2}", notification.Id, notification.GetSender(), notification.Event);
                return(TaskUtil.TrueCompletedTask);
            },
                                                      command =>
            {
                WriteInfo("Command with id '{0}' received from '{1}' - Method: {2} - URI: {3}", command.Id, command.GetSender(), command.Method, command.Uri);
                return(TaskUtil.TrueCompletedTask);
            });


            await clientChannel.EstablishAsync(cancellationToken);

            channelListener.Start(clientChannel);

            return(clientChannel);
        }
Exemple #8
0
 static async Task <TResponse> Send <TRequest, TResponse>(TRequest request)
 {
     using (ChannelFactory <ICallbackService <TRequest, TResponse> > channelFactory = ClientChannelBuilder.GetChannelFactory <TRequest, TResponse>(serverUrl))
         using (ICallbackService <TRequest, TResponse> client = channelFactory.CreateChannel())
         {
             return(await client.SendRequest(request));
         }
 }
Exemple #9
0
        static async Task MainAsync(string[] args)
        {
            Clear();
            WriteLine("Available transport types:");
            WriteLine("1 - TcpTransport (default)");
            WriteLine("2 - PipeTcpTransport");
            WriteLine("3 - WebSocketTransport");
            WriteLine("4 - PipeWebSocketTransport");

            Write("Select type: ");
            if (!int.TryParse(ReadLine(), out var transportType))
            {
                transportType = 1;
            }

            Func <ITransportListener> transportListenerFactory;
            Func <ITransport>         clientTransportFactory;
            Uri uri;
            var envelopeSerializer = new EnvelopeSerializer(new DocumentTypeResolver());
            RemoteCertificateValidationCallback certificateValidationCallback = (sender, certificate, chain, errors) => true;

            switch (transportType)
            {
            case 2:
                uri = new Uri("net.tcp://*****:*****@msging.net/default", transportListenerFactory())
                         .WithChannelConsumers(
                m => reportActionBlock.SendAsync(m),
                n => reportActionBlock.SendAsync(n),
                c => reportActionBlock.SendAsync(c))
                         .WithEnabledEncryptionOptions(new SessionEncryption[] { SessionEncryption.None, SessionEncryption.TLS })
                         .WithExceptionHandler(e =>
            {
                var cursorTop   = CursorTop;
                CursorTop       = 20;
                ForegroundColor = ConsoleColor.Red;
                WriteLine(e.ToString());
                ResetColor();
                CursorTop = cursorTop;
                return(Task.CompletedTask);
            })
                         .WithEnvelopeBufferSize(-1)
                         .Build();

            await server.StartAsync(CancellationToken.None);

            WriteLine("Server started.");

            var cursorLeft = CursorLeft;
            var cursorTop  = CursorTop;

            while (true)
            {
                CursorLeft = cursorLeft;
                CursorTop  = cursorTop;
                WriteLine("                                                            ");
                WriteLine("                                                            ");
                WriteLine("                                                            ");
                WriteLine("                                                            ");
                WriteLine("                                                            ");
                WriteLine("                                                            ");
                WriteLine("                                                            ");
                WriteLine("                                                            ");
                WriteLine("                                                            ");
                WriteLine("                                                            ");
                CursorLeft = cursorLeft;
                CursorTop  = cursorTop;

                Write("Number of channels (ENTER for 1, EXIT to quit): ");

                var line = ReadLine();
                if (line != null && line.ToLowerInvariant().Equals("exit"))
                {
                    break;
                }

                if (!uint.TryParse(line, out var channelCount))
                {
                    channelCount = 1;
                }

                Write("Envelope buffer size (ENTER for 1): ");
                if (!int.TryParse(ReadLine(), out var envelopeBufferSize))
                {
                    envelopeBufferSize = 1;
                }

                Write("Module delay (ENTER for 0): ");
                if (!uint.TryParse(ReadLine(), out var moduleDelay))
                {
                    moduleDelay = 0;
                }

                WriteLine("Starting the client...");

                var delayMessageChannelModule = new ChannelModule <Message>(
                    async(message, token) =>
                {
                    await Task.Delay((int)moduleDelay, token);
                    return(message);
                },
                    async(message, token) =>
                {
                    await Task.Delay((int)moduleDelay, token);
                    return(message);
                },
                    state => { });

                var channelBuilder = ClientChannelBuilder
                                     .Create(clientTransportFactory, uri)
                                     .WithEnvelopeBufferSize(envelopeBufferSize)
                                     .CreateEstablishedClientChannelBuilder()
                                     .AddEstablishedHandler((channel, token) =>
                {
                    if (moduleDelay > 0)
                    {
                        channel.MessageModules.Add(delayMessageChannelModule);
                    }
                    return(Task.CompletedTask);
                })
                                     .WithEncryption(SessionEncryption.TLS);

                IEstablishedChannel client;

                if (channelCount > 1)
                {
                    client = new MultiplexerClientChannel(channelBuilder);
                    await((MultiplexerClientChannel)client).EstablishAsync(CancellationToken.None);
                }
                else
                {
                    client = await channelBuilder.BuildAndEstablishAsync(CancellationToken.None);
                }

                WriteLine("Client started.");

                Write("Number of tasks (ENTER for 10): ");
                if (!uint.TryParse(ReadLine(), out var taskCount))
                {
                    taskCount = 10;
                }

                Write("Number of messages (ENTER for 1000): ");
                if (!uint.TryParse(ReadLine(), out var messagesCount))
                {
                    messagesCount = 1000;
                }

                Write("Number of notifications (ENTER for 1000): ");
                if (!uint.TryParse(ReadLine(), out var notificationsCount))
                {
                    notificationsCount = 1000;
                }

                Write("Number of commands (ENTER for 1000): ");
                if (!uint.TryParse(ReadLine(), out var commandsCount))
                {
                    commandsCount = 1000;
                }

                _reporter = new Reporter(
                    (int)(taskCount * (messagesCount + notificationsCount + commandsCount)),
                    CursorTop + 2,
                    $"Transp {transportType} Ch {channelCount} Buf {envelopeBufferSize} Delay {moduleDelay} Tasks {taskCount} Msgs {messagesCount} Not {notificationsCount} Cmds {commandsCount}");

                var to      = Node.Parse("name@domain/instance");
                var limeUri = new LimeUri("/ping");

                await Task.WhenAll(
                    Enumerable
                    .Range(0, (int)taskCount)
                    .Select(i => Task.Run(async() =>
                {
                    var messagesTask = Task.Run(async() =>
                    {
                        for (int j = 0; j < messagesCount; j++)
                        {
                            await client.SendMessageAsync(
                                new Message()
                            {
                                Id      = $"{i}_{j}",
                                To      = to,
                                Content = "Testing a message"
                            },
                                CancellationToken.None);
                        }
                    });

                    var notificationsTask = Task.Run(async() =>
                    {
                        for (int j = 0; j < notificationsCount; j++)
                        {
                            await client.SendNotificationAsync(
                                new Notification()
                            {
                                Id    = $"{i}_{j}",
                                To    = to,
                                Event = Event.Received
                            },
                                CancellationToken.None);
                        }
                    });

                    var commandsTask = Task.Run(async() =>
                    {
                        for (int j = 0; j < commandsCount; j++)
                        {
                            await client.SendCommandAsync(
                                new Command()
                            {
                                Id     = $"{i}_{j}",
                                To     = to,
                                Method = CommandMethod.Observe,
                                Uri    = limeUri
                            },
                                CancellationToken.None);
                        }
                    });

                    await Task.WhenAll(messagesTask, notificationsTask, commandsTask);
                })));

                _reporter.ReportSendComplete();
                await _reporter.ReportTask;
                _reporter = null;

                using var finishCts = new CancellationTokenSource(TimeSpan.FromSeconds(5));

                if (client is IOnDemandClientChannel onDemandClientChannel)
                {
                    await onDemandClientChannel.FinishAsync(finishCts.Token);
                }
                else if (client is IClientChannel clientChannel)
                {
                    await clientChannel.SendFinishingSessionAsync(finishCts.Token);

                    await clientChannel.ReceiveFinishedSessionAsync(finishCts.Token);
                }

                client.DisposeIfDisposable();
            }

            using var stopCts = new CancellationTokenSource(TimeSpan.FromSeconds(5));

            await server.StopAsync(stopCts.Token);

            WriteLine("Server stopped. Press ENTER to exit.");
            ReadLine();
        }
Exemple #10
0
        static async Task MainAsync(string[] args)
        {
            WriteLine("Starting the server...");

            var messageBufferBlock = new BufferBlock <Message>(
                new DataflowBlockOptions
            {
                BoundedCapacity = DataflowBlockOptions.Unbounded
            }
                );
            var messageActionBlock = new ActionBlock <Message>(
                ReceiveMessageAsync,
                new ExecutionDataflowBlockOptions
            {
                MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded
            });

            messageBufferBlock.LinkTo(messageActionBlock);

            var uri = new Uri("net.tcp://*****:*****@msging.net/default",
                new TcpTransportListener(uri, null, new JsonNetSerializer()))
                         .WithChannelConsumers(m => messageBufferBlock.SendAsync(m), n => TaskUtil.TrueCompletedTask,
                                               c => TaskUtil.TrueCompletedTask)
                         .WithExceptionHandler(e =>
            {
                ForegroundColor = ConsoleColor.Red;
                WriteLine(e.ToString());
                ResetColor();
                return(Task.CompletedTask);
            })
                         .Build();



            await server.StartAsync(CancellationToken.None);

            using (var cts = new CancellationTokenSource())
            {
                WriteLine("Server started.");
                WriteLine("Starting the client...");


                var client = await ClientChannelBuilder
                             .Create(() => new TcpTransport(new JsonNetSerializer()), uri)
                             .CreateEstablishedClientChannelBuilder()
                             .BuildAndEstablishAsync(CancellationToken.None);

                WriteLine("Client started.");


                var reportTask = Task.Run(() => DoReport(cts.Token), cts.Token);

                while (true)
                {
                    SetCursorPosition(0, 5);
                    Write("                                                 ");
                    Write("                                                 ");
                    Write("                                                 ");
                    Write("                                                 ");
                    SetCursorPosition(0, 5);


                    Write("Number of tasks (ENTER for default): ");
                    if (!int.TryParse(Console.ReadLine(), out var taskCount))
                    {
                        taskCount = 10;
                    }

                    Write("Number of messages (ENTER for default): ");
                    if (!int.TryParse(Console.ReadLine(), out var messagesCount))
                    {
                        messagesCount = 1000;
                    }

                    Reset();

                    var stopwatch = Stopwatch.StartNew();

                    await Task.WhenAll(
                        Enumerable
                        .Range(0, taskCount)
                        .Select(i => Task.Run(async() =>
                    {
                        for (int j = 0; j < messagesCount; j++)
                        {
                            await client.SendMessageAsync(new Message()
                            {
                                Id      = $"{i}_{j}",
                                Content = "Testing a message"
                            },
                                                          CancellationToken.None);
                        }
                    })));

                    stopwatch.Stop();

                    WriteLine($"Elapsed: {stopwatch.ElapsedMilliseconds} ms             ");
                }

                cts.Cancel();
                await reportTask;
            }

            await server.StopAsync(CancellationToken.None);

            WriteLine("Server stopped. Press ENTER to exit.");
            ReadLine();
        }