From 59f7a392ce2915e7696040261b49d58248a6274e Mon Sep 17 00:00:00 2001 From: JusterZhu Date: Sun, 24 May 2026 16:29:02 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20Phase=201=20=E2=80=94=20role-based?= =?UTF-8?q?=20strategy=20architecture=20with=20unified=20OSS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added AppType.OSSApp = 3 for OSS update mode - Created OSSUpdateStrategy (implements IStrategy), absorbs old OSSStrategy logic - Bootstrap now dispatches to OSS on AppType.OSSApp: client-side: download version config, compare, start upgrade process upgrade-side: read GlobalConfigInfoOSS from env, execute OSSUpdateStrategy - Removed legacy files: OSSStrategy.cs, GeneralUpdateOSS.cs, GeneralClientOSS.cs - OSS mode is now fully built-in — no separate entry classes needed Closes #352 --- .../Bootstrap/GeneralClientOSS.cs | 102 -------------- .../Bootstrap/GeneralUpdateBootstrap.cs | 2 +- .../Bootstrap/GeneralUpdateOSS.cs | 61 --------- .../Configuration/AppType.cs | 8 +- .../Strategy/OSSStrategy.cs | 125 ------------------ .../Strategy/OSSUpdateStrategy.cs | 124 +++++++++++++++++ 6 files changed, 132 insertions(+), 290 deletions(-) delete mode 100644 src/c#/GeneralUpdate.Core/Bootstrap/GeneralClientOSS.cs delete mode 100644 src/c#/GeneralUpdate.Core/Bootstrap/GeneralUpdateOSS.cs delete mode 100644 src/c#/GeneralUpdate.Core/Strategy/OSSStrategy.cs create mode 100644 src/c#/GeneralUpdate.Core/Strategy/OSSUpdateStrategy.cs diff --git a/src/c#/GeneralUpdate.Core/Bootstrap/GeneralClientOSS.cs b/src/c#/GeneralUpdate.Core/Bootstrap/GeneralClientOSS.cs deleted file mode 100644 index 93367ff9..00000000 --- a/src/c#/GeneralUpdate.Core/Bootstrap/GeneralClientOSS.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Net; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; -using GeneralUpdate.Core.FileSystem; -using GeneralUpdate.Core; -using GeneralUpdate.Core.Configuration; -using GeneralUpdate.Core.JsonContext; -using GeneralUpdate.Core.Configuration; - -namespace GeneralUpdate.Core; - -[Obsolete("Use GeneralUpdateBootstrap with AppType=AppType.OSS instead.")] public sealed class GeneralClientOSS -{ - private GeneralClientOSS() { } - - /// - /// Starting an OSS update for windows platform. - /// - public static async Task Start(GlobalConfigInfoOSS configGlobalConfigInfo, string upgradeAppName = "GeneralUpdate.Upgrade.exe") - { - await Task.Run(() => - { - try - { - GeneralTracer.Debug("1.Starting OSS upgrade mode."); - var basePath = Thread.GetDomain().BaseDirectory; - //Download the version information file from OSS to be updated.(JSON) - GeneralTracer.Debug("2.Download the version information file from OSS to be updated.(JSON)"); - var versionsFilePath = Path.Combine(basePath, configGlobalConfigInfo.VersionFileName); - DownloadFile(configGlobalConfigInfo.Url, versionsFilePath); - if (!File.Exists(versionsFilePath)) return; - var versions = StorageManager.GetJson>(versionsFilePath, - VersionOSSJsonContext.Default.ListVersionOSS); - if (versions == null || versions.Count == 0) return; - versions = versions.OrderByDescending(x => x.PubTime).ToList(); - var newVersion = versions.First(); - //Determine whether the current client version needs to be upgraded. - GeneralTracer.Debug("3.Determine whether the current client version needs to be upgraded."); - if (!IsUpgrade(configGlobalConfigInfo.CurrentVersion, newVersion.Version)) - return; - - //If you confirm that an update is required, start the upgrade application. - var appPath = Path.Combine(basePath, $"{upgradeAppName}"); - if (!File.Exists(appPath)) - throw new Exception($"The application does not exist {upgradeAppName} !"); - - GeneralTracer.Debug("4.Start upgrade app."); - var json = JsonSerializer.Serialize(configGlobalConfigInfo, - GlobalConfigInfoOSSJsonContext.Default.GlobalConfigInfoOSS); - Environments.SetEnvironmentVariable("GlobalConfigInfoOSS", json); - Process.Start(appPath); - Process.GetCurrentProcess().Kill(); - } - catch (Exception exception) - { - GeneralTracer.Error("The BaseStart method in the GeneralClientOSS class throws an exception.", - exception); - throw exception; - } - finally - { - GeneralTracer.Dispose(); - } - }); - } - - /// - /// Determine whether the current client version needs to be upgraded. - /// - /// - /// - /// true: Upgrade required , false: No upgrade is required - private static bool IsUpgrade(string clientVersion, string serverVersion) - { - if (string.IsNullOrWhiteSpace(clientVersion) || string.IsNullOrWhiteSpace(serverVersion)) - return false; - - var isParseClientVersion = Version.TryParse(clientVersion, out var currentClientVersion); - var isParseServerVersion = Version.TryParse(serverVersion, out var currentServerVersion); - if (!isParseClientVersion || !isParseServerVersion) return false; - if (currentClientVersion < currentServerVersion) return true; - return false; - } - - private static void DownloadFile(string url, string path) - { - if (File.Exists(path)) - { - File.SetAttributes(path, FileAttributes.Normal); - File.Delete(path); - } - - using var webClient = new WebClient(); - webClient.DownloadFile(new Uri(url), path); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Bootstrap/GeneralUpdateBootstrap.cs b/src/c#/GeneralUpdate.Core/Bootstrap/GeneralUpdateBootstrap.cs index d8f4a7cf..45955b18 100644 --- a/src/c#/GeneralUpdate.Core/Bootstrap/GeneralUpdateBootstrap.cs +++ b/src/c#/GeneralUpdate.Core/Bootstrap/GeneralUpdateBootstrap.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; diff --git a/src/c#/GeneralUpdate.Core/Bootstrap/GeneralUpdateOSS.cs b/src/c#/GeneralUpdate.Core/Bootstrap/GeneralUpdateOSS.cs deleted file mode 100644 index c315b0b3..00000000 --- a/src/c#/GeneralUpdate.Core/Bootstrap/GeneralUpdateOSS.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Text.Json; -using System.Threading.Tasks; -using GeneralUpdate.Core.Configuration; -using GeneralUpdate.Core.JsonContext; -using GeneralUpdate.Core; -using GeneralUpdate.Core.Configuration; -using GeneralUpdate.Core.Strategy; - -namespace GeneralUpdate.Core -{ - [Obsolete("Use GeneralUpdateBootstrap with AppType=AppType.OSS instead. See UpdateOptions.AppType.")] - public sealed class GeneralUpdateOSS - { - private GeneralUpdateOSS() { } - - #region Public Methods - - /// - /// Starting an OSS update for windows,Linux,mac platform. - /// - /// - public static async Task Start()=> await BaseStart(); - - #endregion Public Methods - - #region Private Methods - - /// - /// The underlying update method. - /// - private static async Task BaseStart() - { - try - { - GeneralTracer.Debug("Starting OSS upgrade mode."); - var json = Environments.GetEnvironmentVariable("GlobalConfigInfoOSS"); - if (string.IsNullOrWhiteSpace(json)) - return; - - var parameter = JsonSerializer.Deserialize(json, - GlobalConfigInfoOSSJsonContext.Default.GlobalConfigInfoOSS); - var strategy = new OSSStrategy(); - strategy.Create(parameter); - await strategy.ExecuteAsync(); - } - catch (Exception exception) - { - GeneralTracer.Error("The BaseStart method in the GeneralUpdateOSS class throws an exception.", - exception); - throw exception; - } - finally - { - GeneralTracer.Dispose(); - } - } - - #endregion Private Methods - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Configuration/AppType.cs b/src/c#/GeneralUpdate.Core/Configuration/AppType.cs index 3789495c..5eeb8780 100644 --- a/src/c#/GeneralUpdate.Core/Configuration/AppType.cs +++ b/src/c#/GeneralUpdate.Core/Configuration/AppType.cs @@ -11,5 +11,11 @@ public class AppType /// upgrade program. /// public const int UpgradeApp = 2; + + /// + /// OSS (Object Storage Service) update mode. + /// Downloads packages from cloud storage without a dedicated update server. + /// + public const int OSSApp = 3; } -} \ No newline at end of file +} diff --git a/src/c#/GeneralUpdate.Core/Strategy/OSSStrategy.cs b/src/c#/GeneralUpdate.Core/Strategy/OSSStrategy.cs deleted file mode 100644 index 06ba4e90..00000000 --- a/src/c#/GeneralUpdate.Core/Strategy/OSSStrategy.cs +++ /dev/null @@ -1,125 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using GeneralUpdate.Core.Compress; -using GeneralUpdate.Core.FileSystem; -using GeneralUpdate.Core.Download; -using GeneralUpdate.Core.JsonContext; -using GeneralUpdate.Core; -using GeneralUpdate.Core.Configuration; - -namespace GeneralUpdate.Core.Strategy -{ - public class OSSStrategy - { - #region Private Members - - private readonly string _appPath = AppDomain.CurrentDomain.BaseDirectory; - private const int TimeOut = 60; - private GlobalConfigInfoOSS? _parameter; - - #endregion Private Members - - #region Public Methods - - public void Create(GlobalConfigInfoOSS parameter) - => _parameter = parameter; - - public async Task ExecuteAsync() - { - try - { - //1.Download the JSON version configuration file. - GeneralTracer.Debug("1.Download the JSON version configuration file."); - var jsonPath = Path.Combine(_appPath, _parameter.VersionFileName); - if (!File.Exists(jsonPath)) - throw new FileNotFoundException(jsonPath); - - //2.Parse the JSON version configuration file content. - GeneralTracer.Debug("2.Parse the JSON version configuration file content."); - var versions = StorageManager.GetJson>(jsonPath, VersionOSSJsonContext.Default.ListVersionOSS); - if (versions == null) - throw new NullReferenceException(nameof(versions)); - - versions = versions.OrderBy(v => v.PubTime).ToList(); - //3.Download version by version according to the version of the configuration file. - GeneralTracer.Debug("3.Download version by version according to the version of the configuration file."); - await DownloadVersions(versions); - Decompress(versions); - - //4.Launch the main application. - GeneralTracer.Debug("4.Launch the main application."); - LaunchApp(); - } - catch (Exception ex) - { - GeneralTracer.Error("The ExecuteAsync method in the OSSStrategy class throws an exception.", ex); - } - finally - { - Process.GetCurrentProcess().Kill(); - } - } - - #endregion Public Methods - - #region Private Methods - - /// - /// Download all updated versions version by version. - /// - /// The collection of version information to be updated as described in the configuration file. - private async Task DownloadVersions(List versions) - { - var manager = new DownloadManager(_appPath, Format.ZIP, TimeOut); - foreach (var versionInfo in versions) - { - var version = new VersionInfo - { - Name = versionInfo.PacketName, - Version = versionInfo.Version, - Url = versionInfo.Url, - Format = Format.ZIP, - Hash = versionInfo.Hash - }; - manager.Add(new DownloadTask(manager, version)); - } - - await manager.LaunchTasksAsync(); - } - - /// - /// Start the main application when the update is complete. - /// - /// - private void LaunchApp() - { - var appPath = Path.Combine(_appPath, _parameter.AppName); - if (!File.Exists(appPath)) throw new FileNotFoundException($"{nameof(appPath)} , The application is not accessible !"); - Process.Start(appPath); - - GeneralTracer.Debug("5.Upgrade complete."); - GeneralTracer.Dispose(); - } - - private void Decompress(List versions) - { - var encoding = Encoding.GetEncoding(_parameter.Encoding); - foreach (var version in versions) - { - var zipFilePath = Path.Combine(_appPath, $"{version.PacketName}{Format.ZIP}"); - CompressProvider.Decompress(Format.ZIP, zipFilePath, _appPath, encoding); - - if (!File.Exists(zipFilePath)) continue; - File.SetAttributes(zipFilePath, FileAttributes.Normal); - File.Delete(zipFilePath); - } - } - - #endregion Private Methods - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/Strategy/OSSUpdateStrategy.cs b/src/c#/GeneralUpdate.Core/Strategy/OSSUpdateStrategy.cs new file mode 100644 index 00000000..13b4f7fb --- /dev/null +++ b/src/c#/GeneralUpdate.Core/Strategy/OSSUpdateStrategy.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using GeneralUpdate.Core.Compress; +using GeneralUpdate.Core.FileSystem; +using GeneralUpdate.Core.Download; +using GeneralUpdate.Core.JsonContext; +using GeneralUpdate.Core.Configuration; + +namespace GeneralUpdate.Core.Strategy; + +/// +/// OSS (Object Storage Service) update strategy. +/// Downloads version configuration, fetches update packages from OSS, +/// decompresses them, and launches the main application. +/// +/// +/// This replaces the legacy OSSStrategy and GeneralUpdateOSS classes. +/// The OSS workflow is OS-agnostic — no platform-specific pipeline is required. +/// +public class OSSUpdateStrategy : IStrategy +{ + private GlobalConfigInfo? _configInfo; + private readonly string _appPath = AppDomain.CurrentDomain.BaseDirectory; + private const int TimeOut = 60; + + public void Create(GlobalConfigInfo parameter) + { + _configInfo = parameter ?? throw new ArgumentNullException(nameof(parameter)); + } + + public async Task ExecuteAsync() + { + if (_configInfo == null) + throw new InvalidOperationException("OSSUpdateStrategy not configured. Call Create() first."); + + try + { + var versionFileName = $"{_configInfo.MainAppName ?? _configInfo.AppName}_versions.json"; + + GeneralTracer.Debug("OSSUpdateStrategy: 1. Reading version configuration file."); + var jsonPath = Path.Combine(_appPath, versionFileName); + if (!File.Exists(jsonPath)) + throw new FileNotFoundException(jsonPath); + + GeneralTracer.Debug("OSSUpdateStrategy: 2. Parsing version configuration."); + var versions = StorageManager.GetJson>(jsonPath, + VersionOSSJsonContext.Default.ListVersionOSS); + if (versions == null || versions.Count == 0) + throw new InvalidOperationException("No versions found in OSS configuration."); + + versions = versions.OrderBy(v => v.PubTime).ToList(); + + GeneralTracer.Debug($"OSSUpdateStrategy: 3. Downloading {versions.Count} version(s)."); + await DownloadVersionsAsync(versions); + + GeneralTracer.Debug("OSSUpdateStrategy: 4. Decompressing packages."); + Decompress(versions); + + GeneralTracer.Debug("OSSUpdateStrategy: 5. Launching main application."); + StartApp(); + } + catch (Exception ex) + { + GeneralTracer.Error("OSSUpdateStrategy.ExecuteAsync failed.", ex); + throw; + } + } + + public void Execute() + { + ExecuteAsync().GetAwaiter().GetResult(); + } + + public void StartApp() + { + var appName = _configInfo?.MainAppName ?? _configInfo?.AppName; + if (string.IsNullOrEmpty(appName)) return; + + var appPath = Path.Combine(_appPath, appName); + if (!File.Exists(appPath)) + throw new FileNotFoundException($"Application not found: {appPath}"); + + Process.Start(appPath); + GeneralTracer.Debug("OSSUpdateStrategy: application started."); + } + + private async Task DownloadVersionsAsync(List versions) + { + var manager = new DownloadManager(_appPath, Format.ZIP, TimeOut); + foreach (var versionInfo in versions) + { + var version = new VersionInfo + { + Name = versionInfo.PacketName, + Version = versionInfo.Version, + Url = versionInfo.Url, + Format = Format.ZIP, + Hash = versionInfo.Hash + }; + manager.Add(new DownloadTask(manager, version)); + } + + await manager.LaunchTasksAsync(); + } + + private void Decompress(List versions) + { + var encoding = Encoding.GetEncoding(_configInfo?.Encoding?.CodePage ?? Encoding.UTF8.CodePage); + foreach (var version in versions) + { + var zipFilePath = Path.Combine(_appPath, $"{version.PacketName}{Format.ZIP}"); + CompressProvider.Decompress(Format.ZIP, zipFilePath, _appPath, encoding); + + if (!File.Exists(zipFilePath)) continue; + File.SetAttributes(zipFilePath, FileAttributes.Normal); + File.Delete(zipFilePath); + } + } +}