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 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 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 async Task <bool> EnsureHybridConnectionExists(TraceSource traceSource, RelayConnectionStringBuilder connectionString, RelayNamespaceManager namespaceManager) { bool createdHybridConnection = false; try { traceSource.TraceVerbose($"Checking whether HybridConnection '{connectionString.EntityPath}' exists"); if (!await namespaceManager.HybridConnectionExistsAsync(connectionString.EntityPath)) { traceSource.TraceEvent(TraceEventType.Information, (int)ConsoleColor.White, $"Creating HybridConnection '{connectionString.EntityPath}'"); createdHybridConnection = true; await namespaceManager.CreateHybridConnectionAsync(new HybridConnectionDescription(connectionString.EntityPath)); traceSource.TraceInformation("Created"); } } catch (Exception exception) { RelayTraceSource.TraceException(exception, $"Ensuring HybridConnection '{connectionString.EntityPath}' exists"); } return(createdHybridConnection); }
public static async Task <int> VerifyListenAsync(TraceSource traceSource, RelayConnectionStringBuilder connectionString, string responseBody, int responseChunkLength, HttpStatusCode statusCode, string statusDescription) { var namespaceManager = new RelayNamespaceManager(connectionString.ToString()); bool createdHybridConnection = await EnsureHybridConnectionExists(traceSource, connectionString, namespaceManager); HybridConnectionListener listener = null; try { listener = new HybridConnectionListener(connectionString.ToString()); listener.Connecting += (s, e) => RelayTraceSource.TraceException(listener.LastError, TraceEventType.Warning, "HybridConnectionListener Re-Connecting"); listener.Online += (s, e) => RelayTraceSource.Instance.TraceEvent(TraceEventType.Information, (int)ConsoleColor.Green, "HybridConnectionListener is online"); EventHandler offlineHandler = (s, e) => RelayTraceSource.TraceException(listener.LastError, "HybridConnectionListener is OFFLINE"); listener.Offline += offlineHandler; var responseBytes = Encoding.UTF8.GetBytes(responseBody); listener.RequestHandler = async(context) => { try { var stopwatch = new Stopwatch(); LogHttpRequest(context, traceSource); context.Response.StatusCode = statusCode; if (statusDescription != null) { context.Response.StatusDescription = statusDescription; } context.Response.Headers[HttpResponseHeader.ContentType] = "text/html"; int bytesWritten = 0; do { int countToWrite = Math.Min(responseBody.Length - bytesWritten, responseChunkLength); stopwatch.Restart(); await context.Response.OutputStream.WriteAsync(responseBytes, bytesWritten, countToWrite); bytesWritten += countToWrite; traceSource.TraceEvent(TraceEventType.Verbose, 0, "Sent {0} bytes in {1} ms", countToWrite, stopwatch.ElapsedMilliseconds); }while (bytesWritten < responseBody.Length); stopwatch.Restart(); await context.Response.CloseAsync(); traceSource.TraceEvent(TraceEventType.Verbose, 0, "Close completed in {0} ms", stopwatch.ElapsedMilliseconds); } catch (Exception exception) { RelayTraceSource.TraceException(exception, $"RequestHandler Error"); } }; traceSource.TraceInformation($"Opening {listener}"); await listener.OpenAsync(); RunAcceptPump(listener); traceSource.TraceInformation("Press <ENTER> to close the listener "); Console.ReadLine(); traceSource.TraceInformation($"Closing {listener}"); listener.Offline -= offlineHandler; // Avoid a spurious trace on expected shutdown. await listener.CloseAsync(); traceSource.TraceInformation("Closed"); return(0); } catch (Exception) { listener?.CloseAsync(); throw; } finally { if (createdHybridConnection) { try { traceSource.TraceEvent(TraceEventType.Information, (int)ConsoleColor.White, $"Deleting HybridConnection '{connectionString.EntityPath}'"); await namespaceManager.DeleteHybridConnectionAsync(connectionString.EntityPath); traceSource.TraceInformation("Deleted"); } catch (Exception exception) { RelayTraceSource.TraceException(exception, "Deleting HybridConnection"); } } } }
public static async Task <int> RunTestsAsync(RelayConnectionStringBuilder connectionString, TraceSource traceSource) { if (string.IsNullOrEmpty(connectionString.EntityPath)) { connectionString.EntityPath = HybridConnectionCommands.DefaultPath; } var namespaceManager = new RelayNamespaceManager(connectionString.ToString()); namespaceManager.Settings.OperationTimeout = TimeSpan.FromSeconds(5); HybridConnectionListener listener = null; bool createdHybridConnection = false; int returnCode = 0; var testResults = new List <TestResult>(); var cts = new CancellationTokenSource(TimeSpan.FromSeconds(70)); try { createdHybridConnection = await EnsureHybridConnectionExists(traceSource, connectionString, namespaceManager); listener = new HybridConnectionListener(connectionString.ToString()); traceSource.TraceInformation($"Opening {listener}"); await listener.OpenAsync(cts.Token); traceSource.TraceInformation("Listener Opened"); Uri hybridHttpUri = new Uri($"https://{connectionString.Endpoint.GetComponents(UriComponents.HostAndPort, UriFormat.SafeUnescaped)}/{connectionString.EntityPath}"); var token = await listener.TokenProvider.GetTokenAsync(hybridHttpUri.AbsoluteUri, TimeSpan.FromMinutes(20)); using (var client = new HttpClient { BaseAddress = hybridHttpUri }) { client.DefaultRequestHeaders.ExpectContinue = false; await RunTestAsync("TestPostLargeRequestSmallResponse", null, testResults, () => TestPostLargeRequestSmallResponse(listener, token, client, traceSource)); await RunTestAsync("TestPostLargeRequestWithLargeResponse", null, testResults, () => TestPostLargeRequestWithLargeResponse(listener, token, client, traceSource)); await RunTestAsync("TestGetLargeResponse", null, testResults, () => TestGetLargeResponse(listener, token, client, traceSource)); await RunTestAsync("TestGetSmallResponse", null, testResults, () => TestGetSmallResponse(listener, token, client, traceSource)); } await RunTestAsync("TestStreaming", null, testResults, () => TestStreaming(listener, connectionString, traceSource)); returnCode = ReportTestResults(testResults); } catch (Exception exception) { traceSource.TraceError("FAILURE WHILE RUNNING TESTS"); RelayTraceSource.TraceException(exception, nameof(HybridConnectionTests)); returnCode = exception.HResult; } finally { cts.Dispose(); var cleanupCancelSource = new CancellationTokenSource(TimeSpan.FromSeconds(10)); try { if (listener != null) { traceSource.TraceInformation($"Closing {listener}"); await listener.CloseAsync(cleanupCancelSource.Token); traceSource.TraceInformation("Listener Closed"); } if (createdHybridConnection) { traceSource.TraceEvent(TraceEventType.Information, (int)ConsoleColor.White, $"Deleting HybridConnection '{connectionString.EntityPath}'"); await namespaceManager.DeleteHybridConnectionAsync(connectionString.EntityPath); } } catch (Exception cleanupException) { traceSource.TraceWarning($"Error during cleanup: {cleanupException.GetType()}: {cleanupException.Message}"); } finally { cleanupCancelSource.Dispose(); } } return(returnCode); }