public async Task EnterFromAsync(FirefoxProcessManager p, State fromState) { if (!TryEnter(p, fromState)) { // Delegate KillAsync to current state, because it has already changed since // transition to this state was initiated. await p._currentState.KillAsync(p).ConfigureAwait(false); } try { await p._attemptToGracefullyCloseFunc().ConfigureAwait(false); if (!p.Process.HasExited) { p.Process.Kill(); } } catch (InvalidOperationException) { // Ignore return; } await WaitForExitAsync(p).ConfigureAwait(false); }
public Task EnterFromAsync(FirefoxProcessManager p, State fromState) { if (TryEnter(p, fromState)) { // Process has not exited or been killed since transition to this state was initiated LogProcessCount(p, Interlocked.Increment(ref _processCount)); } return(Task.CompletedTask); }
/// <summary> /// Attempts thread-safe transitions from a given state to this state. /// </summary> /// <param name="p">The Firefox process.</param> /// <param name="fromState">The state from which state transition takes place.</param> /// <returns>Returns <c>true</c> if transition is successful, or <c>false</c> if transition /// cannot be made because current state does not equal <paramref name="fromState"/>.</returns> protected bool TryEnter(FirefoxProcessManager p, State fromState) { if (Interlocked.CompareExchange(ref p._currentState, this, fromState) == fromState) { fromState.Leave(p); return(true); } return(false); }
/// <inheritdoc cref="IBrowserType.LaunchBrowserAppAsync(LaunchOptions)"/> public override async Task <IBrowserApp> LaunchBrowserAppAsync(LaunchOptions options = null) { options ??= new LaunchOptions(); var(firefoxArguments, tempProfileDir) = PrepareFirefoxArgs(options); string firefoxExecutable = GetBrowserExecutablePath(options); BrowserApp browserApp = null; var process = new FirefoxProcessManager( firefoxExecutable, firefoxArguments, tempProfileDir, options.Timeout, async() => { if (browserApp == null) { return; } var transport = await BrowserHelper.CreateTransportAsync(browserApp.ConnectOptions).ConfigureAwait(false); await transport.SendAsync(new BrowserCloseRequest().Command).ConfigureAwait(false); }, (exitCode) => { browserApp?.ProcessKilled(exitCode); }); try { SetEnvVariables(process.Process.StartInfo.Environment, options.Env, Environment.GetEnvironmentVariables()); if (options.DumpIO) { process.Process.ErrorDataReceived += (sender, e) => Console.Error.WriteLine(e.Data); } await process.StartAsync().ConfigureAwait(false); var connectOptions = new ConnectOptions() { BrowserWSEndpoint = process.Endpoint, SlowMo = options.SlowMo, }; return(new BrowserApp(process, () => Task.CompletedTask, connectOptions)); } catch { await process.KillAsync().ConfigureAwait(false); throw; } }
public Task EnterFromAsync(FirefoxProcessManager p, State fromState) { if (!TryEnter(p, fromState)) { // Delegate StartAsync to current state, because it has already changed since // transition to this state was initiated. return(p._currentState.StartAsync(p)); } return(StartCoreAsync(p)); }
public override async Task ExitAsync(FirefoxProcessManager p, TimeSpan timeout) { var waitForExitTask = WaitForExitAsync(p); await waitForExitTask.WithTimeout( async() => { await Killing.EnterFromAsync(p, this).ConfigureAwait(false); await waitForExitTask.ConfigureAwait(false); }, timeout, CancellationToken.None).ConfigureAwait(false); }
/// <summary> /// Kills process if it is still alive. /// </summary> /// <param name="p">Process to kill.</param> private static void Kill(FirefoxProcessManager p) { try { if (!p.Process.HasExited) { p.Process.Kill(); } } catch (InvalidOperationException) { // Ignore } }
private static void LogProcessCount(FirefoxProcessManager p, int processCount) { // TODO Add logger Console.WriteLine(p.ToString() + processCount); /* * try * { * // p._logger?.LogInformation("Process Count: {ProcessCount}", processCount); * } * catch * { * // Prevent logging exception from causing havoc * }*/ }
public void EnterFrom(FirefoxProcessManager p, State fromState) { if (!TryEnter(p, fromState)) { // Delegate Dispose to current state, because it has already changed since // transition to this state was initiated. p._currentState.Dispose(p); } else if (fromState != Exited) { Kill(p); p._exitCompletionSource.TrySetException(new ObjectDisposedException(p.ToString())); p._tempUserDataDir?.Dispose(); } }
public void EnterFrom(FirefoxProcessManager p, State fromState) { while (!TryEnter(p, fromState)) { // Current state has changed since transition to this state was requested. // Therefore retry transition to this state from the current state. This ensures // that Leave() operation of current state is properly called. fromState = p._currentState; if (fromState == this) { return; } } p._onKill(p.Process?.ExitCode ?? 0); p._exitCompletionSource.TrySetResult(true); p._tempUserDataDir?.Dispose(); }
public override Task KillAsync(FirefoxProcessManager p) => Task.CompletedTask;
public override Task ExitAsync(FirefoxProcessManager p, TimeSpan timeout) => Task.CompletedTask;
public override Task KillAsync(FirefoxProcessManager p) => WaitForExitAsync(p);
public override Task WaitForExitAsync(FirefoxProcessManager p) => Task.FromException(InvalidOperation("wait for exit"));
public override Task ExitAsync(FirefoxProcessManager p, TimeSpan timeout) => WaitForExitAsync(p);
public override void Dispose(FirefoxProcessManager p) { // Nothing to do }
private async Task StartCoreAsync(FirefoxProcessManager p) { var output = new StringBuilder(); void OnProcessDataReceivedWhileStarting(object sender, DataReceivedEventArgs e) { if (e.Data != null) { output.AppendLine(e.Data); var match = Regex.Match(e.Data, "^Juggler listening on (ws:\\/\\/.*)"); if (match.Success) { p._startCompletionSource.TrySetResult(match.Groups[1].Value); } } } void OnProcessExitedWhileStarting(object sender, EventArgs e) => p._startCompletionSource.TrySetException(new PlaywrightSharpException($"Failed to launch Firefox! {output}")); void OnProcessExited(object sender, EventArgs e) => Exited.EnterFrom(p, p._currentState); p.Process.OutputDataReceived += OnProcessDataReceivedWhileStarting; p.Process.Exited += OnProcessExitedWhileStarting; p.Process.Exited += OnProcessExited; CancellationTokenSource cts = null; try { p.Process.Start(); await Started.EnterFromAsync(p, this).ConfigureAwait(false); p.Process.BeginOutputReadLine(); p.Process.BeginErrorReadLine(); int timeout = p.Timeout; if (timeout > 0) { cts = new CancellationTokenSource(timeout); cts.Token.Register(() => p._startCompletionSource.TrySetException( new PlaywrightSharpException($"Timed out after {timeout} ms while trying to connect to Firefox!"))); } try { await p._startCompletionSource.Task.ConfigureAwait(false); await Started.EnterFromAsync(p, this).ConfigureAwait(false); } catch { await Killing.EnterFromAsync(p, this).ConfigureAwait(false); throw; } } finally { cts?.Dispose(); p.Process.Exited -= OnProcessExitedWhileStarting; p.Process.OutputDataReceived -= OnProcessDataReceivedWhileStarting; } }
public override Task StartAsync(FirefoxProcessManager p) => p._startCompletionSource.Task;
public override Task ExitAsync(FirefoxProcessManager p, TimeSpan timeout) => throw new ObjectDisposedException(p.ToString());
protected override void Leave(FirefoxProcessManager p) => LogProcessCount(p, Interlocked.Decrement(ref _processCount));
public override Task ExitAsync(FirefoxProcessManager p, TimeSpan timeout) => Exiting.EnterFromAsync(p, this, timeout);
public override Task StartAsync(FirefoxProcessManager p) => Starting.EnterFromAsync(p, this);
public override Task WaitForExitAsync(FirefoxProcessManager p) => Task.CompletedTask;
public override Task KillAsync(FirefoxProcessManager p) { Exited.EnterFrom(p, this); return(Task.CompletedTask); }
/// <summary> /// Notifies that state machine is about to transition to another state. /// </summary> /// <param name="p">The Firefox process.</param> protected virtual void Leave(FirefoxProcessManager p) { }
public override void Dispose(FirefoxProcessManager p) { p._startCompletionSource.TrySetException(new ObjectDisposedException(p.ToString())); base.Dispose(p); }
public override Task KillAsync(FirefoxProcessManager p) => throw new ObjectDisposedException(p.ToString());
public override Task KillAsync(FirefoxProcessManager p) => Killing.EnterFromAsync(p, this);
public Task EnterFromAsync(FirefoxProcessManager p, State fromState, TimeSpan timeout) => !TryEnter(p, fromState) ? p._currentState.ExitAsync(p, timeout) : ExitAsync(p, timeout);
public override Task ExitAsync(FirefoxProcessManager p, TimeSpan timeout) { Exited.EnterFrom(p, this); return(Task.CompletedTask); }