Skip to content

Commit

Permalink
Core: Add PipelineController to reduce code duplication
Browse files Browse the repository at this point in the history
  • Loading branch information
jvyden committed Nov 3, 2024
1 parent 39798b1 commit 46e5514
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 96 deletions.
48 changes: 24 additions & 24 deletions Refresher.AndroidApp/PipelineActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class PipelineActivity : RefresherActivity
internal static PipelineActivity Instance { get; private set; }

private Pipeline? _pipeline;
private PipelineController _controller;
private CancellationTokenSource? _cts;

private LinearLayout _pipelineInputs = null!;
Expand All @@ -26,6 +27,8 @@ public class PipelineActivity : RefresherActivity
private ProgressBar _progressBar = null!;
private ProgressBar _currentProgressBar = null!;

private bool _usedAutoDiscover = false;

private readonly Handler _handler = new(Looper.MainLooper!);

public PipelineActivity()
Expand Down Expand Up @@ -75,6 +78,7 @@ private void InitializePipeline()
Pipeline pipeline = (Pipeline)Activator.CreateInstance(pipelineType)!;
pipeline.Initialize();
this._pipeline = pipeline;
this._controller = new PipelineController(pipeline, action => this._handler.Post(action));

if (this.ActionBar != null)
{
Expand Down Expand Up @@ -132,24 +136,24 @@ private void OnButtonClick(object? sender, EventArgs e)
this._pipeline.Inputs.Add(id, value);
}

Task.Run(async () =>
{
try
{
State.Logger.LogInfo(LogType.Pipeline, "Executing Pipeline...");
await this._pipeline.ExecuteAsync(this._cts?.Token ?? default);
this._handler.Post(this.UpdateFormState);
}
catch (Exception ex)
{
State.Logger.LogError(LogType.Pipeline, $"Error while running pipeline {this._pipeline.Name}: {ex.Message}");
}
}, this._cts?.Token ?? default);
this._controller.MainButtonClick();
}

private void OnAutoDiscoverClick(object? sender, EventArgs e)
{
throw new NotImplementedException();
if(this._pipelineInputs.FindViewWithTag("url") is not EditText text)
throw new Exception("URL input was not found");

this._controller.AutoDiscoverButtonClick(text.Text, autoDiscover =>
{
this._usedAutoDiscover = true;

System.Diagnostics.Debug.Assert(this._autoDiscoverButton != null);
this._autoDiscoverButton.Enabled = false;

text.Text = autoDiscover.Url;
text.Enabled = false;
});
}

private void OnRevertEbootClick(object? sender, EventArgs e)
Expand All @@ -162,7 +166,7 @@ private void UpdateFormState()
this._progressBar.Progress = (int)((this._pipeline?.Progress ?? 0) * 100);
this._currentProgressBar.Progress = (int)((this._pipeline?.CurrentProgress ?? 0) * 100);

bool enableControls = this._pipeline?.State != PipelineState.Running;
bool enableControls = this._controller.EnableControls;

// highlight progress bars while patching
this._currentProgressBar.Enabled = !enableControls;
Expand All @@ -175,15 +179,11 @@ private void UpdateFormState()
if(this._revertButton != null)
this._revertButton.Enabled = enableControls;

this._button.Text = this._pipeline?.State switch
{
PipelineState.NotStarted => "Patch!",
PipelineState.Running => "Patching... (click to cancel)",
PipelineState.Finished => "Complete!",
PipelineState.Cancelled => "Patch!",
PipelineState.Error => "Retry",
_ => throw new ArgumentOutOfRangeException(),
};
// set text of autodiscover button
if (this._autoDiscoverButton != null)
this._autoDiscoverButton.Text = this._controller.AutoDiscoverButtonText;

this._button.Text = this._controller.MainButtonText;
}

private void UpdateFormStateLoop()
Expand Down
118 changes: 118 additions & 0 deletions Refresher.Core/Pipelines/PipelineController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
using System.Net.Mime;
using Refresher.Core.Verification.AutoDiscover;

namespace Refresher.Core.Pipelines;

/// <summary>
/// A set of common utilities to assist in controlling a pipeline from a UI.
/// </summary>
public class PipelineController
{
private readonly Pipeline _pipeline;
private readonly Action<Action> _uiThread;

private CancellationTokenSource? _cts;

Check warning on line 14 in Refresher.Core/Pipelines/PipelineController.cs

View workflow job for this annotation

GitHub Actions / Build, Test, and Upload Builds (ubuntu-latest)

Field 'PipelineController._cts' is never assigned to, and will always have its default value null

Check warning on line 14 in Refresher.Core/Pipelines/PipelineController.cs

View workflow job for this annotation

GitHub Actions / Build, Test, and Upload Builds (windows-latest)

Field 'PipelineController._cts' is never assigned to, and will always have its default value null

Check warning on line 14 in Refresher.Core/Pipelines/PipelineController.cs

View workflow job for this annotation

GitHub Actions / Build, Test, and Upload Builds (macos-latest)

Field 'PipelineController._cts' is never assigned to, and will always have its default value null
private CancellationTokenSource? _autoDiscoverCts;

public PipelineController(Pipeline pipeline, Action<Action> uiThread)
{
this._pipeline = pipeline;
this._uiThread = uiThread;
}

public bool PipelineRunning => this._cts != null;
public bool AutoDiscoverRunning => this._autoDiscoverCts != null;

public bool EnableControls => this._pipeline.State != PipelineState.Running;

public string MainButtonText => this._pipeline.State switch
{
PipelineState.NotStarted => "Patch!",
PipelineState.Running => "Patching... (click to cancel)",
PipelineState.Finished => "Complete!",
PipelineState.Cancelled => "Patch!",
PipelineState.Error => "Retry",
_ => throw new ArgumentOutOfRangeException(),
};

private string? _autoDiscoverButtonText;
public string AutoDiscoverButtonText
{
get
{
if(this._autoDiscoverButtonText != null)
return this._autoDiscoverButtonText;

if (this.AutoDiscoverRunning)
return "Running AutoDiscover... (click to cancel)";

return "AutoDiscover";
}
}

public void CancelPipeline()
{
this._cts?.Cancel();
}

public void MainButtonClick()
{
if (this._pipeline.State == PipelineState.Running)
{
this.CancelPipeline();
return;
}

if (this._pipeline.State is PipelineState.Cancelled or PipelineState.Error or PipelineState.Finished)
{
this._pipeline.Reset();
}

Task.Run(async () =>
{
try
{
await this._pipeline.ExecuteAsync(this._cts?.Token ?? default);
}
catch (Exception ex)
{
State.Logger.LogError(LogType.Pipeline, $"Error while running pipeline {this._pipeline.Name}: {ex}");
}
}, this._cts?.Token ?? default);
}

public void AutoDiscoverButtonClick(string url, Action<AutoDiscoverResponse> onSuccess)
{
if (this._autoDiscoverCts != null)
{
this._autoDiscoverCts.Cancel();
return;
}

this._autoDiscoverCts = new CancellationTokenSource();

Task.Run(async () =>
{
try
{
AutoDiscoverResponse? autoDiscover =
await this._pipeline.InvokeAutoDiscoverAsync(url, this._autoDiscoverCts.Token);

if (autoDiscover != null)
{
this._autoDiscoverButtonText = $"AutoDiscover [locked to {autoDiscover.ServerBrand}]";
this._uiThread.Invoke(() => onSuccess.Invoke(autoDiscover));
}
}
catch (Exception ex)
{
State.Logger.LogError(LogType.Pipeline, $"Error while invoking autodiscover: {ex}");
SentrySdk.CaptureException(ex);
}
finally
{
this._autoDiscoverCts = null;
}
}, this._autoDiscoverCts.Token);
}
}
88 changes: 16 additions & 72 deletions Refresher/UI/PipelineForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ namespace Refresher.UI;
public class PipelineForm<TPipeline> : RefresherForm where TPipeline : Pipeline, new()
{
private TPipeline? _pipeline;
private PipelineController? _controller;

private readonly Button _button;
private readonly Button? _revertButton;
Expand All @@ -31,9 +32,6 @@ namespace Refresher.UI;
private readonly TableLayout _formLayout;
private Button? _connectButton;
private DropDown? _gamesDropDown;

private CancellationTokenSource? _cts;
private CancellationTokenSource? _autoDiscoverCts;

private bool _usedAutoDiscover = false;

Expand Down Expand Up @@ -94,7 +92,7 @@ private void UpdateFormState()
this._currentProgressBar.Value = (int)(this._pipeline?.CurrentProgress * 100 ?? 0);
this._progressBar.ToolTip = this._pipeline?.State.ToString() ?? "Uninitialized";

bool enableControls = this._pipeline?.State != PipelineState.Running;
bool enableControls = this._controller.EnableControls;

Check warning on line 95 in Refresher/UI/PipelineForm.cs

View workflow job for this annotation

GitHub Actions / Build, Test, and Upload Builds (ubuntu-latest)

Dereference of a possibly null reference.

Check warning on line 95 in Refresher/UI/PipelineForm.cs

View workflow job for this annotation

GitHub Actions / Build, Test, and Upload Builds (ubuntu-latest)

Dereference of a possibly null reference.

Check warning on line 95 in Refresher/UI/PipelineForm.cs

View workflow job for this annotation

GitHub Actions / Build, Test, and Upload Builds (ubuntu-latest)

Dereference of a possibly null reference.

Check warning on line 95 in Refresher/UI/PipelineForm.cs

View workflow job for this annotation

GitHub Actions / Build, Test, and Upload Builds (windows-latest)

Dereference of a possibly null reference.

Check warning on line 95 in Refresher/UI/PipelineForm.cs

View workflow job for this annotation

GitHub Actions / Build, Test, and Upload Builds (macos-latest)

Dereference of a possibly null reference.

Check warning on line 95 in Refresher/UI/PipelineForm.cs

View workflow job for this annotation

GitHub Actions / Build, Test, and Upload Builds (macos-latest)

Dereference of a possibly null reference.

// highlight progress bars while patching
this._currentProgressBar.Enabled = !enableControls;
Expand All @@ -109,29 +107,15 @@ private void UpdateFormState()

// set text of autodiscover button
if (this._autoDiscoverButton != null)
{
if (this._autoDiscoverCts != null)
this._autoDiscoverButton.Text = "Running AutoDiscover... (click to cancel)";
else if (this._pipeline?.AutoDiscover == null)
this._autoDiscoverButton.Text = "AutoDiscover";
}
this._autoDiscoverButton.Text = this._controller.AutoDiscoverButtonText;

this._button.Text = this._pipeline?.State switch
{
PipelineState.NotStarted => "Patch!",
PipelineState.Running => "Patching... (click to cancel)",
PipelineState.Finished => "Complete!",
PipelineState.Cancelled => "Patch!",
PipelineState.Error => "Retry",
_ => throw new ArgumentOutOfRangeException(),
};
this._button.Text = this._controller.MainButtonText;
}

private void InitializePipeline()
{
this._cts = new CancellationTokenSource();

this._pipeline = new TPipeline();
this._controller = new PipelineController(this._pipeline, Application.Instance.Invoke);
this._pipeline.Initialize();

this._formLayout.Rows.Clear();
Expand Down Expand Up @@ -207,7 +191,7 @@ private void OnButtonClick(object? sender, EventArgs e)

if (this._pipeline.State == PipelineState.Running)
{
this._cts?.Cancel();
this._controller?.CancelPipeline();
return;
}

Expand Down Expand Up @@ -240,19 +224,8 @@ private void OnButtonClick(object? sender, EventArgs e)
}

this.AddFormInputsToPipeline();

Task.Run(async () =>
{
try
{
await this._pipeline.ExecuteAsync(this._cts?.Token ?? default);
}
catch (Exception ex)
{
State.Logger.LogError(LogType.Pipeline, $"Error while running pipeline {this._pipeline.Name}: {ex}");
}
}, this._cts?.Token ?? default);


this._controller?.MainButtonClick();
this.UpdateFormState();
}

Expand Down Expand Up @@ -349,52 +322,23 @@ private void OnAutoDiscoverClick(object? sender, EventArgs e)

if (this._pipeline.State == PipelineState.Running)
return;

if (this._autoDiscoverCts != null)
{
this._autoDiscoverCts.Cancel();
return;
}

this._autoDiscoverCts = new CancellationTokenSource();

TextControl control = (TextControl)this._formLayout.Rows
.Where(r => r.Cells[0].Control.ToolTip == CommonStepInputs.ServerUrl.Id)
.Select(r => r.Cells[1].Control)
.First();

string url = control.Text;

Task.Run(async () =>
this._controller?.AutoDiscoverButtonClick(url, autoDiscover =>
{
try
{
AutoDiscoverResponse? autoDiscover =
await this._pipeline.InvokeAutoDiscoverAsync(url, this._autoDiscoverCts.Token);
this._usedAutoDiscover = true;

if (autoDiscover != null)
{
this._usedAutoDiscover = true;
await Application.Instance.InvokeAsync(() =>
{
this._autoDiscoverButton.Enabled = false;
this._autoDiscoverButton.Text = $"AutoDiscover [locked to {autoDiscover.ServerBrand}]";

control.Text = autoDiscover.Url;
control.Enabled = false;
});
}
}
catch (Exception ex)
{
State.Logger.LogError(LogType.Pipeline, $"Error while invoking autodiscover: {ex}");
SentrySdk.CaptureException(ex);
}
finally
{
this._autoDiscoverCts = null;
}
}, this._autoDiscoverCts.Token);
Debug.Assert(this._autoDiscoverButton != null);
this._autoDiscoverButton.Enabled = false;

control.Text = autoDiscover.Url;
control.Enabled = false;
});
}

private void OnViewGuideClick(object? sender, EventArgs _)
Expand Down

0 comments on commit 46e5514

Please sign in to comment.