public VTFGenerator(Stream inputStream, Stream outputStream) { processDelegate = new ProcessAsync(this.Process); _output = new VTFOutput(outputStream); _smallInputFile = new MemoryStream(); inputStream.CopyTo(_smallInputFile); }
/// <summary>Ensure <paramref name="process"/> is actually running.</summary> private async Task <bool> EnsureRunningAsync(ProcessAsync process, CancellationToken token) { int i = 0; while (true) { i++; bool isRunning = await TcpConnectionFactory.IsTorRunningAsync().ConfigureAwait(false); if (isRunning) { return(true); } if (process.HasExited) { Logger.LogError("Tor process failed to start!"); return(false); } const int MaxAttempts = 25; if (i >= MaxAttempts) { Logger.LogError($"All {MaxAttempts} attempts to connect to Tor failed."); return(false); } // Wait 250 milliseconds between attempts. await Task.Delay(250, token).ConfigureAwait(false); } }
/// <summary> /// Stops bitcoin daemon process when PID file exists. /// </summary> /// <remarks>If there is not PID file, no process is stopped.</remarks> /// <param name="onlyOwned">Only stop if this node owns the process.</param> public async Task StopAsync(bool onlyOwned) { Logger.LogDebug($"> {nameof(onlyOwned)}={onlyOwned}"); if (Process is null) { Logger.LogDebug("< Process is null."); return; } // "process" variable is guaranteed to be non-null at this point. ProcessAsync process = Process; using var cts = new CancellationTokenSource(_reasonableCoreShutdownTimeout); int?pid = await PidFile.TryReadAsync().ConfigureAwait(false); // If the cached PID is PID, then we own the process. if (pid.HasValue && (!onlyOwned || CachedPid == pid)) { Logger.LogDebug($"User is responsible for the daemon process with PID {pid}. Stop it."); try { bool isKilled = false; try { // Stop Bitcoin daemon using RPC "stop" command. // The command actually only initiates the bitcoind graceful shutdown procedure. // Our time budget for the bitcoind to stop is given by "ReasonableCoreShutdownTimeout". await RpcClient.StopAsync().ConfigureAwait(false); } catch (Exception ex) { Logger.LogWarning(ex); process.Kill(); isKilled = true; } if (!isKilled) { Logger.LogDebug($"Wait until the process is stopped."); await process.WaitForExitAsync(cts.Token).ConfigureAwait(false); } } finally { Logger.LogDebug($"Wait until the process is stopped."); process.Dispose(); Process = null; PidFile.TryDelete(); } } else { Logger.LogDebug("User is NOT responsible for the daemon process."); } Logger.LogDebug("<"); }
public VTFGenerator(string inputFile, string outputFile) { processDelegate = new ProcessAsync(this.Process); // Create the output directories (new FileInfo(outputFile)).Directory.Create(); _output = new VTFOutput(outputFile); _smallInputFile = new FileStream(inputFile, FileMode.Open); }
/// <remarks>Use the constructor only in tests.</remarks> internal LinuxInhibitorTask(InhibitWhat what, TimeSpan period, string reason, ProcessAsync process) { What = what; BasePeriod = period; Reason = reason; Process = process; Cts = new CancellationTokenSource(period); _ = WaitAsync(); }
/// <summary> /// Subscribes to <see cref="PipeReader"/> and executes <see cref="ProcessAsync"/> whenever /// a message was fully received /// </summary> /// <param name="reader">The reader that provides the data</param> /// <param name="processAsync"> /// The event handler that is invoked every time a message is fully parsed /// </param> /// <param name="cancellationToken"> /// The cancellation token that cancels /// </param> /// <returns> /// A task that is completed when <paramref name="cancellationToken"/> is cancelled /// </returns> public static Task Start( PipeReader reader, ProcessAsync processAsync, CancellationToken cancellationToken) { return(Task.Factory.StartNew( () => ProcessMessagesAsync(reader, processAsync, cancellationToken), cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default)); }
public async Task Start_NeverCalled_NotStarted() { // arrange ProcessAsync a = (_, _) => default; Mock <ISocketClient> socketClientMock = new(MockBehavior.Strict); ISocketClient socketClient = socketClientMock.Object; // act await using var messagePipeline = new MessagePipeline(socketClient, a); // assert socketClientMock.VerifyAll(); }
public async Task Start_StartOnce_StartDataReceive() { // arrange ProcessAsync a = (_, _) => default; SocketClientStub socketClient = new() { IsClosed = false }; await using var messagePipeline = new MessagePipeline(socketClient, a); // act messagePipeline.Start(); await socketClient.WaitTillFinished(); // assert Assert.Equal(1, socketClient.GetCallCount(x => x.ReceiveAsync(default !, default !)));
/// <summary> /// Stops bitcoin daemon process when PID file exists. /// </summary> /// <remarks>If there is not PID file, no process is stopped.</remarks> /// <param name="onlyOwned">Only stop if this node owns the process.</param> public async Task StopAsync(bool onlyOwned) { Logger.LogDebug($"> {nameof(onlyOwned)}={onlyOwned}"); if (Process is null) { Logger.LogDebug("< Process is null."); return; } ProcessAsync process = Process; // process is guaranteed to be non-null at this point. using var cts = new CancellationTokenSource(ReasonableCoreShutdownTimeout); int?pid = await PidFile.TryReadAsync().ConfigureAwait(false); // If the cached PID is PID, then we own the process. if (pid.HasValue && (!onlyOwned || CachedPid == pid)) { Logger.LogDebug($"User is responsible for the daemon process with PID {pid}. Stop it."); try { try { await RpcClient.StopAsync().ConfigureAwait(false); } catch (Exception ex) { Logger.LogWarning(ex); process.Kill(); } Logger.LogDebug($"Wait until the process is stopped."); await process.WaitForExitAsync(cts.Token).ConfigureAwait(false); } finally { Logger.LogDebug($"Wait until the process is stopped."); process.Dispose(); Process = null; PidFile.TryDelete(); } } else { Logger.LogDebug("User is NOT responsible for the daemon process."); } Logger.LogDebug("<"); }
public async Task Constructor_AllArgs_Construct() { // arrange ProcessAsync a = (_, _) => default; ISocketClient socketClient = new SocketClientStub() { IsClosed = false }; // act await using var messagePipeline = new MessagePipeline(socketClient, a); // assert Assert.IsType <MessagePipeline>(messagePipeline); }
private static async Task ProcessMessagesAsync( PipeReader reader, ProcessAsync processAsync, CancellationToken cancellationToken) { try { while (true) { ReadResult result = await reader .ReadAsync(cancellationToken) .ConfigureAwait(false); ReadOnlySequence <byte> buffer = result.Buffer; SequencePosition? position = null; do { position = buffer.PositionOf(Delimiter); if (position != null) { await processAsync( buffer.Slice(0, position.Value), cancellationToken) .ConfigureAwait(false); // Skip the message which was read. buffer = buffer.Slice(buffer.GetPosition(1, position.Value)); } } while (position != null); reader.AdvanceTo(buffer.Start, buffer.End); if (result.IsCompleted) { break; } } } catch (TaskCanceledException) { } finally { await reader.CompleteAsync().ConfigureAwait(false); } }
public async void SendCommandImmediateCancelAsync() { await Assert.ThrowsAsync <TaskCanceledException>(async() => { using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); var startInfo = new ProcessStartInfo() { FileName = MicroserviceHelpers.GetBinaryPath("bitcoind"), Arguments = "-regtest=1" }; using var process = new ProcessAsync(startInfo); process.Start(); await process.WaitForExitAsync(cts.Token, killOnCancel: true); }); }
public void Start( IPEndPoint endPoint, ProcessAsync processRequestAsync) { if (!this._stop) { throw new InvalidOperationException($"{nameof(TcpServer)} already started."); } this.ProcessRequestAsyncCallback = processRequestAsync ?? throw new ArgumentNullException(nameof(processRequestAsync)); this._stop = false; this._cts = new CancellationTokenSource(); this._listener.Start(endPoint); var serverThread = new Thread(Run); serverThread.Start(); }
/// <summary> /// This method can be called only once. /// </summary> public async Task StartAsync(CancellationToken cancel) { int ptcv = PrintToConsole ? 1 : 0; string processPath = MicroserviceHelpers.GetBinaryPath("bitcoind"); string networkArgument = NetworkTranslator.GetCommandLineArguments(Network); string args = $"{networkArgument} -datadir=\"{DataDir}\" -printtoconsole={ptcv}"; // Start bitcoind process. Process = new ProcessAsync(ProcessStartInfoFactory.Make(processPath, args)); Process.Start(); // Store PID in PID file. await PidFile.WriteFileAsync(Process.Id).ConfigureAwait(false); CachedPid = Process.Id; try { var exceptionTracker = new LastExceptionTracker(); // Try to connect to bitcoin daemon RPC until we succeed. while (true) { try { TimeSpan timeSpan = await RpcClient.UptimeAsync(cancel).ConfigureAwait(false); Logger.LogInfo("RPC connection is successfully established."); Logger.LogDebug($"RPC uptime is: {timeSpan}."); // Bitcoin daemon is started. We are done. break; } catch (Exception ex) { ExceptionInfo exceptionInfo = exceptionTracker.Process(ex); // Don't log extensively. if (exceptionInfo.IsFirst) { Logger.LogInfo($"{Constants.BuiltinBitcoinNodeName} is not yet ready... Reason: {exceptionInfo.Exception.Message}"); } if (Process is { } p&& p.HasExited) { throw new BitcoindException($"Failed to start daemon, location: '{p.StartInfo.FileName} {p.StartInfo.Arguments}'", ex); } } if (cancel.IsCancellationRequested) { Logger.LogDebug("Bitcoin daemon was not started yet and user requested to cancel the operation."); await StopAsync(onlyOwned : true).ConfigureAwait(false); cancel.ThrowIfCancellationRequested(); } // Wait a moment before the next check. await Task.Delay(100, cancel).ConfigureAwait(false); } } catch (Exception) { Process?.Dispose(); throw; } }
/// <summary> /// Installs Tor if it is not installed, then it starts Tor. /// </summary> /// <param name="ensureRunning"> /// If <c>false</c>, Tor is started but no attempt to verify that it actually runs is made. /// <para>If <c>true</c>, we start Tor and attempt to connect to it to verify it is running (at most 25 attempts).</para> /// </param> public async Task <bool> StartAsync(bool ensureRunning) { try { // Is Tor already running? Either our Tor process from previous Wasabi Wallet run or possibly user's own Tor. bool isAlreadyRunning = await TorSocks5Client.IsTorRunningAsync().ConfigureAwait(false); if (isAlreadyRunning) { string msg = TorSocks5EndPoint is IPEndPoint endpoint ? $"Tor is already running on {endpoint.Address}:{endpoint.Port}." : "Tor is already running."; Logger.LogInfo(msg); return(true); } // Install Tor if it is not installed and verify Tor is not tampered with (using hash/checksum). bool verified = await new TorInstallator(Settings).VerifyInstallationAsync().ConfigureAwait(false); if (!verified) { Logger.LogInfo("Failed to verify Tor installation."); return(false); } string torArguments = Settings.GetCmdArguments(TorSocks5EndPoint) + $" --Log \"notice file {Settings.LogFilePath}\""; var startInfo = new ProcessStartInfo { FileName = Settings.TorBinaryFilePath, Arguments = torArguments, UseShellExecute = false, CreateNoWindow = true, RedirectStandardOutput = true, WorkingDirectory = Settings.TorDir }; if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { var env = startInfo.EnvironmentVariables; env["LD_LIBRARY_PATH"] = !env.ContainsKey("LD_LIBRARY_PATH") || string.IsNullOrEmpty(env["LD_LIBRARY_PATH"]) ? Settings.TorBinaryDir : Settings.TorBinaryDir + Path.PathSeparator + env["LD_LIBRARY_PATH"]; Logger.LogDebug($"Environment variable 'LD_LIBRARY_PATH' set to: '{env["LD_LIBRARY_PATH"]}'."); } TorProcess = new ProcessAsync(startInfo); Logger.LogInfo($"Starting Tor process ..."); TorProcess.Start(); if (ensureRunning) { int i = 0; while (true) { i++; bool isRunning = await TorSocks5Client.IsTorRunningAsync().ConfigureAwait(false); if (isRunning) { break; } const int MaxAttempts = 25; if (i >= MaxAttempts) { Logger.LogError($"All {MaxAttempts} attempts to connect to Tor failed."); return(false); } // Wait 250 milliseconds between attempts. await Task.Delay(250).ConfigureAwait(false); } Logger.LogInfo("Tor is running."); return(true); } } catch (Exception ex) { Logger.LogError("Could not automatically start Tor. Try running Tor manually.", ex); } return(false); }
private async Task <(string response, int exitCode)> SendCommandAsync(ProcessStartInfo startInfo, CancellationToken token, Action <StreamWriter>?standardInputWriter = null) { using var processAsync = new ProcessAsync(startInfo); if (standardInputWriter is { })