public async Task ReadWriteRequest() { var request = new BuildRequest( BuildProtocolConstants.ProtocolVersion, RequestLanguage.VisualBasicCompile, "HashValue", ImmutableArray.Create( new BuildRequest.Argument(BuildProtocolConstants.ArgumentId.CurrentDirectory, argumentIndex: 0, value: "directory"), new BuildRequest.Argument(BuildProtocolConstants.ArgumentId.CommandLineArgument, argumentIndex: 1, value: "file"))); var memoryStream = new MemoryStream(); await request.WriteAsync(memoryStream, default(CancellationToken)); Assert.True(memoryStream.Position > 0); memoryStream.Position = 0; var read = await BuildRequest.ReadAsync(memoryStream, default(CancellationToken)); Assert.Equal(BuildProtocolConstants.ProtocolVersion, read.ProtocolVersion); Assert.Equal(RequestLanguage.VisualBasicCompile, read.Language); Assert.Equal("HashValue", read.CompilerHash); Assert.Equal(2, read.Arguments.Count); Assert.Equal(BuildProtocolConstants.ArgumentId.CurrentDirectory, read.Arguments[0].ArgumentId); Assert.Equal(0, read.Arguments[0].ArgumentIndex); Assert.Equal("directory", read.Arguments[0].Value); Assert.Equal(BuildProtocolConstants.ArgumentId.CommandLineArgument, read.Arguments[1].ArgumentId); Assert.Equal(1, read.Arguments[1].ArgumentIndex); Assert.Equal("file", read.Arguments[1].Value); }
public void ReadWriteRequest() { Task.Run(async() => { var request = new BuildRequest( BuildProtocolConstants.ProtocolVersion, BuildProtocolConstants.RequestLanguage.VisualBasicCompile, ImmutableArray.Create( new BuildRequest.Argument(BuildProtocolConstants.ArgumentId.CurrentDirectory, argumentIndex: 0, value: "directory"), new BuildRequest.Argument(BuildProtocolConstants.ArgumentId.CommandLineArgument, argumentIndex: 1, value: "file"))); var memoryStream = new MemoryStream(); await request.WriteAsync(memoryStream, default(CancellationToken)).ConfigureAwait(false); Assert.True(memoryStream.Position > 0); memoryStream.Position = 0; var read = await BuildRequest.ReadAsync(memoryStream, default(CancellationToken)).ConfigureAwait(false); Assert.Equal(BuildProtocolConstants.ProtocolVersion, read.ProtocolVersion); Assert.Equal(BuildProtocolConstants.RequestLanguage.VisualBasicCompile, read.Language); Assert.Equal(2, read.Arguments.Length); Assert.Equal(BuildProtocolConstants.ArgumentId.CurrentDirectory, read.Arguments[0].ArgumentId); Assert.Equal(0u, read.Arguments[0].ArgumentIndex); Assert.Equal("directory", read.Arguments[0].Value); Assert.Equal(BuildProtocolConstants.ArgumentId.CommandLineArgument, read.Arguments[1].ArgumentId); Assert.Equal(1u, read.Arguments[1].ArgumentIndex); Assert.Equal("file", read.Arguments[1].Value); }).Wait(); }
public async Task ShutdownRequestWriteRead() { var memoryStream = new MemoryStream(); var request = BuildRequest.CreateShutdown(); await request.WriteAsync(memoryStream, CancellationToken.None); memoryStream.Position = 0; var read = await BuildRequest.ReadAsync(memoryStream, CancellationToken.None); VerifyShutdownRequest(read); }
public async Task <ConnectionData> HandleConnection(bool allowCompilationRequests = true, CancellationToken cancellationToken = default(CancellationToken)) { try { BuildRequest request; try { Log("Begin reading request."); request = await BuildRequest.ReadAsync(_stream, cancellationToken).ConfigureAwait(false); ValidateBuildRequest(request); Log("End reading request."); } catch (Exception e) { LogException(e, "Error reading build request."); return(new ConnectionData(CompletionReason.CompilationNotStarted)); } if (request.ProtocolVersion != BuildProtocolConstants.ProtocolVersion) { return(await HandleMismatchedVersionRequest(cancellationToken).ConfigureAwait(false)); } else if (!string.Equals(request.CompilerHash, BuildProtocolConstants.GetCommitHash(), StringComparison.OrdinalIgnoreCase)) { return(await HandleIncorrectHashRequest(cancellationToken).ConfigureAwait(false)); } else if (IsShutdownRequest(request)) { return(await HandleShutdownRequest(cancellationToken).ConfigureAwait(false)); } else if (!allowCompilationRequests) { return(await HandleRejectedRequest(cancellationToken).ConfigureAwait(false)); } else { return(await HandleCompilationRequest(request, cancellationToken).ConfigureAwait(false)); } } finally { Close(); } }
internal async Task <ConnectionResult> AcceptConnection(Task <Connection> task, bool accept, CancellationToken cancellationToken) { Connection connection; try { connection = await task; } catch (Exception ex) { // Unable to establish a connection with the client. The client is responsible for // handling this case. Nothing else for us to do here. CompilerServerLogger.LogException(ex, "Error creating client named pipe"); return(new ConnectionResult(ConnectionResult.Reason.CompilationNotStarted)); } try { using (connection) { BuildRequest request; try { CompilerServerLogger.Log("Begin reading request."); request = await BuildRequest.ReadAsync(connection.Stream, cancellationToken).ConfigureAwait(false); CompilerServerLogger.Log("End reading request."); } catch (Exception e) { CompilerServerLogger.LogException(e, "Error reading build request."); return(new ConnectionResult(ConnectionResult.Reason.CompilationNotStarted)); } if (request.IsShutdownRequest()) { // Reply with the PID of this process so that the client can wait for it to exit. var response = new ShutdownBuildResponse(Process.GetCurrentProcess().Id); await response.WriteAsync(connection.Stream, cancellationToken); // We can safely disconnect the client, then when this connection gets cleaned up by the event loop // the server will go to a shutdown state. return(new ConnectionResult(ConnectionResult.Reason.ClientShutdownRequest)); } else if (!accept) { // We're already in shutdown mode, respond gracefully so the client can run in-process. var response = new RejectedBuildResponse(); await response.WriteAsync(connection.Stream, cancellationToken).ConfigureAwait(false); return(new ConnectionResult(ConnectionResult.Reason.CompilationNotStarted)); } else { // If we get here then this is a real request that we will accept and process. // // Kick off both the compilation and a task to monitor the pipe for closing. var buildCancelled = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); var watcher = connection.WaitForDisconnectAsync(buildCancelled.Token); var worker = ExecuteRequestAsync(request, buildCancelled.Token); // await will end when either the work is complete or the connection is closed. await Task.WhenAny(worker, watcher); // Do an 'await' on the completed task, preference being compilation, to force // any exceptions to be realized in this method for logging. ConnectionResult.Reason reason; if (worker.IsCompleted) { var response = await worker; try { CompilerServerLogger.Log("Begin writing response."); await response.WriteAsync(connection.Stream, cancellationToken); CompilerServerLogger.Log("End writing response."); reason = ConnectionResult.Reason.CompilationCompleted; } catch { reason = ConnectionResult.Reason.ClientDisconnect; } } else { await watcher; reason = ConnectionResult.Reason.ClientDisconnect; } // Begin the tear down of the Task which didn't complete. buildCancelled.Cancel(); return(new ConnectionResult(reason, request.KeepAlive)); } } } catch (Exception ex) { CompilerServerLogger.LogException(ex, "Error handling connection"); return(new ConnectionResult(ConnectionResult.Reason.ClientException)); } }