Skip to content

Commit 0735936

Browse files
committed
refactor: integrate manifest reading into OssStrategy, simplify Validate()
- OssStrategy.ExecuteAsync() now calls AppMetadataDiscoverer.Discover() to fill identity fields from generalupdate.manifest.json, same as the standard ClientStrategy flow. - OssStrategy.ExecuteUpgradeAsync() calls ManifestInfo.TryUpdateVersion() after decompression to persist the applied version back to manifest, preventing infinite update loops. - UpdateRequest.Validate() no longer requires MainAppName, UpdateAppName, ClientVersion — these are filled from manifest by strategies at runtime. This also aligns with SetSource() which never set these fields. - Updated UpdateRequestTests to reflect the relaxed validation rules. - Simplified ClientTest/UpgradeTest: only secrets in SetConfig(), identity fields come from manifest automatically.
1 parent 8d3e9f3 commit 0735936

5 files changed

Lines changed: 40 additions & 71 deletions

File tree

src/c#/GeneralUpdate.Core/Configuration/UpdateRequest.cs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,17 +62,8 @@ public void Validate()
6262
if (!string.IsNullOrWhiteSpace(UpdateLogUrl) && !Uri.IsWellFormedUriString(UpdateLogUrl, UriKind.Absolute))
6363
throw new ArgumentException("Invalid UpdateLogUrl");
6464

65-
if (string.IsNullOrWhiteSpace(UpdateAppName))
66-
throw new ArgumentException("UpdateAppName cannot be empty");
67-
68-
if (string.IsNullOrWhiteSpace(MainAppName))
69-
throw new ArgumentException("MainAppName cannot be empty");
70-
7165
if (string.IsNullOrWhiteSpace(AppSecretKey))
7266
throw new ArgumentException("AppSecretKey cannot be empty");
73-
74-
if (string.IsNullOrWhiteSpace(ClientVersion))
75-
throw new ArgumentException("ClientVersion cannot be empty");
7667
}
7768
}
7869
}

src/c#/GeneralUpdate.Core/Strategy/OssStrategy.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,12 @@ public async Task ExecuteAsync()
150150
if (_configInfo == null)
151151
throw new InvalidOperationException("OssStrategy not configured. Call Create() first.");
152152

153-
// Dispatch by role �?no env-var detection needed.
153+
// Fill missing identity fields from generalupdate.manifest.json,
154+
// making the manifest the single source of configuration across
155+
// all update flows (standard ClientStrategy and OssStrategy).
156+
Configuration.AppMetadataDiscoverer.Discover(_configInfo);
157+
158+
// Dispatch by role — no env-var detection needed.
154159
if (_role == AppType.OssUpgrade)
155160
{
156161
await ExecuteUpgradeAsync();
@@ -371,6 +376,12 @@ private async Task ExecuteUpgradeAsync()
371376
var encoding = Encoding.GetEncoding(_configInfo?.Encoding?.CodePage ?? Encoding.UTF8.CodePage);
372377
DecompressAssets(assets, installPath, encoding);
373378

379+
// Update generalupdate.manifest.json ClientVersion so the client
380+
// reads the correct version on next startup, preventing infinite loops.
381+
Configuration.ManifestInfo.TryUpdateVersion(
382+
installPath,
383+
clientVersion: _configInfo.LastVersion);
384+
374385
await SafeOnDownloadCompletedAsync(ctx).ConfigureAwait(false);
375386
await SafeOnAfterUpdateAsync(ctx).ConfigureAwait(false);
376387
await SafeReportUpdateAppliedAsync(ctx).ConfigureAwait(false);

tests/ClientTest/Program.cs

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -39,37 +39,21 @@ static async Task RunOssClientAsync()
3939
Console.WriteLine($"Started at {DateTime.Now}");
4040
Console.WriteLine($"Running from: {AppDomain.CurrentDomain.BaseDirectory}");
4141

42+
// Secrets come from code. Identity fields (MainAppName, ClientVersion,
43+
// UpdateAppName, UpdatePath) are read from generalupdate.manifest.json
44+
// by OssStrategy via AppMetadataDiscoverer.Discover() — same as standard flow.
4245
var updateUrl = "http://localhost:5000/packages/versions.json";
46+
var appSecretKey = "dfeb5833-975e-4afb-88f1-6278ee9aeff6";
4347

44-
// Read current version from marker file (written by UpgradeTest after each successful update).
45-
// This prevents infinite update loops when the package doesn't change the client binary.
46-
var markerPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ".current_version");
47-
var clientVersion = "1.0.0";
48-
if (File.Exists(markerPath))
49-
{
50-
clientVersion = File.ReadAllText(markerPath).Trim();
51-
Console.WriteLine($"Marker file found: current version = {clientVersion}");
52-
}
53-
54-
Console.WriteLine($"UpdateUrl (versions.json): {updateUrl}");
55-
Console.WriteLine($"Current version: {clientVersion}");
48+
Console.WriteLine($"UpdateUrl: {updateUrl}");
5649
Console.WriteLine();
5750

58-
// OssClient flow:
59-
// 1. Download versions.json from UpdateUrl to InstallPath
60-
// 2. Deserialize as List<OssVersionRecord>, sort by PubTime desc
61-
// 3. Compare latest.Version > ClientVersion
62-
// 4. If newer: launch UpdateAppName from InstallPath, then exit
6351
await new GeneralUpdateBootstrap()
6452
.SetConfig(new UpdateRequest
6553
{
6654
UpdateUrl = updateUrl,
6755
InstallPath = AppDomain.CurrentDomain.BaseDirectory,
68-
ClientVersion = clientVersion,
69-
MainAppName = "ClientTest.exe",
70-
UpdateAppName = "UpgradeTest.exe",
71-
UpdatePath = "update",
72-
AppSecretKey = "dfeb5833-975e-4afb-88f1-6278ee9aeff6"
56+
AppSecretKey = appSecretKey
7357
})
7458
.SetOption(Option.AppType, AppType.OssClient)
7559
.Hooks<ClientTestHooks>()

tests/CoreTest/Configuration/UpdateRequestTests.cs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,9 @@ public void Validate_UpdateLogUrlInvalid_ThrowsArgumentException()
9595
[InlineData(null)]
9696
[InlineData("")]
9797
[InlineData(" ")]
98-
public void Validate_UpgradeAppNameNullOrWhitespace_ThrowsArgumentException(string appName)
98+
public void Validate_UpgradeAppNameNullOrWhitespace_NoException(string appName)
9999
{
100+
// UpdateAppName is optional — filled from manifest by strategies.
100101
var config = new UpdateRequest
101102
{
102103
UpdateUrl = "https://api.example.com",
@@ -106,15 +107,17 @@ public void Validate_UpgradeAppNameNullOrWhitespace_ThrowsArgumentException(stri
106107
ClientVersion = "1.0.0",
107108
InstallPath = "C:\\app"
108109
};
109-
Assert.Throws<ArgumentException>(() => config.Validate());
110+
var ex = Record.Exception(() => config.Validate());
111+
Assert.Null(ex);
110112
}
111113

112114
[Theory]
113115
[InlineData(null)]
114116
[InlineData("")]
115117
[InlineData(" ")]
116-
public void Validate_MainAppNameNullOrWhitespace_ThrowsArgumentException(string mainUpgradeAppName)
118+
public void Validate_MainAppNameNullOrWhitespace_NoException(string mainUpgradeAppName)
117119
{
120+
// MainAppName is optional — filled from manifest by strategies.
118121
var config = new UpdateRequest
119122
{
120123
UpdateUrl = "https://api.example.com",
@@ -124,7 +127,8 @@ public void Validate_MainAppNameNullOrWhitespace_ThrowsArgumentException(string
124127
ClientVersion = "1.0.0",
125128
InstallPath = "C:\\app"
126129
};
127-
Assert.Throws<ArgumentException>(() => config.Validate());
130+
var ex = Record.Exception(() => config.Validate());
131+
Assert.Null(ex);
128132
}
129133

130134
[Theory]
@@ -149,8 +153,9 @@ public void Validate_AppSecretKeyNullOrWhitespace_ThrowsArgumentException(string
149153
[InlineData(null)]
150154
[InlineData("")]
151155
[InlineData(" ")]
152-
public void Validate_ClientVersionNullOrWhitespace_ThrowsArgumentException(string clientVersion)
156+
public void Validate_ClientVersionNullOrWhitespace_NoException(string clientVersion)
153157
{
158+
// ClientVersion is optional — filled from manifest by strategies.
154159
var config = new UpdateRequest
155160
{
156161
UpdateUrl = "https://api.example.com",
@@ -160,7 +165,8 @@ public void Validate_ClientVersionNullOrWhitespace_ThrowsArgumentException(strin
160165
ClientVersion = clientVersion,
161166
InstallPath = "C:\\app"
162167
};
163-
Assert.Throws<ArgumentException>(() => config.Validate());
168+
var ex = Record.Exception(() => config.Validate());
169+
Assert.Null(ex);
164170
}
165171

166172
[Theory]

tests/UpgradeTest/Program.cs

Lines changed: 10 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -33,39 +33,24 @@ static async Task RunOssUpgradeAsync()
3333
Console.WriteLine($"Started at {DateTime.Now}");
3434
Console.WriteLine($"Running from: {AppDomain.CurrentDomain.BaseDirectory}");
3535

36-
// OssUpgrade flow:
37-
// 1. Read {MainAppName}_versions.json from InstallPath (downloaded by OssClient)
38-
// 2. Filter versions > ClientVersion, sorted by PubTime asc
39-
// 3. Download each asset's ZIP from the URL in the version record
40-
// 4. Decompress all ZIPs to InstallPath, delete archives
41-
// 5. Launch MainAppName, then exit
42-
//
43-
// NOTE: Unlike the standard Upgrade path (which reads config from IPC),
44-
// OssUpgrade requires explicit SetConfig() so it knows where to find
45-
// the version JSON and which version to compare against.
46-
//
47-
// InstallPath must point to the SAME directory as the OssClient's InstallPath,
48-
// because the versions.json was downloaded there. When the upgrade runs from
49-
// a subdirectory (e.g. update/), we resolve up to the parent.
50-
36+
// OssUpgrade runs from a subdirectory (e.g. update/), but the manifest
37+
// and versions.json are in the parent directory (same as OssClient).
38+
// InstallPath resolves to the parent so OssStrategy reads the correct
39+
// manifest and versions.json.
5140
var baseDir = AppDomain.CurrentDomain.BaseDirectory;
52-
// baseDir ends with '\' (e.g. "...\update\"), so Path.Combine with ".." goes up one level.
5341
var installPath = Path.GetFullPath(Path.Combine(baseDir, ".."));
5442

55-
Console.WriteLine($"[OssUpgrade] BaseDir={baseDir}");
56-
Console.WriteLine($"[OssUpgrade] InstallPath={installPath}");
57-
GeneralUpdate.Core.GeneralTracer.Info($"[OssUpgrade] BaseDir={baseDir}");
58-
GeneralUpdate.Core.GeneralTracer.Info($"[OssUpgrade] InstallPath={installPath}");
43+
Console.WriteLine($"BaseDir={baseDir}");
44+
Console.WriteLine($"InstallPath={installPath} (parent, where manifest + versions.json live)");
45+
Console.WriteLine();
5946

6047
await new GeneralUpdateBootstrap()
6148
.SetConfig(new UpdateRequest
6249
{
6350
UpdateUrl = "http://localhost:5000/packages/versions.json",
6451
InstallPath = installPath,
65-
ClientVersion = "1.0.0",
66-
MainAppName = "ClientTest.exe",
67-
UpdateAppName = "UpgradeTest.exe",
6852
AppSecretKey = "dfeb5833-975e-4afb-88f1-6278ee9aeff6"
53+
// Identity fields from generalupdate.manifest.json via Discover().
6954
})
7055
.SetOption(Option.AppType, AppType.OssUpgrade)
7156
.Hooks<UpgradeTestHooks>()
@@ -160,16 +145,8 @@ public async Task OnDownloadCompletedAsync(DownloadContext ctx)
160145
public async Task OnAfterUpdateAsync(HookContext ctx)
161146
{
162147
Console.WriteLine($"[Hook] OnAfterUpdate: {ctx.CurrentVersion} -> {ctx.TargetVersion}");
163-
164-
// Write version marker to prevent infinite update loops.
165-
// The OssClient reads this file on startup to know its current version.
166-
if (!string.IsNullOrWhiteSpace(ctx.TargetVersion) && !string.IsNullOrWhiteSpace(ctx.InstallPath))
167-
{
168-
var markerPath = Path.Combine(ctx.InstallPath, ".current_version");
169-
File.WriteAllText(markerPath, ctx.TargetVersion);
170-
Console.WriteLine($"[Hook] Version marker written: {markerPath} = {ctx.TargetVersion}");
171-
}
172-
148+
// Manifest ClientVersion is updated by OssStrategy itself via
149+
// ManifestInfo.TryUpdateVersion() after decompression.
173150
await Task.CompletedTask;
174151
}
175152

0 commit comments

Comments
 (0)