public async Task <int> RunIpcClientTcpServerRouter(CancellationToken token, string ipcClient, string tcpServer, int runtimeTimeout, string verbose)
        {
            checkLoopbackOnly(tcpServer);

            using CancellationTokenSource cancelRouterTask  = new CancellationTokenSource();
            using CancellationTokenSource linkedCancelToken = CancellationTokenSource.CreateLinkedTokenSource(token, cancelRouterTask.Token);

            LogLevel logLevel = LogLevel.Information;

            if (string.Compare(verbose, "debug", StringComparison.OrdinalIgnoreCase) == 0)
            {
                logLevel = LogLevel.Debug;
            }
            else if (string.Compare(verbose, "trace", StringComparison.OrdinalIgnoreCase) == 0)
            {
                logLevel = LogLevel.Trace;
            }

            using var factory = new LoggerFactory();
            factory.AddConsole(logLevel, false);

            Launcher.SuspendProcess = true;
            Launcher.ConnectMode    = true;
            Launcher.Verbose        = logLevel != LogLevel.Information;
            Launcher.CommandToken   = token;

            var routerTask = DiagnosticsServerRouterRunner.runIpcClientTcpServerRouter(linkedCancelToken.Token, ipcClient, tcpServer, runtimeTimeout == Timeout.Infinite ? runtimeTimeout : runtimeTimeout * 1000, factory.CreateLogger("dotnet-dsrounter"), Launcher);

            while (!linkedCancelToken.IsCancellationRequested)
            {
                await Task.WhenAny(routerTask, Task.Delay(250)).ConfigureAwait(false);

                if (routerTask.IsCompleted)
                {
                    break;
                }

                if (!Console.IsInputRedirected && Console.KeyAvailable)
                {
                    ConsoleKey cmd = Console.ReadKey(true).Key;
                    if (cmd == ConsoleKey.Q)
                    {
                        cancelRouterTask.Cancel();
                        break;
                    }
                }
            }

            return(routerTask.Result);
        }
        static void checkLoopbackOnly(string tcpServer)
        {
            if (!string.IsNullOrEmpty(tcpServer) && !DiagnosticsServerRouterRunner.isLoopbackOnly(tcpServer))
            {
                StringBuilder message = new StringBuilder();

                message.Append("WARNING: Binding tcp server endpoint to anything except loopback interface ");
                message.Append("(localhost, 127.0.0.1 or [::1]) is NOT recommended. Any connections towards ");
                message.Append("tcp server endpoint will be unauthenticated and unencrypted. This component ");
                message.Append("is intented for development use and should only be run in development and ");
                message.Append("testing environments.");
                message.AppendLine();

                var currentColor = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine(message.ToString());
                Console.ForegroundColor = currentColor;
            }
        }
        public async Task <int> RunIpcClientTcpServerRouter(CancellationToken token, string ipcClient, string tcpServer, int runtimeTimeout, string verbose, string forwardPort)
        {
            checkLoopbackOnly(tcpServer);

            using CancellationTokenSource cancelRouterTask  = new CancellationTokenSource();
            using CancellationTokenSource linkedCancelToken = CancellationTokenSource.CreateLinkedTokenSource(token, cancelRouterTask.Token);

            LogLevel logLevel = LogLevel.Information;

            if (string.Compare(verbose, "debug", StringComparison.OrdinalIgnoreCase) == 0)
            {
                logLevel = LogLevel.Debug;
            }
            else if (string.Compare(verbose, "trace", StringComparison.OrdinalIgnoreCase) == 0)
            {
                logLevel = LogLevel.Trace;
            }

            using var factory = new LoggerFactory();
            factory.AddConsole(logLevel, false);

            Launcher.SuspendProcess = true;
            Launcher.ConnectMode    = true;
            Launcher.Verbose        = logLevel != LogLevel.Information;
            Launcher.CommandToken   = token;

            var logger = factory.CreateLogger("dotnet-dsrouter");

            TcpServerRouterFactory.CreateInstanceDelegate tcpServerRouterFactory = TcpServerRouterFactory.CreateDefaultInstance;
            if (!string.IsNullOrEmpty(forwardPort))
            {
                if (string.Compare(forwardPort, "android", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    tcpServerRouterFactory = ADBTcpServerRouterFactory.CreateADBInstance;
                }
                else
                {
                    logger.LogError($"Unknown port forwarding argument, {forwardPort}. Only Android port fowarding is supported for TcpServer mode. Ignoring --forward-port argument.");
                }
            }

            var routerTask = DiagnosticsServerRouterRunner.runIpcClientTcpServerRouter(linkedCancelToken.Token, ipcClient, tcpServer, runtimeTimeout == Timeout.Infinite ? runtimeTimeout : runtimeTimeout * 1000, tcpServerRouterFactory, logger, Launcher);

            while (!linkedCancelToken.IsCancellationRequested)
            {
                await Task.WhenAny(routerTask, Task.Delay(250)).ConfigureAwait(false);

                if (routerTask.IsCompleted)
                {
                    break;
                }

                if (!Console.IsInputRedirected && Console.KeyAvailable)
                {
                    ConsoleKey cmd = Console.ReadKey(true).Key;
                    if (cmd == ConsoleKey.Q)
                    {
                        cancelRouterTask.Cancel();
                        break;
                    }
                }
            }

            return(routerTask.Result);
        }