private async Task PrivateRunAsync(CancellationToken cancellationToken) { using (var pipe = new NamedPipeServerStream(ServerInfo.Name, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous)) { while (!cancellationToken.IsCancellationRequested) { await pipe.WaitForConnectionAsync(cancellationToken); using (var reader = new NonClosingStreamReader(pipe)) using (var writer = new NonClosingStreamWriter(pipe) { AutoFlush = true }) { var input = await reader.ReadCommandAsync(); _log.Information("Retrieved input {Input}", input); switch (input) { case NamedPipeCommand.FindRepo: await writer.WriteAsync(NamedPipeCommand.Ready); await FindRepo(writer, await reader.ReadLineAsync(), cancellationToken); break; case NamedPipeCommand.GetAllRepos: await writer.WriteAsync(NamedPipeCommand.Ready); await GetAllRepos(writer, cancellationToken); break; case NamedPipeCommand.RemoveRepo: await writer.WriteAsync(NamedPipeCommand.Ready); await RemoveRepo(writer, reader, cancellationToken); break; case NamedPipeCommand.ClearCache: await writer.WriteAsync(NamedPipeCommand.Ready); await ProcessClearCacheAsync(writer, cancellationToken); break; case NamedPipeCommand.ExpandGitCommand: await writer.WriteAsync(NamedPipeCommand.Ready); await ProcessExpandGitCommandAsync(writer, reader, cancellationToken); break; default: await writer.WriteAsync(NamedPipeCommand.BadCommand); break; } } // This must be after the reader and writer are closed // Otherwise, an InvalidOperationException is thrown pipe.WaitForPipeDrain(); pipe.Disconnect(); } } }
private async Task <T> SendReceiveCommandAsync <T>(Func <StreamReader, StreamWriter, Task <T> > func, NamedPipeCommand command, CancellationToken cancellationToken, T defaultValue = default(T)) { // Time out after 2 seconds to access named pipe using (var innerCancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(2))) { try { // Ensure that the named pipe cancellation token gets cancelled if the main token is using (cancellationToken.Register(innerCancellationTokenSource.Cancel)) using (var pipe = new NamedPipeClientStream(NamedPipePoshGitServer.ServerName, ServerInfo.Name, PipeDirection.InOut, PipeOptions.Asynchronous)) { await pipe.ConnectAsync(innerCancellationTokenSource.Token); using (var writer = new NonClosingStreamWriter(pipe) { AutoFlush = true }) using (var reader = new NonClosingStreamReader(pipe)) { await writer.WriteAsync(command); var response = await reader.ReadCommandAsync(); if (response != NamedPipeCommand.Ready) { return(defaultValue); } return(await func(reader, writer)); } } } catch (OperationCanceledException) { _log.Error("Named pipe communication with server was cancelled"); return(defaultValue); } } }