Skip to content

Commit 76ccf70

Browse files
authored
Merge pull request #2013 from DGP-Studio/develop
2 parents 36f5c36 + b6db150 commit 76ccf70

File tree

226 files changed

+4095
-2167
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

226 files changed

+4095
-2167
lines changed

appveyor.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ version: 1.0.{build}
22
branches:
33
only:
44
- "release"
5-
build_cloud: HUTAO-ACTIONS
5+
# build_cloud: HUTAO-ACTIONS
6+
build_cloud: GCE
67
image: Visual Studio 2022
78
clone_depth: 3
89
clone_folder: C:\Users\Public\appveyor\Snap.Hutao

src/Snap.Hutao/Snap.Hutao/Core/ComponentModel/NotifyPropertyChangedBox.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ internal sealed partial class NotifyPropertyChangedBox<TNotifyPropertyChanged, T
1010
{
1111
private readonly TNotifyPropertyChanged notifyPropertyChanged;
1212
private readonly string propertyName;
13-
private readonly Func<TNotifyPropertyChanged, T> valueAccessor;
13+
private readonly Func<TNotifyPropertyChanged, T> valueFactory;
1414

15-
public NotifyPropertyChangedBox(T value, TNotifyPropertyChanged notifyPropertyChanged, string propertyName, Func<TNotifyPropertyChanged, T> valueAccessor)
15+
public NotifyPropertyChangedBox(T value, TNotifyPropertyChanged notifyPropertyChanged, string propertyName, Func<TNotifyPropertyChanged, T> valueFactory)
1616
: base(value)
1717
{
1818
this.notifyPropertyChanged = notifyPropertyChanged;
1919
this.propertyName = propertyName;
20-
this.valueAccessor = valueAccessor;
20+
this.valueFactory = valueFactory;
2121
notifyPropertyChanged.PropertyChanged += OnPropertyChanged;
2222
}
2323

@@ -35,6 +35,6 @@ private void OnPropertyChanged(object? sender, PropertyChangedEventArgs args)
3535
}
3636

3737
(Value as IDisposable)?.Dispose();
38-
Value = valueAccessor(notifyPropertyChanged);
38+
Value = valueFactory(notifyPropertyChanged);
3939
}
4040
}

src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/DependencyInjection.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,8 @@
1111

1212
namespace Snap.Hutao.Core.DependencyInjection;
1313

14-
/// <summary>
15-
/// 依赖注入
16-
/// </summary>
1714
internal static class DependencyInjection
1815
{
19-
/// <summary>
20-
/// 初始化依赖注入
21-
/// </summary>
22-
/// <returns>服务提供器</returns>
2316
public static ServiceProvider Initialize()
2417
{
2518
ServiceProvider serviceProvider = new ServiceCollection()

src/Snap.Hutao/Snap.Hutao/Core/DependencyInjection/IocHttpClientConfiguration.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@ public static IServiceCollection AddConfiguredHttpClients(this IServiceCollectio
2222
.ConfigurePrimaryHttpMessageHandler((handler, provider) =>
2323
{
2424
SocketsHttpHandler typedHandler = (SocketsHttpHandler)handler;
25-
typedHandler.AllowAutoRedirect = true;
2625
typedHandler.UseProxy = true;
27-
typedHandler.MaxConnectionsPerServer = 16;
2826
typedHandler.Proxy = provider.GetRequiredService<HttpProxyUsingSystemProxy>();
2927
});
3028
})
@@ -36,7 +34,6 @@ public static IServiceCollection AddConfiguredHttpClients(this IServiceCollectio
3634
{
3735
SocketsHttpHandler typedHandler = (SocketsHttpHandler)handler;
3836
typedHandler.ConnectTimeout = TimeSpan.FromSeconds(30);
39-
typedHandler.AllowAutoRedirect = true;
4037
typedHandler.UseProxy = true;
4138
typedHandler.MaxConnectionsPerServer = 16;
4239
typedHandler.Proxy = provider.GetRequiredService<HttpProxyUsingSystemProxy>();

src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/ExceptionFormat.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace Snap.Hutao.Core.ExceptionService;
99

1010
internal sealed class ExceptionFormat
1111
{
12-
private static readonly string SectionSeparator = new('-', 40);
12+
private static readonly string SectionSeparator = "----------------------------------------";
1313

1414
public static string Format(Exception exception)
1515
{

src/Snap.Hutao/Snap.Hutao/Core/IO/DirectoryOperation.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,17 @@ public static unsafe bool UnsafeRename(string path, string name, FILEOPERATION_F
4141

4242
using (fileOperation)
4343
{
44-
IFileOperation* pFileOperation = (IFileOperation*)fileOperation.ThisPtr;
45-
4644
if (!SUCCEEDED(SHCreateItemFromParsingName(path, default, in IShellItem.IID, out ObjectReference<IShellItem.Vftbl> shellItem)))
4745
{
4846
return false;
4947
}
5048

5149
using (shellItem)
5250
{
53-
pFileOperation->SetOperationFlags(flags);
54-
pFileOperation->RenameItem(shellItem, name, default!);
51+
fileOperation.SetOperationFlags(flags);
52+
fileOperation.RenameItem(shellItem, name, default!);
5553

56-
return SUCCEEDED(pFileOperation->PerformOperations());
54+
return SUCCEEDED(fileOperation.PerformOperations());
5755
}
5856
}
5957
}

src/Snap.Hutao/Snap.Hutao/Core/IO/FileOperation.cs

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -76,20 +76,15 @@ public static unsafe bool UnsafeDelete(string path)
7676

7777
using (fileOperation)
7878
{
79-
IFileOperation* pFileOperation = (IFileOperation*)fileOperation.ThisPtr;
80-
8179
if (!SUCCEEDED(SHCreateItemFromParsingName(path, default, in IShellItem.IID, out ObjectReference<IShellItem.Vftbl> shellItem)))
8280
{
8381
return false;
8482
}
8583

8684
using (shellItem)
8785
{
88-
IShellItem* pShellItem = (IShellItem*)shellItem.ThisPtr;
89-
90-
pFileOperation->DeleteItem(pShellItem, default!);
91-
92-
return SUCCEEDED(pFileOperation->PerformOperations());
86+
fileOperation.DeleteItem(shellItem, default!);
87+
return SUCCEEDED(fileOperation.PerformOperations());
9388
}
9489
}
9590
}
@@ -103,29 +98,22 @@ public static unsafe bool UnsafeMove(string sourceFileName, string destFileName)
10398

10499
using (fileOperation)
105100
{
106-
IFileOperation* pFileOperation = (IFileOperation*)fileOperation.ThisPtr;
107-
108101
if (!SUCCEEDED(SHCreateItemFromParsingName(sourceFileName, default, in IShellItem.IID, out ObjectReference<IShellItem.Vftbl> sourceShellItem)))
109102
{
110103
return false;
111104
}
112105

113106
using (sourceShellItem)
114107
{
115-
IShellItem* pSourceShellItem = (IShellItem*)sourceShellItem.ThisPtr;
116-
117108
if (!SUCCEEDED(SHCreateItemFromParsingName(destFileName, default, in IShellItem.IID, out ObjectReference<IShellItem.Vftbl> destShellItem)))
118109
{
119110
return false;
120111
}
121112

122113
using (destShellItem)
123114
{
124-
IShellItem* pDestShellItem = (IShellItem*)destShellItem.ThisPtr;
125-
126-
pFileOperation->MoveItem(pSourceShellItem, destShellItem, default, default!);
127-
128-
return SUCCEEDED(pFileOperation->PerformOperations());
115+
fileOperation.MoveItem(sourceShellItem, destShellItem, default, default!);
116+
return SUCCEEDED(fileOperation.PerformOperations());
129117
}
130118
}
131119
}

src/Snap.Hutao/Snap.Hutao/Core/IO/Http/Loopback/LoopbackManager.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ private void Initialize(out string containerStringSID)
6969
}
7070
finally
7171
{
72-
// This function returns 1 rather than 0 specfied in the document.
72+
// This function returns 1 rather than 0 specified in the document.
7373
_ = NetworkIsolationFreeAppContainers(pContainers);
7474
}
7575

@@ -93,9 +93,12 @@ private void Initialize(out string containerStringSID)
9393
}
9494
finally
9595
{
96-
for (uint index = 0; index < count; index++)
96+
if (pSids is not null)
9797
{
98-
HeapFree(GetProcessHeap(), 0, pSids[index].Sid);
98+
for (uint index = 0; index < count; index++)
99+
{
100+
HeapFree(GetProcessHeap(), 0, pSids[index].Sid);
101+
}
99102
}
100103

101104
HeapFree(GetProcessHeap(), 0, pSids);

src/Snap.Hutao/Snap.Hutao/Core/IO/Http/Sharding/HttpShardCopyWorkerOptions.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ namespace Snap.Hutao.Core.IO.Http.Sharding;
1010

1111
internal sealed class HttpShardCopyWorkerOptions<TStatus>
1212
{
13+
private readonly LazySlim<SafeFileHandle> lazyDestinationFileHandle;
14+
1315
private bool isReadOnly;
1416
private HttpClient httpClient = default!;
1517
private string sourceUrl = default!;
@@ -19,7 +21,10 @@ internal sealed class HttpShardCopyWorkerOptions<TStatus>
1921
private int bufferSize = 80 * 1024;
2022
private int maxDegreeOfParallelism = Environment.ProcessorCount;
2123

22-
private SafeFileHandle? destinationFileHandle;
24+
public HttpShardCopyWorkerOptions()
25+
{
26+
lazyDestinationFileHandle = new(GetFileHandle);
27+
}
2328

2429
public HttpClient HttpClient
2530
{
@@ -51,7 +56,7 @@ public string DestinationFilePath
5156
}
5257
}
5358

54-
public SafeFileHandle DestinationFileHandle { get => destinationFileHandle ??= GetFileHandle(); }
59+
public SafeFileHandle DestinationFileHandle { get => lazyDestinationFileHandle.Value; }
5560

5661
public long ContentLength
5762
{

src/Snap.Hutao/Snap.Hutao/Core/IO/StreamCopyWorker.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
// Copyright (c) DGP Studio. All rights reserved.
22
// Licensed under the MIT license.
33

4+
using Snap.Hutao.Core.Threading.RateLimiting;
45
using System.Buffers;
56
using System.IO;
67
using System.Runtime.CompilerServices;
78
using System.Threading.RateLimiting;
8-
using Snap.Hutao.Core.Threading.RateLimiting;
99

1010
namespace Snap.Hutao.Core.IO;
1111

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright (c) DGP Studio. All rights reserved.
2+
// Licensed under the MIT license.
3+
4+
using System.Collections;
5+
6+
namespace Snap.Hutao.Core.Linq;
7+
8+
internal sealed partial class DictionaryLookup<TKey, TEnumerable, TValue> : ILookup<TKey, TValue>
9+
where TKey : notnull
10+
where TEnumerable : IEnumerable<TValue>
11+
{
12+
private readonly Dictionary<TKey, TEnumerable> inner;
13+
14+
public DictionaryLookup(Dictionary<TKey, TEnumerable> source)
15+
{
16+
inner = source;
17+
}
18+
19+
public int Count { get => inner.Count; }
20+
21+
public IEnumerable<TValue> this[TKey key] { get => inner[key]; }
22+
23+
public bool Contains(TKey key)
24+
{
25+
return inner.ContainsKey(key);
26+
}
27+
28+
public IEnumerator<IGrouping<TKey, TValue>> GetEnumerator()
29+
{
30+
foreach ((TKey key, TEnumerable values) in inner)
31+
{
32+
yield return new Grouping(key, values);
33+
}
34+
}
35+
36+
IEnumerator IEnumerable.GetEnumerator()
37+
{
38+
return GetEnumerator();
39+
}
40+
41+
internal sealed class Grouping : IGrouping<TKey, TValue>
42+
{
43+
private readonly TEnumerable enumerable;
44+
45+
public Grouping(TKey key, TEnumerable enumerable)
46+
{
47+
Key = key;
48+
this.enumerable = enumerable;
49+
}
50+
51+
public TKey Key { get; }
52+
53+
public IEnumerator<TValue> GetEnumerator()
54+
{
55+
return enumerable.GetEnumerator();
56+
}
57+
58+
IEnumerator IEnumerable.GetEnumerator()
59+
{
60+
return GetEnumerator();
61+
}
62+
}
63+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) DGP Studio. All rights reserved.
2+
// Licensed under the MIT license.
3+
4+
namespace Snap.Hutao.Core.Linq;
5+
6+
internal static class DictionaryLookupExtension
7+
{
8+
public static ILookup<TKey, TValue> ToLookup<TKey, TValue>(this Dictionary<TKey, List<TValue>> dictionary)
9+
where TKey : notnull
10+
{
11+
return new DictionaryLookup<TKey, List<TValue>, TValue>(dictionary);
12+
}
13+
}

src/Snap.Hutao/Snap.Hutao/Core/Setting/SettingKeys.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ internal static class SettingKeys
5757
public const string IsHomeCardGachaStatisticsPresented = "IsHomeCardGachaStatisticsPresented";
5858
public const string IsHomeCardAchievementPresented = "IsHomeCardAchievementPresented";
5959
public const string IsHomeCardDailyNotePresented = "IsHomeCardDailyNotePresented";
60+
public const string IsHomeCardCalendarPresented = "IsHomeCardCalendarPresented";
6061
#endregion
6162

6263
#region DevTool

src/Snap.Hutao/Snap.Hutao/Core/Shell/ShellLinkInterop.cs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,10 @@ private unsafe bool UnsafeTryCreateDesktopShoutcutForElevatedLaunch(string targe
4545

4646
using (shellLink)
4747
{
48-
IShellLinkW* pShellLink = (IShellLinkW*)shellLink.ThisPtr;
49-
50-
pShellLink->SetPath(elevatedLauncherPath);
51-
pShellLink->SetArguments(runtimeOptions.FamilyName);
52-
pShellLink->SetShowCmd(SHOW_WINDOW_CMD.SW_NORMAL);
53-
pShellLink->SetIconLocation(targetLogoPath, 0);
48+
shellLink.SetPath(elevatedLauncherPath);
49+
shellLink.SetArguments(runtimeOptions.FamilyName);
50+
shellLink.SetShowCmd(SHOW_WINDOW_CMD.SW_NORMAL);
51+
shellLink.SetIconLocation(targetLogoPath, 0);
5452

5553
if (!SUCCEEDED(shellLink.TryAs(IPersistFile.IID, out ObjectReference<IPersistFile.Vftbl> persistFile)))
5654
{
@@ -60,12 +58,10 @@ private unsafe bool UnsafeTryCreateDesktopShoutcutForElevatedLaunch(string targe
6058

6159
using (persistFile)
6260
{
63-
IPersistFile* pPersistFile = (IPersistFile*)persistFile.ThisPtr;
64-
6561
string desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
6662
string target = Path.Combine(desktop, $"{SH.FormatAppNameAndVersion(runtimeOptions.Version)}.lnk");
6763

68-
return SUCCEEDED(pPersistFile->Save(target, false));
64+
return SUCCEEDED(persistFile.Save(target, false));
6965
}
7066
}
7167
}

src/Snap.Hutao/Snap.Hutao/Core/Threading/AsyncKeyedLock.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ namespace Snap.Hutao.Core.Threading;
99
internal sealed class AsyncKeyedLock<TKey>
1010
where TKey : notnull
1111
{
12+
private static readonly Func<Task, object?, Releaser> Continuation = RunContinuation;
13+
1214
private readonly ConcurrentDictionary<TKey, AsyncSemaphore> semaphores;
1315

1416
public AsyncKeyedLock()
@@ -21,7 +23,6 @@ public AsyncKeyedLock(IEqualityComparer<TKey>? comparer)
2123
semaphores = new(comparer);
2224
}
2325

24-
[SuppressMessage("", "SH007")]
2526
public Task<Releaser> LockAsync(TKey key)
2627
{
2728
Task wait;
@@ -31,7 +32,13 @@ public Task<Releaser> LockAsync(TKey key)
3132
}
3233

3334
State stateObj = new(this, key);
34-
return wait.IsCompleted ? Task.FromResult<Releaser>(new(stateObj)) : wait.ContinueWith((_, state) => new Releaser((State)state!), stateObj, default, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
35+
return wait.IsCompleted ? Task.FromResult<Releaser>(new(stateObj)) : wait.ContinueWith(Continuation, stateObj, default, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
36+
}
37+
38+
private static Releaser RunContinuation(Task task, object? state)
39+
{
40+
ArgumentNullException.ThrowIfNull(state);
41+
return new Releaser((State)state);
3542
}
3643

3744
internal readonly struct Releaser : IDisposable

src/Snap.Hutao/Snap.Hutao/Core/Threading/AsyncLock.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ namespace Snap.Hutao.Core.Threading;
77
[SuppressMessage("", "SH003")]
88
internal sealed class AsyncLock
99
{
10+
private static readonly Func<Task, object?, Releaser> Continuation = RunContinuation;
11+
1012
private readonly AsyncSemaphore semaphore;
1113
private readonly Task<Releaser> releaser;
1214

@@ -20,7 +22,13 @@ public AsyncLock()
2022
public Task<Releaser> LockAsync()
2123
{
2224
Task wait = semaphore.WaitAsync();
23-
return wait.IsCompleted ? releaser : wait.ContinueWith((_, state) => new Releaser((AsyncLock)state!), this, default, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
25+
return wait.IsCompleted ? releaser : wait.ContinueWith(Continuation, this, default, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
26+
}
27+
28+
private static Releaser RunContinuation(Task task, object? state)
29+
{
30+
ArgumentNullException.ThrowIfNull(state);
31+
return new Releaser((AsyncLock)state);
2432
}
2533

2634
internal readonly struct Releaser : IDisposable

0 commit comments

Comments
 (0)