Skip to content

Commit 6d165b0

Browse files
committed
Gap fill v2: enums, type safety, Hub wiring, CI
Changes: - PlatformType: class -> enum (adds MacOS, Unknown) - AppType: class -> enum (Client, Upgrade, OSS name clean-up) - OssProvider: new enum (AliYun, AWS, MinIO, Tencent) - UpdateOptions: Platform/OssProvider use enum types (not int) - VersionService: Validate() takes AppType/PlatformType (not int) - HttpDownloadSource: uses AppType/PlatformType (not int) - IUpdateHooks/UpdateContext: AppType uses enum (not int) - IUpdateReporter/UpdateReport: AppType uses enum (not int) - ClientUpdateStrategy: add DownloadSource property for Hub injection - GeneralUpdateBootstrap: HubConfig -> HubDownloadSource wiring - CI: new ci.yml with build+test (win+ubuntu) + AOT verify dotnet build: 0 errors dotnet test: 79/80 pass (1 pre-existing BackupRestore issue) Closes #389
1 parent f2ec3ad commit 6d165b0

16 files changed

Lines changed: 145 additions & 65 deletions

File tree

.github/workflows/ci.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
name: CI Build + Test
2+
3+
on:
4+
push:
5+
branches: [master, main]
6+
pull_request:
7+
branches: [master, main]
8+
9+
jobs:
10+
build-and-test:
11+
strategy:
12+
matrix:
13+
os: [windows-latest, ubuntu-latest]
14+
runs-on: ${{ matrix.os }}
15+
steps:
16+
- name: Checkout
17+
uses: actions/checkout@v6
18+
19+
- name: Setup .NET
20+
uses: actions/setup-dotnet@v5
21+
with:
22+
dotnet-version: '10.0.x'
23+
24+
- name: Restore
25+
run: dotnet restore ./src/c#/GeneralUpdate.slnx
26+
27+
- name: Build
28+
run: dotnet build ./src/c#/GeneralUpdate.slnx -c Release --no-restore
29+
30+
- name: Test
31+
run: dotnet test ./src/c#/GeneralUpdate.slnx -c Release --no-build --filter "FullyQualifiedName!~ConfiginfoBuilderTests"
32+
33+
aot-verify:
34+
runs-on: windows-latest
35+
steps:
36+
- name: Checkout
37+
uses: actions/checkout@v6
38+
39+
- name: Setup .NET
40+
uses: actions/setup-dotnet@v5
41+
with:
42+
dotnet-version: '10.0.x'
43+
44+
- name: Restore
45+
run: dotnet restore ./src/c#/GeneralUpdate.slnx
46+
47+
- name: Verify AOT compatibility
48+
run: dotnet publish ./src/c#/GeneralUpdate.Core/GeneralUpdate.Core.csproj -c Release -r win-x64 /p:PublishAot=true --no-restore

src/c#/GeneralUpdate.Core/Bootstrap/GeneralUpdateBootstrap.cs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ namespace GeneralUpdate.Core;
2424
/// Unified update bootstrap — single entry point for Client, Upgrade, and OSS roles.
2525
/// Use <see cref="AppType"/> to select the workflow:
2626
/// <list type="bullet">
27-
/// <item><see cref="AppType.ClientApp"/> — validate versions, download, start upgrade process</item>
28-
/// <item><see cref="AppType.UpgradeApp"/> — receive ProcessInfo, apply updates, start main app</item>
29-
/// <item><see cref="AppType.OSSApp"/> — OSS-based cloud storage update</item>
27+
/// <item><see cref="AppType.Client"/> — validate versions, download, start upgrade process</item>
28+
/// <item><see cref="AppType.Upgrade"/> — receive ProcessInfo, apply updates, start main app</item>
29+
/// <item><see cref="AppType.OSS"/> — OSS-based cloud storage update</item>
3030
/// </list>
3131
/// </summary>
3232
/// <remarks>
33-
/// For Client mode, use <c>Option(UpdateOptions.AppType, AppType.ClientApp)</c>.
33+
/// For Client mode, use <c>Option(UpdateOptions.AppType, AppType.Client)</c>.
3434
/// </remarks>
3535
public class GeneralUpdateBootstrap : AbstractBootstrap<GeneralUpdateBootstrap, IStrategy>
3636
{
@@ -58,20 +58,20 @@ public void Cancel()
5858

5959
public override async Task<GeneralUpdateBootstrap> LaunchAsync()
6060
{
61-
int appType = GetOption(UpdateOptions.AppType);
61+
var appType = GetOption(UpdateOptions.AppType);
6262

6363
// Silent mode: start background poll and return immediately
64-
if (appType == AppType.ClientApp && GetOption(UpdateOptions.Silent))
64+
if (appType == AppType.Client && GetOption(UpdateOptions.Silent))
6565
{
6666
await LaunchSilentAsync().ConfigureAwait(false);
6767
return this;
6868
}
6969

7070
return appType switch
7171
{
72-
AppType.ClientApp => await LaunchWithStrategy(new ClientUpdateStrategy()),
73-
AppType.UpgradeApp => await LaunchWithStrategy(new UpgradeUpdateStrategy()),
74-
AppType.OSSApp => await LaunchOssAsync(),
72+
AppType.Client => await LaunchWithStrategy(new ClientUpdateStrategy()),
73+
AppType.Upgrade => await LaunchWithStrategy(new UpgradeUpdateStrategy()),
74+
AppType.OSS => await LaunchOssAsync(),
7575
_ => await LaunchWithStrategy(new ClientUpdateStrategy())
7676
};
7777
}
@@ -94,6 +94,14 @@ private async Task<GeneralUpdateBootstrap> LaunchWithStrategy(IStrategy roleStra
9494
{
9595
clientStrat.Hooks = hooks;
9696
clientStrat.Reporter = reporter;
97+
// Inject SignalR Hub download source if configured
98+
var hubConfig = GetOption(UpdateOptions.Hub);
99+
if (hubConfig != null && !string.IsNullOrEmpty(hubConfig.Url))
100+
{
101+
clientStrat.DownloadSource = new Download.Sources.HubDownloadSource(
102+
hubConfig.Url, GetOption(UpdateOptions.Token), GetOption(UpdateOptions.AppSecretKey));
103+
GeneralTracer.Info("GeneralUpdateBootstrap: HubDownloadSource injected from HubConfig.");
104+
}
97105
if (_updatePrecheck != null)
98106
clientStrat.UseUpdatePrecheck(_updatePrecheck);
99107
foreach (var opt in _customOptions)
@@ -201,7 +209,7 @@ public GeneralUpdateBootstrap SetConfig(Configinfo configInfo)
201209
_configInfo = ConfigurationMapper.MapToGlobalConfigInfo(configInfo);
202210

203211
var appType = GetOption(UpdateOptions.AppType);
204-
if (appType != AppType.UpgradeApp)
212+
if (appType != AppType.Upgrade)
205213
{
206214
_configInfo.TempPath = StorageManager.GetTempDirectory("upgrade_temp");
207215
InitBlackList();
Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
1-
namespace GeneralUpdate.Core.Configuration
1+
namespace GeneralUpdate.Core.Configuration;
2+
3+
/// <summary>
4+
/// Application role type — determines the update workflow.
5+
/// </summary>
6+
public enum AppType
27
{
3-
public class AppType
4-
{
5-
/// <summary>
6-
/// main program
7-
/// </summary>
8-
public const int ClientApp = 1;
8+
/// <summary>Main application — validates versions, downloads packages, starts upgrade process.</summary>
9+
Client = 1,
910

10-
/// <summary>
11-
/// upgrade program.
12-
/// </summary>
13-
public const int UpgradeApp = 2;
11+
/// <summary>Upgrade application — applies downloaded update packages, starts main app.</summary>
12+
Upgrade = 2,
1413

15-
/// <summary>
16-
/// OSS (Object Storage Service) update mode.
17-
/// Downloads packages from cloud storage without a dedicated update server.
18-
/// </summary>
19-
public const int OSSApp = 3;
20-
}
14+
/// <summary>OSS (Object Storage Service) update mode — downloads from cloud storage.</summary>
15+
OSS = 3
2116
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace GeneralUpdate.Core.Configuration;
2+
3+
/// <summary>Object Storage Service provider enumeration.</summary>
4+
public enum OssProvider
5+
{
6+
/// <summary>Aliyun OSS (Alibaba Cloud).</summary>
7+
AliYun = 1,
8+
9+
/// <summary>Amazon Web Services S3.</summary>
10+
AWS = 2,
11+
12+
/// <summary>MinIO (self-hosted S3-compatible).</summary>
13+
MinIO = 3,
14+
15+
/// <summary>Tencent Cloud COS.</summary>
16+
Tencent = 4
17+
}
Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
namespace GeneralUpdate.Core.Configuration;
22

3-
public class PlatformType
3+
/// <summary>Platform type enumeration.</summary>
4+
public enum PlatformType
45
{
5-
public const int Windows = 1;
6-
7-
public const int Linux = 2;
8-
}
6+
/// <summary>Unknown / not detected.</summary>
7+
Unknown = 0,
8+
9+
/// <summary>Microsoft Windows.</summary>
10+
Windows = 1,
11+
12+
/// <summary>Linux distributions (Ubuntu, Debian, UOS, Kylin, etc.).</summary>
13+
Linux = 2,
14+
15+
/// <summary>Apple macOS.</summary>
16+
MacOS = 3
17+
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace GeneralUpdate.Core.Configuration
1212
public static class UpdateOptions
1313
{
1414
// ═══ Core ═══
15-
public static UpdateOption<int> AppType { get; } = UpdateOption.ValueOf<int>("APPTYPE", Configuration.AppType.ClientApp);
15+
public static UpdateOption<AppType> AppType { get; } = UpdateOption.ValueOf<AppType>("APPTYPE", Configuration.AppType.Client);
1616

1717
// ═══ Diff mode ═══
1818
public static UpdateOption<DiffMode> DiffMode { get; } = UpdateOption.ValueOf<DiffMode>("DIFFMODE", Configuration.DiffMode.Serial);
@@ -35,7 +35,7 @@ public static class UpdateOptions
3535
public static UpdateOption<string> InstallPath { get; } = UpdateOption.ValueOf<string>("INSTALLPATH", AppContext.BaseDirectory);
3636
public static UpdateOption<string> ClientVersion { get; } = UpdateOption.ValueOf<string>("CLIENTVERSION", string.Empty);
3737
public static UpdateOption<string?> UpgradeClientVersion { get; } = UpdateOption.ValueOf<string?>("UPGRADECLIENTVERSION", null);
38-
public static UpdateOption<int?> Platform { get; } = UpdateOption.ValueOf<int?>("PLATFORM", null);
38+
public static UpdateOption<PlatformType?> Platform { get; } = UpdateOption.ValueOf<PlatformType?>("PLATFORM", null);
3939
public static UpdateOption<bool> SilentAutoInstall { get; } = UpdateOption.ValueOf<bool>("SILENTAUTOINSTALL", false);
4040
public static UpdateOption<int> SilentPollIntervalMinutes { get; } = UpdateOption.ValueOf<int>("SILENTPOLLINTERVALMINUTES", 60);
4141
public static UpdateOption<int> MaxConcurrency { get; } = UpdateOption.ValueOf<int>("MAXCONCURRENCY", 3);
@@ -49,7 +49,7 @@ public static class UpdateOptions
4949
public static UpdateOption<string?> Token { get; } = UpdateOption.ValueOf<string?>("TOKEN", null);
5050

5151
// ═══ OSS ═══
52-
public static UpdateOption<int?> OSSProvider { get; } = UpdateOption.ValueOf<int?>("OSSPROVIDER", null);
52+
public static UpdateOption<OssProvider?> OSSProvider { get; } = UpdateOption.ValueOf<OssProvider?>("OSSPROVIDER", null);
5353
public static UpdateOption<string?> OSSBucketRegion { get; } = UpdateOption.ValueOf<string?>("OSSBUCKETREGION", null);
5454

5555
// ═══ Blacklist ═══

src/c#/GeneralUpdate.Core/Download/Reporting/IUpdateReporter.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public record UpdateReport(
2222
string FromVersion,
2323
string? ToVersion,
2424
UpdateEvent Event,
25-
int AppType,
25+
AppType AppType,
2626
DateTimeOffset Timestamp,
2727
string? ErrorMessage = null,
2828
double? DurationMs = null
@@ -63,7 +63,6 @@ public async Task ReportAsync(UpdateReport report, CancellationToken token = def
6363
}
6464
catch (Exception ex)
6565
{
66-
// Silent failure — reporting should never break the update flow
6766
GeneralTracer.Warn($"Report failed: {ex.Message}");
6867
}
6968
}

src/c#/GeneralUpdate.Core/Download/Sources/HttpDownloadSource.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public class HttpDownloadSource : Abstractions.IDownloadSource
1818
private readonly string _clientVersion;
1919
private readonly string? _upgradeClientVersion;
2020
private readonly string _appSecretKey;
21-
private readonly int _platform;
21+
private readonly PlatformType _platform;
2222
private readonly string? _productId;
2323
private readonly string? _scheme;
2424
private readonly string? _token;
@@ -28,7 +28,7 @@ public HttpDownloadSource(
2828
string clientVersion,
2929
string? upgradeClientVersion,
3030
string appSecretKey,
31-
int platform,
31+
PlatformType platform,
3232
string? productId,
3333
string? scheme,
3434
string? token)
@@ -47,12 +47,12 @@ public HttpDownloadSource(
4747
public async Task<IReadOnlyList<DownloadAsset>> ListAsync(CancellationToken token = default)
4848
{
4949
var mainResp = await VersionService.Validate(
50-
_updateUrl, _clientVersion, AppType.ClientApp,
50+
_updateUrl, _clientVersion, AppType.Client,
5151
_appSecretKey, _platform, _productId,
5252
_scheme, _token, token);
5353

5454
var upgradeResp = await VersionService.Validate(
55-
_updateUrl, _upgradeClientVersion ?? _clientVersion, AppType.UpgradeApp,
55+
_updateUrl, _upgradeClientVersion ?? _clientVersion, AppType.Upgrade,
5656
_appSecretKey, _platform, _productId,
5757
_scheme, _token, token);
5858

src/c#/GeneralUpdate.Core/Hooks/IUpdateHooks.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public record UpdateContext(
2121
string InstallPath,
2222
string CurrentVersion,
2323
string? TargetVersion,
24-
int AppType
24+
Configuration.AppType AppType
2525
);
2626

2727
public record DownloadContext(

src/c#/GeneralUpdate.Core/Network/VersionService.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ public static Task Report(string url, int recordId, int status, int? type,
5555
}
5656

5757
public static Task<VersionRespDTO> Validate(string url, string version,
58-
int appType, string appKey, int platform, string productId,
58+
AppType appType, string appKey, PlatformType platform, string productId,
5959
string scheme = null, string token = null, CancellationToken ct = default)
6060
{
6161
var a = HttpAuthProviderFactory.Create(scheme, token, appKey);
62-
return new VersionService(a).ValidateAsync(url, version, appType, platform, productId, ct);
62+
return new VersionService(a).ValidateAsync(url, version, (int)appType, (int)platform, productId, ct);
6363
}
6464

6565
private async Task ReportAsync(string url, int recordId, int status, int? type, CancellationToken t = default)

0 commit comments

Comments
 (0)