Skip to content

Commit

Permalink
Use wrapper for disposing CancellationTokenSource
Browse files Browse the repository at this point in the history
+ Since we can't have an indicator whenever the CancellationTokenSource is cancelled, so it's now wrapped by CancellationTokenSourceWrapper with an additional IsDisposed property to indicate the disposal

+ Update NuGet
  • Loading branch information
neon-nyan committed Dec 7, 2023
1 parent 3ff8cdf commit e0cbea5
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public static async void ApplyAccentColor(Page page, Bitmap bitmapInput, string
public static void SetColorPalette(Page page, Windows.UI.Color[] palette = null)
{
if (palette == null || palette?.Length < 2)
palette = EnsureLengthCopyLast(new Windows.UI.Color [] {(Windows.UI.Color)Application.Current.Resources["TemplateAccentColor"]}, 2);
palette = EnsureLengthCopyLast(new Windows.UI.Color[] { (Windows.UI.Color)Application.Current.Resources["TemplateAccentColor"] }, 2);

if (IsAppThemeLight)
{
Expand Down
105 changes: 59 additions & 46 deletions CollapseLauncher/Classes/RegionManagement/RegionManagement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@

namespace CollapseLauncher
{
public class CancellationTokenSourceWrapper : CancellationTokenSource
{
public bool IsDisposed = false;
protected override void Dispose(bool disposing)
{
IsDisposed = true;
base.Dispose(disposing);
}
}

public sealed partial class MainPage : Page
{
private enum ResourceLoadingType
Expand All @@ -35,19 +45,19 @@ private enum ResourceLoadingType
private GamePresetProperty CurrentGameProperty;
private bool IsLoadRegionComplete;
private bool IsExplicitCancel;
private CancellationTokenSource InnerTokenSource;

private uint MaxRetry = 5; // Max 5 times of retry attempt
private uint LoadTimeout = 10; // 10 seconds of initial Load Timeout
private uint BackgroundImageLoadTimeout = 3600; // Give background image download 1 hour of timeout
private uint LoadTimeoutStep = 5; // Step 5 seconds for each timeout retries
private CancellationTokenSourceWrapper CurrentRegionLoadTokenSource;

private string RegionToChangeName;
private List<object> LastNavigationItem;
private HomeMenuPanel LastRegionNewsProp;
public static string PreviousTag = string.Empty;

public async Task<bool> LoadRegionFromCurrentConfigV2(PresetConfigV2 preset, bool IsInitialStartUp = false)
public async Task<bool> LoadRegionFromCurrentConfigV2(PresetConfigV2 preset)
{
IsExplicitCancel = false;
RegionToChangeName = $"{CurrentConfigV2GameCategory} - {CurrentConfigV2GameRegion}";
Expand All @@ -59,9 +69,10 @@ public async Task<bool> LoadRegionFromCurrentConfigV2(PresetConfigV2 preset, boo
// Clear MainPage State, like NavigationView, Load State, etc.
ClearMainPageState();

bool IsLoadLocalizedResourceSuccess = await TryLoadResourceInfo(ResourceLoadingType.LocalizedResource, preset),
IsLoadResourceRegionSuccess = false;

// Load Region Resource from Launcher API
bool IsLoadLocalizedResourceSuccess = await TryLoadResourceInfo(ResourceLoadingType.LocalizedResource, preset);
bool IsLoadResourceRegionSuccess = false;
if (IsLoadLocalizedResourceSuccess) IsLoadResourceRegionSuccess = await TryLoadResourceInfo(ResourceLoadingType.DownloadInformation, preset);

if (IsExplicitCancel)
Expand Down Expand Up @@ -111,7 +122,6 @@ public void ClearMainPageState()
PreviousTagString.Clear();
PreviousTagString.Add(PreviousTag);
LauncherFrame.BackStack.Clear();
InnerTokenSource?.Cancel();
ResetRegionProp();
}

Expand All @@ -121,49 +131,49 @@ private async ValueTask<bool> TryLoadResourceInfo(ResourceLoadingType resourceTy
uint RetryCount = 0;
while (RetryCount < MaxRetry)
{
// Store the old token into oldToken to check and avoid unnecessary re-throw
CancellationTokenSource oldToken = InnerTokenSource;
using (CancellationTokenSourceWrapper tokenSource = new CancellationTokenSourceWrapper())
{
// Register token source for cancellation registration
CurrentRegionLoadTokenSource = tokenSource;

// Assign new cancellation token source
InnerTokenSource = new CancellationTokenSource(); // Assign the new token
// Watch for timeout
WatchAndCancelIfTimeout(tokenSource, CurrentTimeout);

// Watch for timeout
WatchAndCancelIfTimeout(InnerTokenSource, CurrentTimeout);
// Assign task based on type
ConfiguredValueTaskAwaitable loadTask = (resourceType switch
{
ResourceLoadingType.LocalizedResource => FetchLauncherLocalizedResources(tokenSource.Token, preset),
ResourceLoadingType.DownloadInformation => FetchLauncherDownloadInformation(tokenSource.Token, preset),
ResourceLoadingType.DownloadBackground => DownloadBackgroundImage(tokenSource.Token),
_ => throw new InvalidOperationException($"Operation is not supported!")
}).ConfigureAwait(false);

// Assign task based on type
ConfiguredValueTaskAwaitable loadTask = (resourceType switch
{
ResourceLoadingType.LocalizedResource => FetchLauncherLocalizedResources(InnerTokenSource.Token, preset),
ResourceLoadingType.DownloadInformation => FetchLauncherDownloadInformation(InnerTokenSource.Token, preset),
ResourceLoadingType.DownloadBackground => DownloadBackgroundImage(InnerTokenSource.Token),
_ => throw new InvalidOperationException($"Operation is not supported!")
}).ConfigureAwait(false);
try
{
// Run and await task
await loadTask;

try
{
// Run and await task
await loadTask;
// Return true as successful
return true;
}
catch (OperationCanceledException)
{
CurrentTimeout = SendTimeoutCancelationMessage(new OperationCanceledException($"Loading was cancelled because timeout has been exceeded!"), CurrentTimeout, ShowLoadingMsg);
}
catch (Exception ex)
{
CurrentTimeout = SendTimeoutCancelationMessage(ex, CurrentTimeout, ShowLoadingMsg);
}

// Return true as successful
return true;
}
catch (OperationCanceledException)
{
CurrentTimeout = SendTimeoutCancelationMessage(new OperationCanceledException($"Loading was cancelled because timeout has been exceeded!"), CurrentTimeout, ShowLoadingMsg);
}
catch (Exception ex)
{
CurrentTimeout = SendTimeoutCancelationMessage(ex, CurrentTimeout, ShowLoadingMsg);
}
// If explicit cancel was triggered, then return false
if (IsExplicitCancel)
{
return false;
}

// If explicit cancel was triggered, then return false
if (IsExplicitCancel)
{
return false;
// Increment retry count
RetryCount++;
}

// Increment retry count
RetryCount++;
}

// Return false as fail
Expand Down Expand Up @@ -535,7 +545,7 @@ private uint SendTimeoutCancelationMessage(Exception ex, uint currentTimeout, bo
return currentTimeout;
}

private async void WatchAndCancelIfTimeout(CancellationTokenSource TokenSource, uint Timeout)
private async void WatchAndCancelIfTimeout(CancellationTokenSourceWrapper TokenSource, uint Timeout)
{
// Wait until it timeout
await Task.Delay((int)Timeout * 1000);
Expand All @@ -544,7 +554,7 @@ private async void WatchAndCancelIfTimeout(CancellationTokenSource TokenSource,
if (TokenSource.IsCancellationRequested) return;

// If InnerTask still not loaded successfully, then cancel it
if (!IsLoadRegionComplete)
if (!IsLoadRegionComplete && !TokenSource.IsDisposed)
{
TokenSource.Cancel();
ChangeTimer();
Expand Down Expand Up @@ -678,7 +688,7 @@ private async Task<bool> LoadRegionRootButton()
PresetConfigV2 Preset = LoadCurrentConfigV2(GameCategory, GameRegion);

// Start region loading
DelayedLoadingRegionPageTask();
ShowAsyncLoadingTimedOutPill();
if (await LoadRegionFromCurrentConfigV2(Preset))
{
LogWriteLine($"Region changed to {Preset.ZoneFullname}", Hi3Helper.LogType.Scheme, true);
Expand Down Expand Up @@ -717,7 +727,10 @@ private void CancelLoadRegion(object sender, RoutedEventArgs e)
{
IsExplicitCancel = true;
LockRegionChangeBtn = false;
InnerTokenSource.Cancel();

if (CurrentRegionLoadTokenSource != null && !CurrentRegionLoadTokenSource.IsDisposed)
CurrentRegionLoadTokenSource.Cancel();

ChangeRegionConfirmProgressBar.Visibility = Visibility.Collapsed;
ChangeRegionConfirmBtn.IsEnabled = true;
ChangeRegionConfirmBtnNoWarning.IsEnabled = true;
Expand All @@ -728,7 +741,7 @@ private void CancelLoadRegion(object sender, RoutedEventArgs e)
ChangeTimer();
}

private async void DelayedLoadingRegionPageTask()
private async void ShowAsyncLoadingTimedOutPill()
{
await Task.Delay(1000);
if (!IsLoadRegionComplete)
Expand Down
7 changes: 3 additions & 4 deletions CollapseLauncher/CollapseLauncher.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- General Properties -->
<OutputType>WinExe</OutputType>
Expand All @@ -23,7 +23,6 @@
<TieredCompilation>true</TieredCompilation>
<TieredCompilationQuickJit>false</TieredCompilationQuickJit>
<TieredCompilationQuickJitForLoops>false</TieredCompilationQuickJitForLoops>
<InvariantGlobalization>false</InvariantGlobalization>
<!-- WinUI Properties -->
<UseWinUI>true</UseWinUI>
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
Expand All @@ -32,6 +31,7 @@
<EnablePreviewMsixTooling>true</EnablePreviewMsixTooling>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<InvariantGlobalization>false</InvariantGlobalization>
</PropertyGroup>

<!--
Expand Down Expand Up @@ -85,9 +85,8 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="H.NotifyIcon.WinUI" Version="2.0.123" />
<PackageReference Include="ImageEx" Version="2.0.0" />
<PackageReference Include="ImageEx" Version="2.1.1" />
<PackageReference Include="Microsoft.Graphics.Win2D" Version="1.1.1" />
<PackageReference Include="Microsoft.NETCore.Platforms" Version="8.0.0-preview.7.23375.6" />
<PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.0.4" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.231115000" />
Expand Down
2 changes: 1 addition & 1 deletion CollapseLauncher/XAMLs/MainApp/MainPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ private async Task InitializeStartup()

InitKeyboardShortcuts();
HideLoadingPopup(false, Lang._MainPage.RegionLoadingTitle, Preset.ZoneFullname);
if (await LoadRegionFromCurrentConfigV2(Preset, true))
if (await LoadRegionFromCurrentConfigV2(Preset))
{
MainFrameChanger.ChangeMainFrame(Page);
HideLoadingPopup(true, Lang._MainPage.RegionLoadingTitle, Preset.ZoneFullname);
Expand Down

0 comments on commit e0cbea5

Please sign in to comment.