壳子替换

This commit is contained in:
QWQLwToo
2026-07-06 23:08:53 +08:00
parent 31d778710b
commit b9578edc3a
12 changed files with 450 additions and 34 deletions
@@ -110,12 +110,15 @@ public sealed class LocalToolVendorAssetService(
Path.Combine(cacheRoot, "manifest.json"),
manifestHash,
extracted);
await logService.WriteAsync(
"Information",
"tool-vendor",
"Local JS vendor assets extracted",
$"files={extracted.Count}; hash={manifestHash}",
cancellationToken).ConfigureAwait(false);
if (logService is not null)
{
await logService.WriteAsync(
"Information",
"tool-vendor",
"Local JS vendor assets extracted",
$"files={extracted.Count}; hash={manifestHash}",
cancellationToken).ConfigureAwait(false);
}
return _snapshot;
}
finally
@@ -131,9 +134,12 @@ public sealed class LocalToolVendorAssetService(
? Directory.EnumerateFiles(sourceRoot, "*", SearchOption.AllDirectories).OrderBy(path => path, StringComparer.OrdinalIgnoreCase).ToArray()
: [];
var manifest = Path.Combine(sourceRoot, "manifest.json");
var hash = File.Exists(manifest)
? Convert.ToHexString(await SHA256.HashDataAsync(File.OpenRead(manifest), cancellationToken).ConfigureAwait(false)).ToLowerInvariant()
: HashText(string.Join("|", files.Select(Path.GetFileName)));
var hash = HashText(string.Join("|", files.Select(Path.GetFileName)));
if (File.Exists(manifest))
{
await using var manifestStream = File.OpenRead(manifest);
hash = Convert.ToHexString(await SHA256.HashDataAsync(manifestStream, cancellationToken).ConfigureAwait(false)).ToLowerInvariant();
}
return new LocalToolVendorAssetSnapshot(sourceRoot, manifest, hash, files);
}
@@ -1,4 +1,4 @@
using YMhut.Box.Core.App;
using YMhut.Box.Core.App;
using YMhut.Box.Core.Data;
using YMhut.Box.Core.Downloads;
using YMhut.Box.Core.Logging;
@@ -160,12 +160,12 @@ public sealed class StartupInitializationService(
context.Report(1, T("本地设置已载入。", "Local settings loaded."));
});
yield return Stage("resources", T("验证随包资源", "Validating bundled resources"), 10, false, (context, token) =>
yield return Stage("resources", T("验证随包资源", "Validating bundled resources"), 10, false, async (context, token) =>
{
if (!getSettings().ValidateResourcesOnStartup)
{
context.Report(1, T("已跳过随包资源完整性检查。", "Bundled resource validation skipped."));
return Task.CompletedTask;
return;
}
context.Report(0.2, T("正在检查三国杀、本地参考数据和工具结果前端资源...", "Checking Sanguosha, local reference data, and tool result frontend assets..."));
@@ -173,15 +173,16 @@ public sealed class StartupInitializationService(
"data/sanguosha/skin_config.json",
"data/sanguosha/GeneralSkinInfoConfig.json",
"data/sanguosha/十周年皮肤配置对应关系.xlsx");
context.Report(0.72, T("正在准备本地 JS 工具库缓存...", "Preparing local JS tool vendor cache..."));
var vendor = await localToolVendorAssets.EnsureExtractedAsync(token).ConfigureAwait(false);
var vendorHealthy = vendor.Files.Count > 0 && File.Exists(vendor.ManifestPath);
context.Report(
1,
validation.IsHealthy
? T("三国杀随包资源已就绪。", "Sanguosha bundled resources are ready.")
: T($"缺少 {validation.MissingPaths.Count} 个随包资源,相关工具会显示修复提示。", $"{validation.MissingPaths.Count} bundled resources are missing; affected tools will show repair guidance."),
validation.IsHealthy ? StartupCheckSeverity.Info : StartupCheckSeverity.Warning);
return Task.CompletedTask;
validation.IsHealthy && vendorHealthy
? T("三国杀随包资源和本地 JS 工具库已就绪。", "Sanguosha resources and local JS vendor assets are ready.")
: T($"缺少 {validation.MissingPaths.Count} 个随包资源,本地 JS 文件 {vendor.Files.Count} 个。", $"{validation.MissingPaths.Count} bundled resources are missing; {vendor.Files.Count} local JS files are visible."),
validation.IsHealthy && vendorHealthy ? StartupCheckSeverity.Info : StartupCheckSeverity.Warning);
});
yield return Stage("database", T("初始化主 SQLite", "Initializing main SQLite"), 10, true, async (context, token) =>
{
context.Report(0.25, T("正在初始化日志与主数据库...", "Initializing logs and main database..."));
@@ -295,3 +296,4 @@ public sealed class StartupInitializationService(
private static string T(string zh, string en) => AppLocalizer.T(zh, en);
}
+35 -1
View File
@@ -1,5 +1,6 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Web.WebView2.Core;
using Windows.ApplicationModel.DataTransfer;
using Windows.System;
@@ -11,7 +12,8 @@ namespace YMhut.Box.WinUI.Services;
public sealed class ToolResultWebBridge(
IToolResultExperienceCatalog experienceCatalog,
ISettingsService settingsService,
IToolLinkNavigationService linkNavigationService)
IToolLinkNavigationService linkNavigationService,
IServiceProvider services)
{
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web)
{
@@ -97,6 +99,38 @@ public sealed class ToolResultWebBridge(
case "openSystemBrowser":
await linkNavigationService.OpenAsync(value, ToolLinkTarget.SystemBrowser);
break;
case "openExternal":
await linkNavigationService.OpenAsync(value, ToolLinkTarget.SystemBrowser);
break;
case "navigateTool":
if (!string.IsNullOrWhiteSpace(value) &&
services.GetService<IShellNavigationService>()?.NavigateToTool(value) == true)
{
ToastService.Show(AppLocalizer.T("已跳转到相关工具", "Opened related tool"), ToastKind.Success);
}
else
{
ToastService.Show(AppLocalizer.T("暂时无法跳转到该工具", "Unable to open related tool"), ToastKind.Warning);
}
break;
case "navigateRoute":
if (!string.IsNullOrWhiteSpace(value) &&
services.GetService<IShellNavigationService>()?.Navigate(value) == true)
{
ToastService.Show(AppLocalizer.T("已打开相关页面", "Opened related page"), ToastKind.Success);
}
else
{
ToastService.Show(AppLocalizer.T("暂时无法打开相关页面", "Unable to open related page"), ToastKind.Warning);
}
break;
case "rerunWithInput":
if (!string.IsNullOrWhiteSpace(value) &&
services.GetService<IShellNavigationService>()?.NavigateToTool(value) == true)
{
ToastService.Show(AppLocalizer.T("已打开工具,请确认输入后重新运行", "Tool opened; review the input and run again"), ToastKind.Information);
}
break;
}
}