static void ConfigureListCommand(CommandLineApplication hcCommand)
        {
            hcCommand.RelayCommand("list", (listCmd) =>
            {
                listCmd.Description          = "List HybridConnection(s)";
                var connectionStringArgument = listCmd.Argument("connectionString", "Relay ConnectionString");

                listCmd.OnExecute(async() =>
                {
                    string connectionString = ConnectionStringUtility.ResolveConnectionString(connectionStringArgument);
                    if (string.IsNullOrEmpty(connectionString))
                    {
                        TraceMissingArgument(connectionStringArgument.Name);
                        listCmd.ShowHelp();
                        return(1);
                    }

                    var connectionStringBuilder = new RelayConnectionStringBuilder(connectionString);
                    RelayTraceSource.TraceInfo($"Listing HybridConnections for {connectionStringBuilder.Endpoint.Host}");
                    RelayTraceSource.TraceInfo($"{"Path",-38} {"ListenerCount",-15} {"RequiresClientAuth",-20}");
                    var namespaceManager = new RelayNamespaceManager(connectionString);
                    IEnumerable <HybridConnectionDescription> hybridConnections = await namespaceManager.GetHybridConnectionsAsync();
                    foreach (var hybridConnection in hybridConnections)
                    {
                        RelayTraceSource.TraceInfo($"{hybridConnection.Path,-38} {hybridConnection.ListenerCount,-15} {hybridConnection.RequiresClientAuthorization}");
                    }

                    return(0);
                });
            });
        }
        static void ConfigureSendCommand(CommandLineApplication hcCommand)
        {
            hcCommand.RelayCommand("send", (sendCmd) =>
            {
                sendCmd.Description          = "HybridConnection send command";
                var pathArgument             = sendCmd.Argument("path", "HybridConnection path");
                var connectionStringArgument = sendCmd.Argument("connectionString", "Relay ConnectionString");

                var numberOption        = sendCmd.Option(CommandStrings.NumberTemplate, CommandStrings.NumberDescription, CommandOptionType.SingleValue);
                var methodOption        = sendCmd.Option("-m|--method <method>", "The HTTP Method (GET|POST|PUT|DELETE|WEBSOCKET)", CommandOptionType.SingleValue);
                var requestOption       = sendCmd.Option(CommandStrings.RequestTemplate, CommandStrings.RequestDescription, CommandOptionType.SingleValue);
                var requestLengthOption = sendCmd.Option(CommandStrings.RequestLengthTemplate, CommandStrings.RequestLengthDescription, CommandOptionType.SingleValue);

                sendCmd.OnExecute(async() =>
                {
                    string connectionString = ConnectionStringUtility.ResolveConnectionString(connectionStringArgument);
                    if (string.IsNullOrEmpty(connectionString))
                    {
                        TraceMissingArgument(connectionStringArgument.Name);
                        sendCmd.ShowHelp();
                        return(1);
                    }

                    var connectionStringBuilder        = new RelayConnectionStringBuilder(connectionString);
                    connectionStringBuilder.EntityPath = pathArgument.Value ?? connectionStringBuilder.EntityPath ?? DefaultPath;

                    int number            = GetIntOption(numberOption, 1);
                    string method         = GetStringOption(methodOption, "GET");
                    string requestContent = GetMessageBody(requestOption, requestLengthOption, null);
                    await HybridConnectionTests.VerifySendAsync(connectionStringBuilder, number, method, requestContent, RelayTraceSource.Instance);
                    return(0);
                });
            });
        }
        static void ConfigureCreateCommand(CommandLineApplication hcCommand)
        {
            hcCommand.RelayCommand("create", (createCmd) =>
            {
                createCmd.Description = "Create a HybridConnection";

                var pathArgument             = createCmd.Argument("path", "HybridConnection path");
                var connectionStringArgument = createCmd.Argument("connectionString", "Relay ConnectionString");

                var requireClientAuthOption = createCmd.Option(
                    CommandStrings.RequiresClientAuthTemplate, CommandStrings.RequiresClientAuthDescription, CommandOptionType.SingleValue);

                createCmd.OnExecute(async() =>
                {
                    string connectionString = ConnectionStringUtility.ResolveConnectionString(connectionStringArgument);
                    if (string.IsNullOrEmpty(connectionString) || string.IsNullOrEmpty(pathArgument.Value))
                    {
                        TraceMissingArgument(string.IsNullOrEmpty(connectionString) ? connectionStringArgument.Name : pathArgument.Name);
                        createCmd.ShowHelp();
                        return(1);
                    }

                    var connectionStringBuilder = new RelayConnectionStringBuilder(connectionString);
                    RelayTraceSource.TraceInfo($"Creating HybridConnection '{pathArgument.Value}' in {connectionStringBuilder.Endpoint.Host}...");
                    var hcDescription = new HybridConnectionDescription(pathArgument.Value);
                    hcDescription.RequiresClientAuthorization = GetBoolOption(requireClientAuthOption, true);
                    var namespaceManager = new RelayNamespaceManager(connectionString);
                    await namespaceManager.CreateHybridConnectionAsync(hcDescription);
                    RelayTraceSource.TraceInfo($"Creating HybridConnection '{pathArgument.Value}' in {connectionStringBuilder.Endpoint.Host} succeeded");
                    return(0);
                });
            });
        }
        static void ConfigureListenCommand(CommandLineApplication hcCommand)
        {
            hcCommand.RelayCommand("listen", (listenCmd) =>
            {
                listenCmd.Description        = "HybridConnection listen command";
                var pathArgument             = listenCmd.Argument("path", "HybridConnection path");
                var connectionStringArgument = listenCmd.Argument("connectionString", "Relay ConnectionString");

                var responseOption            = listenCmd.Option("--response <response>", "Response to return", CommandOptionType.SingleValue);
                var responseLengthOption      = listenCmd.Option("--response-length <responseLength>", "Length of response to return", CommandOptionType.SingleValue);
                var responseChunkLengthOption = listenCmd.Option("--response-chunk-length <responseLength>", "Length of response to return", CommandOptionType.SingleValue);
                var statusCodeOption          = listenCmd.Option("--status-code <statusCode>", "The HTTP Status Code to return (200|201|401|404|etc.)", CommandOptionType.SingleValue);
                var statusDescriptionOption   = listenCmd.Option("--status-description <statusDescription>", "The HTTP Status Description to return", CommandOptionType.SingleValue);

                listenCmd.OnExecute(async() =>
                {
                    string connectionString = ConnectionStringUtility.ResolveConnectionString(connectionStringArgument);
                    if (string.IsNullOrEmpty(connectionString))
                    {
                        TraceMissingArgument(connectionStringArgument.Name);
                        listenCmd.ShowHelp();
                        return(1);
                    }

                    string response                    = GetMessageBody(responseOption, responseLengthOption, "<html><head><title>Azure Relay HybridConnection</title></head><body>Response Body from Listener</body></html>");
                    var connectionStringBuilder        = new RelayConnectionStringBuilder(connectionString);
                    connectionStringBuilder.EntityPath = pathArgument.Value ?? connectionStringBuilder.EntityPath ?? DefaultPath;
                    var statusCode          = (HttpStatusCode)GetIntOption(statusCodeOption, 200);
                    int responseChunkLength = GetIntOption(responseChunkLengthOption, response.Length);
                    return(await HybridConnectionTests.VerifyListenAsync(RelayTraceSource.Instance, connectionStringBuilder, response, responseChunkLength, statusCode, statusDescriptionOption.Value()));
                });
            });
        }
        static void ConfigureCountCommand(CommandLineApplication hcCommand)
        {
            hcCommand.RelayCommand("count", (countCommand) =>
            {
                countCommand.Description = "Get HybridConnection Count";

                var connectionStringArgument = countCommand.Argument("connectionString", "Relay ConnectionString");

                countCommand.OnExecute(async() =>
                {
                    string connectionString = ConnectionStringUtility.ResolveConnectionString(connectionStringArgument);
                    if (string.IsNullOrEmpty(connectionString))
                    {
                        TraceMissingArgument(connectionStringArgument.Name);
                        countCommand.ShowHelp();
                        return(1);
                    }

                    var namespaceManager = Microsoft.ServiceBus.NamespaceManager.CreateFromConnectionString(connectionString);
                    Uri namespaceUri     = namespaceManager.Address;
                    string namespaceHost = namespaceUri.Host;
                    var tokenProvider    = namespaceManager.Settings.TokenProvider;

                    RelayTraceSource.TraceVerbose($"Getting HybridConnection count for '{namespaceUri}");

                    int count = await NamespaceUtility.GetEntityCountAsync(namespaceUri, tokenProvider, "HybridConnections");
                    RelayTraceSource.TraceInfo(string.Format($"{{0,-{namespaceHost.Length}}}  {{1}}", "Namespace", "HybridConnectionCount"));
                    RelayTraceSource.TraceInfo(string.Format($"{{0,-{namespaceHost.Length}}}  {{1}}", namespaceHost, count));

                    return(0);
                });
            });
        }
        static void ConfigureDeleteCommand(CommandLineApplication hcCommand)
        {
            hcCommand.RelayCommand("delete", (deleteCmd) =>
            {
                deleteCmd.Description        = "Delete a HybridConnection";
                var pathArgument             = deleteCmd.Argument("path", "HybridConnection path");
                var connectionStringArgument = deleteCmd.Argument("connectionString", "Relay ConnectionString");

                deleteCmd.OnExecute(async() =>
                {
                    string connectionString = ConnectionStringUtility.ResolveConnectionString(connectionStringArgument);
                    if (string.IsNullOrEmpty(connectionString) || string.IsNullOrEmpty(pathArgument.Value))
                    {
                        TraceMissingArgument(string.IsNullOrEmpty(connectionString) ? connectionStringArgument.Name : pathArgument.Name);
                        deleteCmd.ShowHelp();
                        return(1);
                    }

                    var connectionStringBuilder = new RelayConnectionStringBuilder(connectionString);
                    RelayTraceSource.TraceInfo($"Deleting HybridConnection '{pathArgument.Value}' in {connectionStringBuilder.Endpoint.Host}...");
                    var namespaceManager = new RelayNamespaceManager(connectionString);
                    await namespaceManager.DeleteHybridConnectionAsync(pathArgument.Value);
                    RelayTraceSource.TraceInfo($"Deleting HybridConnection '{pathArgument.Value}' in {connectionStringBuilder.Endpoint.Host} succeeded");
                    return(0);
                });
            });
        }
        static void ConfigureCreateCommand(CommandLineApplication sasCommand)
        {
            sasCommand.RelayCommand("create", (createCmd) =>
            {
                createCmd.Description = "Create a Sas Token";

                var pathArgument             = createCmd.Argument("path", "Entity path");
                var connectionStringArgument = createCmd.Argument("connectionString", "The ConnectionString to use");

                createCmd.OnExecute(async() =>
                {
                    string connectionString = ConnectionStringUtility.ResolveConnectionString(connectionStringArgument);
                    if (string.IsNullOrEmpty(connectionString))
                    {
                        TraceMissingArgument(connectionStringArgument.Name);
                        createCmd.ShowHelp();
                        return(1);
                    }

                    var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);

                    var audience = new UriBuilder(namespaceManager.Address);
                    if (!string.IsNullOrEmpty(pathArgument.Value))
                    {
                        audience.Path = pathArgument.Value;
                    }

                    string token = await namespaceManager.Settings.TokenProvider.GetWebTokenAsync(audience.Uri.AbsoluteUri, string.Empty, true, TimeSpan.FromMinutes(20));
                    RelayTraceSource.TraceInfo($"Token:\r\n{token}");
                    return(0);
                });
            });
        }
        static void ConfigureTestCommand(CommandLineApplication hcCommand)
        {
            hcCommand.RelayCommand("test", (testCmd) =>
            {
                testCmd.Description          = "HybridConnection tests";
                var connectionStringArgument = testCmd.Argument("connectionString", "Relay ConnectionString");

                testCmd.OnExecute(async() =>
                {
                    string connectionString = ConnectionStringUtility.ResolveConnectionString(connectionStringArgument);
                    if (string.IsNullOrEmpty(connectionString))
                    {
                        TraceMissingArgument(connectionStringArgument.Name);
                        testCmd.ShowHelp();
                        return(1);
                    }

                    return(await HybridConnectionTests.RunTestsAsync(new RelayConnectionStringBuilder(connectionString), RelayTraceSource.Instance));
                });
            });
        }
        internal static void ConfigureCommands(CommandLineApplication app)
        {
            app.RelayCommand("diag", (diagCommand) =>
            {
                diagCommand.Description = "Operations for diagnosing relay/hc issues (Analyze)";
                var namespaceOrConnectionStringArgument = diagCommand.Argument(NamespaceOrConnectionStringArgumentName, NamespaceOrConnectionStringArgumentDescription);

                CommandOption allOption = diagCommand.Option(
                    "-a|--all",
                    "Show all details",
                    CommandOptionType.NoValue);

                CommandOption namespaceOption = diagCommand.Option(
                    "-n|-ns|--namespace",
                    "Show namespace details",
                    CommandOptionType.NoValue);

                CommandOption netStatOption = diagCommand.Option(
                    "--netstat",
                    "Show netstat output",
                    CommandOptionType.NoValue);

                CommandOption portsOption = diagCommand.Option(
                    "-p|--ports",
                    "Probe Relay Ports",
                    CommandOptionType.NoValue);

                CommandOption instancePortsOption = diagCommand.Option(
                    "-ip|--instance-ports <instanceCount>",
                    "Probe Relay Instance Level Ports",
                    CommandOptionType.SingleValue);

                CommandOption osOption = diagCommand.Option(
                    "-o|--os",
                    "Display Platform/OS/.NET information",
                    CommandOptionType.NoValue);

                CommandOption protocolOption = diagCommand.AddSecurityProtocolOption();

                diagCommand.OnExecute(async() =>
                {
                    ConfigureSecurityProtocol(protocolOption);

                    bool defaultOptions = !allOption.HasValue() && !namespaceOption.HasValue() && !netStatOption.HasValue() &&
                                          !portsOption.HasValue() && !osOption.HasValue();

                    // Run netstat before we try to lookup the namespace to keep ourself out of the results
                    // NetStat output isn't part of the default run, must specify --netstat or --all
                    if (netStatOption.HasValue() || allOption.HasValue())
                    {
                        ExecuteNetStatCommand();
                    }

                    NamespaceDetails namespaceDetails = default;
                    string connectionString           = ConnectionStringUtility.ResolveConnectionString(namespaceOrConnectionStringArgument); // Might not be present
                    if (!string.IsNullOrEmpty(connectionString))
                    {
                        var connectionStringBuilder = new ServiceBusConnectionStringBuilder(connectionString);
                        try
                        {
                            namespaceDetails = await NamespaceUtility.GetNamespaceDetailsAsync(connectionStringBuilder.Endpoints.First().Host);
                        }
                        catch (Exception e)
                        {
                            RelayTraceSource.TraceException(e, "Getting namespace details");
                        }
                    }

                    if (defaultOptions || osOption.HasValue() || allOption.HasValue())
                    {
                        await ExecutePlatformCommandAsync(namespaceDetails);
                    }

                    if (defaultOptions || namespaceOption.HasValue() || allOption.HasValue())
                    {
                        ExecuteNamespaceCommand(namespaceDetails);
                    }

                    if (defaultOptions || portsOption.HasValue() || allOption.HasValue() || instancePortsOption.HasValue())
                    {
                        int gatewayCount = GetIntOption(instancePortsOption, 1);
                        await ExecutePortsCommandAsync(namespaceDetails, gatewayCount);
                    }

                    return(0);
                });
            });
        }