Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
464 changes: 0 additions & 464 deletions src/c#/GeneralUpdate.Core/Bootstrap/GeneralClientBootstrap.cs

This file was deleted.

16 changes: 7 additions & 9 deletions src/c#/GeneralUpdate.Core/Bootstrap/GeneralUpdateBootstrap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ namespace GeneralUpdate.Core;
/// </list>
/// </summary>
/// <remarks>
/// <b>Migration from GeneralClientBootstrap:</b>
/// Replace <c>new GeneralClientBootstrap().SetConfig(cfg).LaunchAsync()</c> with
/// <c>new GeneralUpdateBootstrap().Option(UpdateOptions.AppType, AppType.ClientApp).SetConfig(cfg).LaunchAsync()</c>.
/// For Client mode, use <c>Option(UpdateOptions.AppType, AppType.ClientApp)</c>.
/// </remarks>
public class GeneralUpdateBootstrap : AbstractBootstrap<GeneralUpdateBootstrap, IStrategy>
{
Expand Down Expand Up @@ -72,7 +70,7 @@ private async Task<GeneralUpdateBootstrap> LaunchWithStrategy(IStrategy roleStra
clientStrat.UseUpdatePrecheck(_updatePrecheck);
foreach (var opt in _customOptions)
clientStrat.UseCustomOption(opt);
CallSmallBowlHome(_configInfo.Bowl);
await CallSmallBowlHomeAsync(_configInfo.Bowl).ConfigureAwait(false);
}

roleStrategy.Create(_configInfo);
Expand Down Expand Up @@ -141,7 +139,7 @@ private async Task<GeneralUpdateBootstrap> LaunchOssAsync()
GlobalConfigInfoOSSJsonContext.Default.GlobalConfigInfoOSS);
Environments.SetEnvironmentVariable("GlobalConfigInfoOSS", serialized);
Process.Start(appPath);
Process.GetCurrentProcess().Kill();
await GracefulExit.CurrentProcessAsync().ConfigureAwait(false);
}
catch (Exception ex)
{
Expand Down Expand Up @@ -241,21 +239,21 @@ private void InitBlackList()
BlackListManager.Instance.AddSkipDirectorys(_configInfo.SkipDirectorys);
}

private void CallSmallBowlHome(string processName)
private async Task CallSmallBowlHomeAsync(string processName)
{
if (string.IsNullOrWhiteSpace(processName)) return;
try
{
var processes = Process.GetProcessesByName(processName);
foreach (var process in processes)
{
GeneralTracer.Info($"Killing process {process.ProcessName} (ID: {process.Id})");
process.Kill();
GeneralTracer.Info($"Shutting down process {process.ProcessName} (ID: {process.Id})");
await GracefulExit.ShutdownAsync(process).ConfigureAwait(false);
}
}
catch (Exception ex)
{
GeneralTracer.Error("CallSmallBowlHome failed.", ex);
GeneralTracer.Error("CallSmallBowlHomeAsync failed.", ex);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public static ProcessInfo MapToProcessInfo(
throw new ArgumentNullException(nameof(source), "GlobalConfigInfo source cannot be null");

// Create ProcessInfo with all required parameters in a single location
// This replaces the error-prone manual parameter passing in GeneralClientBootstrap
// Centralized parameter mapping for ProcessInfo creation
return new ProcessInfo(
appName: source.MainAppName, // Maps MainAppName to ProcessInfo.AppName
installPath: source.InstallPath,
Expand Down
22 changes: 12 additions & 10 deletions src/c#/GeneralUpdate.Core/Strategy/ClientUpdateStrategy.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
Expand Down Expand Up @@ -49,7 +49,7 @@ public async Task ExecuteAsync()
try
{
GeneralTracer.Debug("ClientUpdateStrategy.ExecuteAsync start.");
CallSmallBowlHome(_configInfo.Bowl);
await CallSmallBowlHomeAsync(_configInfo.Bowl);
ExecuteCustomOptions();
await ExecuteWorkflowAsync();
}
Expand Down Expand Up @@ -88,7 +88,7 @@ public ClientUpdateStrategy UseCustomOption(Func<bool> func)

private async Task ExecuteWorkflowAsync()
{
// Silent mode — delegate to SilentUpdateMode
// Silent mode ¡ª delegate to SilentUpdateMode
// (encoding/format/timeout are read from _configInfo)
var defaultEncoding = Encoding.UTF8;
var defaultTimeout = 60;
Expand Down Expand Up @@ -167,18 +167,18 @@ private async Task ExecuteStandardWorkflowAsync(Encoding encoding, int timeout)
switch (_configInfo.IsUpgradeUpdate)
{
case true when _configInfo.IsMainUpdate:
GeneralTracer.Info("ClientUpdateStrategy: both upgrade+main — downloading and executing.");
GeneralTracer.Info("ClientUpdateStrategy: both upgrade+main ¡ª downloading and executing.");
await DownloadAsync();
await _osStrategy.ExecuteAsync();
_osStrategy.StartApp();
break;
case true when !_configInfo.IsMainUpdate:
GeneralTracer.Info("ClientUpdateStrategy: upgrade-only — downloading and executing.");
GeneralTracer.Info("ClientUpdateStrategy: upgrade-only ¡ª downloading and executing.");
await DownloadAsync();
await _osStrategy.ExecuteAsync();
break;
case false when _configInfo.IsMainUpdate:
GeneralTracer.Info("ClientUpdateStrategy: main-only — starting updater.");
GeneralTracer.Info("ClientUpdateStrategy: main-only ¡ª starting updater.");
_osStrategy.StartApp();
break;
}
Expand All @@ -194,6 +194,8 @@ private static IStrategy ResolveOsStrategy()
return new WindowsStrategy();
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return new LinuxStrategy();
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
return new MacStrategy();
throw new PlatformNotSupportedException("The current operating system is not supported!");
}

Expand Down Expand Up @@ -254,7 +256,7 @@ private static int GetPlatform()
return -1;
}

private void CallSmallBowlHome(string processName)
private async Task CallSmallBowlHomeAsync(string processName)
{
if (string.IsNullOrWhiteSpace(processName)) return;
try
Expand All @@ -263,13 +265,13 @@ private void CallSmallBowlHome(string processName)
if (processes.Length == 0) return;
foreach (var process in processes)
{
GeneralTracer.Info($"Killing process {process.ProcessName} (ID: {process.Id})");
process.Kill();
GeneralTracer.Info($"Shutting down process {process.ProcessName} (ID: {process.Id})");
await GracefulExit.ShutdownAsync(process).ConfigureAwait(false);
}
}
catch (Exception ex)
{
GeneralTracer.Error("CallSmallBowlHome failed.", ex);
GeneralTracer.Error("CallSmallBowlHomeAsync failed.", ex);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/c#/GeneralUpdate.Core/Strategy/LinuxStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public override void StartApp()
{
GeneralTracer.Info("GeneralUpdate.Core.LinuxStrategy.StartApp: releasing tracer and terminating updater process.");
GeneralTracer.Dispose();
Process.GetCurrentProcess().Kill();
GracefulExit.CurrentProcessAsync().GetAwaiter().GetResult();
}
}

Expand Down Expand Up @@ -136,4 +136,4 @@ private void ExecuteScript()
EventManager.Instance.Dispatch(this, new ExceptionEventArgs(ex, "Script execution failed"));
}
}
}
}
142 changes: 21 additions & 121 deletions src/c#/GeneralUpdate.Core/Strategy/UpgradeUpdateStrategy.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using GeneralUpdate.Core.Configuration;
using GeneralUpdate.Core.Download;
using GeneralUpdate.Core.Event;
using GeneralUpdate.Core.FileSystem;
using GeneralUpdate.Core.Network;

namespace GeneralUpdate.Core.Strategy;

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

public UpgradeUpdateStrategy(Download.Abstractions.IDownloadOrchestrator? orchestrator = null) { _orchestrator = orchestrator; }

public void Create(GlobalConfigInfo parameter)
{
Expand All @@ -44,23 +38,22 @@ public async Task ExecuteAsync()
try
{
GeneralTracer.Debug("UpgradeUpdateStrategy.ExecuteAsync start.");
StrategyFactory();

var mode = UpdateMode.Default; // should come from config
switch (mode)
ApplyRuntimeOptions();
_osStrategy!.Create(_configInfo);

// Apply updates via OS-specific pipeline (Hash → Compress → Patch)
if (_configInfo.UpdateVersions?.Count > 0)
{
GeneralTracer.Info($"UpgradeUpdateStrategy: applying {_configInfo.UpdateVersions.Count} update(s).");
await _osStrategy.ExecuteAsync();
}
else
{
case UpdateMode.Default:
ApplyRuntimeOptions();
_osStrategy!.Create(_configInfo);
await DownloadAsync();
await _osStrategy.ExecuteAsync();
break;
case UpdateMode.Scripts:
await ExecuteScriptsWorkflowAsync();
break;
default:
throw new ArgumentOutOfRangeException();
GeneralTracer.Info("UpgradeUpdateStrategy: no updates to apply, starting application directly.");
}

_osStrategy.StartApp();
}
catch (Exception ex)
{
Expand All @@ -79,57 +72,6 @@ public void StartApp()
_osStrategy?.StartApp();
}

#region Scripts Mode Workflow

private async Task ExecuteScriptsWorkflowAsync()
{
GeneralTracer.Info($"UpgradeUpdateStrategy: validating version. Url={_configInfo!.UpdateUrl}, Version={_configInfo.ClientVersion}");

var mainResp = await VersionService.Validate(
_configInfo.UpdateUrl, _configInfo.ClientVersion,
AppType.ClientApp, _configInfo.AppSecretKey,
GetPlatform(), _configInfo.ProductId,
_configInfo.Scheme, _configInfo.Token);

_configInfo.IsMainUpdate = CheckUpgrade(mainResp);
EventManager.Instance.Dispatch(this, new UpdateInfoEventArgs(mainResp));

if (CheckForcibly(mainResp.Body) == false && ShouldSkip())
{
GeneralTracer.Info("UpgradeUpdateStrategy: update skipped.");
return;
}

InitBlackList();
ApplyRuntimeOptions();

_configInfo.TempPath = StorageManager.GetTempDirectory("main_temp");
_configInfo.BackupDirectory = Path.Combine(
_configInfo.InstallPath,
$"{StorageManager.DirectoryName}{_configInfo.ClientVersion}");

_configInfo.UpdateVersions = mainResp.Body!
.OrderBy(x => x.ReleaseDate).ToList();

Backup();

_osStrategy!.Create(_configInfo);

if (_configInfo.IsMainUpdate)
{
GeneralTracer.Info("UpgradeUpdateStrategy: main update required.");
await DownloadAsync();
await _osStrategy.ExecuteAsync();
}
else
{
GeneralTracer.Info("UpgradeUpdateStrategy: no update needed, starting application.");
_osStrategy.StartApp();
}
}

#endregion

#region Helpers

private static IStrategy ResolveOsStrategy()
Expand All @@ -138,57 +80,15 @@ private static IStrategy ResolveOsStrategy()
return new WindowsStrategy();
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return new LinuxStrategy();
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
return new MacStrategy();
throw new PlatformNotSupportedException("The current operating system is not supported!");
}

private void StrategyFactory()
{
_osStrategy ??= ResolveOsStrategy();
}

private void ApplyRuntimeOptions()
{
_configInfo!.Encoding = Encoding.UTF8;
_configInfo.Format = Format.ZIP;
_configInfo.DownloadTimeOut = 60;
}

private void InitBlackList()
{
BlackListManager.Instance.AddBlackFiles(_configInfo!.BlackFiles);
BlackListManager.Instance.AddBlackFormats(_configInfo.BlackFormats);
BlackListManager.Instance.AddSkipDirectorys(_configInfo.SkipDirectorys);
}

private void Backup()
{
GeneralTracer.Info($"UpgradeUpdateStrategy: backing up {_configInfo!.InstallPath} -> {_configInfo.BackupDirectory}");
StorageManager.Backup(_configInfo.InstallPath, _configInfo.BackupDirectory,
BlackListManager.Instance.SkipDirectorys);
}

private async Task DownloadAsync()
{
var manager = new DownloadManager(
_configInfo!.TempPath, _configInfo.Format, _configInfo.DownloadTimeOut);
foreach (var version in _configInfo.UpdateVersions)
manager.Add(new DownloadTask(manager, version));
await manager.LaunchTasksAsync();
}

private static bool ShouldSkip() => false;

private static bool CheckUpgrade(VersionRespDTO? response)
=> response?.Code == 200 && response.Body?.Count > 0;

private static bool CheckForcibly(IEnumerable<VersionInfo>? versions)
=> versions?.Any(v => v.IsForcibly == true) == true;

private static int GetPlatform()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return PlatformType.Windows;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return PlatformType.Linux;
return -1;
}

#endregion
Expand Down
4 changes: 2 additions & 2 deletions src/c#/GeneralUpdate.Core/Strategy/WindowsStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ public override void StartApp()
{
GeneralTracer.Info("GeneralUpdate.Core.WindowsStrategy.StartApp: releasing tracer and terminating updater process.");
GeneralTracer.Dispose();
Process.GetCurrentProcess().Kill();
GracefulExit.CurrentProcessAsync().GetAwaiter().GetResult();
}
}
}
}
}
Loading