mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
remove CoreEnvironment
This commit is contained in:
@@ -61,4 +61,12 @@ public class CSharpLanguageFeatureTest
|
||||
ValueB = 2,
|
||||
ValueC = 3,
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetTwiceOnPropertyResultsSame()
|
||||
{
|
||||
Assert.AreEqual(UUID, UUID);
|
||||
}
|
||||
|
||||
public static Guid UUID { get => Guid.NewGuid(); }
|
||||
}
|
||||
@@ -21,19 +21,22 @@ namespace Snap.Hutao;
|
||||
[SuppressMessage("", "SH001")]
|
||||
public sealed partial class App : Application
|
||||
{
|
||||
private const string AppInstanceKey = "main";
|
||||
private readonly ILogger<App> logger;
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the singleton application object.
|
||||
/// </summary>
|
||||
/// <param name="logger">日志器</param>
|
||||
public App(ILogger<App> logger)
|
||||
/// <param name="serviceProvider">服务提供器</param>
|
||||
public App(IServiceProvider serviceProvider)
|
||||
{
|
||||
// load app resource
|
||||
// Load app resource
|
||||
InitializeComponent();
|
||||
this.logger = logger;
|
||||
|
||||
_ = new ExceptionRecorder(this, logger);
|
||||
logger = serviceProvider.GetRequiredService<ILogger<App>>();
|
||||
serviceProvider.GetRequiredService<ExceptionRecorder>().Record(this);
|
||||
this.serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -42,7 +45,7 @@ public sealed partial class App : Application
|
||||
try
|
||||
{
|
||||
AppActivationArguments activatedEventArgs = AppInstance.GetCurrent().GetActivatedEventArgs();
|
||||
AppInstance firstInstance = AppInstance.FindOrRegisterForKey("main");
|
||||
AppInstance firstInstance = AppInstance.FindOrRegisterForKey(AppInstanceKey);
|
||||
|
||||
if (firstInstance.IsCurrent)
|
||||
{
|
||||
@@ -51,10 +54,8 @@ public sealed partial class App : Application
|
||||
firstInstance.Activated += Activation.Activate;
|
||||
ToastNotificationManagerCompat.OnActivated += Activation.NotificationActivate;
|
||||
|
||||
logger.LogInformation("Snap Hutao | {name} : {version}", CoreEnvironment.FamilyName, CoreEnvironment.Version);
|
||||
logger.LogInformation("Cache folder : {folder}", ApplicationData.Current.LocalCacheFolder.Path);
|
||||
|
||||
JumpListHelper.ConfigureAsync().SafeForget(logger);
|
||||
LogDiagnosticInformation();
|
||||
PostLaunchAsync().SafeForget(logger);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -69,4 +70,18 @@ public sealed partial class App : Application
|
||||
Process.GetCurrentProcess().Kill();
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task PostLaunchAsync()
|
||||
{
|
||||
await JumpListHelper.ConfigureAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private void LogDiagnosticInformation()
|
||||
{
|
||||
HutaoOptions hutaoOptions = serviceProvider.GetRequiredService<HutaoOptions>();
|
||||
|
||||
logger.LogInformation("Snap Hutao FamilyName: {name}", hutaoOptions.FamilyName);
|
||||
logger.LogInformation("Snap Hutao Version: {version}", hutaoOptions.Version);
|
||||
logger.LogInformation("Snap Hutao LocalCache: {folder}", hutaoOptions.LocalCache);
|
||||
}
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.Win32;
|
||||
using Snap.Hutao.Core.Json;
|
||||
using Snap.Hutao.Core.Setting;
|
||||
using Snap.Hutao.Web.Hoyolab.DynamicSecret;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json.Serialization.Metadata;
|
||||
using Windows.ApplicationModel;
|
||||
|
||||
namespace Snap.Hutao.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 核心环境参数
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal static class CoreEnvironment
|
||||
{
|
||||
/// <summary>
|
||||
/// 米游社请求UA
|
||||
/// </summary>
|
||||
public const string HoyolabUA = $"Mozilla/5.0 (Windows NT 10.0; Win64; x64) miHoYoBBS/{HoyolabXrpcVersion}";
|
||||
|
||||
/// <summary>
|
||||
/// Hoyolab请求UA
|
||||
/// </summary>
|
||||
public const string HoyolabOsUA = $"Mozilla/5.0 (Windows NT 10.0; Win64; x64) miHoYoBBSOversea/{HoyolabOsXrpcVersion}";
|
||||
|
||||
/// <summary>
|
||||
/// 米游社移动端请求UA
|
||||
/// </summary>
|
||||
public const string HoyolabMobileUA = $"Mozilla/5.0 (Linux; Android 12) Mobile miHoYoBBS/{HoyolabXrpcVersion}";
|
||||
|
||||
/// <summary>
|
||||
/// Hoyolab 移动端请求UA
|
||||
/// </summary>
|
||||
public const string HoyolabOsMobileUA = $"Mozilla/5.0 (Linux; Android 12) Mobile miHoYoBBSOversea/{HoyolabOsXrpcVersion}";
|
||||
|
||||
/// <summary>
|
||||
/// 米游社 Rpc 版本
|
||||
/// </summary>
|
||||
public const string HoyolabXrpcVersion = "2.49.1";
|
||||
|
||||
/// <summary>
|
||||
/// Hoyolab Rpc 版本
|
||||
/// </summary>
|
||||
public const string HoyolabOsXrpcVersion = "2.30.0";
|
||||
|
||||
/// <summary>
|
||||
/// 盐
|
||||
/// </summary>
|
||||
// https://github.com/UIGF-org/Hoyolab.Salt
|
||||
public static readonly ImmutableDictionary<SaltType, string> DynamicSecretSalts = new Dictionary<SaltType, string>()
|
||||
{
|
||||
[SaltType.K2] = "egBrFMO1BPBG0UX5XOuuwMRLZKwTVKRV",
|
||||
[SaltType.LK2] = "DG8lqMyc9gquwAUFc7zBS62ijQRX9XF7",
|
||||
[SaltType.X4] = "xV8v4Qu54lUKrEYFZkJhB8cuOh9Asafs",
|
||||
[SaltType.X6] = "t0qEgfub6cvueAPgR5m9aQWWVciEer7v",
|
||||
[SaltType.PROD] = "JwYDpKvLj6MrMqqYU6jTKF17KNO2PXoS",
|
||||
|
||||
// This SALT is not reliable
|
||||
[SaltType.OSK2] = "6cqshh5dhw73bzxn20oexa9k516chk7s",
|
||||
}.ToImmutableDictionary();
|
||||
|
||||
/// <summary>
|
||||
/// 默认的Json序列化选项
|
||||
/// </summary>
|
||||
public static readonly JsonSerializerOptions JsonOptions = new()
|
||||
{
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
||||
PropertyNameCaseInsensitive = true,
|
||||
WriteIndented = true,
|
||||
TypeInfoResolver = new DefaultJsonTypeInfoResolver()
|
||||
{
|
||||
Modifiers =
|
||||
{
|
||||
JsonTypeInfoResolvers.ResolveEnumType,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 当前版本
|
||||
/// </summary>
|
||||
public static readonly Version Version;
|
||||
|
||||
/// <summary>
|
||||
/// 标准UA
|
||||
/// </summary>
|
||||
public static readonly string CommonUA;
|
||||
|
||||
/// <summary>
|
||||
/// 数据文件夹
|
||||
/// </summary>
|
||||
public static readonly string DataFolder;
|
||||
|
||||
/// <summary>
|
||||
/// 包家族名称
|
||||
/// </summary>
|
||||
public static readonly string FamilyName;
|
||||
|
||||
/// <summary>
|
||||
/// 米游社设备Id
|
||||
/// </summary>
|
||||
public static readonly string HoyolabDeviceId;
|
||||
|
||||
/// <summary>
|
||||
/// 胡桃设备Id
|
||||
/// </summary>
|
||||
public static readonly string HutaoDeviceId;
|
||||
|
||||
/// <summary>
|
||||
/// 安装位置
|
||||
/// </summary>
|
||||
public static readonly string InstalledLocation;
|
||||
|
||||
private const string CryptographyKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\";
|
||||
private const string MachineGuidValue = "MachineGuid";
|
||||
|
||||
static CoreEnvironment()
|
||||
{
|
||||
DataFolder = GetDatafolderPath();
|
||||
Version = Package.Current.Id.Version.ToVersion();
|
||||
FamilyName = Package.Current.Id.FamilyName;
|
||||
InstalledLocation = Package.Current.InstalledLocation.Path;
|
||||
CommonUA = $"Snap Hutao/{Version}";
|
||||
|
||||
// simply assign a random guid
|
||||
HoyolabDeviceId = Guid.NewGuid().ToString();
|
||||
HutaoDeviceId = GetUniqueUserID();
|
||||
}
|
||||
|
||||
private static string GetUniqueUserID()
|
||||
{
|
||||
string userName = Environment.UserName;
|
||||
object? machineGuid = Registry.GetValue(CryptographyKey, MachineGuidValue, userName);
|
||||
return Convert.ToMd5HexString($"{userName}{machineGuid}");
|
||||
}
|
||||
|
||||
private static string GetDatafolderPath()
|
||||
{
|
||||
string preferredPath = LocalSetting.Get(SettingKeys.DataFolderPath, string.Empty);
|
||||
|
||||
if (string.IsNullOrEmpty(preferredPath))
|
||||
{
|
||||
string myDocument = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
|
||||
#if RELEASE
|
||||
// 将测试版与正式版的文件目录分离
|
||||
string folderName = Package.Current.PublisherDisplayName == "DGP Studio CI" ? "HutaoAlpha" : "Hutao";
|
||||
#else
|
||||
// 使得迁移能正常生成
|
||||
string folderName = "Hutao";
|
||||
#endif
|
||||
string path = Path.GetFullPath(Path.Combine(myDocument, folderName));
|
||||
Directory.CreateDirectory(path);
|
||||
return path;
|
||||
}
|
||||
else
|
||||
{
|
||||
return preferredPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
|
||||
namespace Snap.Hutao.Core.DependencyInjection;
|
||||
|
||||
/// <summary>
|
||||
/// 依赖注入
|
||||
/// </summary>
|
||||
internal static class DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化依赖注入
|
||||
/// </summary>
|
||||
/// <returns>服务提供器</returns>
|
||||
public static ServiceProvider Initialize()
|
||||
{
|
||||
ServiceProvider serviceProvider = new ServiceCollection()
|
||||
|
||||
// Microsoft extension
|
||||
.AddLogging(builder => builder.AddDebug())
|
||||
.AddMemoryCache()
|
||||
|
||||
// Hutao extensions
|
||||
.AddJsonOptions()
|
||||
.AddDatabase()
|
||||
.AddInjections()
|
||||
.AddHttpClients()
|
||||
|
||||
// Discrete services
|
||||
.AddSingleton<IMessenger>(WeakReferenceMessenger.Default)
|
||||
|
||||
.BuildServiceProvider(true);
|
||||
|
||||
Ioc.Default.ConfigureServices(serviceProvider);
|
||||
return serviceProvider;
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,12 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Snap.Hutao.Core.Json;
|
||||
using Snap.Hutao.Model.Entity.Database;
|
||||
using Snap.Hutao.Service;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using Windows.Globalization;
|
||||
|
||||
namespace Snap.Hutao.Core.DependencyInjection;
|
||||
|
||||
@@ -20,7 +24,7 @@ internal static class IocConfiguration
|
||||
/// <returns>可继续操作的集合</returns>
|
||||
public static IServiceCollection AddJsonOptions(this IServiceCollection services)
|
||||
{
|
||||
return services.AddSingleton(CoreEnvironment.JsonOptions);
|
||||
return services.AddSingleton(JsonOptions.Default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -30,28 +34,51 @@ internal static class IocConfiguration
|
||||
/// <returns>可继续操作的集合</returns>
|
||||
public static IServiceCollection AddDatabase(this IServiceCollection services)
|
||||
{
|
||||
string dbFile = System.IO.Path.Combine(CoreEnvironment.DataFolder, "Userdata.db");
|
||||
return services.AddDbContext<AppDbContext>(AddDbContextCore);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化语言
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider">服务提供器</param>
|
||||
/// <returns>服务提供器,用于链式调用</returns>
|
||||
public static IServiceProvider InitializeCulture(this IServiceProvider serviceProvider)
|
||||
{
|
||||
AppOptions appOptions = serviceProvider.GetRequiredService<AppOptions>();
|
||||
appOptions.PreviousCulture = CultureInfo.CurrentCulture;
|
||||
|
||||
CultureInfo cultureInfo = appOptions.CurrentCulture;
|
||||
|
||||
CultureInfo.CurrentCulture = cultureInfo;
|
||||
CultureInfo.CurrentUICulture = cultureInfo;
|
||||
ApplicationLanguages.PrimaryLanguageOverride = cultureInfo.Name;
|
||||
|
||||
return serviceProvider;
|
||||
}
|
||||
|
||||
private static void AddDbContextCore(IServiceProvider provider, DbContextOptionsBuilder builder)
|
||||
{
|
||||
HutaoOptions hutaoOptions = provider.GetRequiredService<HutaoOptions>();
|
||||
string dbFile = System.IO.Path.Combine(hutaoOptions.DataFolder, "Userdata.db");
|
||||
string sqlConnectionString = $"Data Source={dbFile}";
|
||||
|
||||
// temporarily create a context
|
||||
// Temporarily create a context
|
||||
using (AppDbContext context = AppDbContext.Create(sqlConnectionString))
|
||||
{
|
||||
if (context.Database.GetPendingMigrations().Any())
|
||||
{
|
||||
#if DEBUG
|
||||
Debug.WriteLine("[Debug] Performing AppDbContext Migrations");
|
||||
Debug.WriteLine("[Database] Performing AppDbContext Migrations");
|
||||
#endif
|
||||
context.Database.Migrate();
|
||||
}
|
||||
}
|
||||
|
||||
return services.AddDbContext<AppDbContext>(builder =>
|
||||
{
|
||||
builder
|
||||
builder
|
||||
#if DEBUG
|
||||
.EnableSensitiveDataLogging()
|
||||
.EnableSensitiveDataLogging()
|
||||
#endif
|
||||
.UseSqlite(sqlConnectionString);
|
||||
});
|
||||
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)
|
||||
.UseSqlite(sqlConnectionString);
|
||||
}
|
||||
}
|
||||
@@ -24,10 +24,12 @@ internal static partial class IocHttpClientConfiguration
|
||||
/// 默认配置
|
||||
/// </summary>
|
||||
/// <param name="client">配置后的客户端</param>
|
||||
private static void DefaultConfiguration(HttpClient client)
|
||||
private static void DefaultConfiguration(IServiceProvider serviceProvider, HttpClient client)
|
||||
{
|
||||
HutaoOptions hutaoOptions = serviceProvider.GetRequiredService<HutaoOptions>();
|
||||
|
||||
client.Timeout = Timeout.InfiniteTimeSpan;
|
||||
client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreEnvironment.CommonUA);
|
||||
client.DefaultRequestHeaders.UserAgent.ParseAdd(hutaoOptions.UserAgent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -37,11 +39,11 @@ internal static partial class IocHttpClientConfiguration
|
||||
private static void XRpcConfiguration(HttpClient client)
|
||||
{
|
||||
client.Timeout = Timeout.InfiniteTimeSpan;
|
||||
client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreEnvironment.HoyolabUA);
|
||||
client.DefaultRequestHeaders.UserAgent.ParseAdd(HoyolabOptions.UserAgent);
|
||||
client.DefaultRequestHeaders.Accept.ParseAdd(ApplicationJson);
|
||||
client.DefaultRequestHeaders.Add("x-rpc-app_version", CoreEnvironment.HoyolabXrpcVersion);
|
||||
client.DefaultRequestHeaders.Add("x-rpc-app_version", HoyolabOptions.XrpcVersion);
|
||||
client.DefaultRequestHeaders.Add("x-rpc-client_type", "5");
|
||||
client.DefaultRequestHeaders.Add("x-rpc-device_id", CoreEnvironment.HoyolabDeviceId);
|
||||
client.DefaultRequestHeaders.Add("x-rpc-device_id", HoyolabOptions.DeviceId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -51,13 +53,13 @@ internal static partial class IocHttpClientConfiguration
|
||||
private static void XRpc2Configuration(HttpClient client)
|
||||
{
|
||||
client.Timeout = Timeout.InfiniteTimeSpan;
|
||||
client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreEnvironment.HoyolabUA);
|
||||
client.DefaultRequestHeaders.UserAgent.ParseAdd(HoyolabOptions.UserAgent);
|
||||
client.DefaultRequestHeaders.Accept.ParseAdd(ApplicationJson);
|
||||
client.DefaultRequestHeaders.Add("x-rpc-aigis", string.Empty);
|
||||
client.DefaultRequestHeaders.Add("x-rpc-app_id", "bll8iq97cem8");
|
||||
client.DefaultRequestHeaders.Add("x-rpc-app_version", CoreEnvironment.HoyolabXrpcVersion);
|
||||
client.DefaultRequestHeaders.Add("x-rpc-app_version", HoyolabOptions.XrpcVersion);
|
||||
client.DefaultRequestHeaders.Add("x-rpc-client_type", "2");
|
||||
client.DefaultRequestHeaders.Add("x-rpc-device_id", CoreEnvironment.HoyolabDeviceId);
|
||||
client.DefaultRequestHeaders.Add("x-rpc-device_id", HoyolabOptions.DeviceId);
|
||||
client.DefaultRequestHeaders.Add("x-rpc-game_biz", "bbs_cn");
|
||||
client.DefaultRequestHeaders.Add("x-rpc-sdk_version", "1.3.1.2");
|
||||
}
|
||||
@@ -70,7 +72,7 @@ internal static partial class IocHttpClientConfiguration
|
||||
private static void XRpc3Configuration(HttpClient client)
|
||||
{
|
||||
client.Timeout = Timeout.InfiniteTimeSpan;
|
||||
client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreEnvironment.HoyolabOsUA);
|
||||
client.DefaultRequestHeaders.UserAgent.ParseAdd(HoyolabOptions.UserAgentOversea);
|
||||
client.DefaultRequestHeaders.Accept.ParseAdd(ApplicationJson);
|
||||
client.DefaultRequestHeaders.Add("x-rpc-app_version", "1.5.0");
|
||||
client.DefaultRequestHeaders.Add("x-rpc-client_type", "4");
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Collections;
|
||||
using System.Text;
|
||||
|
||||
namespace Snap.Hutao.Core.ExceptionService;
|
||||
|
||||
/// <summary>
|
||||
/// 异常格式化
|
||||
/// </summary>
|
||||
internal sealed class ExceptionFormat
|
||||
{
|
||||
private const string SectionSeparator = "----------------------------------------";
|
||||
|
||||
/// <summary>
|
||||
/// 格式化异常
|
||||
/// </summary>
|
||||
/// <param name="exception">异常</param>
|
||||
/// <returns>格式化后的异常</returns>
|
||||
public static string Format(Exception exception)
|
||||
{
|
||||
StringBuilder builder = new();
|
||||
builder.AppendLine("Exception Data:");
|
||||
|
||||
foreach (DictionaryEntry entry in exception.Data)
|
||||
{
|
||||
builder
|
||||
.Append(entry.Key)
|
||||
.Append(':')
|
||||
.Append(entry.Value)
|
||||
.Append(StringLiterals.CRLF);
|
||||
}
|
||||
|
||||
builder.AppendLine(SectionSeparator);
|
||||
builder.Append(exception.ToString());
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,6 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml;
|
||||
using System.Collections;
|
||||
using System.Text;
|
||||
|
||||
namespace Snap.Hutao.Core.ExceptionService;
|
||||
|
||||
@@ -11,50 +9,56 @@ namespace Snap.Hutao.Core.ExceptionService;
|
||||
/// 异常记录器
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
[Injection(InjectAs.Singleton)]
|
||||
internal sealed class ExceptionRecorder
|
||||
{
|
||||
private readonly ILogger logger;
|
||||
private readonly ILogger<ExceptionRecorder> logger;
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的异常记录器
|
||||
/// </summary>
|
||||
/// <param name="application">应用程序</param>
|
||||
/// <param name="serviceProvider">服务提供器</param>
|
||||
/// <param name="logger">日志器</param>
|
||||
public ExceptionRecorder(Application application, ILogger logger)
|
||||
public ExceptionRecorder(IServiceProvider serviceProvider)
|
||||
{
|
||||
this.logger = logger;
|
||||
logger = serviceProvider.GetRequiredService<ILogger<ExceptionRecorder>>();
|
||||
this.serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
application.UnhandledException += OnAppUnhandledException;
|
||||
application.DebugSettings.BindingFailed += OnXamlBindingFailed;
|
||||
application.DebugSettings.XamlResourceReferenceFailed += OnXamlResourceReferenceFailed;
|
||||
/// <summary>
|
||||
/// 记录应用程序异常
|
||||
/// </summary>
|
||||
/// <param name="app">应用程序</param>
|
||||
public void Record(Application app)
|
||||
{
|
||||
app.UnhandledException += OnAppUnhandledException;
|
||||
app.DebugSettings.BindingFailed += OnXamlBindingFailed;
|
||||
app.DebugSettings.XamlResourceReferenceFailed += OnXamlResourceReferenceFailed;
|
||||
}
|
||||
|
||||
private void OnAppUnhandledException(object? sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
|
||||
{
|
||||
#if RELEASE
|
||||
#pragma warning disable VSTHRD002
|
||||
Ioc.Default.GetRequiredService<Web.Hutao.HomaLogUploadClient>().UploadLogAsync(e.Exception).GetAwaiter().GetResult();
|
||||
serviceProvider
|
||||
.GetRequiredService<Web.Hutao.HomaLogUploadClient>()
|
||||
.UploadLogAsync(serviceProvider, e.Exception)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
#pragma warning restore VSTHRD002
|
||||
#endif
|
||||
StringBuilder dataDetailBuilder = new();
|
||||
foreach (DictionaryEntry entry in e.Exception.Data)
|
||||
{
|
||||
string key = $"{entry.Key}";
|
||||
string value = $"{entry.Value}";
|
||||
|
||||
dataDetailBuilder.Append(key).Append(':').Append(value).Append("\r\n");
|
||||
}
|
||||
|
||||
logger.LogError(e.Exception, "未经处理的异常\r\n{detail}", dataDetailBuilder.ToString());
|
||||
logger.LogError("未经处理的全局异常:\r\n{detail}", ExceptionFormat.Format(e.Exception));
|
||||
}
|
||||
|
||||
private void OnXamlBindingFailed(object? sender, BindingFailedEventArgs e)
|
||||
{
|
||||
logger.LogCritical("XAML绑定失败: {message}", e.Message);
|
||||
logger.LogCritical("XAML 绑定失败:{message}", e.Message);
|
||||
}
|
||||
|
||||
private void OnXamlResourceReferenceFailed(DebugSettings sender, XamlResourceReferenceFailedEventArgs e)
|
||||
{
|
||||
logger.LogCritical("XAML资源引用失败: {message}", e.Message);
|
||||
logger.LogCritical("XAML 资源引用失败:{message}", e.Message);
|
||||
}
|
||||
}
|
||||
73
src/Snap.Hutao/Snap.Hutao/Core/HoyolabOptions.cs
Normal file
73
src/Snap.Hutao/Snap.Hutao/Core/HoyolabOptions.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
using Snap.Hutao.Web.Hoyolab.DynamicSecret;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace Snap.Hutao.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 米游社选项
|
||||
/// </summary>
|
||||
[Injection(InjectAs.Singleton)]
|
||||
internal sealed class HoyolabOptions : IOptions<HoyolabOptions>
|
||||
{
|
||||
/// <summary>
|
||||
/// 米游社请求UA
|
||||
/// </summary>
|
||||
public const string UserAgent = $"Mozilla/5.0 (Windows NT 10.0; Win64; x64) miHoYoBBS/{XrpcVersion}";
|
||||
|
||||
/// <summary>
|
||||
/// Hoyolab 请求UA
|
||||
/// </summary>
|
||||
public const string UserAgentOversea = $"Mozilla/5.0 (Windows NT 10.0; Win64; x64) miHoYoBBSOversea/{XrpcVersionOversea}";
|
||||
|
||||
/// <summary>
|
||||
/// 米游社移动端请求UA
|
||||
/// </summary>
|
||||
public const string MobileUserAgent = $"Mozilla/5.0 (Linux; Android 12) Mobile miHoYoBBS/{XrpcVersion}";
|
||||
|
||||
/// <summary>
|
||||
/// Hoyolab 移动端请求UA
|
||||
/// </summary>
|
||||
public const string MobileUserAgentOversea = $"Mozilla/5.0 (Linux; Android 12) Mobile miHoYoBBSOversea/{XrpcVersionOversea}";
|
||||
|
||||
/// <summary>
|
||||
/// 米游社 Rpc 版本
|
||||
/// </summary>
|
||||
public const string XrpcVersion = "2.49.1";
|
||||
|
||||
/// <summary>
|
||||
/// Hoyolab Rpc 版本
|
||||
/// </summary>
|
||||
public const string XrpcVersionOversea = "2.30.0";
|
||||
|
||||
// https://github.com/UIGF-org/Hoyolab.Salt
|
||||
private static readonly ImmutableDictionary<SaltType, string> SaltsInner = new Dictionary<SaltType, string>()
|
||||
{
|
||||
[SaltType.K2] = "egBrFMO1BPBG0UX5XOuuwMRLZKwTVKRV",
|
||||
[SaltType.LK2] = "DG8lqMyc9gquwAUFc7zBS62ijQRX9XF7",
|
||||
[SaltType.X4] = "xV8v4Qu54lUKrEYFZkJhB8cuOh9Asafs",
|
||||
[SaltType.X6] = "t0qEgfub6cvueAPgR5m9aQWWVciEer7v",
|
||||
[SaltType.PROD] = "JwYDpKvLj6MrMqqYU6jTKF17KNO2PXoS",
|
||||
|
||||
// This SALT is not reliable
|
||||
[SaltType.OSK2] = "6cqshh5dhw73bzxn20oexa9k516chk7s",
|
||||
}.ToImmutableDictionary();
|
||||
|
||||
private static string? deviceId;
|
||||
|
||||
/// <summary>
|
||||
/// 米游社设备Id
|
||||
/// </summary>
|
||||
public static string DeviceId { get => deviceId ??= Guid.NewGuid().ToString(); }
|
||||
|
||||
/// <summary>
|
||||
/// 盐
|
||||
/// </summary>
|
||||
public static ImmutableDictionary<SaltType, string> Salts { get => SaltsInner; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public HoyolabOptions Value { get => this; }
|
||||
}
|
||||
102
src/Snap.Hutao/Snap.Hutao/Core/HutaoOptions.cs
Normal file
102
src/Snap.Hutao/Snap.Hutao/Core/HutaoOptions.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Win32;
|
||||
using Snap.Hutao.Core.Setting;
|
||||
using System.IO;
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.Storage;
|
||||
|
||||
namespace Snap.Hutao.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 胡桃选项
|
||||
/// 存储环境相关的选项
|
||||
/// </summary>
|
||||
[Injection(InjectAs.Singleton)]
|
||||
internal sealed class HutaoOptions : IOptions<HutaoOptions>
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造一个新的胡桃选项
|
||||
/// </summary>
|
||||
public HutaoOptions()
|
||||
{
|
||||
DataFolder = GetDataFolderPath();
|
||||
LocalCache = ApplicationData.Current.LocalCacheFolder.Path;
|
||||
InstalledLocation = Package.Current.InstalledLocation.Path;
|
||||
FamilyName = Package.Current.Id.FamilyName;
|
||||
|
||||
Version = Package.Current.Id.Version.ToVersion();
|
||||
UserAgent = $"Snap Hutao/{Version}";
|
||||
|
||||
DeviceId = GetUniqueUserId();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前版本
|
||||
/// </summary>
|
||||
public Version Version { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 标准UA
|
||||
/// </summary>
|
||||
public string UserAgent { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据文件夹路径
|
||||
/// </summary>
|
||||
public string DataFolder { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 安装位置
|
||||
/// </summary>
|
||||
public string InstalledLocation { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 本地缓存
|
||||
/// </summary>
|
||||
public string LocalCache { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 包家族名称
|
||||
/// </summary>
|
||||
public string FamilyName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 设备Id
|
||||
/// </summary>
|
||||
public string DeviceId { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public HutaoOptions Value { get => this; }
|
||||
|
||||
private static string GetDataFolderPath()
|
||||
{
|
||||
string preferredPath = LocalSetting.Get(SettingKeys.DataFolderPath, string.Empty);
|
||||
|
||||
if (!string.IsNullOrEmpty(preferredPath) && Directory.Exists(preferredPath))
|
||||
{
|
||||
return preferredPath;
|
||||
}
|
||||
|
||||
string myDocument = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
|
||||
#if RELEASE
|
||||
// 将测试版与正式版的文件目录分离
|
||||
string folderName = Package.Current.PublisherDisplayName == "DGP Studio CI" ? "HutaoAlpha" : "Hutao";
|
||||
#else
|
||||
// 使得迁移能正常生成
|
||||
string folderName = "Hutao";
|
||||
#endif
|
||||
string path = Path.GetFullPath(Path.Combine(myDocument, folderName));
|
||||
Directory.CreateDirectory(path);
|
||||
return path;
|
||||
}
|
||||
|
||||
private static string GetUniqueUserId()
|
||||
{
|
||||
string userName = Environment.UserName;
|
||||
object? machineGuid = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\", "MachineGuid", userName);
|
||||
return Convert.ToMd5HexString($"{userName}{machineGuid}");
|
||||
}
|
||||
}
|
||||
33
src/Snap.Hutao/Snap.Hutao/Core/Json/JsonOptions.cs
Normal file
33
src/Snap.Hutao/Snap.Hutao/Core/Json/JsonOptions.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json.Serialization.Metadata;
|
||||
|
||||
namespace Snap.Hutao.Core.Json;
|
||||
|
||||
/// <summary>
|
||||
/// Json 选项
|
||||
/// </summary>
|
||||
internal static class JsonOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// 默认的Json序列化选项
|
||||
/// </summary>
|
||||
public static readonly JsonSerializerOptions Default = new()
|
||||
{
|
||||
AllowTrailingCommas = true,
|
||||
ReadCommentHandling = JsonCommentHandling.Skip,
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
||||
PropertyNameCaseInsensitive = true,
|
||||
WriteIndented = true,
|
||||
TypeInfoResolver = new DefaultJsonTypeInfoResolver()
|
||||
{
|
||||
Modifiers =
|
||||
{
|
||||
JsonTypeInfoResolvers.ResolveEnumType,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -32,9 +32,8 @@ internal static class JsonTypeInfoResolvers
|
||||
if (property.AttributeProvider is System.Reflection.ICustomAttributeProvider provider)
|
||||
{
|
||||
object[] attributes = provider.GetCustomAttributes(JsonEnumAttributeType, false);
|
||||
if (attributes.Length == 1)
|
||||
if (attributes.SingleOrDefault() is JsonEnumAttribute attr)
|
||||
{
|
||||
JsonEnumAttribute attr = (JsonEnumAttribute)attributes[0];
|
||||
property.CustomConverter = attr.CreateConverter(property);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,4 +28,6 @@ internal static class StringLiterals
|
||||
/// False
|
||||
/// </summary>
|
||||
public const string False = "False";
|
||||
|
||||
public const string CRLF = "\r\n";
|
||||
}
|
||||
30
src/Snap.Hutao/Snap.Hutao/Core/Threading/ITaskContext.cs
Normal file
30
src/Snap.Hutao/Snap.Hutao/Core/Threading/ITaskContext.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Core.Threading;
|
||||
|
||||
/// <summary>
|
||||
/// 任务上下文
|
||||
/// </summary>
|
||||
internal interface ITaskContext
|
||||
{
|
||||
/// <summary>
|
||||
/// 在主线程上同步等待执行操作
|
||||
/// </summary>
|
||||
/// <param name="action">操作</param>
|
||||
void InvokeOnMainThread(Action action);
|
||||
|
||||
/// <summary>
|
||||
/// 异步切换到 后台线程
|
||||
/// </summary>
|
||||
/// <remarks>使用 <see cref="SwitchToMainThreadAsync"/> 异步切换到 主线程</remarks>
|
||||
/// <returns>等待体</returns>
|
||||
ThreadPoolSwitchOperation SwitchToBackgroundAsync();
|
||||
|
||||
/// <summary>
|
||||
/// 异步切换到 主线程
|
||||
/// </summary>
|
||||
/// <remarks>使用 <see cref="SwitchToBackgroundAsync"/> 异步切换到 后台线程</remarks>
|
||||
/// <returns>等待体</returns>
|
||||
DispatherQueueSwitchOperation SwitchToMainThreadAsync();
|
||||
}
|
||||
51
src/Snap.Hutao/Snap.Hutao/Core/Threading/TaskContext.cs
Normal file
51
src/Snap.Hutao/Snap.Hutao/Core/Threading/TaskContext.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Dispatching;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Snap.Hutao.Core.Threading;
|
||||
|
||||
/// <summary>
|
||||
/// 任务上下文
|
||||
/// </summary>
|
||||
[Injection(InjectAs.Singleton, typeof(ITaskContext))]
|
||||
internal sealed class TaskContext : ITaskContext
|
||||
{
|
||||
private readonly DispatcherQueue dispatcherQueue;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的任务上下文
|
||||
/// </summary>
|
||||
public TaskContext()
|
||||
{
|
||||
dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||
DispatcherQueueSynchronizationContext context = new(dispatcherQueue);
|
||||
SynchronizationContext.SetSynchronizationContext(context);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ThreadPoolSwitchOperation SwitchToBackgroundAsync()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DispatherQueueSwitchOperation SwitchToMainThreadAsync()
|
||||
{
|
||||
return new(dispatcherQueue!);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void InvokeOnMainThread(Action action)
|
||||
{
|
||||
if (dispatcherQueue!.HasThreadAccess)
|
||||
{
|
||||
action();
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatcherQueue.Invoke(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Dispatching;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Snap.Hutao.Core.Threading;
|
||||
@@ -9,21 +8,20 @@ namespace Snap.Hutao.Core.Threading;
|
||||
/// <summary>
|
||||
/// 线程帮助类
|
||||
/// </summary>
|
||||
[Obsolete("Use TaskContext instead")]
|
||||
internal static class ThreadHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 主线程队列
|
||||
/// </summary>
|
||||
private static volatile DispatcherQueue? dispatcherQueue;
|
||||
private static volatile ITaskContext taskContext;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
public static void Initialize()
|
||||
public static void Initialize(ITaskContext taskContext)
|
||||
{
|
||||
dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||
DispatcherQueueSynchronizationContext context = new(dispatcherQueue);
|
||||
SynchronizationContext.SetSynchronizationContext(context);
|
||||
ThreadHelper.taskContext = taskContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -34,7 +32,7 @@ internal static class ThreadHelper
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ThreadPoolSwitchOperation SwitchToBackgroundAsync()
|
||||
{
|
||||
return default;
|
||||
return taskContext.SwitchToBackgroundAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -45,7 +43,7 @@ internal static class ThreadHelper
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static DispatherQueueSwitchOperation SwitchToMainThreadAsync()
|
||||
{
|
||||
return new(dispatcherQueue!);
|
||||
return taskContext.SwitchToMainThreadAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -55,13 +53,6 @@ internal static class ThreadHelper
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void InvokeOnMainThread(Action action)
|
||||
{
|
||||
if (dispatcherQueue!.HasThreadAccess)
|
||||
{
|
||||
action();
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatcherQueue.Invoke(action);
|
||||
}
|
||||
taskContext.InvokeOnMainThread(action);
|
||||
}
|
||||
}
|
||||
@@ -11,9 +11,9 @@ using Snap.Hutao.Message;
|
||||
using Snap.Hutao.Service;
|
||||
using Snap.Hutao.Win32;
|
||||
using System.IO;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Graphics;
|
||||
using Windows.UI;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.Graphics.Dwm;
|
||||
using static Windows.Win32.PInvoke;
|
||||
|
||||
@@ -30,7 +30,6 @@ internal sealed class ExtendedWindow<TWindow> : IRecipient<FlyoutOpenCloseMessag
|
||||
private readonly WindowOptions<TWindow> options;
|
||||
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
private readonly ILogger<ExtendedWindow<TWindow>> logger;
|
||||
private readonly WindowSubclass<TWindow> subclass;
|
||||
|
||||
private ExtendedWindow(TWindow window, FrameworkElement titleBar, IServiceProvider serviceProvider)
|
||||
@@ -38,7 +37,6 @@ internal sealed class ExtendedWindow<TWindow> : IRecipient<FlyoutOpenCloseMessag
|
||||
options = new(window, titleBar);
|
||||
subclass = new(options);
|
||||
|
||||
logger = serviceProvider.GetRequiredService<ILogger<ExtendedWindow<TWindow>>>();
|
||||
this.serviceProvider = serviceProvider;
|
||||
|
||||
InitializeWindow();
|
||||
@@ -63,8 +61,10 @@ internal sealed class ExtendedWindow<TWindow> : IRecipient<FlyoutOpenCloseMessag
|
||||
|
||||
private void InitializeWindow()
|
||||
{
|
||||
options.AppWindow.Title = string.Format(SH.AppNameAndVersion, CoreEnvironment.Version);
|
||||
options.AppWindow.SetIcon(Path.Combine(CoreEnvironment.InstalledLocation, "Assets/Logo.ico"));
|
||||
HutaoOptions hutaoOptions = serviceProvider.GetRequiredService<HutaoOptions>();
|
||||
|
||||
options.AppWindow.Title = string.Format(SH.AppNameAndVersion, hutaoOptions.Version);
|
||||
options.AppWindow.SetIcon(Path.Combine(hutaoOptions.InstalledLocation, "Assets/Logo.ico"));
|
||||
ExtendsContentIntoTitleBar();
|
||||
|
||||
Persistence.RecoverOrInit(options);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Snap.Hutao.Core;
|
||||
using Snap.Hutao.Core.Json;
|
||||
|
||||
namespace Snap.Hutao.Model.Entity.Configuration;
|
||||
|
||||
@@ -18,8 +18,8 @@ internal sealed class JsonTextValueConverter<TProperty> : ValueConverter<TProper
|
||||
/// </summary>
|
||||
public JsonTextValueConverter()
|
||||
: base(
|
||||
obj => JsonSerializer.Serialize(obj, CoreEnvironment.JsonOptions),
|
||||
str => JsonSerializer.Deserialize<TProperty>(str, CoreEnvironment.JsonOptions)!)
|
||||
obj => JsonSerializer.Serialize(obj, JsonOptions.Default),
|
||||
str => JsonSerializer.Deserialize<TProperty>(str, JsonOptions.Default)!)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -47,15 +47,17 @@ internal sealed class UIAFInfo
|
||||
/// <summary>
|
||||
/// 构造一个新的专用 UIAF 信息
|
||||
/// </summary>
|
||||
/// <param name="uid">uid</param>
|
||||
/// <param name="serviceProvider">服务提供器</param>
|
||||
/// <returns>专用 UIAF 信息</returns>
|
||||
public static UIAFInfo Create()
|
||||
public static UIAFInfo Create(IServiceProvider serviceProvider)
|
||||
{
|
||||
HutaoOptions hutaoOptions = serviceProvider.GetRequiredService<HutaoOptions>();
|
||||
|
||||
return new()
|
||||
{
|
||||
ExportTimestamp = DateTimeOffset.Now.ToUnixTimeSeconds(),
|
||||
ExportApp = SH.AppName,
|
||||
ExportAppVersion = CoreEnvironment.Version.ToString(),
|
||||
ExportAppVersion = hutaoOptions.Version.ToString(),
|
||||
UIAFVersion = UIAF.CurrentVersion,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -60,17 +60,20 @@ internal sealed class UIGFInfo
|
||||
/// <summary>
|
||||
/// 构造一个新的专用 UIGF 信息
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider">服务提供器</param>
|
||||
/// <param name="uid">uid</param>
|
||||
/// <returns>专用 UIGF 信息</returns>
|
||||
public static UIGFInfo Create(string uid)
|
||||
public static UIGFInfo Create(IServiceProvider serviceProvider, string uid)
|
||||
{
|
||||
HutaoOptions hutaoOptions = serviceProvider.GetRequiredService<HutaoOptions>();
|
||||
|
||||
return new()
|
||||
{
|
||||
Uid = uid,
|
||||
Language = "zh-cn",
|
||||
ExportTimestamp = DateTimeOffset.Now.ToUnixTimeSeconds(),
|
||||
ExportApp = SH.AppName,
|
||||
ExportAppVersion = CoreEnvironment.Version.ToString(),
|
||||
ExportAppVersion = hutaoOptions.Version.ToString(),
|
||||
UIGFVersion = UIGF.CurrentVersion,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -60,17 +60,20 @@ internal sealed class UIIFInfo
|
||||
/// <summary>
|
||||
/// 构造一个新的专用 UIGF 信息
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider">服务提供器</param>
|
||||
/// <param name="uid">uid</param>
|
||||
/// <returns>专用 UIGF 信息</returns>
|
||||
public static UIIFInfo Create(string uid)
|
||||
public static UIIFInfo Create(IServiceProvider serviceProvider, string uid)
|
||||
{
|
||||
HutaoOptions hutaoOptions = serviceProvider.GetRequiredService<HutaoOptions>();
|
||||
|
||||
return new()
|
||||
{
|
||||
Uid = uid,
|
||||
Language = "zh-cn",
|
||||
ExportTimestamp = DateTimeOffset.Now.ToUnixTimeSeconds(),
|
||||
ExportApp = "胡桃",
|
||||
ExportAppVersion = CoreEnvironment.Version.ToString(),
|
||||
ExportAppVersion = hutaoOptions.Version.ToString(),
|
||||
UIIFVersion = UIIF.CurrentVersion,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace Snap.Hutao.Model.Metadata;
|
||||
[HighQuality]
|
||||
internal sealed class ParameterFormat : IFormatProvider, ICustomFormatter
|
||||
{
|
||||
private static readonly Lazy<ParameterFormat> LazyFormat = new();
|
||||
|
||||
/// <summary>
|
||||
/// 格式化
|
||||
/// </summary>
|
||||
@@ -20,7 +22,7 @@ internal sealed class ParameterFormat : IFormatProvider, ICustomFormatter
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static string Format(string str, object param)
|
||||
{
|
||||
return string.Format(new ParameterFormat(), str, param);
|
||||
return string.Format(LazyFormat.Value, str, param);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Snap.Hutao.Service;
|
||||
using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Windows.Globalization;
|
||||
using WinRT;
|
||||
|
||||
[assembly:InternalsVisibleTo("Snap.Hutao.Test")]
|
||||
// Visible to test project.
|
||||
[assembly: InternalsVisibleTo("Snap.Hutao.Test")]
|
||||
|
||||
namespace Snap.Hutao;
|
||||
|
||||
@@ -20,67 +17,37 @@ namespace Snap.Hutao;
|
||||
[SuppressMessage("", "SH001")]
|
||||
public static partial class Program
|
||||
{
|
||||
private static readonly ApplicationInitializationCallback AppInitializationCallback = InitializeApp;
|
||||
|
||||
[LibraryImport("Microsoft.ui.xaml.dll")]
|
||||
private static partial void XamlCheckProcessRequirements();
|
||||
|
||||
[STAThread]
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
_ = args;
|
||||
System.Diagnostics.Debug.WriteLine($"[Arguments]:{args}");
|
||||
|
||||
XamlCheckProcessRequirements();
|
||||
ComWrappersSupport.InitializeComWrappers();
|
||||
|
||||
// by adding the using statement, we can dispose the injected services when we closing
|
||||
using (ServiceProvider serviceProvider = InitializeDependencyInjection())
|
||||
// By adding the using statement, we can dispose the injected services when we closing
|
||||
using (ServiceProvider serviceProvider = DependencyInjection.Initialize())
|
||||
{
|
||||
InitializeCulture(serviceProvider);
|
||||
serviceProvider.InitializeCulture();
|
||||
|
||||
// In a Desktop app this runs a message pump internally,
|
||||
// and does not return until the application shuts down.
|
||||
Application.Start(InitializeApp);
|
||||
Application.Start(AppInitializationCallback);
|
||||
Control.ScopedPage.DisposePreviousScope();
|
||||
}
|
||||
}
|
||||
|
||||
private static void InitializeApp(ApplicationInitializationCallbackParams param)
|
||||
{
|
||||
ThreadHelper.Initialize();
|
||||
_ = Ioc.Default.GetRequiredService<App>();
|
||||
}
|
||||
IServiceProvider serviceProvider = Ioc.Default;
|
||||
|
||||
private static void InitializeCulture(IServiceProvider serviceProvider)
|
||||
{
|
||||
AppOptions appOptions = serviceProvider.GetRequiredService<AppOptions>();
|
||||
appOptions.PreviousCulture = CultureInfo.CurrentCulture;
|
||||
|
||||
CultureInfo cultureInfo = appOptions.CurrentCulture;
|
||||
|
||||
CultureInfo.CurrentCulture = cultureInfo;
|
||||
CultureInfo.CurrentUICulture = cultureInfo;
|
||||
ApplicationLanguages.PrimaryLanguageOverride = cultureInfo.Name;
|
||||
}
|
||||
|
||||
private static ServiceProvider InitializeDependencyInjection()
|
||||
{
|
||||
ServiceProvider services = new ServiceCollection()
|
||||
|
||||
// Microsoft extension
|
||||
.AddLogging(builder => builder.AddDebug())
|
||||
.AddMemoryCache()
|
||||
|
||||
// Hutao extensions
|
||||
.AddJsonOptions()
|
||||
.AddDatabase()
|
||||
.AddInjections()
|
||||
.AddHttpClients()
|
||||
|
||||
// Discrete services
|
||||
.AddSingleton<IMessenger>(WeakReferenceMessenger.Default)
|
||||
|
||||
.BuildServiceProvider(true);
|
||||
|
||||
Ioc.Default.ConfigureServices(services);
|
||||
return services;
|
||||
ITaskContext taskContext = serviceProvider.GetRequiredService<ITaskContext>();
|
||||
ThreadHelper.Initialize(taskContext);
|
||||
_ = serviceProvider.GetRequiredService<App>();
|
||||
}
|
||||
}
|
||||
@@ -28,19 +28,22 @@ internal sealed class AchievementService : IAchievementService
|
||||
private readonly ILogger<AchievementService> logger;
|
||||
private readonly DbCurrent<AchievementArchive, Message.AchievementArchiveChangedMessage> dbCurrent;
|
||||
private readonly AchievementDbOperation achievementDbOperation;
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
|
||||
private ObservableCollection<AchievementArchive>? archiveCollection;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的成就服务
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider">服务提供器</param>
|
||||
/// <param name="appDbContext">数据库上下文</param>
|
||||
/// <param name="logger">日志器</param>
|
||||
/// <param name="messenger">消息器</param>
|
||||
public AchievementService(AppDbContext appDbContext, ILogger<AchievementService> logger, IMessenger messenger)
|
||||
public AchievementService(IServiceProvider serviceProvider, AppDbContext appDbContext, ILogger<AchievementService> logger, IMessenger messenger)
|
||||
{
|
||||
this.appDbContext = appDbContext;
|
||||
this.logger = logger;
|
||||
this.serviceProvider = serviceProvider;
|
||||
|
||||
dbCurrent = new(appDbContext.AchievementArchives, messenger);
|
||||
achievementDbOperation = new(appDbContext);
|
||||
@@ -174,7 +177,7 @@ internal sealed class AchievementService : IAchievementService
|
||||
|
||||
UIAF uigf = new()
|
||||
{
|
||||
Info = UIAFInfo.Create(),
|
||||
Info = UIAFInfo.Create(serviceProvider),
|
||||
List = list,
|
||||
};
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace Snap.Hutao.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 应用程序选项
|
||||
/// 存储服务相关的选项
|
||||
/// </summary>
|
||||
[Injection(InjectAs.Singleton)]
|
||||
internal sealed class AppOptions : DbStoreOptions
|
||||
|
||||
@@ -15,14 +15,16 @@ namespace Snap.Hutao.Service.GachaLog;
|
||||
internal sealed class GachaLogExportService : IGachaLogExportService
|
||||
{
|
||||
private readonly AppDbContext appDbContext;
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的祈愿记录导出服务
|
||||
/// </summary>
|
||||
/// <param name="appDbContext">数据库上下文</param>
|
||||
public GachaLogExportService(AppDbContext appDbContext)
|
||||
public GachaLogExportService(IServiceProvider serviceProvider, AppDbContext appDbContext)
|
||||
{
|
||||
this.appDbContext = appDbContext;
|
||||
this.serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -37,7 +39,7 @@ internal sealed class GachaLogExportService : IGachaLogExportService
|
||||
|
||||
UIGF uigf = new()
|
||||
{
|
||||
Info = UIGFInfo.Create(archive.Uid),
|
||||
Info = UIGFInfo.Create(serviceProvider, archive.Uid),
|
||||
List = list,
|
||||
};
|
||||
|
||||
|
||||
@@ -21,16 +21,19 @@ internal sealed class PackageConverter
|
||||
{
|
||||
private readonly JsonSerializerOptions options;
|
||||
private readonly HttpClient httpClient;
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的游戏文件转换器
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider">服务提供器</param>
|
||||
/// <param name="options">Json序列化选项</param>
|
||||
/// <param name="httpClient">http客户端</param>
|
||||
public PackageConverter(JsonSerializerOptions options, HttpClient httpClient)
|
||||
public PackageConverter(IServiceProvider serviceProvider, HttpClient httpClient)
|
||||
{
|
||||
this.options = options;
|
||||
options = serviceProvider.GetRequiredService<JsonSerializerOptions>();
|
||||
this.httpClient = httpClient;
|
||||
this.serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -228,7 +231,8 @@ internal sealed class PackageConverter
|
||||
}
|
||||
|
||||
// Cache folder
|
||||
string cacheFolder = Path.Combine(Core.CoreEnvironment.DataFolder, "ServerCache");
|
||||
Core.HutaoOptions hutaoOptions = serviceProvider.GetRequiredService<Core.HutaoOptions>();
|
||||
string cacheFolder = Path.Combine(hutaoOptions.DataFolder, "ServerCache");
|
||||
|
||||
// 执行下载与移动操作
|
||||
foreach (ItemOperationInfo info in operations)
|
||||
|
||||
@@ -47,6 +47,7 @@ internal sealed partial class MetadataService : IMetadataService, IMetadataServi
|
||||
/// <param name="logger">日志器</param>
|
||||
/// <param name="memoryCache">内存缓存</param>
|
||||
public MetadataService(
|
||||
Core.HutaoOptions hutaoOptions,
|
||||
IInfoBarService infoBarService,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
JsonSerializerOptions options,
|
||||
@@ -60,7 +61,7 @@ internal sealed partial class MetadataService : IMetadataService, IMetadataServi
|
||||
httpClient = httpClientFactory.CreateClient(nameof(MetadataService));
|
||||
|
||||
locale = GetTextMapLocale();
|
||||
metadataFolderPath = Path.Combine(Core.CoreEnvironment.DataFolder, "Metadata", locale);
|
||||
metadataFolderPath = Path.Combine(hutaoOptions.DataFolder, "Metadata", locale);
|
||||
Directory.CreateDirectory(metadataFolderPath);
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
TextWrapping="Wrap"/>
|
||||
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}" Text="{shcm:ResourceString Name=ViewPageSettingAboutHeader}"/>
|
||||
<clw:SettingsCard
|
||||
Description="{Binding AppVersion}"
|
||||
Description="{Binding HutaoOptions.Version}"
|
||||
Header="{shcm:ResourceString Name=AppName}"
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}"/>
|
||||
<clw:SettingsCard
|
||||
@@ -82,7 +82,7 @@
|
||||
ActionIcon="{shcm:FontIcon Glyph=}"
|
||||
ActionIconToolTip="{shcm:ResourceString Name=ViewPageSettingCopyDeviceIdAction}"
|
||||
Command="{Binding CopyDeviceIdCommand}"
|
||||
Description="{Binding DeviceId}"
|
||||
Description="{Binding HutaoOptions.DeviceId}"
|
||||
Header="{shcm:ResourceString Name=ViewPageSettingDeviceIdHeader}"
|
||||
HeaderIcon="{shcm:FontIcon Glyph=}"
|
||||
IsClickEnabled="True"/>
|
||||
|
||||
@@ -26,11 +26,18 @@ internal sealed partial class TitleView : UserControl
|
||||
[SuppressMessage("", "CA1822")]
|
||||
public string Title
|
||||
{
|
||||
get
|
||||
{
|
||||
Core.HutaoOptions hutaoOptions = Ioc.Default.GetRequiredService<Core.HutaoOptions>();
|
||||
|
||||
string format =
|
||||
#if DEBUG
|
||||
get => string.Format(SH.AppDevNameAndVersion, Core.CoreEnvironment.Version);
|
||||
SH.AppDevNameAndVersion;
|
||||
#else
|
||||
get => string.Format(SH.AppNameAndVersion, Core.CoreEnvironment.Version);
|
||||
SH.AppNameAndVersion;
|
||||
#endif
|
||||
return string.Format(format, hutaoOptions.Version);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -6,6 +6,7 @@ using CommunityToolkit.Mvvm.Input;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.Windows.AppLifecycle;
|
||||
using Snap.Hutao.Core;
|
||||
using Snap.Hutao.Factory.Abstraction;
|
||||
using Snap.Hutao.Model.Entity.Database;
|
||||
using Windows.Storage;
|
||||
@@ -52,12 +53,14 @@ internal sealed class ExperimentalFeaturesViewModel : ObservableObject
|
||||
|
||||
private Task OpenCacheFolderAsync()
|
||||
{
|
||||
return Launcher.LaunchFolderAsync(ApplicationData.Current.LocalCacheFolder).AsTask();
|
||||
HutaoOptions hutaoOptions = serviceProvider.GetRequiredService<HutaoOptions>();
|
||||
return Launcher.LaunchFolderPathAsync(hutaoOptions.LocalCache).AsTask();
|
||||
}
|
||||
|
||||
private Task OpenDataFolderAsync()
|
||||
{
|
||||
return Launcher.LaunchFolderPathAsync(Core.CoreEnvironment.DataFolder).AsTask();
|
||||
HutaoOptions hutaoOptions = serviceProvider.GetRequiredService<HutaoOptions>();
|
||||
return Launcher.LaunchFolderPathAsync(hutaoOptions.DataFolder).AsTask();
|
||||
}
|
||||
|
||||
private async Task DangerousDeleteUsersAsync()
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Microsoft.Windows.AppLifecycle;
|
||||
using Snap.Hutao.Core;
|
||||
using Snap.Hutao.Core.IO;
|
||||
using Snap.Hutao.Core.IO.DataTransfer;
|
||||
using Snap.Hutao.Core.LifeCycle;
|
||||
@@ -67,6 +68,7 @@ internal sealed class SettingViewModel : Abstraction.ViewModel
|
||||
Experimental = serviceProvider.GetRequiredService<ExperimentalFeaturesViewModel>();
|
||||
Options = serviceProvider.GetRequiredService<AppOptions>();
|
||||
UserOptions = serviceProvider.GetRequiredService<HutaoUserOptions>();
|
||||
HutaoOptions = serviceProvider.GetRequiredService<HutaoOptions>();
|
||||
this.serviceProvider = serviceProvider;
|
||||
|
||||
selectedCulture = cultures.FirstOrDefault(c => c.Value == Options.CurrentCulture.Name);
|
||||
@@ -82,15 +84,6 @@ internal sealed class SettingViewModel : Abstraction.ViewModel
|
||||
NavigateToHutaoPassportCommand = new RelayCommand(NavigateToHutaoPassport);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 版本
|
||||
/// </summary>
|
||||
[SuppressMessage("", "CA1822")]
|
||||
public string AppVersion
|
||||
{
|
||||
get => Core.CoreEnvironment.Version.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WebView2 版本
|
||||
/// </summary>
|
||||
@@ -100,20 +93,16 @@ internal sealed class SettingViewModel : Abstraction.ViewModel
|
||||
get => Core.WebView2Helper.Version;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设备Id
|
||||
/// </summary>
|
||||
[SuppressMessage("", "CA1822")]
|
||||
public string DeviceId
|
||||
{
|
||||
get => Core.CoreEnvironment.HutaoDeviceId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 应用程序设置
|
||||
/// </summary>
|
||||
public AppOptions Options { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 胡桃选项
|
||||
/// </summary>
|
||||
public HutaoOptions HutaoOptions { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 胡桃用户选项
|
||||
/// </summary>
|
||||
@@ -317,7 +306,7 @@ internal sealed class SettingViewModel : Abstraction.ViewModel
|
||||
|
||||
try
|
||||
{
|
||||
Clipboard.SetText(DeviceId);
|
||||
Clipboard.SetText(HutaoOptions.DeviceId);
|
||||
infoBarService.Success(SH.ViewModelSettingCopyDeviceIdSuccess);
|
||||
}
|
||||
catch (COMException ex)
|
||||
|
||||
@@ -6,6 +6,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using CommunityToolkit.WinUI.Notifications;
|
||||
using Snap.Hutao.Core;
|
||||
using Snap.Hutao.Core.Caching;
|
||||
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||
using Snap.Hutao.Core.IO;
|
||||
@@ -146,7 +147,8 @@ internal sealed class WelcomeViewModel : ObservableObject
|
||||
public DownloadSummary(IServiceProvider serviceProvider, string fileName)
|
||||
{
|
||||
httpClient = serviceProvider.GetRequiredService<HttpClient>();
|
||||
httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(Core.CoreEnvironment.CommonUA);
|
||||
HutaoOptions hutaoOptions = serviceProvider.GetRequiredService<HutaoOptions>();
|
||||
httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(hutaoOptions.UserAgent);
|
||||
|
||||
this.serviceProvider = serviceProvider;
|
||||
|
||||
|
||||
@@ -15,29 +15,29 @@ internal static class CoreWebView2Extension
|
||||
/// <summary>
|
||||
/// 设置 移动端UA
|
||||
/// </summary>
|
||||
/// <param name="webView">webview2</param>
|
||||
/// <param name="webView">webView2</param>
|
||||
/// <returns>链式调用的WebView2</returns>
|
||||
public static CoreWebView2 SetMobileUserAgent(this CoreWebView2 webView)
|
||||
{
|
||||
webView.Settings.UserAgent = Core.CoreEnvironment.HoyolabMobileUA;
|
||||
webView.Settings.UserAgent = Core.HoyolabOptions.MobileUserAgent;
|
||||
return webView;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置 移动端OsUA
|
||||
/// </summary>
|
||||
/// <param name="webView">webview2</param>
|
||||
/// <param name="webView">webView2</param>
|
||||
/// <returns>链式调用的WebView2</returns>
|
||||
public static CoreWebView2 SetMobileOverseaUserAgent(this CoreWebView2 webView)
|
||||
{
|
||||
webView.Settings.UserAgent = Core.CoreEnvironment.HoyolabOsMobileUA;
|
||||
webView.Settings.UserAgent = Core.HoyolabOptions.MobileUserAgentOversea;
|
||||
return webView;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置WebView2的Cookie
|
||||
/// </summary>
|
||||
/// <param name="webView">webview2</param>
|
||||
/// <param name="webView">webView2</param>
|
||||
/// <param name="cookieToken">CookieToken</param>
|
||||
/// <param name="lToken">LToken</param>
|
||||
/// <param name="sToken">SToken</param>
|
||||
|
||||
@@ -87,8 +87,8 @@ internal class MiHoYoJSInterface
|
||||
Data = new Dictionary<string, string>()
|
||||
{
|
||||
{ "x-rpc-client_type", "5" },
|
||||
{ "x-rpc-device_id", Core.CoreEnvironment.HoyolabDeviceId },
|
||||
{ "x-rpc-app_version", Core.CoreEnvironment.HoyolabXrpcVersion },
|
||||
{ "x-rpc-device_id", Core.HoyolabOptions.DeviceId },
|
||||
{ "x-rpc-app_version", Core.HoyolabOptions.XrpcVersion },
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -120,7 +120,7 @@ internal class MiHoYoJSInterface
|
||||
/// <returns>响应</returns>
|
||||
public virtual JsResult<Dictionary<string, string>> GetDynamicSecrectV1(JsParam param)
|
||||
{
|
||||
string salt = Core.CoreEnvironment.DynamicSecretSalts[SaltType.LK2];
|
||||
string salt = Core.HoyolabOptions.Salts[SaltType.LK2];
|
||||
long t = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
string r = GetRandomString();
|
||||
string check = Core.Convert.ToMd5HexString($"salt={salt}&t={t}&r={r}").ToLowerInvariant();
|
||||
@@ -151,7 +151,7 @@ internal class MiHoYoJSInterface
|
||||
public virtual JsResult<Dictionary<string, string>> GetDynamicSecrectV2(JsParam<DynamicSecrect2Playload> param)
|
||||
{
|
||||
// TODO: Salt X4 for hoyolab user
|
||||
string salt = Core.CoreEnvironment.DynamicSecretSalts[SaltType.X4];
|
||||
string salt = Core.HoyolabOptions.Salts[SaltType.X4];
|
||||
long t = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
int r = GetRandom();
|
||||
string b = param.Payload.Body;
|
||||
|
||||
@@ -35,8 +35,8 @@ internal sealed class SignInJSInterfaceOversea : MiHoYoJSInterface
|
||||
Data = new Dictionary<string, string>()
|
||||
{
|
||||
{ "x-rpc-client_type", "2" },
|
||||
{ "x-rpc-device_id", Core.CoreEnvironment.HoyolabDeviceId },
|
||||
{ "x-rpc-app_version", Core.CoreEnvironment.HoyolabOsXrpcVersion },
|
||||
{ "x-rpc-device_id", Core.HoyolabOptions.DeviceId },
|
||||
{ "x-rpc-app_version", Core.HoyolabOptions.XrpcVersionOversea },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ internal sealed class SignInJsInterface : MiHoYoJSInterface
|
||||
Data = new Dictionary<string, string>()
|
||||
{
|
||||
{ "x-rpc-client_type", "2" },
|
||||
{ "x-rpc-device_id", Core.CoreEnvironment.HoyolabDeviceId },
|
||||
{ "x-rpc-app_version", Core.CoreEnvironment.HoyolabXrpcVersion },
|
||||
{ "x-rpc-device_id", Core.HoyolabOptions.DeviceId },
|
||||
{ "x-rpc-app_version", Core.HoyolabOptions.XrpcVersion },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ internal sealed class DynamicSecretHandler : DelegatingHandler
|
||||
|
||||
private static async Task ProcessRequestWithOptionsAsync(HttpRequestMessage request, DynamicSecretCreationOptions options, CancellationToken token)
|
||||
{
|
||||
string salt = Core.CoreEnvironment.DynamicSecretSalts[options.SaltType];
|
||||
string salt = Core.HoyolabOptions.Salts[options.SaltType];
|
||||
|
||||
long t = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core;
|
||||
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||
using Snap.Hutao.Web.Hutao.Log;
|
||||
using Snap.Hutao.Web.Response;
|
||||
@@ -29,11 +30,12 @@ internal sealed class HomaLogUploadClient
|
||||
/// <summary>
|
||||
/// 上传日志
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider">服务提供器</param>
|
||||
/// <param name="exception">异常</param>
|
||||
/// <returns>任务</returns>
|
||||
public async Task<string?> UploadLogAsync(Exception exception)
|
||||
public async Task<string?> UploadLogAsync(IServiceProvider serviceProvider, Exception exception)
|
||||
{
|
||||
HutaoLog log = BuildFromException(exception);
|
||||
HutaoLog log = BuildFromException(serviceProvider, exception);
|
||||
|
||||
Response<string>? a = await httpClient
|
||||
.TryCatchPostAsJsonAsync<HutaoLog, Response<string>>(HutaoEndpoints.HutaoLogUpload, log)
|
||||
@@ -41,13 +43,15 @@ internal sealed class HomaLogUploadClient
|
||||
return a?.Data;
|
||||
}
|
||||
|
||||
private static HutaoLog BuildFromException(Exception exception)
|
||||
private static HutaoLog BuildFromException(IServiceProvider serviceProvider, Exception exception)
|
||||
{
|
||||
HutaoOptions hutaoOptions = serviceProvider.GetRequiredService<HutaoOptions>();
|
||||
|
||||
return new()
|
||||
{
|
||||
Id = Core.CoreEnvironment.HutaoDeviceId,
|
||||
Id = hutaoOptions.DeviceId,
|
||||
Time = DateTimeOffset.Now.ToUnixTimeMilliseconds(),
|
||||
Info = exception.ToString(),
|
||||
Info = Core.ExceptionService.ExceptionFormat.Format(exception),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user