Skip to content

Commit 317d6e5

Browse files
committed
Make PresetConfig Metadata loads in Parallel
1 parent 0238c45 commit 317d6e5

File tree

5 files changed

+315
-193
lines changed

5 files changed

+315
-193
lines changed

CollapseLauncher/Classes/Helper/Loading/LoadingMessageHelper.cs

Lines changed: 62 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using CollapseLauncher.Helper.Animation;
33
using CommunityToolkit.WinUI;
44
using CommunityToolkit.WinUI.Animations;
5+
using Microsoft.UI.Dispatching;
56
using Microsoft.UI.Text;
67
using Microsoft.UI.Xaml;
78
using Microsoft.UI.Xaml.Controls;
@@ -18,6 +19,7 @@ internal static class LoadingMessageHelper
1819
internal static bool IsLoadingProgressIndeterminate = true;
1920
internal static bool IsCurrentlyShow;
2021
internal static List<RoutedEventHandler> CurrentActionButtonHandler = [];
22+
internal static DispatcherQueue CurrentDispatcherQueue;
2123

2224
/// <summary>
2325
/// Initialize the necessary <c>MainWindow</c> for spawning the loading frame overlay.
@@ -26,6 +28,8 @@ internal static void Initialize()
2628
{
2729
if (WindowUtility.CurrentWindow is MainWindow window)
2830
CurrentMainWindow = window;
31+
32+
CurrentDispatcherQueue = CurrentMainWindow.DispatcherQueue;
2933
}
3034

3135
/// <summary>
@@ -35,10 +39,13 @@ internal static void Initialize()
3539
/// <param name="subtitle">Set the subtitle of the loading frame. You can set the value to <c>null</c> to ignore the change of the subtitle or <c>string.Empty</c> to disable the subtitle</param>
3640
internal static void SetMessage(string title, string subtitle)
3741
{
38-
if (title != null) CurrentMainWindow!.LoadingStatusTextTitle!.Text = title;
39-
if (subtitle != null) CurrentMainWindow!.LoadingStatusTextSubtitle!.Text = subtitle;
42+
CurrentDispatcherQueue.TryEnqueue(() =>
43+
{
44+
if (title != null) CurrentMainWindow.LoadingStatusTextTitle.Text = title;
45+
if (subtitle != null) CurrentMainWindow.LoadingStatusTextSubtitle.Text = subtitle;
4046

41-
CurrentMainWindow!.LoadingStatusTextSeparator!.Visibility = title == string.Empty || subtitle == string.Empty ? Visibility.Collapsed : Visibility.Visible;
47+
CurrentMainWindow.LoadingStatusTextSeparator.Visibility = title == string.Empty || subtitle == string.Empty ? Visibility.Collapsed : Visibility.Visible;
48+
});
4249
}
4350

4451
/// <summary>
@@ -47,7 +54,7 @@ internal static void SetMessage(string title, string subtitle)
4754
/// Note: If you would like to set the progress ring's value, make sure to set the <c>isProgressIndeterminate</c> to <c>true</c> with <c>SetProgressBarState()</c> method.
4855
/// </summary>
4956
/// <param name="value">Set the current value of the progress ring</param>
50-
internal static void SetProgressBarValue(double value) => CurrentMainWindow!.LoadingStatusProgressRing!.Value = value;
57+
internal static void SetProgressBarValue(double value) => CurrentDispatcherQueue.TryEnqueue(() => CurrentMainWindow.LoadingStatusProgressRing.Value = value);
5158

5259
/// <summary>
5360
/// Set the state and the maximum value of the progress ring.
@@ -56,9 +63,12 @@ internal static void SetMessage(string title, string subtitle)
5663
/// <param name="isProgressIndeterminate">Set the state of the progress ring's indeterminate.</param>
5764
internal static void SetProgressBarState(double maxValue = 100d, bool isProgressIndeterminate = true)
5865
{
59-
IsLoadingProgressIndeterminate = isProgressIndeterminate;
60-
CurrentMainWindow!.LoadingStatusProgressRing!.Maximum = maxValue;
61-
CurrentMainWindow!.LoadingStatusProgressRing!.IsIndeterminate = IsLoadingProgressIndeterminate;
66+
CurrentDispatcherQueue.TryEnqueue(() =>
67+
{
68+
IsLoadingProgressIndeterminate = isProgressIndeterminate;
69+
CurrentMainWindow.LoadingStatusProgressRing.Maximum = maxValue;
70+
CurrentMainWindow.LoadingStatusProgressRing.IsIndeterminate = IsLoadingProgressIndeterminate;
71+
});
6272
}
6373

6474
/// <summary>
@@ -87,17 +97,17 @@ private static async Task ShowLoadingFrameInner()
8797
if (IsCurrentlyShow) return;
8898

8999
IsCurrentlyShow = true;
90-
CurrentMainWindow!.LoadingStatusGrid!.Visibility = Visibility.Visible;
91-
CurrentMainWindow!.LoadingStatusBackgroundGrid!.Visibility = Visibility.Visible;
100+
CurrentMainWindow.LoadingStatusGrid.Visibility = Visibility.Visible;
101+
CurrentMainWindow.LoadingStatusBackgroundGrid.Visibility = Visibility.Visible;
92102

93103
TimeSpan duration = TimeSpan.FromSeconds(0.25);
94104

95105
await Task.WhenAll(
96106
CurrentMainWindow.LoadingStatusBackgroundGrid.StartAnimation(duration,
97-
CurrentMainWindow.LoadingStatusBackgroundGrid.GetElementCompositor()!.CreateScalarKeyFrameAnimation("Opacity", 1, 0)),
107+
CurrentMainWindow.LoadingStatusBackgroundGrid.GetElementCompositor().CreateScalarKeyFrameAnimation("Opacity", 1, 0)),
98108
CurrentMainWindow.LoadingStatusGrid.StartAnimation(duration,
99-
CurrentMainWindow.LoadingStatusGrid.GetElementCompositor()!.CreateVector3KeyFrameAnimation("Translation", new Vector3(0, 0, CurrentMainWindow.LoadingStatusGrid.Translation.Z), new Vector3(0, (float)(CurrentMainWindow.LoadingStatusGrid.ActualHeight + 16), CurrentMainWindow.LoadingStatusGrid.Translation.Z)),
100-
CurrentMainWindow.LoadingStatusGrid.GetElementCompositor()!.CreateScalarKeyFrameAnimation("Opacity", 1, 0))
109+
CurrentMainWindow.LoadingStatusGrid.GetElementCompositor().CreateVector3KeyFrameAnimation("Translation", new Vector3(0, 0, CurrentMainWindow.LoadingStatusGrid.Translation.Z), new Vector3(0, (float)(CurrentMainWindow.LoadingStatusGrid.ActualHeight + 16), CurrentMainWindow.LoadingStatusGrid.Translation.Z)),
110+
CurrentMainWindow.LoadingStatusGrid.GetElementCompositor().CreateScalarKeyFrameAnimation("Opacity", 1, 0))
101111
);
102112
}
103113

@@ -131,14 +141,14 @@ private static async Task HideLoadingFrameInner()
131141
TimeSpan duration = TimeSpan.FromSeconds(0.25);
132142
await Task.WhenAll(
133143
CurrentMainWindow.LoadingStatusBackgroundGrid.StartAnimation(duration,
134-
CurrentMainWindow.LoadingStatusBackgroundGrid.GetElementCompositor()!.CreateScalarKeyFrameAnimation("Opacity", 0, 1)),
144+
CurrentMainWindow.LoadingStatusBackgroundGrid.GetElementCompositor().CreateScalarKeyFrameAnimation("Opacity", 0, 1)),
135145
CurrentMainWindow.LoadingStatusGrid.StartAnimation(duration,
136-
CurrentMainWindow.LoadingStatusGrid.GetElementCompositor()!.CreateVector3KeyFrameAnimation("Translation", new Vector3(0, (float)(CurrentMainWindow.LoadingStatusGrid.ActualHeight + 16), CurrentMainWindow.LoadingStatusGrid.Translation.Z), new Vector3(0, 0, CurrentMainWindow.LoadingStatusGrid.Translation.Z)),
137-
CurrentMainWindow.LoadingStatusGrid.GetElementCompositor()!.CreateScalarKeyFrameAnimation("Opacity", 0, 1))
146+
CurrentMainWindow.LoadingStatusGrid.GetElementCompositor().CreateVector3KeyFrameAnimation("Translation", new Vector3(0, (float)(CurrentMainWindow.LoadingStatusGrid.ActualHeight + 16), CurrentMainWindow.LoadingStatusGrid.Translation.Z), new Vector3(0, 0, CurrentMainWindow.LoadingStatusGrid.Translation.Z)),
147+
CurrentMainWindow.LoadingStatusGrid.GetElementCompositor().CreateScalarKeyFrameAnimation("Opacity", 0, 1))
138148
);
139149

140-
CurrentMainWindow.LoadingStatusGrid.Visibility = Visibility.Collapsed;
141-
CurrentMainWindow.LoadingStatusBackgroundGrid!.Visibility = Visibility.Collapsed;
150+
CurrentMainWindow.LoadingStatusGrid.Visibility = Visibility.Collapsed;
151+
CurrentMainWindow.LoadingStatusBackgroundGrid.Visibility = Visibility.Collapsed;
142152
HideActionButton();
143153
}
144154

@@ -155,50 +165,56 @@ await Task.WhenAll(
155165
/// <param name="routedEvent">Set the event callback for the button's click event.</param>
156166
internal static void ShowActionButton(object buttonContent, string buttonIconGlyph = null, RoutedEventHandler routedEvent = null)
157167
{
158-
if (routedEvent != null)
168+
CurrentDispatcherQueue.TryEnqueue(() =>
159169
{
160-
CurrentActionButtonHandler!.Add(routedEvent);
161-
CurrentMainWindow!.LoadingStatusActionButton!.Click += routedEvent;
162-
}
170+
if (routedEvent != null)
171+
{
172+
CurrentActionButtonHandler!.Add(routedEvent);
173+
CurrentMainWindow.LoadingStatusActionButton.Click += routedEvent;
174+
}
163175

164-
bool isHasIcon = !string.IsNullOrEmpty(buttonIconGlyph);
165-
CurrentMainWindow!.LoadingStatusActionButtonIcon!.Visibility = isHasIcon ? Visibility.Visible : Visibility.Collapsed;
166-
CurrentMainWindow!.LoadingStatusActionButton!.Visibility = Visibility.Visible;
167-
if (isHasIcon) CurrentMainWindow.LoadingStatusActionButtonIcon.Glyph = buttonIconGlyph;
176+
bool isHasIcon = !string.IsNullOrEmpty(buttonIconGlyph);
177+
CurrentMainWindow.LoadingStatusActionButtonIcon.Visibility = isHasIcon ? Visibility.Visible : Visibility.Collapsed;
178+
CurrentMainWindow.LoadingStatusActionButton.Visibility = Visibility.Visible;
179+
if (isHasIcon) CurrentMainWindow.LoadingStatusActionButtonIcon.Glyph = buttonIconGlyph;
168180

169-
if (buttonContent is string buttonText)
170-
{
171-
TextBlock textBlock = new()
181+
if (buttonContent is string buttonText)
172182
{
173-
TextWrapping = TextWrapping.Wrap,
174-
TextAlignment = TextAlignment.Left,
175-
VerticalAlignment = VerticalAlignment.Center,
176-
Margin = new Thickness(0, isHasIcon ? -2 : 0, 0, 0)
177-
};
178-
textBlock.AddTextBlockLine(buttonText, FontWeights.SemiBold);
179-
CurrentMainWindow.LoadingStatusActionButtonContentContainer!.Children!.Clear();
180-
CurrentMainWindow.LoadingStatusActionButtonContentContainer!.AddElementToGridRowColumn(textBlock);
181-
return;
182-
}
183+
TextBlock textBlock = new()
184+
{
185+
TextWrapping = TextWrapping.Wrap,
186+
TextAlignment = TextAlignment.Left,
187+
VerticalAlignment = VerticalAlignment.Center,
188+
Margin = new Thickness(0, isHasIcon ? -2 : 0, 0, 0)
189+
};
190+
textBlock.AddTextBlockLine(buttonText, FontWeights.SemiBold);
191+
CurrentMainWindow.LoadingStatusActionButtonContentContainer.Children.Clear();
192+
CurrentMainWindow.LoadingStatusActionButtonContentContainer.AddElementToGridRowColumn(textBlock);
193+
return;
194+
}
183195

184-
CurrentMainWindow.LoadingStatusActionButtonContentContainer!.Children!.Clear();
185-
CurrentMainWindow.LoadingStatusActionButtonContentContainer!.AddElementToGridRowColumn(buttonContent as FrameworkElement);
196+
CurrentMainWindow.LoadingStatusActionButtonContentContainer.Children.Clear();
197+
CurrentMainWindow.LoadingStatusActionButtonContentContainer.AddElementToGridRowColumn(buttonContent as FrameworkElement);
198+
});
186199
}
187200

188201
/// <summary>
189202
/// Hide the action button from the loading frame.
190203
/// </summary>
191204
internal static void HideActionButton()
192205
{
193-
if (CurrentActionButtonHandler!.Count > 0)
206+
CurrentDispatcherQueue.TryEnqueue(() =>
194207
{
195-
foreach (var t in CurrentActionButtonHandler)
196-
CurrentMainWindow!.LoadingStatusActionButton!.Click -= t;
208+
if (CurrentActionButtonHandler.Count > 0)
209+
{
210+
foreach (var t in CurrentActionButtonHandler)
211+
CurrentMainWindow.LoadingStatusActionButton.Click -= t;
197212

198-
CurrentActionButtonHandler.Clear();
199-
}
213+
CurrentActionButtonHandler.Clear();
214+
}
200215

201-
CurrentMainWindow!.LoadingStatusActionButton!.Visibility = Visibility.Collapsed;
216+
CurrentMainWindow.LoadingStatusActionButton.Visibility = Visibility.Collapsed;
217+
});
202218
}
203219
}
204220
}

CollapseLauncher/Classes/Helper/Metadata/DataCooker.cs

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Runtime.InteropServices;
88
using System.Security.Cryptography;
99
using System.Text;
10+
using System.Threading;
1011

1112
// ReSharper disable IdentifierTypo
1213
using ZstdDecompressStream = ZstdNet.DecompressionStream;
@@ -25,7 +26,8 @@ internal static class DataCooker
2526
private const long CollapseSignature = 7310310183885631299;
2627
private const int AllowedBufferPoolSize = 1 << 20; // 1 MiB
2728

28-
internal static RSA RsaInstance;
29+
internal static RSA RsaInstance;
30+
private static readonly Lock RsaDecryptLock = new Lock();
2931

3032
internal static string ServeV3Data(string data)
3133
{
@@ -66,20 +68,19 @@ internal static void GetServeV3DataSize(ReadOnlySpan<byte> data, out long compre
6668
throw new FormatException("The MetadataV3 data format is corrupted!");
6769
}
6870

69-
compressedSize = MemoryMarshal.Read<long>(data.Slice(16));
70-
decompressedSize = MemoryMarshal.Read<long>(data.Slice(24));
71+
compressedSize = MemoryMarshal.Read<long>(data[16..]);
72+
decompressedSize = MemoryMarshal.Read<long>(data[24..]);
7173
}
7274

7375
private static void GetServeV3Attribute(ReadOnlySpan<byte> data, out CompressionType compressionType,
7476
out bool isUseEncryption)
7577
{
76-
long attribNumber = MemoryMarshal.Read<long>(data.Slice(sizeof(long)));
78+
long attribNumber = MemoryMarshal.Read<long>(data[sizeof(long)..]);
7779

7880
compressionType = (CompressionType)(byte)attribNumber;
7981
isUseEncryption = (byte)(attribNumber >> 8) == 1;
8082
}
8183

82-
8384
internal static void ServeV3Data(ReadOnlySpan<byte> data, Span<byte> outData, int compressedSize,
8485
int decompressedSize, out int dataWritten)
8586
{
@@ -105,38 +106,41 @@ internal static void ServeV3Data(ReadOnlySpan<byte> data, Span<byte>
105106
: new byte[dataRawBuffer.Length];
106107
isDecryptPoolUsed = isDecryptPoolAllowed;
107108

108-
if (RsaInstance == null)
109+
lock (RsaDecryptLock)
109110
{
110-
RsaInstance = RSA.Create();
111-
byte[] key;
112-
if (IsServeV3Data(LauncherMetadataHelper.CurrentMasterKey?.Key))
111+
if (RsaInstance == null)
113112
{
114-
GetServeV3DataSize(LauncherMetadataHelper.CurrentMasterKey?.Key, out long keyCompSize,
115-
out long keyDecompSize);
116-
key = new byte[keyCompSize];
117-
ServeV3Data(LauncherMetadataHelper.CurrentMasterKey?.Key, key, (int)keyCompSize,
118-
(int)keyDecompSize, out _);
113+
RsaInstance = RSA.Create();
114+
byte[] key;
115+
if (IsServeV3Data(LauncherMetadataHelper.CurrentMasterKey?.Key))
116+
{
117+
GetServeV3DataSize(LauncherMetadataHelper.CurrentMasterKey?.Key, out long keyCompSize,
118+
out long keyDecompSize);
119+
key = new byte[keyCompSize];
120+
ServeV3Data(LauncherMetadataHelper.CurrentMasterKey?.Key, key, (int)keyCompSize,
121+
(int)keyDecompSize, out _);
122+
}
123+
else
124+
{
125+
key = LauncherMetadataHelper.CurrentMasterKey?.Key;
126+
}
127+
128+
RsaInstance.ImportRSAPrivateKey(key, out _);
119129
}
120-
else
130+
131+
int offset = 0;
132+
int offsetOut = 0;
133+
while (offset < dataRawBuffer.Length)
121134
{
122-
key = LauncherMetadataHelper.CurrentMasterKey?.Key;
135+
int decryptWritten = RsaInstance.Decrypt(dataRawBuffer.Slice(offset, encBitLength),
136+
decryptedDataSpan.AsSpan(offsetOut),
137+
RSAEncryptionPadding.Pkcs1);
138+
offsetOut += decryptWritten;
139+
offset += encBitLength;
123140
}
124141

125-
RsaInstance.ImportRSAPrivateKey(key, out _);
126-
}
127-
128-
int offset = 0;
129-
int offsetOut = 0;
130-
while (offset < dataRawBuffer.Length)
131-
{
132-
int decryptWritten = RsaInstance.Decrypt(dataRawBuffer.Slice(offset, encBitLength),
133-
decryptedDataSpan.AsSpan(offsetOut),
134-
RSAEncryptionPadding.Pkcs1);
135-
offsetOut += decryptWritten;
136-
offset += encBitLength;
142+
dataRawBuffer = decryptedDataSpan.AsSpan(0, offsetOut);
137143
}
138-
139-
dataRawBuffer = decryptedDataSpan.AsSpan(0, offsetOut);
140144
}
141145

142146
if (dataRawBuffer.Length != compressedSize)
@@ -186,7 +190,7 @@ private static int DecompressDataFromBrotli(Span<byte> outData, int compressedSi
186190
int decompressedWritten = 0;
187191
while (offset < compressedSize)
188192
{
189-
decoder.Decompress(dataRawBuffer.Slice(offset), outData.Slice(decompressedWritten),
193+
decoder.Decompress(dataRawBuffer[offset..], outData[decompressedWritten..],
190194
out int dataConsumedWritten, out int dataDecodedWritten);
191195
decompressedWritten += dataDecodedWritten;
192196
offset += dataConsumedWritten;

0 commit comments

Comments
 (0)