Skip to content

Commit 83ba93d

Browse files
authored
Batch 1: Clean up legacy code and fix strategy workflows (#362)
- Remove deprecated GeneralClientBootstrap class (#361) - Refactor UpgradeUpdateStrategy to zero-network design: Remove version validation and download logic Upgrade only applies pipeline and starts main app - Add macOS (MacStrategy) support to OS resolution in both ClientUpdateStrategy and UpgradeUpdateStrategy - Replace all Process.Kill() calls with GracefulExit for graceful process shutdown with timeout fallback Closes #361
1 parent 8f69a63 commit 83ba93d

7 files changed

Lines changed: 45 additions & 609 deletions

File tree

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

Lines changed: 0 additions & 464 deletions
This file was deleted.

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

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,7 @@ namespace GeneralUpdate.Core;
2727
/// </list>
2828
/// </summary>
2929
/// <remarks>
30-
/// <b>Migration from GeneralClientBootstrap:</b>
31-
/// Replace <c>new GeneralClientBootstrap().SetConfig(cfg).LaunchAsync()</c> with
32-
/// <c>new GeneralUpdateBootstrap().Option(UpdateOptions.AppType, AppType.ClientApp).SetConfig(cfg).LaunchAsync()</c>.
30+
/// For Client mode, use <c>Option(UpdateOptions.AppType, AppType.ClientApp)</c>.
3331
/// </remarks>
3432
public class GeneralUpdateBootstrap : AbstractBootstrap<GeneralUpdateBootstrap, IStrategy>
3533
{
@@ -72,7 +70,7 @@ private async Task<GeneralUpdateBootstrap> LaunchWithStrategy(IStrategy roleStra
7270
clientStrat.UseUpdatePrecheck(_updatePrecheck);
7371
foreach (var opt in _customOptions)
7472
clientStrat.UseCustomOption(opt);
75-
CallSmallBowlHome(_configInfo.Bowl);
73+
await CallSmallBowlHomeAsync(_configInfo.Bowl).ConfigureAwait(false);
7674
}
7775

7876
roleStrategy.Create(_configInfo);
@@ -141,7 +139,7 @@ private async Task<GeneralUpdateBootstrap> LaunchOssAsync()
141139
GlobalConfigInfoOSSJsonContext.Default.GlobalConfigInfoOSS);
142140
Environments.SetEnvironmentVariable("GlobalConfigInfoOSS", serialized);
143141
Process.Start(appPath);
144-
Process.GetCurrentProcess().Kill();
142+
await GracefulExit.CurrentProcessAsync().ConfigureAwait(false);
145143
}
146144
catch (Exception ex)
147145
{
@@ -241,21 +239,21 @@ private void InitBlackList()
241239
BlackListManager.Instance.AddSkipDirectorys(_configInfo.SkipDirectorys);
242240
}
243241

244-
private void CallSmallBowlHome(string processName)
242+
private async Task CallSmallBowlHomeAsync(string processName)
245243
{
246244
if (string.IsNullOrWhiteSpace(processName)) return;
247245
try
248246
{
249247
var processes = Process.GetProcessesByName(processName);
250248
foreach (var process in processes)
251249
{
252-
GeneralTracer.Info($"Killing process {process.ProcessName} (ID: {process.Id})");
253-
process.Kill();
250+
GeneralTracer.Info($"Shutting down process {process.ProcessName} (ID: {process.Id})");
251+
await GracefulExit.ShutdownAsync(process).ConfigureAwait(false);
254252
}
255253
}
256254
catch (Exception ex)
257255
{
258-
GeneralTracer.Error("CallSmallBowlHome failed.", ex);
256+
GeneralTracer.Error("CallSmallBowlHomeAsync failed.", ex);
259257
}
260258
}
261259

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public static ProcessInfo MapToProcessInfo(
7575
throw new ArgumentNullException(nameof(source), "GlobalConfigInfo source cannot be null");
7676

7777
// Create ProcessInfo with all required parameters in a single location
78-
// This replaces the error-prone manual parameter passing in GeneralClientBootstrap
78+
// Centralized parameter mapping for ProcessInfo creation
7979
return new ProcessInfo(
8080
appName: source.MainAppName, // Maps MainAppName to ProcessInfo.AppName
8181
installPath: source.InstallPath,

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

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.Diagnostics;
44
using System.IO;
@@ -49,7 +49,7 @@ public async Task ExecuteAsync()
4949
try
5050
{
5151
GeneralTracer.Debug("ClientUpdateStrategy.ExecuteAsync start.");
52-
CallSmallBowlHome(_configInfo.Bowl);
52+
await CallSmallBowlHomeAsync(_configInfo.Bowl);
5353
ExecuteCustomOptions();
5454
await ExecuteWorkflowAsync();
5555
}
@@ -88,7 +88,7 @@ public ClientUpdateStrategy UseCustomOption(Func<bool> func)
8888

8989
private async Task ExecuteWorkflowAsync()
9090
{
91-
// Silent mode delegate to SilentUpdateMode
91+
// Silent mode ¡ª delegate to SilentUpdateMode
9292
// (encoding/format/timeout are read from _configInfo)
9393
var defaultEncoding = Encoding.UTF8;
9494
var defaultTimeout = 60;
@@ -167,18 +167,18 @@ private async Task ExecuteStandardWorkflowAsync(Encoding encoding, int timeout)
167167
switch (_configInfo.IsUpgradeUpdate)
168168
{
169169
case true when _configInfo.IsMainUpdate:
170-
GeneralTracer.Info("ClientUpdateStrategy: both upgrade+main downloading and executing.");
170+
GeneralTracer.Info("ClientUpdateStrategy: both upgrade+main ¡ª downloading and executing.");
171171
await DownloadAsync();
172172
await _osStrategy.ExecuteAsync();
173173
_osStrategy.StartApp();
174174
break;
175175
case true when !_configInfo.IsMainUpdate:
176-
GeneralTracer.Info("ClientUpdateStrategy: upgrade-only downloading and executing.");
176+
GeneralTracer.Info("ClientUpdateStrategy: upgrade-only ¡ª downloading and executing.");
177177
await DownloadAsync();
178178
await _osStrategy.ExecuteAsync();
179179
break;
180180
case false when _configInfo.IsMainUpdate:
181-
GeneralTracer.Info("ClientUpdateStrategy: main-only starting updater.");
181+
GeneralTracer.Info("ClientUpdateStrategy: main-only ¡ª starting updater.");
182182
_osStrategy.StartApp();
183183
break;
184184
}
@@ -194,6 +194,8 @@ private static IStrategy ResolveOsStrategy()
194194
return new WindowsStrategy();
195195
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
196196
return new LinuxStrategy();
197+
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
198+
return new MacStrategy();
197199
throw new PlatformNotSupportedException("The current operating system is not supported!");
198200
}
199201

@@ -254,7 +256,7 @@ private static int GetPlatform()
254256
return -1;
255257
}
256258

257-
private void CallSmallBowlHome(string processName)
259+
private async Task CallSmallBowlHomeAsync(string processName)
258260
{
259261
if (string.IsNullOrWhiteSpace(processName)) return;
260262
try
@@ -263,13 +265,13 @@ private void CallSmallBowlHome(string processName)
263265
if (processes.Length == 0) return;
264266
foreach (var process in processes)
265267
{
266-
GeneralTracer.Info($"Killing process {process.ProcessName} (ID: {process.Id})");
267-
process.Kill();
268+
GeneralTracer.Info($"Shutting down process {process.ProcessName} (ID: {process.Id})");
269+
await GracefulExit.ShutdownAsync(process).ConfigureAwait(false);
268270
}
269271
}
270272
catch (Exception ex)
271273
{
272-
GeneralTracer.Error("CallSmallBowlHome failed.", ex);
274+
GeneralTracer.Error("CallSmallBowlHomeAsync failed.", ex);
273275
}
274276
}
275277

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public override void StartApp()
7676
{
7777
GeneralTracer.Info("GeneralUpdate.Core.LinuxStrategy.StartApp: releasing tracer and terminating updater process.");
7878
GeneralTracer.Dispose();
79-
Process.GetCurrentProcess().Kill();
79+
GracefulExit.CurrentProcessAsync().GetAwaiter().GetResult();
8080
}
8181
}
8282

@@ -136,4 +136,4 @@ private void ExecuteScript()
136136
EventManager.Instance.Dispatch(this, new ExceptionEventArgs(ex, "Script execution failed"));
137137
}
138138
}
139-
}
139+
}

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

Lines changed: 21 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,9 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Diagnostics;
4-
using System.IO;
5-
using System.Linq;
1+
using System;
62
using System.Runtime.InteropServices;
73
using System.Text;
84
using System.Threading.Tasks;
95
using GeneralUpdate.Core.Configuration;
10-
using GeneralUpdate.Core.Download;
116
using GeneralUpdate.Core.Event;
12-
using GeneralUpdate.Core.FileSystem;
13-
using GeneralUpdate.Core.Network;
147

158
namespace GeneralUpdate.Core.Strategy;
169

@@ -21,15 +14,16 @@ namespace GeneralUpdate.Core.Strategy;
2114
/// <remarks>
2215
/// This is the AppType.UpgradeApp role strategy. It composes an OS-specific
2316
/// strategy for platform operations (Windows/Linux/Mac).
17+
///
18+
/// <b>Design:</b> Upgrade does NOT validate versions or download packages.
19+
/// The client has already validated versions, downloaded all packages, and
20+
/// passed the results via ProcessInfo. Upgrade only applies updates and
21+
/// starts the main application — zero network.
2422
/// </remarks>
2523
public class UpgradeUpdateStrategy : IStrategy
2624
{
2725
private GlobalConfigInfo? _configInfo;
2826
private IStrategy? _osStrategy;
29-
private readonly Download.Abstractions.IDownloadOrchestrator? _orchestrator;
30-
private readonly DiffMode _diffMode = DiffMode.Serial;
31-
32-
public UpgradeUpdateStrategy(Download.Abstractions.IDownloadOrchestrator? orchestrator = null) { _orchestrator = orchestrator; }
3327

3428
public void Create(GlobalConfigInfo parameter)
3529
{
@@ -44,23 +38,22 @@ public async Task ExecuteAsync()
4438
try
4539
{
4640
GeneralTracer.Debug("UpgradeUpdateStrategy.ExecuteAsync start.");
47-
StrategyFactory();
4841

49-
var mode = UpdateMode.Default; // should come from config
50-
switch (mode)
42+
ApplyRuntimeOptions();
43+
_osStrategy!.Create(_configInfo);
44+
45+
// Apply updates via OS-specific pipeline (Hash → Compress → Patch)
46+
if (_configInfo.UpdateVersions?.Count > 0)
47+
{
48+
GeneralTracer.Info($"UpgradeUpdateStrategy: applying {_configInfo.UpdateVersions.Count} update(s).");
49+
await _osStrategy.ExecuteAsync();
50+
}
51+
else
5152
{
52-
case UpdateMode.Default:
53-
ApplyRuntimeOptions();
54-
_osStrategy!.Create(_configInfo);
55-
await DownloadAsync();
56-
await _osStrategy.ExecuteAsync();
57-
break;
58-
case UpdateMode.Scripts:
59-
await ExecuteScriptsWorkflowAsync();
60-
break;
61-
default:
62-
throw new ArgumentOutOfRangeException();
53+
GeneralTracer.Info("UpgradeUpdateStrategy: no updates to apply, starting application directly.");
6354
}
55+
56+
_osStrategy.StartApp();
6457
}
6558
catch (Exception ex)
6659
{
@@ -79,57 +72,6 @@ public void StartApp()
7972
_osStrategy?.StartApp();
8073
}
8174

82-
#region Scripts Mode Workflow
83-
84-
private async Task ExecuteScriptsWorkflowAsync()
85-
{
86-
GeneralTracer.Info($"UpgradeUpdateStrategy: validating version. Url={_configInfo!.UpdateUrl}, Version={_configInfo.ClientVersion}");
87-
88-
var mainResp = await VersionService.Validate(
89-
_configInfo.UpdateUrl, _configInfo.ClientVersion,
90-
AppType.ClientApp, _configInfo.AppSecretKey,
91-
GetPlatform(), _configInfo.ProductId,
92-
_configInfo.Scheme, _configInfo.Token);
93-
94-
_configInfo.IsMainUpdate = CheckUpgrade(mainResp);
95-
EventManager.Instance.Dispatch(this, new UpdateInfoEventArgs(mainResp));
96-
97-
if (CheckForcibly(mainResp.Body) == false && ShouldSkip())
98-
{
99-
GeneralTracer.Info("UpgradeUpdateStrategy: update skipped.");
100-
return;
101-
}
102-
103-
InitBlackList();
104-
ApplyRuntimeOptions();
105-
106-
_configInfo.TempPath = StorageManager.GetTempDirectory("main_temp");
107-
_configInfo.BackupDirectory = Path.Combine(
108-
_configInfo.InstallPath,
109-
$"{StorageManager.DirectoryName}{_configInfo.ClientVersion}");
110-
111-
_configInfo.UpdateVersions = mainResp.Body!
112-
.OrderBy(x => x.ReleaseDate).ToList();
113-
114-
Backup();
115-
116-
_osStrategy!.Create(_configInfo);
117-
118-
if (_configInfo.IsMainUpdate)
119-
{
120-
GeneralTracer.Info("UpgradeUpdateStrategy: main update required.");
121-
await DownloadAsync();
122-
await _osStrategy.ExecuteAsync();
123-
}
124-
else
125-
{
126-
GeneralTracer.Info("UpgradeUpdateStrategy: no update needed, starting application.");
127-
_osStrategy.StartApp();
128-
}
129-
}
130-
131-
#endregion
132-
13375
#region Helpers
13476

13577
private static IStrategy ResolveOsStrategy()
@@ -138,57 +80,15 @@ private static IStrategy ResolveOsStrategy()
13880
return new WindowsStrategy();
13981
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
14082
return new LinuxStrategy();
83+
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
84+
return new MacStrategy();
14185
throw new PlatformNotSupportedException("The current operating system is not supported!");
14286
}
14387

144-
private void StrategyFactory()
145-
{
146-
_osStrategy ??= ResolveOsStrategy();
147-
}
148-
14988
private void ApplyRuntimeOptions()
15089
{
15190
_configInfo!.Encoding = Encoding.UTF8;
15291
_configInfo.Format = Format.ZIP;
153-
_configInfo.DownloadTimeOut = 60;
154-
}
155-
156-
private void InitBlackList()
157-
{
158-
BlackListManager.Instance.AddBlackFiles(_configInfo!.BlackFiles);
159-
BlackListManager.Instance.AddBlackFormats(_configInfo.BlackFormats);
160-
BlackListManager.Instance.AddSkipDirectorys(_configInfo.SkipDirectorys);
161-
}
162-
163-
private void Backup()
164-
{
165-
GeneralTracer.Info($"UpgradeUpdateStrategy: backing up {_configInfo!.InstallPath} -> {_configInfo.BackupDirectory}");
166-
StorageManager.Backup(_configInfo.InstallPath, _configInfo.BackupDirectory,
167-
BlackListManager.Instance.SkipDirectorys);
168-
}
169-
170-
private async Task DownloadAsync()
171-
{
172-
var manager = new DownloadManager(
173-
_configInfo!.TempPath, _configInfo.Format, _configInfo.DownloadTimeOut);
174-
foreach (var version in _configInfo.UpdateVersions)
175-
manager.Add(new DownloadTask(manager, version));
176-
await manager.LaunchTasksAsync();
177-
}
178-
179-
private static bool ShouldSkip() => false;
180-
181-
private static bool CheckUpgrade(VersionRespDTO? response)
182-
=> response?.Code == 200 && response.Body?.Count > 0;
183-
184-
private static bool CheckForcibly(IEnumerable<VersionInfo>? versions)
185-
=> versions?.Any(v => v.IsForcibly == true) == true;
186-
187-
private static int GetPlatform()
188-
{
189-
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return PlatformType.Windows;
190-
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return PlatformType.Linux;
191-
return -1;
19292
}
19393

19494
#endregion

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ public override void StartApp()
7878
{
7979
GeneralTracer.Info("GeneralUpdate.Core.WindowsStrategy.StartApp: releasing tracer and terminating updater process.");
8080
GeneralTracer.Dispose();
81-
Process.GetCurrentProcess().Kill();
81+
GracefulExit.CurrentProcessAsync().GetAwaiter().GetResult();
8282
}
8383
}
8484
}
85-
}
85+
}

0 commit comments

Comments
 (0)