mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-20 23:54:26 +08:00
Replace UI DispatcherTimer polling with a StudySnapshotRenderGate across multiple widgets to queue and apply only the latest analytics snapshot; components updated include StudyDeductionReasonsWidget, StudyEnvironmentWidget, StudyInterruptDensityWidget, StudyNoiseCurveWidget. Add StudySnapshotRenderGate implementation to coordinate rendering and monitoring leases and update subscription/lease lifecycle handling (subscribe/unsubscribe, Acquire/Dispose leases, Clear/Dispose gate). Rewrite chart controls (StudyNoiseCurveChartControl and StudyNoiseDistributionScatterChartControl) to use stable logical-time origins, split series into static vs dynamic tails, add geometry/sample caching, stable jitter/coordinate mapping helpers, and expose internal helpers & counts for testing. Add unit tests (StudyComponentRenderingTests) covering the render gate and chart behaviors (layer counts, logical X mapping, stable jitter, cache rebuild). These changes improve rendering correctness and performance by avoiding redundant renders and enabling deterministic chart layout.
72 lines
2.9 KiB
C#
72 lines
2.9 KiB
C#
namespace LanMountainDesktop.Shared.Contracts.Update;
|
|
|
|
public static class UpdatePaths
|
|
{
|
|
private const string LauncherDirectoryName = ".Launcher";
|
|
private const string UpdateDirectoryName = "update";
|
|
private const string IncomingDirectoryName = "incoming";
|
|
private const string ObjectsDirectoryName = "objects";
|
|
private const string SnapshotsDirectoryName = "snapshots";
|
|
|
|
public static string ResolveLauncherRoot(string appBaseDirectory)
|
|
{
|
|
var trimmed = appBaseDirectory.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
|
var parent = Path.GetDirectoryName(trimmed);
|
|
return string.IsNullOrWhiteSpace(parent) ? appBaseDirectory : parent;
|
|
}
|
|
|
|
public static string GetLauncherDataRoot(string launcherRoot)
|
|
{
|
|
return Path.Combine(launcherRoot, LauncherDirectoryName);
|
|
}
|
|
|
|
public static string GetIncomingDirectory(string launcherRoot)
|
|
{
|
|
return Path.Combine(launcherRoot, LauncherDirectoryName, UpdateDirectoryName, IncomingDirectoryName);
|
|
}
|
|
|
|
public static string GetObjectsDirectory(string launcherRoot)
|
|
{
|
|
return Path.Combine(GetIncomingDirectory(launcherRoot), ObjectsDirectoryName);
|
|
}
|
|
|
|
public static string GetSnapshotsDirectory(string launcherRoot)
|
|
{
|
|
return Path.Combine(launcherRoot, LauncherDirectoryName, SnapshotsDirectoryName);
|
|
}
|
|
|
|
public static string GetDownloadMarkerPath(string launcherRoot)
|
|
{
|
|
return Path.Combine(GetIncomingDirectory(launcherRoot), ".download-complete");
|
|
}
|
|
|
|
public static string GetPlondsFileMapName() => "plonds-filemap.json";
|
|
public static string GetPlondsSignatureName() => "plonds-filemap.sig";
|
|
public static string GetPlondsUpdateMetadataName() => "plonds-update.json";
|
|
public static string GetLegacyFileMapName() => "files.json";
|
|
public static string GetLegacySignatureName() => "files.json.sig";
|
|
public static string GetLegacyArchiveName() => "update.zip";
|
|
public static string GetPublicKeyFileName() => "public-key.pem";
|
|
|
|
public static string GetPlondsFileMapPath(string launcherRoot)
|
|
=> Path.Combine(GetIncomingDirectory(launcherRoot), GetPlondsFileMapName());
|
|
|
|
public static string GetPlondsSignaturePath(string launcherRoot)
|
|
=> Path.Combine(GetIncomingDirectory(launcherRoot), GetPlondsSignatureName());
|
|
|
|
public static string GetPlondsUpdateMetadataPath(string launcherRoot)
|
|
=> Path.Combine(GetIncomingDirectory(launcherRoot), GetPlondsUpdateMetadataName());
|
|
|
|
public static string GetDownloadMarkerContent(string manifestSha256, string targetVersion, int objectCount)
|
|
{
|
|
return $$"""
|
|
{
|
|
"manifestSha256": "{{manifestSha256}}",
|
|
"targetVersion": "{{targetVersion}}",
|
|
"objectCount": {{objectCount}},
|
|
"completedAt": "{{DateTimeOffset.UtcNow:O}}"
|
|
}
|
|
""";
|
|
}
|
|
}
|