diff --git a/src/c#/GeneralUpdate.Bowl/Bowl.cs b/src/c#/GeneralUpdate.Bowl/Bowl.cs index 2b308a37..a2737421 100644 --- a/src/c#/GeneralUpdate.Bowl/Bowl.cs +++ b/src/c#/GeneralUpdate.Bowl/Bowl.cs @@ -6,11 +6,11 @@ using GeneralUpdate.Bowl.Internal; using GeneralUpdate.Bowl.Strategies; using GeneralUpdate.Bowl.Strategys; -using GeneralUpdate.Common.FileBasic; -using GeneralUpdate.Common.Internal.Bootstrap; -using GeneralUpdate.Common.Internal.JsonContext; -using GeneralUpdate.Common.Shared; -using GeneralUpdate.Common.Shared.Object; +using GeneralUpdate.Core.FileSystem; +using GeneralUpdate.Core.Configuration; +using GeneralUpdate.Core.JsonContext; +using GeneralUpdate.Core; +using GeneralUpdate.Core.Configuration; namespace GeneralUpdate.Bowl; diff --git a/src/c#/GeneralUpdate.Bowl/GeneralUpdate.Bowl.csproj b/src/c#/GeneralUpdate.Bowl/GeneralUpdate.Bowl.csproj index 23557576..2379360a 100644 --- a/src/c#/GeneralUpdate.Bowl/GeneralUpdate.Bowl.csproj +++ b/src/c#/GeneralUpdate.Bowl/GeneralUpdate.Bowl.csproj @@ -1,4 +1,4 @@ - + default enable @@ -17,81 +17,27 @@ bowl.jpeg netstandard2.0; + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + PreserveNewest true - - - + + True diff --git a/src/c#/GeneralUpdate.Bowl/Internal/CrashReporter.cs b/src/c#/GeneralUpdate.Bowl/Internal/CrashReporter.cs index 2347a0de..2aba8195 100644 --- a/src/c#/GeneralUpdate.Bowl/Internal/CrashReporter.cs +++ b/src/c#/GeneralUpdate.Bowl/Internal/CrashReporter.cs @@ -3,8 +3,8 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -using GeneralUpdate.Common.FileBasic; -using GeneralUpdate.Common.Shared; +using GeneralUpdate.Core.FileSystem; +using GeneralUpdate.Core; namespace GeneralUpdate.Bowl.Internal; diff --git a/src/c#/GeneralUpdate.Bowl/Internal/EnvironmentProvider.cs b/src/c#/GeneralUpdate.Bowl/Internal/EnvironmentProvider.cs index 661ea018..fad2ae8a 100644 --- a/src/c#/GeneralUpdate.Bowl/Internal/EnvironmentProvider.cs +++ b/src/c#/GeneralUpdate.Bowl/Internal/EnvironmentProvider.cs @@ -1,6 +1,6 @@ using System.Threading; using System.Threading.Tasks; -using GeneralUpdate.Common.Internal.Bootstrap; +using GeneralUpdate.Core.Configuration; namespace GeneralUpdate.Bowl.Internal; diff --git a/src/c#/GeneralUpdate.Bowl/Internal/WindowsSystemInfoProvider.cs b/src/c#/GeneralUpdate.Bowl/Internal/WindowsSystemInfoProvider.cs index d4c8de07..c5fcd292 100644 --- a/src/c#/GeneralUpdate.Bowl/Internal/WindowsSystemInfoProvider.cs +++ b/src/c#/GeneralUpdate.Bowl/Internal/WindowsSystemInfoProvider.cs @@ -3,7 +3,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -using GeneralUpdate.Common.Shared; +using GeneralUpdate.Core; namespace GeneralUpdate.Bowl.Internal; diff --git a/src/c#/GeneralUpdate.Bowl/Strategies/LinuxBowlStrategy.cs b/src/c#/GeneralUpdate.Bowl/Strategies/LinuxBowlStrategy.cs index b0f97827..6a48f1e1 100644 --- a/src/c#/GeneralUpdate.Bowl/Strategies/LinuxBowlStrategy.cs +++ b/src/c#/GeneralUpdate.Bowl/Strategies/LinuxBowlStrategy.cs @@ -5,7 +5,7 @@ using System.Threading; using System.Threading.Tasks; using GeneralUpdate.Bowl.Internal; -using GeneralUpdate.Common.Shared; +using GeneralUpdate.Core; namespace GeneralUpdate.Bowl.Strategies; diff --git a/src/c#/GeneralUpdate.Bowl/Strategies/MacBowlStrategy.cs b/src/c#/GeneralUpdate.Bowl/Strategies/MacBowlStrategy.cs index 92411947..9d5f3198 100644 --- a/src/c#/GeneralUpdate.Bowl/Strategies/MacBowlStrategy.cs +++ b/src/c#/GeneralUpdate.Bowl/Strategies/MacBowlStrategy.cs @@ -3,7 +3,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -using GeneralUpdate.Common.Shared; +using GeneralUpdate.Core; namespace GeneralUpdate.Bowl.Strategies; diff --git a/src/c#/GeneralUpdate.Bowl/Strategies/ProcessRunner.cs b/src/c#/GeneralUpdate.Bowl/Strategies/ProcessRunner.cs index 356113ac..2b679897 100644 --- a/src/c#/GeneralUpdate.Bowl/Strategies/ProcessRunner.cs +++ b/src/c#/GeneralUpdate.Bowl/Strategies/ProcessRunner.cs @@ -3,7 +3,7 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; -using GeneralUpdate.Common.Shared; +using GeneralUpdate.Core; namespace GeneralUpdate.Bowl.Strategies; diff --git a/src/c#/GeneralUpdate.Bowl/Strategies/WindowsBowlStrategy.cs b/src/c#/GeneralUpdate.Bowl/Strategies/WindowsBowlStrategy.cs index b7e4cc88..dd1c2bfe 100644 --- a/src/c#/GeneralUpdate.Bowl/Strategies/WindowsBowlStrategy.cs +++ b/src/c#/GeneralUpdate.Bowl/Strategies/WindowsBowlStrategy.cs @@ -4,8 +4,8 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -using GeneralUpdate.Common.FileBasic; -using GeneralUpdate.Common.Shared; +using GeneralUpdate.Core.FileSystem; +using GeneralUpdate.Core; namespace GeneralUpdate.Bowl.Strategies; diff --git a/src/c#/GeneralUpdate.Bowl/Strategys/AbstractStrategy.cs b/src/c#/GeneralUpdate.Bowl/Strategys/AbstractStrategy.cs index cf7ad3c0..b207b8a1 100644 --- a/src/c#/GeneralUpdate.Bowl/Strategys/AbstractStrategy.cs +++ b/src/c#/GeneralUpdate.Bowl/Strategys/AbstractStrategy.cs @@ -1,8 +1,8 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Diagnostics; using System.IO; -using GeneralUpdate.Common.FileBasic; -using GeneralUpdate.Common.Shared; +using GeneralUpdate.Core.FileSystem; +using GeneralUpdate.Core; namespace GeneralUpdate.Bowl.Strategys; diff --git a/src/c#/GeneralUpdate.Bowl/Strategys/LinuxStrategy.cs b/src/c#/GeneralUpdate.Bowl/Strategys/LinuxStrategy.cs index 24517ae9..03af8d7e 100644 --- a/src/c#/GeneralUpdate.Bowl/Strategys/LinuxStrategy.cs +++ b/src/c#/GeneralUpdate.Bowl/Strategys/LinuxStrategy.cs @@ -1,10 +1,10 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using GeneralUpdate.Bowl.Internal; -using GeneralUpdate.Common.Shared; +using GeneralUpdate.Core; namespace GeneralUpdate.Bowl.Strategys; diff --git a/src/c#/GeneralUpdate.Bowl/Strategys/WindowStrategy.cs b/src/c#/GeneralUpdate.Bowl/Strategys/WindowStrategy.cs index 9e06b56b..dd8a2130 100644 --- a/src/c#/GeneralUpdate.Bowl/Strategys/WindowStrategy.cs +++ b/src/c#/GeneralUpdate.Bowl/Strategys/WindowStrategy.cs @@ -1,12 +1,12 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using GeneralUpdate.Bowl.Internal; -using GeneralUpdate.Common.FileBasic; -using GeneralUpdate.Common.Internal.Bootstrap; -using GeneralUpdate.Common.Shared; +using GeneralUpdate.Core.FileSystem; +using GeneralUpdate.Core.Configuration; +using GeneralUpdate.Core; namespace GeneralUpdate.Bowl.Strategys; diff --git a/src/c#/GeneralUpdate.ClientCore/Common/git.keep b/src/c#/GeneralUpdate.ClientCore/Common/git.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/c#/GeneralUpdate.ClientCore/GeneralClientBootstrap.cs b/src/c#/GeneralUpdate.ClientCore/GeneralClientBootstrap.cs deleted file mode 100644 index 1843613f..00000000 --- a/src/c#/GeneralUpdate.ClientCore/GeneralClientBootstrap.cs +++ /dev/null @@ -1,467 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Text.Json; -using System.Threading.Tasks; -using GeneralUpdate.ClientCore.Strategys; -using GeneralUpdate.Common.FileBasic; -using GeneralUpdate.Common.Download; -using GeneralUpdate.Common.Internal; -using GeneralUpdate.Common.Internal.Bootstrap; -using GeneralUpdate.Common.Internal.Event; -using GeneralUpdate.Common.Internal.JsonContext; -using GeneralUpdate.Common.Internal.Strategy; -using GeneralUpdate.Common.Shared; -using GeneralUpdate.Common.Shared.Object; -using GeneralUpdate.Common.Shared.Object.Enum; -using GeneralUpdate.Common.Shared.Service; - -namespace GeneralUpdate.ClientCore; - -/// -/// This component is used only for client application bootstrapping classes. -/// -public class GeneralClientBootstrap : AbstractBootstrap -{ - /// - /// All update actions of the core object for automatic upgrades will be related to the packet object. - /// - private GlobalConfigInfo? _configInfo; - private IStrategy? _strategy; - private Func? _updatePrecheck; - private readonly List> _customOptions = new(); - - #region Public Methods - - /// - /// Main function for booting the update startup. - /// - /// - public override async Task LaunchAsync() - { - try - { - GeneralTracer.Debug("GeneralClientBootstrap Launch."); - CallSmallBowlHome(_configInfo.Bowl); - ExecuteCustomOptions(); - await ExecuteWorkflowAsync(); - } - catch (Exception exception) - { - GeneralTracer.Error("The LaunchAsync method in the GeneralClientBootstrap class throws an exception." , exception); - EventManager.Instance.Dispatch(this, new ExceptionEventArgs(exception, exception.Message)); - } - return this; - } - - /// - /// Configure server address (Recommended Windows,Linux,Mac). - /// - public GeneralClientBootstrap SetConfig(Configinfo configInfo) - { - Debug.Assert(configInfo != null, "configInfo should not be null"); - configInfo?.Validate(); - - // Use ConfigurationMapper instead of manual field mapping - // This ensures all fields are consistently mapped and reduces maintenance burden - _configInfo = ConfigurationMapper.MapToGlobalConfigInfo(configInfo); - - return this; - } - - /// - /// Registers a callback that is invoked when update information is available. - /// The callback receives the full and returns - /// true to skip the update or false to proceed with the automatic upgrade. - /// Built-in forced-update protection is still applied; if any version is marked as - /// forcibly required the callback return value is ignored and the update proceeds. - /// - /// - /// A function that receives containing complete update - /// details and returns true to skip, or false to proceed with the update. - /// - /// The current bootstrap instance for fluent method chaining. - public GeneralClientBootstrap AddListenerUpdatePrecheck(Func func) - { - if (func == null) throw new ArgumentNullException(nameof(func)); - _updatePrecheck = func; - return this; - } - - /// - /// Add an asynchronous custom operation. - /// In theory, any custom operation can be done. It is recommended to register the environment check method to ensure - /// that there are normal dependencies and environments after the update is completed. - /// - public GeneralClientBootstrap AddCustomOption(List> funcList) - { - Debug.Assert(funcList != null && funcList.Any()); - _customOptions.AddRange(funcList); - return this; - } - - public GeneralClientBootstrap AddListenerMultiAllDownloadCompleted( - Action callbackAction) - => AddListener(callbackAction); - - public GeneralClientBootstrap AddListenerMultiDownloadCompleted( - Action callbackAction) - => AddListener(callbackAction); - - public GeneralClientBootstrap AddListenerMultiDownloadError( - Action callbackAction) - => AddListener(callbackAction); - - public GeneralClientBootstrap AddListenerMultiDownloadStatistics( - Action callbackAction) - => AddListener(callbackAction); - - public GeneralClientBootstrap AddListenerException(Action callbackAction) - => AddListener(callbackAction); - - public GeneralClientBootstrap AddListenerUpdateInfo(Action callbackAction) - => AddListener(callbackAction); - - #endregion Public Methods - - #region Private Methods - - private async Task ExecuteWorkflowAsync() - { - try - { - Debug.Assert(_configInfo != null); - if (GetOption(UpdateOption.EnableSilentUpdate)) - { - GeneralTracer.Info("GeneralClientBootstrap.ExecuteWorkflowAsync: silent update mode enabled, delegating to SilentUpdateMode."); - await new SilentUpdateMode( - _configInfo, - GetOption(UpdateOption.Encoding) ?? Encoding.Default, - GetOption(UpdateOption.Format) ?? Format.ZIP, - GetOption(UpdateOption.DownloadTimeOut) ?? 60, - GetOption(UpdateOption.Patch) ?? true, - GetOption(UpdateOption.BackUp) ?? true).StartAsync(); - return; - } - //Request the upgrade information needed by the client and upgrade end, and determine if an upgrade is necessary. - GeneralTracer.Info($"GeneralClientBootstrap.ExecuteWorkflowAsync: validating client version={_configInfo.ClientVersion} and upgrade version={_configInfo.UpgradeClientVersion}"); - var mainResp = await VersionService.Validate(_configInfo.UpdateUrl - , _configInfo.ClientVersion - , AppType.ClientApp - , _configInfo.AppSecretKey - , GetPlatform() - , _configInfo.ProductId - , _configInfo.Scheme - , _configInfo.Token); - - var upgradeResp = await VersionService.Validate(_configInfo.UpdateUrl - , _configInfo.UpgradeClientVersion - , AppType.UpgradeApp - , _configInfo.AppSecretKey - , GetPlatform() - , _configInfo.ProductId - , _configInfo.Scheme - , _configInfo.Token); - - _configInfo.IsUpgradeUpdate = CheckUpgrade(upgradeResp); - _configInfo.IsMainUpdate = CheckUpgrade(mainResp); - GeneralTracer.Info($"GeneralClientBootstrap.ExecuteWorkflowAsync: version validation completed. IsMainUpdate={_configInfo.IsMainUpdate}, IsUpgradeUpdate={_configInfo.IsUpgradeUpdate}"); - - var updateInfoArgs = new UpdateInfoEventArgs(mainResp); - EventManager.Instance.Dispatch(this, updateInfoArgs); - - //If the main program needs to be forced to update, the skip will not take effect. - var isForcibly = CheckForcibly(mainResp.Body) || CheckForcibly(upgradeResp.Body); - if (CanSkip(isForcibly, updateInfoArgs)) - { - GeneralTracer.Info("GeneralClientBootstrap.ExecuteWorkflowAsync: update skipped by precheck callback."); - return; - } - - //black list initialization. - BlackListManager.Instance?.AddBlackFiles(_configInfo.BlackFiles); - BlackListManager.Instance?.AddBlackFileFormats(_configInfo.BlackFormats); - BlackListManager.Instance?.AddSkipDirectorys(_configInfo.SkipDirectorys); - - _configInfo.Encoding = GetOption(UpdateOption.Encoding) ?? Encoding.Default; - _configInfo.Format = GetOption(UpdateOption.Format) ?? Format.ZIP; - _configInfo.DownloadTimeOut = GetOption(UpdateOption.DownloadTimeOut) ?? 60; - _configInfo.DriveEnabled = GetOption(UpdateOption.Drive) ?? false; - _configInfo.PatchEnabled = GetOption(UpdateOption.Patch) ?? true; - _configInfo.TempPath = StorageManager.GetTempDirectory("main_temp"); - _configInfo.BackupDirectory = Path.Combine(_configInfo.InstallPath, - $"{StorageManager.DirectoryName}{_configInfo.ClientVersion}"); - - _configInfo.UpdateVersions = _configInfo.IsUpgradeUpdate ? upgradeResp.Body.OrderBy(x => x.ReleaseDate).ToList() : []; - - if (_configInfo.IsMainUpdate) - { - _configInfo.LastVersion = mainResp.Body.OrderBy(x => x.ReleaseDate).Last().Version; - GeneralTracer.Info($"GeneralClientBootstrap.ExecuteWorkflowAsync: main update required, LastVersion={_configInfo.LastVersion}"); - - var failed = CheckFail(_configInfo.LastVersion); - if (failed) - { - GeneralTracer.Warn($"GeneralClientBootstrap.ExecuteWorkflowAsync: version {_configInfo.LastVersion} matches or precedes a known failed upgrade, aborting."); - return; - } - - // Use ConfigurationMapper to create ProcessInfo instead of manual parameter passing - // This centralizes the complex parameter mapping logic and reduces errors - var processInfo = ConfigurationMapper.MapToProcessInfo( - _configInfo, - mainResp.Body, - BlackListManager.Instance.BlackFileFormats.ToList(), - BlackListManager.Instance.BlackFiles.ToList(), - BlackListManager.Instance.SkipDirectorys.ToList()); - - _configInfo.ProcessInfo = - JsonSerializer.Serialize(processInfo, ProcessInfoJsonContext.Default.ProcessInfo); - } - - if (GetOption(UpdateOption.BackUp) ?? true) - { - GeneralTracer.Info($"GeneralClientBootstrap.ExecuteWorkflowAsync: backing up from {_configInfo.InstallPath} to {_configInfo.BackupDirectory}"); - StorageManager.Backup(_configInfo.InstallPath - , _configInfo.BackupDirectory - , BlackListManager.Instance.SkipDirectorys); - GeneralTracer.Info("GeneralClientBootstrap.ExecuteWorkflowAsync: backup completed."); - } - - StrategyFactory(); - GeneralTracer.Info($"GeneralClientBootstrap.ExecuteWorkflowAsync: executing update scenario. IsUpgradeUpdate={_configInfo.IsUpgradeUpdate}, IsMainUpdate={_configInfo.IsMainUpdate}"); - switch (_configInfo.IsUpgradeUpdate) - { - case true when _configInfo.IsMainUpdate: - //Both upgrade and main program update. - GeneralTracer.Info("GeneralClientBootstrap.ExecuteWorkflowAsync: both upgrade and main update required - downloading and executing."); - await Download(); - await _strategy?.ExecuteAsync()!; - _strategy?.StartApp(); - break; - case true when !_configInfo.IsMainUpdate: - //Upgrade program update. - GeneralTracer.Info("GeneralClientBootstrap.ExecuteWorkflowAsync: upgrade-only update - downloading and executing."); - await Download(); - await _strategy?.ExecuteAsync()!; - break; - case false when _configInfo.IsMainUpdate: - //Main program update. - GeneralTracer.Info("GeneralClientBootstrap.ExecuteWorkflowAsync: main update only - starting application (updater will handle it)."); - _strategy?.StartApp(); - break; - } - } - catch (Exception exception) - { - GeneralTracer.Error("The ExecuteWorkflowAsync method in the GeneralClientBootstrap class throws an exception." , exception); - EventManager.Instance.Dispatch(this, new ExceptionEventArgs(exception, exception.Message)); - } - } - - private async Task Download() - { - var manager = new DownloadManager(_configInfo.TempPath, _configInfo.Format, _configInfo.DownloadTimeOut); - manager.MultiAllDownloadCompleted += OnMultiAllDownloadCompleted; - manager.MultiDownloadCompleted += OnMultiDownloadCompleted; - manager.MultiDownloadError += OnMultiDownloadError; - manager.MultiDownloadStatistics += OnMultiDownloadStatistics; - foreach (var versionInfo in _configInfo.UpdateVersions) - { - manager.Add(new DownloadTask(manager, versionInfo)); - } - - await manager.LaunchTasksAsync(); - } - - private int GetPlatform() - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - return PlatformType.Windows; - } - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - return PlatformType.Linux; - } - - return -1; - } - - /// - /// Check if there has been a recent update failure.(only windows) - /// - /// - /// - private bool CheckFail(string version) - { - /* - Read the version number of the last failed upgrade from the system environment variables, then compare it with the version number of the current request. - If it is less than or equal to the failed version number, do not perform the update. - */ - var fail = Environments.GetEnvironmentVariable("UpgradeFail"); - if (string.IsNullOrEmpty(fail) || string.IsNullOrEmpty(version)) - return false; - - var failVersion = new Version(fail); - var lastVersion = new Version(version); - return failVersion >= lastVersion; - } - - /// - /// Determine whether the current version verification result indicates that an update is needed. - /// - /// - /// - private bool CheckUpgrade(VersionRespDTO? response) - { - if (response is null) - return false; - - if (response.Body is null) - return false; - - if (response.Code == 200) - return response.Body.Count > 0; - - return false; - } - - /// - /// During the iteration process, if any version requires a mandatory update, all the update content from this request should be updated. - /// - /// - /// - private bool CheckForcibly(List? versions) - { - if (versions == null) - return false; - - foreach (var item in versions) - { - if (item.IsForcibly == true) - { - return true; - } - } - - return false; - } - - /// - /// User decides if update is required. - /// - /// Whether the update is forcibly required; if true, skip is never allowed. - /// Update information passed to the precheck callback. - /// true to skip (abort) the update; false to continue execution. - private bool CanSkip(bool isForcibly, UpdateInfoEventArgs updateInfo) - { - if (isForcibly) return false; - return _updatePrecheck?.Invoke(updateInfo) == true; - } - - private void CallSmallBowlHome(string processName) - { - if (string.IsNullOrWhiteSpace(processName)) - return; - - try - { - var processes = Process.GetProcessesByName(processName); - if (processes.Length == 0) - { - GeneralTracer.Info($"No process named {processName} found."); - return; - } - - foreach (var process in processes) - { - GeneralTracer.Info($"Killing process {process.ProcessName} (ID: {process.Id})"); - process.Kill(); - } - } - catch (Exception ex) - { - GeneralTracer.Error("The CallSmallBowlHome method in the GeneralClientBootstrap class throws an exception.", ex); - EventManager.Instance.Dispatch(this, new ExceptionEventArgs(ex, ex.Message)); - } - } - - /// - /// Performs all injected custom operations. - /// - /// - private void ExecuteCustomOptions() - { - if (!_customOptions.Any()) return; - - foreach (var option in _customOptions) - { - if (!option.Invoke()) - { - var exception = new Exception($"{nameof(option)}Execution failure!"); - var args = new ExceptionEventArgs(exception, exception.Message); - GeneralTracer.Error("The ExecuteCustomOptions method in the GeneralClientBootstrap class throws an exception.", exception); - EventManager.Instance.Dispatch(this, args); - } - } - } - - protected override void ExecuteStrategy() => throw new NotImplementedException(); - - protected override Task ExecuteStrategyAsync() => throw new NotImplementedException(); - - protected override GeneralClientBootstrap StrategyFactory() - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - _strategy = new WindowsStrategy(); - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - _strategy = new LinuxStrategy(); - else - throw new PlatformNotSupportedException("The current operating system is not supported!"); - - _strategy?.Create(_configInfo!); - return this; - } - - private GeneralClientBootstrap AddListener(Action callbackAction) where TArgs : EventArgs - { - Debug.Assert(callbackAction != null); - EventManager.Instance.AddListener(callbackAction); - return this; - } - - private void OnMultiDownloadStatistics(object sender, MultiDownloadStatisticsEventArgs e) - { - var message = ObjectTranslator.GetPacketHash(e.Version); - GeneralTracer.Info($"Multi download statistics, {message}[BytesReceived]:{e.BytesReceived} [ProgressPercentage]:{e.ProgressPercentage} [Remaining]:{e.Remaining} [TotalBytesToReceive]:{e.TotalBytesToReceive} [Speed]:{e.Speed}"); - EventManager.Instance.Dispatch(sender, e); - } - - private void OnMultiDownloadCompleted(object sender, MultiDownloadCompletedEventArgs e) - { - var message = ObjectTranslator.GetPacketHash(e.Version); - GeneralTracer.Info($"Multi download completed, {message}[IsComplated]:{e.IsComplated}."); - EventManager.Instance.Dispatch(sender, e); - } - - private void OnMultiDownloadError(object sender, MultiDownloadErrorEventArgs e) - { - var message = ObjectTranslator.GetPacketHash(e.Version); - GeneralTracer.Error($"Multi download error {message}.", e.Exception); - EventManager.Instance.Dispatch(sender, e); - } - - private void OnMultiAllDownloadCompleted(object sender, MultiAllDownloadCompletedEventArgs e) - { - GeneralTracer.Info($"Multi all download completed {e.IsAllDownloadCompleted}."); - EventManager.Instance.Dispatch(sender, e); - } - - #endregion Private Methods -} diff --git a/src/c#/GeneralUpdate.ClientCore/GeneralClientOSS.cs b/src/c#/GeneralUpdate.ClientCore/GeneralClientOSS.cs deleted file mode 100644 index 20e112a0..00000000 --- a/src/c#/GeneralUpdate.ClientCore/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.Common.FileBasic; -using GeneralUpdate.Common.Shared; -using GeneralUpdate.Common.Internal.Bootstrap; -using GeneralUpdate.Common.Internal.JsonContext; -using GeneralUpdate.Common.Shared.Object; - -namespace GeneralUpdate.ClientCore; - -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.ClientCore/GeneralUpdate.ico b/src/c#/GeneralUpdate.ClientCore/GeneralUpdate.ico deleted file mode 100644 index 7cb4a86c..00000000 Binary files a/src/c#/GeneralUpdate.ClientCore/GeneralUpdate.ico and /dev/null differ diff --git a/src/c#/GeneralUpdate.ClientCore/GeneralUpdate.png b/src/c#/GeneralUpdate.ClientCore/GeneralUpdate.png deleted file mode 100644 index c8a51ff6..00000000 Binary files a/src/c#/GeneralUpdate.ClientCore/GeneralUpdate.png and /dev/null differ diff --git a/src/c#/GeneralUpdate.ClientCore/Hubs/IUpgradeHubService.cs b/src/c#/GeneralUpdate.ClientCore/Hubs/IUpgradeHubService.cs deleted file mode 100644 index ee29b399..00000000 --- a/src/c#/GeneralUpdate.ClientCore/Hubs/IUpgradeHubService.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace GeneralUpdate.ClientCore.Hubs; - -public interface IUpgradeHubService -{ - /// - /// Add a listener to receive upgrade information pushed from the server. - /// - /// string : group name , string : received message content. - public void AddListenerReceive(Action receiveMessageCallback); - - /// - /// Add a listener to receive online and offline notifications. - /// - /// string : Offline or online information. - public void AddListenerOnline(Action onlineMessageCallback); - - /// - /// Add a listener to receive reconnection notifications. - /// - /// string? : Reconnection information. - public void AddListenerReconnected(Func? reconnectedCallback); - - /// - /// Add a listener to receive disconnection notifications. - /// - /// Exception? : Offline exception information. - public void AddListenerClosed(Func closeCallback); - - /// - /// Start subscribing to upgrade push notifications, and the content of the notifications should be agreed upon independently (it is recommended to use JSON data format). - /// - public Task StartAsync(); - - /// - /// When closing the connection, any ongoing message processing will be completed, but no new messages will be accepted. - /// This should be called before the application closes or goes to sleep, so it can reconnect when it resumes next time. - /// - public Task StopAsync(); - - /// - /// The Hub instance will be completely disposed of and cannot be used for reconnection. - /// - public Task DisposeAsync(); -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.ClientCore/Hubs/RandomRetryPolicy.cs b/src/c#/GeneralUpdate.ClientCore/Hubs/RandomRetryPolicy.cs deleted file mode 100644 index 93ef549c..00000000 --- a/src/c#/GeneralUpdate.ClientCore/Hubs/RandomRetryPolicy.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using Microsoft.AspNetCore.SignalR.Client; - -namespace GeneralUpdate.ClientCore.Hubs; - -public class RandomRetryPolicy : IRetryPolicy -{ - private readonly Random _random = new(); - - public TimeSpan? NextRetryDelay(RetryContext retryContext) - { - // If we've been reconnecting for less than 60 seconds so far, - // wait between 0 and 10 seconds before the next reconnect attempt. - if (retryContext.ElapsedTime < TimeSpan.FromSeconds(60)) - return TimeSpan.FromSeconds(_random.NextDouble() * 10); - // If we've been reconnecting for more than 60 seconds so far, stop reconnecting. - return null; - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.ClientCore/Hubs/UpgradeHubService.cs b/src/c#/GeneralUpdate.ClientCore/Hubs/UpgradeHubService.cs deleted file mode 100644 index 35b60e01..00000000 --- a/src/c#/GeneralUpdate.ClientCore/Hubs/UpgradeHubService.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System; -using System.Threading.Tasks; -using GeneralUpdate.Common.Shared; -using GeneralUpdate.Common.Internal.JsonContext; -using Microsoft.AspNetCore.SignalR; -using Microsoft.AspNetCore.SignalR.Client; -using Microsoft.Extensions.DependencyInjection; - -namespace GeneralUpdate.ClientCore.Hubs; - -/// -/// Upgrade the push notification service. -/// -/// Subscription address, for example: http://127.0.0.1/UpgradeHub -/// ID4 authentication token string. -/// Parameters to be sent to the server upon connection (recommended as a JSON string). -public class UpgradeHubService : IUpgradeHubService -{ - private const string Onlineflag = "Online"; - private const string ReceiveMessageflag = "ReceiveMessage"; - private HubConnection? _connection; - - public UpgradeHubService(string url, string? token = null, string? appkey = null) - => _connection = BuildHubConnection(url, token, appkey); - - private HubConnection BuildHubConnection(string url, string? token = null, string? appkey = null) - { - var builder = new HubConnectionBuilder() - .WithUrl(url, config => - { - if (!string.IsNullOrWhiteSpace(token)) - config.AccessTokenProvider = () => Task.FromResult(token); - - if (!string.IsNullOrWhiteSpace(appkey)) - config.Headers.Add("appkey", appkey); - }).WithAutomaticReconnect(new RandomRetryPolicy()); - builder.Services.Configure(o => - { - o.PayloadSerializerOptions.TypeInfoResolverChain.Insert(0, PacketJsonContext.Default); - }); - return builder.Build(); - } - - public void AddListenerReceive(Action receiveMessageCallback) - => _connection?.On(ReceiveMessageflag, receiveMessageCallback); - - public void AddListenerOnline(Action onlineMessageCallback) - => _connection?.On(Onlineflag, onlineMessageCallback); - - public void AddListenerReconnected(Func? reconnectedCallback) - => _connection!.Reconnected += reconnectedCallback; - - public void AddListenerClosed(Func closeCallback) - => _connection!.Closed += closeCallback; - - public async Task StartAsync() - { - try - { - GeneralTracer.Info($"UpgradeHubService.StartAsync: connecting to SignalR hub. State={_connection?.State}"); - await _connection!.StartAsync(); - GeneralTracer.Info($"UpgradeHubService.StartAsync: SignalR hub connection established. State={_connection?.State}"); - } - catch (Exception e) - { - GeneralTracer.Error("The StartAsync method in the UpgradeHubService class throws an exception." , e); - } - } - - public async Task StopAsync() - { - try - { - GeneralTracer.Info($"UpgradeHubService.StopAsync: stopping SignalR hub connection. State={_connection?.State}"); - await _connection!.StopAsync(); - GeneralTracer.Info("UpgradeHubService.StopAsync: SignalR hub connection stopped."); - } - catch (Exception e) - { - GeneralTracer.Error("The StopAsync method in the UpgradeHubService class throws an exception." , e); - } - } - - public async Task DisposeAsync() - { - try - { - GeneralTracer.Info("UpgradeHubService.DisposeAsync: disposing SignalR hub connection and releasing resources."); - await _connection!.DisposeAsync(); - GeneralTracer.Info("UpgradeHubService.DisposeAsync: SignalR hub connection disposed."); - } - catch (Exception e) - { - GeneralTracer.Error("The DisposeAsync method in the UpgradeHubService class throws an exception." , e); - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.ClientCore/Pipeline/CompressMiddleware.cs b/src/c#/GeneralUpdate.ClientCore/Pipeline/CompressMiddleware.cs deleted file mode 100644 index e11802b6..00000000 --- a/src/c#/GeneralUpdate.ClientCore/Pipeline/CompressMiddleware.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Text; -using System.Threading.Tasks; -using GeneralUpdate.Common.Compress; -using GeneralUpdate.Common.Internal.Pipeline; -using GeneralUpdate.Common.Shared; - -namespace GeneralUpdate.ClientCore.Pipeline; - -public class CompressMiddleware : IMiddleware -{ - public Task InvokeAsync(PipelineContext? context) - { - return Task.Run(() => - { - var format = context.Get("Format"); - var sourcePath = context.Get("ZipFilePath"); - var patchPath = context.Get("PatchPath"); - var encoding = context.Get("Encoding"); - var appPath = context.Get("SourcePath"); - var patchEnabled = context.Get("PatchEnabled"); - var targetPath = patchEnabled == false ? appPath : patchPath; - GeneralTracer.Info($"ClientCore.CompressMiddleware.InvokeAsync: decompressing package. Format={format}, Source={sourcePath}, Target={targetPath}, PatchEnabled={patchEnabled}"); - try - { - CompressProvider.Decompress(format, sourcePath, targetPath, encoding); - GeneralTracer.Info("ClientCore.CompressMiddleware.InvokeAsync: decompression completed successfully."); - } - catch (Exception ex) - { - GeneralTracer.Error("ClientCore.CompressMiddleware.InvokeAsync: decompression failed.", ex); - throw; - } - }); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.ClientCore/Pipeline/HashMiddleware.cs b/src/c#/GeneralUpdate.ClientCore/Pipeline/HashMiddleware.cs deleted file mode 100644 index 7e437d9f..00000000 --- a/src/c#/GeneralUpdate.ClientCore/Pipeline/HashMiddleware.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Security.Cryptography; -using System.Threading.Tasks; -using GeneralUpdate.Common.HashAlgorithms; -using GeneralUpdate.Common.Internal.Pipeline; -using GeneralUpdate.Common.Shared; - -namespace GeneralUpdate.ClientCore.Pipeline; - -public class HashMiddleware : IMiddleware -{ - public async Task InvokeAsync(PipelineContext context) - { - var path = context.Get("ZipFilePath"); - var hash = context.Get("Hash"); - GeneralTracer.Info($"ClientCore.HashMiddleware.InvokeAsync: verifying hash for file={path}, expectedHash={hash}"); - try - { - var isVerify = await VerifyFileHash(path, hash); - if (!isVerify) - { - GeneralTracer.Error($"ClientCore.HashMiddleware.InvokeAsync: hash verification failed for file={path}."); - throw new CryptographicException("Hash verification failed ."); - } - GeneralTracer.Info("ClientCore.HashMiddleware.InvokeAsync: hash verification passed."); - } - catch (CryptographicException) - { - throw; - } - catch (Exception ex) - { - GeneralTracer.Error("ClientCore.HashMiddleware.InvokeAsync: unexpected exception during hash verification.", ex); - throw; - } - } - - private Task VerifyFileHash(string path, string hash) - { - return Task.Run(() => - { - var hashAlgorithm = new Sha256HashAlgorithm(); - var hashSha256 = hashAlgorithm.ComputeHash(path); - return string.Equals(hash, hashSha256, StringComparison.OrdinalIgnoreCase); - }); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.ClientCore/Pipeline/PatchMiddleware.cs b/src/c#/GeneralUpdate.ClientCore/Pipeline/PatchMiddleware.cs deleted file mode 100644 index adba119b..00000000 --- a/src/c#/GeneralUpdate.ClientCore/Pipeline/PatchMiddleware.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Threading.Tasks; -using GeneralUpdate.Common.Internal.Pipeline; -using GeneralUpdate.Common.Shared; -using GeneralUpdate.Differential; - -namespace GeneralUpdate.ClientCore.Pipeline; - -public class PatchMiddleware : IMiddleware -{ - public async Task InvokeAsync(PipelineContext context) - { - var sourcePath = context.Get("SourcePath"); - var targetPath = context.Get("PatchPath"); - GeneralTracer.Info($"ClientCore.PatchMiddleware.InvokeAsync: applying differential patch. SourcePath={sourcePath}, PatchPath={targetPath}"); - try - { - await DifferentialCore.Dirty(sourcePath, targetPath); - GeneralTracer.Info("ClientCore.PatchMiddleware.InvokeAsync: differential patch applied successfully."); - } - catch (Exception ex) - { - GeneralTracer.Error("ClientCore.PatchMiddleware.InvokeAsync: failed to apply differential patch.", ex); - throw; - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.ClientCore/Properties/launchSettings.json b/src/c#/GeneralUpdate.ClientCore/Properties/launchSettings.json deleted file mode 100644 index cb2633b8..00000000 --- a/src/c#/GeneralUpdate.ClientCore/Properties/launchSettings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "profiles": { - "GeneralUpdate.ClientCore": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:65352;http://localhost:65362" - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.ClientCore/SilentUpdateMode.cs b/src/c#/GeneralUpdate.ClientCore/SilentUpdateMode.cs deleted file mode 100644 index c0bbc06e..00000000 --- a/src/c#/GeneralUpdate.ClientCore/SilentUpdateMode.cs +++ /dev/null @@ -1,227 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; -using GeneralUpdate.ClientCore.Strategys; -using GeneralUpdate.Common.Download; -using GeneralUpdate.Common.FileBasic; -using GeneralUpdate.Common.Internal; -using GeneralUpdate.Common.Internal.Bootstrap; -using GeneralUpdate.Common.Internal.JsonContext; -using GeneralUpdate.Common.Internal.Strategy; -using GeneralUpdate.Common.Shared; -using GeneralUpdate.Common.Shared.Object; -using GeneralUpdate.Common.Shared.Object.Enum; -using GeneralUpdate.Common.Shared.Service; - -namespace GeneralUpdate.ClientCore; - -internal sealed class SilentUpdateMode -{ - private const string ProcessInfoEnvironmentKey = "ProcessInfo"; - private static readonly TimeSpan PollingInterval = TimeSpan.FromMinutes(20); - private readonly GlobalConfigInfo _configInfo; - private readonly Encoding _encoding; - private readonly string _format; - private readonly int _downloadTimeOut; - private readonly bool _patchEnabled; - private readonly bool _backupEnabled; - private Task? _pollingTask; - private int _prepared; - private int _updaterStarted; - - public SilentUpdateMode(GlobalConfigInfo configInfo, Encoding encoding, string format, int downloadTimeOut, bool patchEnabled, bool backupEnabled) - { - _configInfo = configInfo; - _encoding = encoding; - _format = format; - _downloadTimeOut = downloadTimeOut; - _patchEnabled = patchEnabled; - _backupEnabled = backupEnabled; - } - - public Task StartAsync() - { - GeneralTracer.Info($"SilentUpdateMode.StartAsync: initializing silent update mode. PollingInterval={PollingInterval.TotalMinutes}min, BackupEnabled={_backupEnabled}, PatchEnabled={_patchEnabled}"); - AppDomain.CurrentDomain.ProcessExit += OnProcessExit; - _pollingTask = Task.Run(PollLoopAsync); - _pollingTask.ContinueWith(task => - { - if (task.Exception != null) - { - GeneralTracer.Error("The StartAsync method in SilentUpdateMode captured a polling exception.", task.Exception); - } - }, TaskContinuationOptions.OnlyOnFaulted); - GeneralTracer.Info("SilentUpdateMode.StartAsync: polling loop started, returning to caller."); - return Task.CompletedTask; - } - - private async Task PollLoopAsync() - { - GeneralTracer.Info("SilentUpdateMode.PollLoopAsync: entering silent update polling loop."); - while (Volatile.Read(ref _prepared) == 0) - { - try - { - GeneralTracer.Info("SilentUpdateMode.PollLoopAsync: polling for available updates."); - await PrepareUpdateIfNeededAsync(); - } - catch (Exception exception) - { - GeneralTracer.Error("The PollLoopAsync method in SilentUpdateMode throws an exception.", exception); - } - - if (Volatile.Read(ref _prepared) == 1) - { - GeneralTracer.Info("SilentUpdateMode.PollLoopAsync: update preparation completed, exiting poll loop."); - break; - } - - GeneralTracer.Info($"SilentUpdateMode.PollLoopAsync: no update prepared this cycle, waiting {PollingInterval.TotalMinutes}min before next poll."); - await Task.Delay(PollingInterval); - } - } - - private async Task PrepareUpdateIfNeededAsync() - { - GeneralTracer.Info($"SilentUpdateMode.PrepareUpdateIfNeededAsync: validating version. UpdateUrl={_configInfo.UpdateUrl}, ClientVersion={_configInfo.ClientVersion}"); - var mainResp = await VersionService.Validate(_configInfo.UpdateUrl - , _configInfo.ClientVersion - , AppType.ClientApp - , _configInfo.AppSecretKey - , GetPlatform() - , _configInfo.ProductId - , _configInfo.Scheme - , _configInfo.Token); - - if (mainResp?.Code != 200 || mainResp.Body == null || mainResp.Body.Count == 0) - { - GeneralTracer.Info($"SilentUpdateMode.PrepareUpdateIfNeededAsync: no update available. ResponseCode={mainResp?.Code}, BodyCount={mainResp?.Body?.Count ?? 0}"); - return; - } - - var versions = mainResp.Body.OrderBy(x => x.ReleaseDate).ToList(); - var latestVersion = versions.Last().Version; - GeneralTracer.Info($"SilentUpdateMode.PrepareUpdateIfNeededAsync: {versions.Count} version(s) available. LatestVersion={latestVersion}"); - - if (CheckFail(latestVersion)) - { - GeneralTracer.Warn($"SilentUpdateMode.PrepareUpdateIfNeededAsync: latest version {latestVersion} matches or precedes a known failed upgrade, skipping."); - return; - } - - BlackListManager.Instance?.AddBlackFiles(_configInfo.BlackFiles); - BlackListManager.Instance?.AddBlackFileFormats(_configInfo.BlackFormats); - BlackListManager.Instance?.AddSkipDirectorys(_configInfo.SkipDirectorys); - - _configInfo.Encoding = _encoding; - _configInfo.Format = _format; - _configInfo.DownloadTimeOut = _downloadTimeOut; - _configInfo.PatchEnabled = _patchEnabled; - _configInfo.IsMainUpdate = true; - _configInfo.LastVersion = latestVersion; - _configInfo.UpdateVersions = versions; - _configInfo.TempPath = StorageManager.GetTempDirectory("main_temp"); - _configInfo.BackupDirectory = Path.Combine(_configInfo.InstallPath, $"{StorageManager.DirectoryName}{_configInfo.ClientVersion}"); - - if (_backupEnabled) - { - GeneralTracer.Info($"SilentUpdateMode.PrepareUpdateIfNeededAsync: backing up from {_configInfo.InstallPath} to {_configInfo.BackupDirectory}"); - StorageManager.Backup(_configInfo.InstallPath, _configInfo.BackupDirectory, BlackListManager.Instance.SkipDirectorys); - GeneralTracer.Info("SilentUpdateMode.PrepareUpdateIfNeededAsync: backup completed."); - } - - var processInfo = ConfigurationMapper.MapToProcessInfo( - _configInfo, - versions, - BlackListManager.Instance.BlackFileFormats.ToList(), - BlackListManager.Instance.BlackFiles.ToList(), - BlackListManager.Instance.SkipDirectorys.ToList()); - _configInfo.ProcessInfo = JsonSerializer.Serialize(processInfo, ProcessInfoJsonContext.Default.ProcessInfo); - - GeneralTracer.Info($"SilentUpdateMode.PrepareUpdateIfNeededAsync: starting download of {versions.Count} package(s)."); - var manager = new DownloadManager(_configInfo.TempPath, _configInfo.Format, _configInfo.DownloadTimeOut); - foreach (var versionInfo in _configInfo.UpdateVersions) - { - manager.Add(new DownloadTask(manager, versionInfo)); - } - await manager.LaunchTasksAsync(); - GeneralTracer.Info("SilentUpdateMode.PrepareUpdateIfNeededAsync: all packages downloaded."); - - GeneralTracer.Info("SilentUpdateMode.PrepareUpdateIfNeededAsync: executing update strategy."); - var strategy = CreateStrategy(); - strategy.Create(_configInfo); - await strategy.ExecuteAsync(); - GeneralTracer.Info("SilentUpdateMode.PrepareUpdateIfNeededAsync: update strategy executed, marking as prepared."); - - Interlocked.Exchange(ref _prepared, 1); - } - - private void OnProcessExit(object? sender, EventArgs e) - { - GeneralTracer.Info($"SilentUpdateMode.OnProcessExit: process exit detected. Prepared={Volatile.Read(ref _prepared)}, UpdaterStarted={Volatile.Read(ref _updaterStarted)}"); - if (Volatile.Read(ref _prepared) != 1 || Interlocked.Exchange(ref _updaterStarted, 1) == 1) - { - GeneralTracer.Info("SilentUpdateMode.OnProcessExit: silent updater launch skipped (not prepared or already started)."); - return; - } - - try - { - Environments.SetEnvironmentVariable(ProcessInfoEnvironmentKey, _configInfo.ProcessInfo); - var updaterPath = Path.Combine(_configInfo.InstallPath, _configInfo.AppName); - GeneralTracer.Info($"SilentUpdateMode.OnProcessExit: launching silent updater. Path={updaterPath}"); - if (File.Exists(updaterPath)) - { - Process.Start(new ProcessStartInfo - { - UseShellExecute = true, - FileName = updaterPath - }); - GeneralTracer.Info("SilentUpdateMode.OnProcessExit: silent updater launched successfully."); - } - else - { - GeneralTracer.Warn($"SilentUpdateMode.OnProcessExit: updater not found at {updaterPath}, cannot launch."); - } - } - catch (Exception exception) - { - GeneralTracer.Error("The OnProcessExit method in SilentUpdateMode throws an exception.", exception); - } - } - - private IStrategy CreateStrategy() - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - return new WindowsStrategy(); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - return new LinuxStrategy(); - throw new PlatformNotSupportedException("The current operating system is not supported!"); - } - - private static int GetPlatform() - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - return PlatformType.Windows; - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - return PlatformType.Linux; - return -1; - } - - private static bool CheckFail(string version) - { - var fail = Environments.GetEnvironmentVariable("UpgradeFail"); - if (string.IsNullOrEmpty(fail) || string.IsNullOrEmpty(version)) - return false; - - var failVersion = new Version(fail); - var latestVersion = new Version(version); - return failVersion >= latestVersion; - } -} diff --git a/src/c#/GeneralUpdate.ClientCore/Strategys/LinuxStrategy.cs b/src/c#/GeneralUpdate.ClientCore/Strategys/LinuxStrategy.cs deleted file mode 100644 index df6cd9c4..00000000 --- a/src/c#/GeneralUpdate.ClientCore/Strategys/LinuxStrategy.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using GeneralUpdate.ClientCore.Pipeline; -using GeneralUpdate.Common.Internal; -using GeneralUpdate.Common.Internal.Bootstrap; -using GeneralUpdate.Common.Internal.Event; -using GeneralUpdate.Common.Internal.Pipeline; -using GeneralUpdate.Common.Internal.Strategy; -using GeneralUpdate.Common.Shared; -using GeneralUpdate.Common.Shared.Object; - -namespace GeneralUpdate.ClientCore.Strategys; - -/// -/// Update policy based on the linux platform. -/// -public class LinuxStrategy : AbstractStrategy -{ - protected override PipelineContext CreatePipelineContext(VersionInfo version, string patchPath) - { - GeneralTracer.Info($"GeneralUpdate.ClientCore.LinuxStrategy.CreatePipelineContext: building context for version={version.Version}, patchPath={patchPath}"); - var context = base.CreatePipelineContext(version, patchPath); - - // Add ClientCore-specific context items (blacklists for Linux) - context.Add("BlackFiles", _configinfo.BlackFiles); - context.Add("BlackFileFormats", _configinfo.BlackFormats); - context.Add("SkipDirectorys", _configinfo.SkipDirectorys); - - return context; - } - - protected override PipelineBuilder BuildPipeline(PipelineContext context) - { - GeneralTracer.Info($"GeneralUpdate.ClientCore.LinuxStrategy.BuildPipeline: assembling middleware pipeline. PatchEnabled={_configinfo.PatchEnabled}"); - return new PipelineBuilder(context) - .UseMiddlewareIf(_configinfo.PatchEnabled) - .UseMiddleware() - .UseMiddleware(); - } - - public override void StartApp() - { - try - { - GeneralTracer.Info($"GeneralUpdate.ClientCore.LinuxStrategy.StartApp: setting ProcessInfo environment variable and launching updater app={_configinfo.AppName}"); - Environments.SetEnvironmentVariable("ProcessInfo", _configinfo.ProcessInfo); - var appPath = Path.Combine(_configinfo.InstallPath, _configinfo.AppName); - if (File.Exists(appPath)) - { - Process.Start(new ProcessStartInfo - { - UseShellExecute = true, - FileName = appPath - }); - GeneralTracer.Info($"GeneralUpdate.ClientCore.LinuxStrategy.StartApp: updater process launched successfully. Path={appPath}"); - } - else - { - GeneralTracer.Warn($"GeneralUpdate.ClientCore.LinuxStrategy.StartApp: updater app not found at path={appPath}, skipping launch."); - } - } - catch (Exception e) - { - GeneralTracer.Error("The StartApp method in the GeneralUpdate.ClientCore.LinuxStrategy class throws an exception." , e); - EventManager.Instance.Dispatch(this, new ExceptionEventArgs(e, e.Message)); - } - finally - { - GeneralTracer.Info("GeneralUpdate.ClientCore.LinuxStrategy.StartApp: releasing tracer and terminating client process."); - GeneralTracer.Dispose(); - Process.GetCurrentProcess().Kill(); - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.ClientCore/Strategys/WindowsStrategy.cs b/src/c#/GeneralUpdate.ClientCore/Strategys/WindowsStrategy.cs deleted file mode 100644 index bc607ef0..00000000 --- a/src/c#/GeneralUpdate.ClientCore/Strategys/WindowsStrategy.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using GeneralUpdate.ClientCore.Pipeline; -using GeneralUpdate.Common.Internal; -using GeneralUpdate.Common.Internal.Bootstrap; -using GeneralUpdate.Common.Internal.Event; -using GeneralUpdate.Common.Internal.Pipeline; -using GeneralUpdate.Common.Internal.Strategy; -using GeneralUpdate.Common.Shared; -using GeneralUpdate.Common.Shared.Object; - -namespace GeneralUpdate.ClientCore.Strategys; - -/// -/// Update policy based on the Windows platform. -/// -public class WindowsStrategy : AbstractStrategy -{ - protected override PipelineContext CreatePipelineContext(VersionInfo version, string patchPath) - { - GeneralTracer.Info($"GeneralUpdate.ClientCore.WindowsStrategy.CreatePipelineContext: building context for version={version.Version}, patchPath={patchPath}"); - var context = base.CreatePipelineContext(version, patchPath); - - // Add ClientCore-specific context items (blacklists are not needed for Windows in Core) - // Keeping this override to maintain extensibility - - return context; - } - - protected override PipelineBuilder BuildPipeline(PipelineContext context) - { - GeneralTracer.Info($"GeneralUpdate.ClientCore.WindowsStrategy.BuildPipeline: assembling middleware pipeline. PatchEnabled={_configinfo.PatchEnabled}"); - return new PipelineBuilder(context) - .UseMiddlewareIf(_configinfo.PatchEnabled) - .UseMiddleware() - .UseMiddleware(); - } - - public override void StartApp() - { - try - { - GeneralTracer.Info($"GeneralUpdate.ClientCore.WindowsStrategy.StartApp: setting ProcessInfo environment variable and launching updater app={_configinfo.AppName}"); - Environments.SetEnvironmentVariable("ProcessInfo", _configinfo.ProcessInfo); - var appPath = Path.Combine(_configinfo.InstallPath, _configinfo.AppName); - if (File.Exists(appPath)) - { - Process.Start(new ProcessStartInfo - { - UseShellExecute = true, - FileName = appPath - }); - GeneralTracer.Info($"GeneralUpdate.ClientCore.WindowsStrategy.StartApp: updater process launched successfully. Path={appPath}"); - } - else - { - GeneralTracer.Warn($"GeneralUpdate.ClientCore.WindowsStrategy.StartApp: updater app not found at path={appPath}, skipping launch."); - } - } - catch (Exception e) - { - GeneralTracer.Error("The StartApp method in the GeneralUpdate.ClientCore.WindowsStrategy class throws an exception." , e); - EventManager.Instance.Dispatch(this, new ExceptionEventArgs(e, e.Message)); - } - finally - { - GeneralTracer.Info("GeneralUpdate.ClientCore.WindowsStrategy.StartApp: releasing tracer and terminating client process."); - GeneralTracer.Dispose(); - Process.GetCurrentProcess().Kill(); - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Compress/CompressProvider.cs b/src/c#/GeneralUpdate.Common/Compress/CompressProvider.cs deleted file mode 100644 index 06f9fa75..00000000 --- a/src/c#/GeneralUpdate.Common/Compress/CompressProvider.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Text; -using GeneralUpdate.Common.Shared.Object; - -namespace GeneralUpdate.Common.Compress; - -public class CompressProvider -{ - private static ICompressionStrategy _compressionStrategy; - - private CompressProvider() { } - - public static void Compress(string compressType,string sourcePath, string destinationPath, bool includeRootDirectory, Encoding encoding) - { - _compressionStrategy = GetCompressionStrategy(compressType); - _compressionStrategy.Compress(sourcePath, destinationPath, includeRootDirectory, encoding); - } - - public static void Decompress(string compressType, string archivePath, string destinationPath, Encoding encoding) - { - _compressionStrategy = GetCompressionStrategy(compressType); - _compressionStrategy.Decompress(archivePath, destinationPath, encoding); - } - - private static ICompressionStrategy GetCompressionStrategy(string compressType) => compressType switch - { - Format.ZIP => new ZipCompressionStrategy(), - _ => throw new ArgumentException("Compression format is not supported!") - }; -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Compress/ICompressionStrategy.cs b/src/c#/GeneralUpdate.Common/Compress/ICompressionStrategy.cs deleted file mode 100644 index be4f22e5..00000000 --- a/src/c#/GeneralUpdate.Common/Compress/ICompressionStrategy.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Text; - -namespace GeneralUpdate.Common.Compress; - -public interface ICompressionStrategy -{ - void Compress(string sourcePath, string destinationPath, bool includeRootDirectory, Encoding encoding); - void Decompress(string archivePath, string destinationPath, Encoding encoding); -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Compress/ZipCompressionStrategy.cs b/src/c#/GeneralUpdate.Common/Compress/ZipCompressionStrategy.cs deleted file mode 100644 index a0cecdb7..00000000 --- a/src/c#/GeneralUpdate.Common/Compress/ZipCompressionStrategy.cs +++ /dev/null @@ -1,196 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using GeneralUpdate.Common.Shared; - -namespace GeneralUpdate.Common.Compress; - -public class ZipCompressionStrategy : ICompressionStrategy -{ - /// - /// Creates a zip archive containing the files and subdirectories of the specified directory. - /// - /// The path of the file directory to be compressed and archived, which can be a relative path or an absolute path. A relative path is a path relative to the current working directory. - /// The archive path of the compressed package to be generated, which can be a relative path or an absolute path. A relative path is a path relative to the current working directory. - /// Enumeration value indicating whether the compression operation emphasizes speed or compression size . - /// Whether the archive contains the parent directory . - public void Compress(string sourceDirectoryName - , string destinationArchiveFileName - , bool includeBaseDirectory - , Encoding encoding) - { - try - { - var compressionLevel = CompressionLevel.Optimal; - if (Directory.Exists(sourceDirectoryName)) - { - if (!File.Exists(destinationArchiveFileName)) - { - ZipFile.CreateFromDirectory(sourceDirectoryName - , destinationArchiveFileName - , compressionLevel - , includeBaseDirectory - , encoding); - } - else - { - var toZipFileDictionaryList = GetAllDirList(sourceDirectoryName, includeBaseDirectory); - using var archive = ZipFile.Open(destinationArchiveFileName, ZipArchiveMode.Update, encoding); - foreach (var toZipFileKey in toZipFileDictionaryList.Keys) - { - if (toZipFileKey == destinationArchiveFileName) continue; - - var toZipedFileName = Path.GetFileName(toZipFileKey); - var toDelArchives = new List(); - foreach (var zipArchiveEntry in archive.Entries) - { - if (toZipedFileName != null && - (zipArchiveEntry.FullName.StartsWith(toZipedFileName) || toZipedFileName.StartsWith(zipArchiveEntry.FullName))) - { - toDelArchives.Add(zipArchiveEntry); - } - } - - foreach (var zipArchiveEntry in toDelArchives) - { - zipArchiveEntry.Delete(); - } - - archive.CreateEntryFromFile(toZipFileKey, toZipFileDictionaryList[toZipFileKey], compressionLevel); - } - } - } - else if (File.Exists(sourceDirectoryName)) - { - if (!File.Exists(destinationArchiveFileName)) - { - ZipFile.CreateFromDirectory(sourceDirectoryName - , destinationArchiveFileName - , compressionLevel - , false - , encoding); - } - else - { - using var archive = ZipFile.Open(destinationArchiveFileName, ZipArchiveMode.Update, encoding); - if (sourceDirectoryName != destinationArchiveFileName) - { - var toZipedFileName = Path.GetFileName(sourceDirectoryName); - var toDelArchives = new List(); - foreach (var zipArchiveEntry in archive.Entries) - { - if (toZipedFileName != null - && (zipArchiveEntry.FullName.StartsWith(toZipedFileName) || toZipedFileName.StartsWith(zipArchiveEntry.FullName))) - { - toDelArchives.Add(zipArchiveEntry); - } - } - - foreach (var zipArchiveEntry in toDelArchives) - { - zipArchiveEntry.Delete(); - } - - archive.CreateEntryFromFile(sourceDirectoryName, toZipedFileName, compressionLevel); - } - } - } - } - catch (Exception exception) - { - GeneralTracer.Error("The Compress method in the ZipCompressionStrategy class throws an exception." , exception); - throw new Exception($"Failed to compress archive: {exception.Message}"); - } - } - - /// - /// Unzip the Zip file and save it to the specified target path folder . - /// - /// - /// - /// - public void Decompress(string zipFilePath, string unZipDir, Encoding encoding) - { - try - { - var dirSeparatorChar = Path.DirectorySeparatorChar.ToString(); - unZipDir = unZipDir.EndsWith(dirSeparatorChar) ? unZipDir : unZipDir + dirSeparatorChar; - - var directoryInfo = new DirectoryInfo(unZipDir); - if (!directoryInfo.Exists) - { - directoryInfo.Create(); - } - - var fileInfo = new FileInfo(zipFilePath); - if (!fileInfo.Exists) - { - return; - } - - using var zipToOpen = new FileStream(zipFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.Read); - using var archive = new ZipArchive(zipToOpen, ZipArchiveMode.Read, false, encoding); - for (int i = 0; i < archive.Entries.Count; i++) - { - var entries = archive.Entries[i]; - var pattern = $"^{dirSeparatorChar}*"; - var entryFilePath = Regex.Replace(entries.FullName.Replace("/", dirSeparatorChar), pattern, - ""); - if (entryFilePath.EndsWith(dirSeparatorChar)) - { - continue; - } - - var filePath = directoryInfo + entryFilePath; - var greatFolder = Directory.GetParent(filePath); - if (greatFolder is not null && !greatFolder.Exists) - { - greatFolder.Create(); - } - - if (File.Exists(filePath)) - { - File.SetAttributes(filePath, FileAttributes.Normal); - File.Delete(filePath); - } - - entries.ExtractToFile(filePath); - } - } - catch (Exception exception) - { - GeneralTracer.Error("The Decompress method in the ZipCompressionStrategy class throws an exception." , exception); - throw new Exception($"Failed to decompress archive: {exception.Message}"); - } - } - - /// - /// Recursively get the set of all files in the specified directory on the disk, the return type is: dictionary [file name, relative file name to be compressed] - /// - /// - /// - /// - /// - private Dictionary GetAllDirList(string strBaseDir - , bool includeBaseDirectory = false - , string namePrefix = "") - { - var resultDictionary = new Dictionary(); - var directoryInfo = new DirectoryInfo(strBaseDir); - var directories = directoryInfo.GetDirectories(); - var fileInfos = directoryInfo.GetFiles(); - if (includeBaseDirectory) - namePrefix += directoryInfo.Name + "\\"; - foreach (var directory in directories) - resultDictionary = resultDictionary.Concat(GetAllDirList(directory.FullName, true, namePrefix)) - .ToDictionary(k => k.Key, k => k.Value); - foreach (var fileInfo in fileInfos) - if (!resultDictionary.ContainsKey(fileInfo.FullName)) - resultDictionary.Add(fileInfo.FullName, namePrefix + fileInfo.Name); - return resultDictionary; - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Download/DownloadManager.cs b/src/c#/GeneralUpdate.Common/Download/DownloadManager.cs deleted file mode 100644 index c474923d..00000000 --- a/src/c#/GeneralUpdate.Common/Download/DownloadManager.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using System.Collections.Immutable; -using System.Diagnostics; -using System.Linq; - -namespace GeneralUpdate.Common.Download -{ - public class DownloadManager(string path, string format, int timeOut) - { - #region Private Members - - private readonly ImmutableList.Builder _downloadTasksBuilder = ImmutableList.Create().ToBuilder(); - private ImmutableList _downloadTasks; - - #endregion Private Members - - #region Public Properties - - public List<(object, string)> FailedVersions { get; } = new(); - - public string Path => path; - - public string Format => format; - - public int TimeOut => timeOut; - - private ImmutableList DownloadTasks => _downloadTasks ?? _downloadTasksBuilder.ToImmutable(); - - public event EventHandler MultiAllDownloadCompleted; - public event EventHandler MultiDownloadCompleted; - public event EventHandler MultiDownloadError; - public event EventHandler MultiDownloadStatistics; - - #endregion Public Properties - - #region Public Methods - - public async Task LaunchTasksAsync() - { - try - { - var downloadTasks = DownloadTasks.Select(task => task.LaunchAsync()).ToList(); - await Task.WhenAll(downloadTasks); - MultiAllDownloadCompleted?.Invoke(this, new MultiAllDownloadCompletedEventArgs(true, FailedVersions)); - } - catch (Exception ex) - { - MultiAllDownloadCompleted?.Invoke(this, new MultiAllDownloadCompletedEventArgs(false, FailedVersions)); - throw new Exception($"Download manager error: {ex.Message}", ex); - } - } - - public void OnMultiDownloadStatistics(object sender, MultiDownloadStatisticsEventArgs e) - => MultiDownloadStatistics?.Invoke(this, e); - - public void OnMultiAsyncCompleted(object sender, MultiDownloadCompletedEventArgs e) - => MultiDownloadCompleted?.Invoke(this, e); - - public void OnMultiDownloadError(object sender, MultiDownloadErrorEventArgs e) - { - MultiDownloadError?.Invoke(this, e); - FailedVersions.Add((e.Version, e.Exception.Message)); - } - - public void Add(DownloadTask task) - { - Debug.Assert(task != null); - if (!_downloadTasksBuilder.Contains(task)) - { - _downloadTasksBuilder.Add(task); - } - } - - #endregion Public Methods - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Download/DownloadTask.cs b/src/c#/GeneralUpdate.Common/Download/DownloadTask.cs deleted file mode 100644 index 40de3d61..00000000 --- a/src/c#/GeneralUpdate.Common/Download/DownloadTask.cs +++ /dev/null @@ -1,305 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading; -using System.Threading.Tasks; -using GeneralUpdate.Common.Shared; -using GeneralUpdate.Common.Shared.Object; - -namespace GeneralUpdate.Common.Download -{ - public class DownloadTask - { - #region Private Members - - private readonly HttpClient _httpClient; - private readonly DownloadManager _manager; - private readonly VersionInfo? _version; - private Timer? _timer; - private DateTime _startTime; - private long _receivedBytes; - private long _totalBytes; - private long _currentBytes; - - #endregion Private Members - - public DownloadTask(DownloadManager manager, VersionInfo version) - { - _manager = manager; - _version = version; - _httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(_manager.TimeOut) }; - - // Set authentication headers if provided - if (!string.IsNullOrEmpty(version?.AuthScheme) && !string.IsNullOrEmpty(version?.AuthToken)) - { - _httpClient.DefaultRequestHeaders.Authorization = - new AuthenticationHeaderValue(version.AuthScheme, version.AuthToken); - } - - _timer = new Timer(_=> Statistics(), null, 0, 1000); - } - - public async Task LaunchAsync() - { - try - { - var path = Path.Combine(_manager.Path, $"{_version?.Name}{_manager.Format}"); - await DownloadFileRangeAsync(_version.Url, path); - } - catch (Exception exception) - { - GeneralTracer.Error("The LaunchAsync method in the DownloadTask class throws an exception." , exception); - _manager.OnMultiDownloadError(this, new MultiDownloadErrorEventArgs(exception, _version)); - } - } - - #region Private Methods - - private async Task DownloadFileRangeAsync(string url, string path) - { - try - { - var tempPath = path + ".temp"; - var startPos = CheckFile(tempPath); - - var requestMessage = new HttpRequestMessage(HttpMethod.Get, url); - if (startPos > 0) - { - requestMessage.Headers.Range = new RangeHeaderValue(startPos, null); - } - - using var response = await _httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead); - if (!response.IsSuccessStatusCode) - throw new HttpRequestException($"Failed to download file: {response.ReasonPhrase}"); - - var totalBytes = response.Content.Headers.ContentLength ?? 0; - Interlocked.Exchange(ref _totalBytes, totalBytes); - - if (startPos >= totalBytes) - { - if (File.Exists(path)) - { - File.SetAttributes(path, FileAttributes.Normal); - File.Delete(path); - } - - File.Move(tempPath, path); - OnDownloadCompleted(true); - return; - } - - await foreach (var chunk in DownloadChunksAsync(response)) - { - await WriteFileAsync(tempPath, chunk, totalBytes); - } - } - catch (Exception exception) - { - OnDownloadCompleted(false); - GeneralTracer.Error("The DownloadFileRangeAsync method in the DownloadTask class throws an exception." , exception); - _manager.OnMultiDownloadError(this, new MultiDownloadErrorEventArgs(exception, _version)); - } - } - - private async IAsyncEnumerable DownloadChunksAsync(HttpResponseMessage response) - { - using var responseStream = await response.Content.ReadAsStreamAsync(); - var buffer = new byte[8192]; - int bytesRead; - while ((bytesRead = await responseStream.ReadAsync(buffer, 0, buffer.Length)) > 0) - { - var chunk = new byte[bytesRead]; - Buffer.BlockCopy(buffer, 0, chunk, 0, bytesRead); - yield return chunk; - } - } - - private async Task WriteFileAsync(string tempPath, byte[] chunk, long totalBytes) - { - try - { - using var fileStream = new FileStream(tempPath, FileMode.Append, FileAccess.Write, FileShare.None); - await fileStream.WriteAsync(chunk, 0, chunk.Length); - Interlocked.Add(ref _receivedBytes, chunk.Length); - if (_receivedBytes >= totalBytes) - { - fileStream.Close(); - var path = tempPath.Replace(".temp", ""); - if (File.Exists(path)) - { - File.SetAttributes(path, FileAttributes.Normal); - File.Delete(path); - } - - File.Move(tempPath, path); - OnDownloadCompleted(true); - } - } - catch (Exception exception) - { - OnDownloadCompleted(false); - GeneralTracer.Error("The WriteFileAsync method in the DownloadTask class throws an exception." , exception); - _manager.OnMultiDownloadError(this, new MultiDownloadErrorEventArgs(exception, _version)); - } - } - - private void Statistics() - { - try - { - var interval = DateTime.Now - _startTime; - var tempTotalBytes = Interlocked.Read(ref _totalBytes); - //Accumulate the downloaded size. - var tempReceivedBytes = Interlocked.Read(ref _receivedBytes); - //Current downloaded size. - var tempCurrentBytes = tempReceivedBytes - Interlocked.Read(ref _currentBytes); - var speed = CalculateDownloadSpeed(tempCurrentBytes, interval); - var formatSpeed = FormatDownloadSpeed(speed); - var remainingTime = CalculateRemainingTime(tempTotalBytes, tempReceivedBytes, speed); - var progress = CalculateDownloadProgress(tempTotalBytes, tempReceivedBytes); - - var args = new MultiDownloadStatisticsEventArgs(_version - , remainingTime - , formatSpeed - , tempTotalBytes - , tempReceivedBytes - , progress); - _manager.OnMultiDownloadStatistics(this, args); - Interlocked.Exchange(ref _currentBytes, tempReceivedBytes); - _startTime = DateTime.Now; - } - catch (Exception exception) - { - _manager.OnMultiDownloadError(this, new MultiDownloadErrorEventArgs(exception, _version)); - } - } - - private void OnDownloadCompleted(bool isComplated) - { - try - { - DisposeTimer(); - var eventArgs = new MultiDownloadCompletedEventArgs(_version, isComplated); - _manager.OnMultiAsyncCompleted(this, eventArgs); - } - catch (Exception exception) - { - GeneralTracer.Error(exception.Message, exception); - _manager.OnMultiDownloadError(this, new MultiDownloadErrorEventArgs(exception, _version)); - } - } - - /// - /// Calculate the remaining download time (in seconds). - /// - /// - /// - /// - /// - private static TimeSpan CalculateRemainingTime(long totalBytes, long bytesReceived, double downloadSpeed) - { - if (downloadSpeed == 0) - { - return new TimeSpan(0, 0, 0, 0); - } - - var bytesRemaining = totalBytes - bytesReceived; - var secondsRemaining = bytesRemaining / downloadSpeed; - return TimeSpan.FromSeconds(secondsRemaining); - } - - /// - /// Calculate the download speed (in bytes per second). - /// - /// - /// - /// - private static double CalculateDownloadSpeed(long bytesReceived, TimeSpan elapsedTime) - { - if (elapsedTime.TotalSeconds == 0) - return 0; - - return bytesReceived / elapsedTime.TotalSeconds; - } - - /// - /// Calculate the download progress (percentage %). - /// - /// - /// - /// - private static double CalculateDownloadProgress(long totalBytes, long bytesReceived) - { - if (totalBytes == 0) - return 0; - - return (double)bytesReceived / totalBytes * 100; - } - - /// - /// Convert the download speed to an appropriate unit (B, KB, MB, GB). - /// - /// - /// - private static string FormatDownloadSpeed(double speedInBytesPerSecond) - { - const double kiloByte = 1024; - const double megaByte = kiloByte * 1024; - const double gigaByte = megaByte * 1024; - - return speedInBytesPerSecond switch - { - >= gigaByte => $"{speedInBytesPerSecond / gigaByte:F2} GB/s", - >= megaByte => $"{speedInBytesPerSecond / megaByte:F2} MB/s", - _ => speedInBytesPerSecond >= kiloByte - ? $"{speedInBytesPerSecond / kiloByte:F2} KB/s" - : $"{speedInBytesPerSecond:F2} B/s" - }; - } - - /// - /// Get the size of the downloaded file for resuming interrupted downloads. - /// - /// - /// - private static long CheckFile(string tempPath) - { - long startPos = 0; - if (!File.Exists(tempPath)) return startPos; - using var fileStream = File.OpenWrite(tempPath); - startPos = fileStream.Length; - fileStream.Seek(startPos, SeekOrigin.Current); - return startPos; - } - - private void DisposeTimer() - { - if (_timer == null) return; - try - { - _timer.Change(Timeout.Infinite, Timeout.Infinite); - using var waitHandle = new ManualResetEvent(false); - _timer.Dispose(waitHandle); - waitHandle.WaitOne(); - } - catch (ObjectDisposedException exception) - { - GeneralTracer.Error("Timer has already been disposed: " + exception.Message); - _manager.OnMultiDownloadError(this, new MultiDownloadErrorEventArgs(exception, _version)); - } - catch (Exception exception) - { - GeneralTracer.Error("An error occurred while disposing the timer.", exception); - _manager.OnMultiDownloadError(this, new MultiDownloadErrorEventArgs(exception, _version)); - } - finally - { - _timer = null; - } - } - - #endregion Private Methods - } -} diff --git a/src/c#/GeneralUpdate.Common/Download/MultiEventArgs/MutiAllDownloadCompletedEventArgs.cs b/src/c#/GeneralUpdate.Common/Download/MultiEventArgs/MutiAllDownloadCompletedEventArgs.cs deleted file mode 100644 index aeec9ee6..00000000 --- a/src/c#/GeneralUpdate.Common/Download/MultiEventArgs/MutiAllDownloadCompletedEventArgs.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace GeneralUpdate.Common.Download -{ - public class MultiAllDownloadCompletedEventArgs : EventArgs - { - public MultiAllDownloadCompletedEventArgs(bool isAllDownloadCompleted, IList<(object, string)> failedVersions) - { - IsAllDownloadCompleted = isAllDownloadCompleted; - FailedVersions = failedVersions; - } - - public bool IsAllDownloadCompleted { get; set; } - - public IList> FailedVersions { get; set; } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Download/MultiEventArgs/MutiDownloadCompletedEventArgs.cs b/src/c#/GeneralUpdate.Common/Download/MultiEventArgs/MutiDownloadCompletedEventArgs.cs deleted file mode 100644 index 3f684162..00000000 --- a/src/c#/GeneralUpdate.Common/Download/MultiEventArgs/MutiDownloadCompletedEventArgs.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace GeneralUpdate.Common.Download -{ - public class MultiDownloadCompletedEventArgs(object version, bool isComplated) : EventArgs - { - public object Version { get; private set; } = version; - - public bool IsComplated { get; private set; } = isComplated; - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Download/MultiEventArgs/MutiDownloadErrorEventArgs.cs b/src/c#/GeneralUpdate.Common/Download/MultiEventArgs/MutiDownloadErrorEventArgs.cs deleted file mode 100644 index 050db181..00000000 --- a/src/c#/GeneralUpdate.Common/Download/MultiEventArgs/MutiDownloadErrorEventArgs.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace GeneralUpdate.Common.Download -{ - public class MultiDownloadErrorEventArgs : EventArgs - { - public MultiDownloadErrorEventArgs(Exception exception, object version) - { - Exception = exception; - Version = version; - } - - public Exception Exception { get; set; } - - public object Version { get; set; } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Download/MultiEventArgs/MutiDownloadStatisticsEventArgs.cs b/src/c#/GeneralUpdate.Common/Download/MultiEventArgs/MutiDownloadStatisticsEventArgs.cs deleted file mode 100644 index 4dad6104..00000000 --- a/src/c#/GeneralUpdate.Common/Download/MultiEventArgs/MutiDownloadStatisticsEventArgs.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; - -namespace GeneralUpdate.Common.Download; - -public class MultiDownloadStatisticsEventArgs(object version - , TimeSpan remaining - , string speed - , long totalBytes - , long bytesReceived - , double progressPercentage) : EventArgs -{ - public object Version { get; private set; } = version; - - public TimeSpan Remaining { get; private set; } = remaining; - - public string Speed { get; private set; } = speed; - - public long TotalBytesToReceive { get; private set; } = totalBytes; - - public long BytesReceived { get; private set; } = bytesReceived; - - public double ProgressPercentage { get; private set; } = progressPercentage; -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Download/MultiEventArgs/UpdateInfoEventArgs.cs b/src/c#/GeneralUpdate.Common/Download/MultiEventArgs/UpdateInfoEventArgs.cs deleted file mode 100644 index ca835da8..00000000 --- a/src/c#/GeneralUpdate.Common/Download/MultiEventArgs/UpdateInfoEventArgs.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; -using GeneralUpdate.Common.Shared.Object; - -namespace GeneralUpdate.Common.Download; - -public class UpdateInfoEventArgs(VersionRespDTO info) : EventArgs -{ - public VersionRespDTO Info { get; private set; } = info; -} diff --git a/src/c#/GeneralUpdate.Common/FileBasic/BlackListManager.cs b/src/c#/GeneralUpdate.Common/FileBasic/BlackListManager.cs deleted file mode 100644 index ed8af84b..00000000 --- a/src/c#/GeneralUpdate.Common/FileBasic/BlackListManager.cs +++ /dev/null @@ -1,139 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; -using GeneralUpdate.Common.Shared.Object; - -namespace GeneralUpdate.Common.FileBasic; - -public class BlackListManager -{ - private static readonly object LockObject = new object(); - private static BlackListManager? _instance; - - private static readonly List _blackFileFormats = - [ - ".patch", - Format.ZIP, - ".rar", - ".tar", - ".json", - ".pdb" - ]; - - private static readonly List _blackFiles = - [ - "Microsoft.Bcl.AsyncInterfaces.dll", - "System.Collections.Immutable.dll", - "System.IO.Pipelines.dll", - "System.Text.Encodings.Web.dll", - "System.Text.Json.dll" - ]; - - private static readonly List _skipDirectorys = ["app-", "fail"]; - - private BlackListManager() { } - - public static BlackListManager? Instance - { - get - { - if (_instance == null) - { - lock (LockObject) - { - if (_instance == null) - { - _instance = new BlackListManager(); - } - } - } - - return _instance; - } - } - - public IReadOnlyList BlackFileFormats => _blackFileFormats.AsReadOnly(); - public IReadOnlyList BlackFiles => _blackFiles.AsReadOnly(); - - public IReadOnlyList SkipDirectorys = _skipDirectorys.AsReadOnly(); - - public void AddBlackFileFormats(List? formats) - { - if (formats == null) - return; - - foreach (var format in formats) - { - AddBlackFileFormat(format); - } - } - - public void AddBlackFileFormat(string format) - { - if (string.IsNullOrWhiteSpace(format)) - return; - - if (!_blackFileFormats.Contains(format)) - { - _blackFileFormats.Add(format); - } - } - - public void AddBlackFiles(List? fileNames) - { - if (fileNames == null) - return; - - foreach (var fileName in fileNames) - { - AddBlackFile(fileName); - } - } - - public void AddBlackFile(string fileName) - { - if (string.IsNullOrWhiteSpace(fileName)) - return; - - if (!_blackFiles.Contains(fileName)) - { - _blackFiles.Add(fileName); - } - } - - public void AddSkipDirectorys(List? directorys) - { - if (directorys == null) - return; - - foreach (var directory in directorys) - { - AddSkipDirectory(directory); - } - } - - public void AddSkipDirectory(string directory) - { - if (string.IsNullOrWhiteSpace(directory)) - return; - - if (!_skipDirectorys.Contains(directory)) - { - _skipDirectorys.Add(directory); - } - } - - public bool IsBlacklisted(string relativeFilePath) - { - var fileName = Path.GetFileName(relativeFilePath); - var fileExtension = Path.GetExtension(relativeFilePath); - - return _blackFiles.Contains(fileName) || _blackFileFormats.Contains(fileExtension); - } - - public bool IsSkipDirectory(string directory) - { - var dirName = new DirectoryInfo(directory).Name; - return _skipDirectorys.Any(dirName.Contains); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/FileBasic/ComparisonResult.cs b/src/c#/GeneralUpdate.Common/FileBasic/ComparisonResult.cs deleted file mode 100644 index 41dbf234..00000000 --- a/src/c#/GeneralUpdate.Common/FileBasic/ComparisonResult.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Collections.Generic; - -namespace GeneralUpdate.Common.FileBasic; - -/// -/// Result of a comparison between two directories. -/// -public class ComparisonResult -{ - private List _leftNodes; - private List _rightNodes; - private List _differentNodes; - - public ComparisonResult() - { - _leftNodes = new List(); - _rightNodes = new List(); - _differentNodes = new List(); - } - - /// - /// List of files that are unique to A. - /// - public IReadOnlyList LeftNodes => _leftNodes.AsReadOnly(); - - /// - /// List of files that are unique to B. - /// - public IReadOnlyList RightNodes => _rightNodes.AsReadOnly(); - - /// - /// List of files that are different between A and B. - /// - public IReadOnlyList DifferentNodes => _differentNodes.AsReadOnly(); - - public void AddToLeft(IEnumerable files) => _leftNodes.AddRange(files); - - public void AddToRight(IEnumerable files) => _rightNodes.AddRange(files); - - public void AddDifferent(IEnumerable files) => _differentNodes.AddRange(files); -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/FileBasic/FileNode.cs b/src/c#/GeneralUpdate.Common/FileBasic/FileNode.cs deleted file mode 100644 index 90b3831a..00000000 --- a/src/c#/GeneralUpdate.Common/FileBasic/FileNode.cs +++ /dev/null @@ -1,150 +0,0 @@ -using System; - -namespace GeneralUpdate.Common.FileBasic; - -public class FileNode -{ - #region Public Properties - - public long Id { get; set; } - - public string Name { get; set; } - - public string FullName { get; set; } - - public string Path { get; set; } - - public string Hash { get; set; } - - public FileNode Left { get; set; } - - public FileNode Right { get; set; } - - public int LeftType { get; set; } - - public int RightType { get; set; } - - public string RelativePath { get; set; } - - #endregion Public Properties - - #region Constructors - - public FileNode() - { - } - - public FileNode(int id) - { - Id = id; - } - - #endregion Constructors - - #region Public Methods - - public void Add(FileNode node) - { - if (node == null) return; - - if (node.Id < Id) - { - if (Left == null) - { - Left = node; - } - else - { - Left.Add(node); - } - } - else - { - if (Right == null) - { - Right = node; - } - else - { - Right.Add(node); - } - } - } - - public void InfixOrder() - { - if (Left != null) - { - Left.InfixOrder(); - } - - if (Right != null) - { - Right.InfixOrder(); - } - } - - public FileNode Search(long id) - { - if (id == Id) - { - return this; - } - else if (id < Id) - { - if (Left == null) return null; - return Left.Search(id); - } - else - { - if (Right == null) return null; - return Right.Search(id); - } - } - - /// - /// Find the parent node of the node that you want to delete. - /// - /// - /// - public FileNode SearchParent(long id) - { - if (Left != null && Left.Id == id || Right != null && Right.Id == id) - { - return this; - } - else - { - if (id < Id && Left != null) - { - return Left.SearchParent(id); - } - else if (id >= Id && Right != null) - { - return Right.SearchParent(id); - } - else - { - return null; - } - } - } - - /// - /// Compare tree nodes equally by Hash and file names. - /// - /// - /// - public override bool Equals(object obj) - { - if (obj == null) return false; - var tempNode = obj as FileNode; - if (tempNode == null) throw new ArgumentException(nameof(tempNode)); - return string.Equals(Hash, tempNode.Hash, StringComparison.OrdinalIgnoreCase) && - string.Equals(Name, tempNode.Name, StringComparison.OrdinalIgnoreCase); - } - - public override int GetHashCode() => base.GetHashCode(); - - #endregion Public Methods -} diff --git a/src/c#/GeneralUpdate.Common/FileBasic/FileTree.cs b/src/c#/GeneralUpdate.Common/FileBasic/FileTree.cs deleted file mode 100644 index 02ea4cc8..00000000 --- a/src/c#/GeneralUpdate.Common/FileBasic/FileTree.cs +++ /dev/null @@ -1,172 +0,0 @@ -using System.Collections.Generic; -using GeneralUpdate.Common.Shared; - -namespace GeneralUpdate.Common.FileBasic; - - /// - /// Simple file binary tree. - /// - public class FileTree - { - #region Private Members - - private FileNode _root; - - #endregion Private Members - - #region Constructors - - public FileTree() - { } - - public FileTree(IEnumerable nodes) - { - foreach (var node in nodes) Add(node); - } - - #endregion Constructors - - #region Public Methods - - public void Add(FileNode node) - { - if (_root == null) - { - _root = node; - } - else - { - _root.Add(node); - } - } - - public void InfixOrder() - { - if (_root != null) - { - _root.InfixOrder(); - } - else - { - GeneralTracer.Info("The binary sort tree is empty and cannot be traversed!"); - } - } - - public FileNode Search(long id) => _root == null ? null : _root.Search(id); - - public FileNode SearchParent(long id) => _root == null ? null : _root.SearchParent(id); - - public long DelRightTreeMin(FileNode node) - { - FileNode target = node; - while (target.Left != null) - { - target = target.Left; - } - DelNode(target.Id); - return target.Id; - } - - public void DelNode(long id) - { - if (_root == null) - { - return; - } - else - { - FileNode targetNode = Search(id); - if (targetNode == null) - { - return; - } - if (_root.Left == null && _root.Right == null) - { - _root = null; - return; - } - - FileNode parent = SearchParent(id); - if (targetNode.Left == null && targetNode.Right == null) - { - if (parent.Left != null && parent.Left.Id == id) - { - parent.Left = null; - } - else if (parent.Right != null && parent.Right.Id == id) - { - parent.Right = null; - } - } - else if (targetNode.Left != null && targetNode.Right != null) - { - long minVal = DelRightTreeMin(targetNode.Right); - targetNode.Id = minVal; - } - else - { - if (targetNode.Left != null) - { - if (parent.Left.Id == id) - { - parent.Left = targetNode.Left; - } - else - { - parent.Right = targetNode.Left; - } - } - else - { - if (parent.Left.Id == id) - { - parent.Left = targetNode.Right; - } - else - { - parent.Right = targetNode.Right; - } - } - } - } - } - - /// - /// Starting from the root node, recursively compares two different child nodes of the binary tree and nodes that are not included. - /// - /// - /// - /// - public void Compare(FileNode node, FileNode node0, ref List nodes) - { - if (node != null && node.Left != null) - { - if (!node.Equals(node0) && node0 != null) nodes.Add(node0); - Compare(node.Left, node0.Left, ref nodes); - } - else if (node0 != null && node0.Left != null) - { - nodes.Add(node0); - Compare(node.Left, node0.Left, ref nodes); - } - - if (node != null && node.Right != null) - { - if (!node.Equals(node0) && node0 != null) nodes.Add(node0); - Compare(node.Right, node0 == null ? null : node0.Right, ref nodes); - } - else if (node0 != null && node0.Right != null) - { - nodes.Add(node0); - Compare(node == null ? null : node.Right, node0.Right, ref nodes); - } - else if (node0 != null) - { - nodes.Add(node0); - } - } - - public FileNode GetRoot() => _root; - - #endregion Public Methods - } \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/FileBasic/StorageManager.cs b/src/c#/GeneralUpdate.Common/FileBasic/StorageManager.cs deleted file mode 100644 index 32970c82..00000000 --- a/src/c#/GeneralUpdate.Common/FileBasic/StorageManager.cs +++ /dev/null @@ -1,268 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text.Json; -using System.Text.Json.Serialization.Metadata; -using System.Threading; -using GeneralUpdate.Common.HashAlgorithms; - -namespace GeneralUpdate.Common.FileBasic -{ - public sealed class StorageManager - { - private long _fileCount = 0; - public const string DirectoryName = "app-"; - - private ComparisonResult ComparisonResult { get; set; } - - #region Public Methods - - /// - /// Using the list on the left as a baseline, find the set of differences between the two file lists. - /// - public IEnumerable? Except(string leftPath, string rightPath) - { - var leftFileNodes = ReadFileNode(leftPath); - var rightFileNodes = ReadFileNode(rightPath); - var rightNodeDic = rightFileNodes.ToDictionary(x => x.RelativePath); - return leftFileNodes.Where(f => !rightNodeDic.ContainsKey(f.RelativePath)).ToList(); - } - - /// - /// Compare two directories. - /// - /// - /// - public ComparisonResult Compare(string leftDir, string rightDir) - { - ResetId(); - ComparisonResult = new ComparisonResult(); - var leftFileNodes = ReadFileNode(leftDir); - var rightFileNodes = ReadFileNode(rightDir); - var leftTree = new FileTree(leftFileNodes); - var rightTree = new FileTree(rightFileNodes); - var differentTreeNode = new List(); - leftTree.Compare(leftTree.GetRoot(), rightTree.GetRoot(), ref differentTreeNode); - ComparisonResult.AddToLeft(leftFileNodes); - ComparisonResult.AddToRight(rightFileNodes); - ComparisonResult.AddDifferent(differentTreeNode); - return ComparisonResult; - } - - public static void CreateJson(string targetPath, T obj, JsonTypeInfo? typeInfo = null) where T : class - { - var folderPath = Path.GetDirectoryName(targetPath) ?? - throw new ArgumentException("invalid path", nameof(targetPath)); - - if (!Directory.Exists(folderPath)) - Directory.CreateDirectory(folderPath); - - var jsonString = typeInfo != null ? JsonSerializer.Serialize(obj, typeInfo) : JsonSerializer.Serialize(obj); - File.WriteAllText(targetPath, jsonString); - } - - public static T? GetJson(string path, JsonTypeInfo? typeInfo = null) where T : class - { - if (File.Exists(path)) - { - var json = File.ReadAllText(path); - if (typeInfo != null) - { - return JsonSerializer.Deserialize(json, typeInfo); - } - return JsonSerializer.Deserialize(json); - } - - return default; - } - - public static string GetTempDirectory(string name) - { - var path = $"generalupdate_{DateTime.Now:yyyy-MM-dd}_{name}"; - var tempDir = Path.Combine(Path.GetTempPath(), path); - if (!Directory.Exists(tempDir)) - { - Directory.CreateDirectory(tempDir); - } - - return tempDir; - } - - public static void DeleteDirectory(string targetDir) - { - foreach (var file in Directory.GetFiles(targetDir)) - { - File.SetAttributes(file, FileAttributes.Normal); - File.Delete(file); - } - - foreach (var dir in Directory.GetDirectories(targetDir)) - { - DeleteDirectory(dir); - } - - Directory.Delete(targetDir, false); - } - - public static List GetAllFiles(string path, List skipDirectorys) - { - try - { - var files = new List(); - files.AddRange(new DirectoryInfo(path).GetFiles()); - var tmpDir = new DirectoryInfo(path).GetDirectories(); - - foreach (var dic in tmpDir) - { - bool shouldSkip = false; - foreach (var notBackup in skipDirectorys) - { - if (dic.Name.Contains(notBackup)) - { - shouldSkip = true; - break; - } - } - - if (!shouldSkip) - files.AddRange(GetAllFiles(dic.FullName, skipDirectorys)); - } - - return files; - } - catch - { - return new List(); - } - } - - public static bool HashEquals(string leftPath, string rightPath) - { - var hashAlgorithm = new Sha256HashAlgorithm(); - var hashLeft = hashAlgorithm.ComputeHash(leftPath); - var hashRight = hashAlgorithm.ComputeHash(rightPath); - return hashLeft.SequenceEqual(hashRight); - } - - /// - /// Backup the all program. - /// - /// - /// - /// - public static void Backup(string sourcePath, string backupPath, IReadOnlyList directoryNames) - { - if (Directory.Exists(backupPath)) - { - DeleteDirectory(backupPath); - } - Directory.CreateDirectory(backupPath); - CopyDirectory(sourcePath, backupPath, directoryNames); - } - - private static void CopyDirectory(string sourceDir, string targetDir, IReadOnlyList directoryNames) - { - foreach (string dirPath in Directory.GetDirectories(sourceDir, "*", SearchOption.TopDirectoryOnly)) - { - if (!directoryNames.Any(name => Path.GetFileName(dirPath).Contains(name))) - { - string newTargetDir = Path.Combine(targetDir, Path.GetFileName(dirPath)); - Directory.CreateDirectory(newTargetDir); - CopyDirectory(dirPath, newTargetDir, directoryNames); - } - } - - foreach (string filePath in Directory.GetFiles(sourceDir, "*.*", SearchOption.TopDirectoryOnly)) - { - string newFilePath = Path.Combine(targetDir, Path.GetFileName(filePath)); - File.Copy(filePath, newFilePath, true); - } - } - - /// - /// Restore the all program. - /// - /// - /// - public static void Restore(string backupPath, string sourcePath) - { - if (!Directory.Exists(sourcePath)) - { - Directory.CreateDirectory(sourcePath); - } - - CopyDirectory(backupPath, sourcePath); - } - - private static void CopyDirectory(string sourceDir, string targetDir) - { - foreach (string dirPath in Directory.GetDirectories(sourceDir, "*", SearchOption.TopDirectoryOnly)) - { - string newTargetDir = Path.Combine(targetDir, Path.GetFileName(dirPath)); - Directory.CreateDirectory(newTargetDir); - CopyDirectory(dirPath, newTargetDir); - } - - foreach (string filePath in Directory.GetFiles(sourceDir, "*.*", SearchOption.TopDirectoryOnly)) - { - string newFilePath = Path.Combine(targetDir, Path.GetFileName(filePath)); - File.Copy(filePath, newFilePath, true); - } - } - - #endregion - - #region Private Methods - - /// - /// Recursively read all files in the folder path. - /// - private IEnumerable ReadFileNode(string path, string rootPath = null) - { - var resultFiles = new List(); - rootPath ??= path; - if (!rootPath.EndsWith("/")) - { - rootPath += "/"; - } - var rootUri = new Uri(rootPath); - - foreach (var subPath in Directory.EnumerateFiles(path)) - { - if (BlackListManager.Instance.IsBlacklisted(subPath)) continue; - - var hashAlgorithm = new Sha256HashAlgorithm(); - var hash = hashAlgorithm.ComputeHash(subPath); - var subFileInfo = new FileInfo(subPath); - var subUri = new Uri(subFileInfo.FullName); - resultFiles.Add(new FileNode - { - Id = GetId(), - Path = path, - Name = subFileInfo.Name, - Hash = hash, - FullName = subFileInfo.FullName, - RelativePath = rootUri.MakeRelativeUri(subUri).ToString() - }); - } - - foreach (var subPath in Directory.EnumerateDirectories(path)) - { - if (BlackListManager.Instance.IsSkipDirectory(subPath)) continue; - resultFiles.AddRange(ReadFileNode(subPath, rootPath)); - } - - return resultFiles; - } - - /// - /// Self-growing file tree node ID. - /// - private long GetId() => Interlocked.Increment(ref _fileCount); - - private void ResetId() => Interlocked.Exchange(ref _fileCount, 0); - - #endregion - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/GeneralUpdate128.png b/src/c#/GeneralUpdate.Common/GeneralUpdate128.png deleted file mode 100644 index a50af55a..00000000 Binary files a/src/c#/GeneralUpdate.Common/GeneralUpdate128.png and /dev/null differ diff --git a/src/c#/GeneralUpdate.Common/HashAlgorithms/HashAlgorithmBase.cs b/src/c#/GeneralUpdate.Common/HashAlgorithms/HashAlgorithmBase.cs deleted file mode 100644 index fcf90816..00000000 --- a/src/c#/GeneralUpdate.Common/HashAlgorithms/HashAlgorithmBase.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.IO; -using System.Security.Cryptography; -using System.Text; - -namespace GeneralUpdate.Common.HashAlgorithms -{ - public abstract class HashAlgorithmBase - { - public string ComputeHash(string fileName) - { - if (!System.IO.File.Exists(fileName)) - throw new FileNotFoundException(nameof(fileName)); - - using var hashAlgorithm = GetHashAlgorithm(); - using var file = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read); - var dataArray = hashAlgorithm.ComputeHash(file); - var stringBuilder = new StringBuilder(); - for (int i = 0; i < dataArray.Length; i++) - { - stringBuilder.Append(dataArray[i].ToString("x2")); - } - return stringBuilder.ToString(); - } - - public byte[] ComputeHashBytes(string fileName) - { - if (!File.Exists(fileName)) - throw new FileNotFoundException(nameof(fileName)); - - using var hashAlgorithm = GetHashAlgorithm(); - using var file = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read); - return hashAlgorithm.ComputeHash(file); - } - - protected abstract HashAlgorithm GetHashAlgorithm(); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/HashAlgorithms/Sha256HashAlgorithm.cs b/src/c#/GeneralUpdate.Common/HashAlgorithms/Sha256HashAlgorithm.cs deleted file mode 100644 index 50c1d625..00000000 --- a/src/c#/GeneralUpdate.Common/HashAlgorithms/Sha256HashAlgorithm.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Security.Cryptography; - -namespace GeneralUpdate.Common.HashAlgorithms -{ - public class Sha256HashAlgorithm : HashAlgorithmBase - { - protected override HashAlgorithm GetHashAlgorithm() => SHA256.Create(); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/Bootstrap/AbstractBootstrap.cs b/src/c#/GeneralUpdate.Common/Internal/Bootstrap/AbstractBootstrap.cs deleted file mode 100644 index 451031bc..00000000 --- a/src/c#/GeneralUpdate.Common/Internal/Bootstrap/AbstractBootstrap.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System.Collections.Concurrent; -using System.Diagnostics; -using System.Threading.Tasks; -using GeneralUpdate.Common.Internal.Strategy; -using GeneralUpdate.Common.Shared; -using GeneralUpdate.Common.Shared.Object; - -namespace GeneralUpdate.Common.Internal.Bootstrap -{ - public abstract class AbstractBootstrap - where TBootstrap : AbstractBootstrap - where TStrategy : IStrategy - { - private readonly ConcurrentDictionary _options; - - protected internal AbstractBootstrap() => - _options = new ConcurrentDictionary(); - - /// - /// Launch async udpate. - /// - /// - public abstract Task LaunchAsync(); - - protected abstract void ExecuteStrategy(); - - protected abstract Task ExecuteStrategyAsync(); - - protected abstract TBootstrap StrategyFactory(); - - /// - /// Setting update configuration. - /// - /// - /// Configuration Action Enumeration. - /// Value - /// - public TBootstrap Option(UpdateOption option, T value) - { - if (value == null) - { - _options.TryRemove(option, out _); - } - else - { - _options[option] = new UpdateOptionValue(option, value); - } - return (TBootstrap)this; - } - - protected T? GetOption(UpdateOption? option) - { - try - { - Debug.Assert(option != null && _options.Count != 0); - var val = _options[option]; - if (val != null) return (T)val.GetValue(); - return default; - } - catch - { - return default; - } - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/Bootstrap/Environments.cs b/src/c#/GeneralUpdate.Common/Internal/Bootstrap/Environments.cs deleted file mode 100644 index 0cb417e1..00000000 --- a/src/c#/GeneralUpdate.Common/Internal/Bootstrap/Environments.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.IO; - -namespace GeneralUpdate.Common.Internal.Bootstrap; - -public static class Environments -{ - public static void SetEnvironmentVariable(string key, string value) - { - var filePath = Path.Combine(Path.GetTempPath(), $"{key}.txt"); - File.WriteAllText(filePath, value); - } - - public static string GetEnvironmentVariable(string key) - { - var filePath = Path.Combine(Path.GetTempPath(), $"{key}.txt"); - if (!File.Exists(filePath)) - return string.Empty; - - var content = File.ReadAllText(filePath); - File.SetAttributes(filePath, FileAttributes.Normal); - File.Delete(filePath); - return content; - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/Bootstrap/UpdateOption.cs b/src/c#/GeneralUpdate.Common/Internal/Bootstrap/UpdateOption.cs deleted file mode 100644 index 9fdb174d..00000000 --- a/src/c#/GeneralUpdate.Common/Internal/Bootstrap/UpdateOption.cs +++ /dev/null @@ -1,240 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.Contracts; -using System.Text; -using System.Threading; -using GeneralUpdate.Common.Shared.Object.Enum; - -namespace GeneralUpdate.Common.Internal.Bootstrap -{ - public abstract class UpdateOption : AbstractConstant - { - private class UpdateOptionPool : ConstantPool - { - protected override IConstant NewConstant(int id, string name) => new UpdateOption(id, name); - } - - private static readonly UpdateOptionPool Pool = new(); - - public static UpdateOption ValueOf(string name) => (UpdateOption)Pool.ValueOf(name); - - /// - /// Update the file format of the package. - /// - public static readonly UpdateOption Format = ValueOf("COMPRESSFORMAT"); - - /// - /// Compress encoding. - /// - public static readonly UpdateOption Encoding = ValueOf("COMPRESSENCODING"); - - /// - /// Timeout period (unit: second). If this parameter is not specified, the default timeout period is 30 seconds. - /// - public static readonly UpdateOption DownloadTimeOut = ValueOf("DOWNLOADTIMEOUT"); - - /// - /// Whether to enable the driver upgrade function. - /// - public static readonly UpdateOption Drive = ValueOf("DRIVE"); - - /// - /// Whether to enable the patch function. - /// - public static readonly UpdateOption Patch = ValueOf("PATCH"); - - /// - /// Whether to enable the backup function. - /// - public static readonly UpdateOption BackUp = ValueOf("BACKUP"); - - /// - /// Specifies the update execution mode. - /// - public static readonly UpdateOption Mode = ValueOf("MODE"); - - /// - /// Whether to enable silent update mode. - /// - public static readonly UpdateOption EnableSilentUpdate = ValueOf("ENABLESILENTUPDATE"); - - internal UpdateOption(int id, string name) - : base(id, name) { } - - public abstract bool Set(IUpdateConfiguration configuration, object value); - } - - public sealed class UpdateOption : UpdateOption - { - internal UpdateOption(int id, string name) - : base(id, name) - { - } - - public void Validate(T value) => Contract.Requires(value != null); - - public override bool Set(IUpdateConfiguration configuration, object value) => configuration.SetOption(this, (T)value); - } - - public abstract class ConstantPool - { - private readonly Dictionary constants = new Dictionary(); - private int nextId = 1; - - /// Shortcut of this.ValueOf(firstNameComponent.Name + "#" + secondNameComponent). - public IConstant ValueOf(Type firstNameComponent, string secondNameComponent) - { - Contract.Requires(firstNameComponent != null); - Contract.Requires(secondNameComponent != null); - return this.ValueOf(firstNameComponent.Name + '#' + secondNameComponent); - } - - /// - /// Returns the which is assigned to the specified name. - /// If there's no such , a new one will be created and returned. - /// Once created, the subsequent calls with the same name will always return the previously created one - /// (i.e. singleton.) - /// - /// the name of the - public IConstant ValueOf(string name) - { - IConstant constant; - lock (this.constants) - { - if (this.constants.TryGetValue(name, out constant)) - { - return constant; - } - else - { - constant = this.NewInstance0(name); - } - } - return constant; - } - - /// Returns true if a exists for the given name. - public bool Exists(string name) - { - CheckNotNullAndNotEmpty(name); - lock (this.constants) - return this.constants.ContainsKey(name); - } - - /// - /// Creates a new for the given name or fail with an - /// if a for the given name exists. - /// - public IConstant NewInstance(string name) - { - if (this.Exists(name)) throw new ArgumentException($"'{name}' is already in use"); - IConstant constant = this.NewInstance0(name); - return constant; - } - - // Be careful that this dose not check whether the argument is null or empty. - private IConstant NewInstance0(string name) - { - lock (this.constants) - { - IConstant constant = this.NewConstant(this.nextId, name); - this.constants[name] = constant; - this.nextId++; - return constant; - } - } - - private static void CheckNotNullAndNotEmpty(string name) => Contract.Requires(!string.IsNullOrEmpty(name)); - - protected abstract IConstant NewConstant(int id, string name); - - [Obsolete] - public int NextId() - { - lock (this.constants) - { - int id = this.nextId; - this.nextId++; - return id; - } - } - } - - public interface IConstant - { - /// Returns the unique number assigned to this . - int Id { get; } - - /// Returns the name of this . - string Name { get; } - } - - public interface IUpdateConfiguration - { - T GetOption(UpdateOption option); - - bool SetOption(UpdateOption option, object value); - - bool SetOption(UpdateOption option, T value); - } - - public abstract class AbstractConstant : IConstant - { - private static long nextUniquifier; - private long volatileUniquifier; - - protected AbstractConstant(int id, string name) - { - this.Id = id; - this.Name = name; - } - - public int Id { get; } - - public string Name { get; } - - public override sealed string ToString() => this.Name; - - protected long Uniquifier - { - get - { - long result; - if ((result = Volatile.Read(ref this.volatileUniquifier)) == 0) - { - result = Interlocked.Increment(ref nextUniquifier); - long previousUniquifier = Interlocked.CompareExchange(ref this.volatileUniquifier, result, 0); - if (previousUniquifier != 0) result = previousUniquifier; - } - return result; - } - } - } - - public abstract class AbstractConstant : AbstractConstant, IComparable, IEquatable - where T : AbstractConstant - { - /// Creates a new instance. - protected AbstractConstant(int id, string name) - : base(id, name) { } - - public override sealed int GetHashCode() => base.GetHashCode(); - - public override sealed bool Equals(object obj) => base.Equals(obj); - - public bool Equals(T other) => ReferenceEquals(this, other); - - public int CompareTo(T o) - { - if (ReferenceEquals(this, o)) return 0; - AbstractConstant other = o; - int returnCode = this.GetHashCode() - other.GetHashCode(); - if (returnCode != 0) return returnCode; - long thisUV = this.Uniquifier; - long otherUV = other.Uniquifier; - if (thisUV < otherUV) return -1; - if (thisUV > otherUV) return 1; - throw new System.Exception("failed to compare two different constants"); - } - } -} diff --git a/src/c#/GeneralUpdate.Common/Internal/Bootstrap/UpdateOptionValue.cs b/src/c#/GeneralUpdate.Common/Internal/Bootstrap/UpdateOptionValue.cs deleted file mode 100644 index 11c049e0..00000000 --- a/src/c#/GeneralUpdate.Common/Internal/Bootstrap/UpdateOptionValue.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace GeneralUpdate.Common.Internal.Bootstrap -{ - public abstract class UpdateOptionValue - { - public abstract UpdateOption Option { get; } - - public abstract bool Set(IUpdateConfiguration config); - - public abstract object GetValue(); - } - - public sealed class UpdateOptionValue : UpdateOptionValue - { - public override UpdateOption Option { get; } - private readonly T value; - - public UpdateOptionValue(UpdateOption option, T value) - { - this.Option = option; - this.value = value; - } - - public override object GetValue() => this.value; - - public override bool Set(IUpdateConfiguration config) => config.SetOption(this.Option, this.value); - - public override string ToString() => this.value.ToString(); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/Event/EventManager.cs b/src/c#/GeneralUpdate.Common/Internal/Event/EventManager.cs deleted file mode 100644 index 94f0a099..00000000 --- a/src/c#/GeneralUpdate.Common/Internal/Event/EventManager.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using GeneralUpdate.Common.Shared; - -namespace GeneralUpdate.Common.Internal.Event -{ - public class EventManager : IDisposable - { - private static readonly object _lockObj = new(); - private static EventManager _instance; - private Dictionary _dicDelegates = new(); - private bool _disposed = false; - - private EventManager() { } - - public static EventManager Instance - { - get - { - if (_instance == null) - { - lock (_lockObj) - { - if (_instance == null) - _instance = new EventManager(); - } - } - return _instance; - } - } - - public void AddListener(Action listener) where TEventArgs : EventArgs - { - try - { - if (listener == null) throw new ArgumentNullException(nameof(listener)); - var delegateType = typeof(Action); - if (_dicDelegates.ContainsKey(delegateType)) - { - _dicDelegates[delegateType] = Delegate.Combine(_dicDelegates[delegateType], listener); - } - else - { - _dicDelegates.Add(delegateType, listener); - } - } - catch (Exception e) - { - GeneralTracer.Error("The AddListener method in the EventManager class throws an exception.", e); - } - } - - public void RemoveListener(Action listener) where TEventArgs : EventArgs - { - try - { - if (listener == null) throw new ArgumentNullException(nameof(listener)); - var delegateType = typeof(Action); - if (_dicDelegates.TryGetValue(delegateType, out var existingDelegate)) - { - _dicDelegates[delegateType] = Delegate.Remove(existingDelegate, listener); - } - } - catch (Exception e) - { - GeneralTracer.Error("The RemoveListener method in the EventManager class throws an exception.", e); - } - } - - public void Dispatch(object sender, TEventArgs eventArgs) where TEventArgs : EventArgs - { - try - { - if (sender == null) throw new ArgumentNullException(nameof(sender)); - if (eventArgs == null) throw new ArgumentNullException(nameof(eventArgs)); - var delegateType = typeof(Action); - if (_dicDelegates.TryGetValue(delegateType, out var existingDelegate)) - { - ((Action)existingDelegate)?.Invoke(sender, eventArgs); - } - } - catch (Exception e) - { - GeneralTracer.Error("The Dispatch method in the EventManager class throws an exception.", e); - } - } - - public void Clear() => _dicDelegates.Clear(); - - public void Dispose() - { - try - { - if (!this._disposed) - { - _dicDelegates.Clear(); - _disposed = true; - } - } - catch (Exception e) - { - GeneralTracer.Error("The Dispose method in the EventManager class throws an exception.", e); - } - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/Event/IEventManager.cs b/src/c#/GeneralUpdate.Common/Internal/Event/IEventManager.cs deleted file mode 100644 index 34e017c4..00000000 --- a/src/c#/GeneralUpdate.Common/Internal/Event/IEventManager.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; - -namespace GeneralUpdate.Common.Internal.Event -{ - /// - /// Event manager interface. - /// - public interface IEventManager - { - /// - /// Adding Event Listeners. - /// - /// Generic delegate. - /// New delegate that needs to be injected. - void AddListener(TDelegate newDelegate) where TDelegate : Delegate; - - /// - /// Removing Event Listening. - /// - /// Generic delegate. - /// Need to remove an existing delegate. - void RemoveListener(TDelegate oldDelegate) where TDelegate : Delegate; - - /// - /// Triggers notifications of the same event type based on the listening event type. - /// - /// generic delegate. - /// Event handler. - /// Event args. - void Dispatch(object sender, EventArgs eventArgs) where TDelegate : Delegate; - - /// - /// Remove all injected delegates. - /// - void Clear(); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/Exception/ExceptionEventArgs.cs b/src/c#/GeneralUpdate.Common/Internal/Exception/ExceptionEventArgs.cs deleted file mode 100644 index ab5634ad..00000000 --- a/src/c#/GeneralUpdate.Common/Internal/Exception/ExceptionEventArgs.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace GeneralUpdate.Common.Internal; - -public class ExceptionEventArgs(Exception? exception = null, string? message = null) : EventArgs -{ - public Exception Exception { get; private set; } = exception; - public string Message { get; private set; } = message; -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/JsonContext/FileNodesJsonContext.cs b/src/c#/GeneralUpdate.Common/Internal/JsonContext/FileNodesJsonContext.cs deleted file mode 100644 index b0ca8541..00000000 --- a/src/c#/GeneralUpdate.Common/Internal/JsonContext/FileNodesJsonContext.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System.Collections.Generic; -using System.Text.Json.Serialization; -using GeneralUpdate.Common.FileBasic; - -namespace GeneralUpdate.Common.Internal.JsonContext; - -[JsonSerializable(typeof(List))] -public partial class FileNodesJsonContext : JsonSerializerContext; \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/JsonContext/GlobalConfigInfoOSSJsonContext.cs b/src/c#/GeneralUpdate.Common/Internal/JsonContext/GlobalConfigInfoOSSJsonContext.cs deleted file mode 100644 index bcb9fbaa..00000000 --- a/src/c#/GeneralUpdate.Common/Internal/JsonContext/GlobalConfigInfoOSSJsonContext.cs +++ /dev/null @@ -1,7 +0,0 @@ -using System.Text.Json.Serialization; -using GeneralUpdate.Common.Shared.Object; - -namespace GeneralUpdate.Common.Internal.JsonContext; - -[JsonSerializable(typeof(GlobalConfigInfoOSS))] -public partial class GlobalConfigInfoOSSJsonContext : JsonSerializerContext; \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/JsonContext/HttpParameterJsonContext.cs b/src/c#/GeneralUpdate.Common/Internal/JsonContext/HttpParameterJsonContext.cs deleted file mode 100644 index 2df040f0..00000000 --- a/src/c#/GeneralUpdate.Common/Internal/JsonContext/HttpParameterJsonContext.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; -using System.Text.Json.Serialization; - -namespace GeneralUpdate.Common.Internal.JsonContext; - -[JsonSerializable(typeof(bool))] -[JsonSerializable(typeof(bool?))] -[JsonSerializable(typeof(int))] -[JsonSerializable(typeof(int?))] -[JsonSerializable(typeof(string))] -[JsonSerializable(typeof(Dictionary))] -public partial class HttpParameterJsonContext: JsonSerializerContext; \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/JsonContext/PacketJsonContext.cs b/src/c#/GeneralUpdate.Common/Internal/JsonContext/PacketJsonContext.cs deleted file mode 100644 index 7b64503d..00000000 --- a/src/c#/GeneralUpdate.Common/Internal/JsonContext/PacketJsonContext.cs +++ /dev/null @@ -1,7 +0,0 @@ -using System.Text.Json.Serialization; -using GeneralUpdate.Common.Shared.Object; - -namespace GeneralUpdate.Common.Internal.JsonContext; - -[JsonSerializable(typeof(Packet))] -public partial class PacketJsonContext : JsonSerializerContext; \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/JsonContext/ProcessInfoJsonContext.cs b/src/c#/GeneralUpdate.Common/Internal/JsonContext/ProcessInfoJsonContext.cs deleted file mode 100644 index ccd4f493..00000000 --- a/src/c#/GeneralUpdate.Common/Internal/JsonContext/ProcessInfoJsonContext.cs +++ /dev/null @@ -1,7 +0,0 @@ -using System.Text.Json.Serialization; -using GeneralUpdate.Common.Shared.Object; - -namespace GeneralUpdate.Common.Internal.JsonContext; - -[JsonSerializable(typeof(ProcessInfo))] -public partial class ProcessInfoJsonContext : JsonSerializerContext; \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/JsonContext/ReportRespJsonContext.cs b/src/c#/GeneralUpdate.Common/Internal/JsonContext/ReportRespJsonContext.cs deleted file mode 100644 index bb6eeb96..00000000 --- a/src/c#/GeneralUpdate.Common/Internal/JsonContext/ReportRespJsonContext.cs +++ /dev/null @@ -1,7 +0,0 @@ -using System.Text.Json.Serialization; -using GeneralUpdate.Common.Shared.Object; - -namespace GeneralUpdate.Common.Internal.JsonContext; - -[JsonSerializable(typeof(BaseResponseDTO))] -public partial class ReportRespJsonContext : JsonSerializerContext; \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/JsonContext/VersionOSSJsonContext.cs b/src/c#/GeneralUpdate.Common/Internal/JsonContext/VersionOSSJsonContext.cs deleted file mode 100644 index bd908333..00000000 --- a/src/c#/GeneralUpdate.Common/Internal/JsonContext/VersionOSSJsonContext.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System.Collections.Generic; -using System.Text.Json.Serialization; -using GeneralUpdate.Common.Shared.Object; - -namespace GeneralUpdate.Common.Internal.JsonContext; - -[JsonSerializable(typeof(List))] -public partial class VersionOSSJsonContext : JsonSerializerContext; \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/JsonContext/VersionRespJsonContext.cs b/src/c#/GeneralUpdate.Common/Internal/JsonContext/VersionRespJsonContext.cs deleted file mode 100644 index c6aa0069..00000000 --- a/src/c#/GeneralUpdate.Common/Internal/JsonContext/VersionRespJsonContext.cs +++ /dev/null @@ -1,7 +0,0 @@ -using System.Text.Json.Serialization; -using GeneralUpdate.Common.Shared.Object; - -namespace GeneralUpdate.Common.Internal.JsonContext; - -[JsonSerializable(typeof(VersionRespDTO))] -public partial class VersionRespJsonContext : JsonSerializerContext; \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/Pipeline/IMiddleware.cs b/src/c#/GeneralUpdate.Common/Internal/Pipeline/IMiddleware.cs deleted file mode 100644 index 606b1c7c..00000000 --- a/src/c#/GeneralUpdate.Common/Internal/Pipeline/IMiddleware.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Threading.Tasks; - -namespace GeneralUpdate.Common.Internal.Pipeline -{ - /// - /// Pipeline middleware. - /// - public interface IMiddleware - { - Task InvokeAsync(PipelineContext context); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/Pipeline/PipelineBuilder.cs b/src/c#/GeneralUpdate.Common/Internal/Pipeline/PipelineBuilder.cs deleted file mode 100644 index f8e45ca5..00000000 --- a/src/c#/GeneralUpdate.Common/Internal/Pipeline/PipelineBuilder.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Immutable; -using System.Threading.Tasks; - -namespace GeneralUpdate.Common.Internal.Pipeline -{ - /// - /// Pipeline builder. - /// - public sealed class PipelineBuilder(PipelineContext context) - { - /// - /// LIFO,Last In First Out. - /// - private ImmutableStack _middlewareStack = ImmutableStack.Empty; - - public PipelineBuilder UseMiddleware() where TMiddleware : IMiddleware, new() - { - var middleware = new TMiddleware(); - _middlewareStack = _middlewareStack.Push(middleware); - return this; - } - - public PipelineBuilder UseMiddlewareIf(bool? condition) - where TMiddleware : IMiddleware, new() - { - if (condition is null or false) - return this; - - var middleware = new TMiddleware(); - _middlewareStack = _middlewareStack.Push(middleware); - return this; - } - - public async Task Build() - { - foreach (var middleware in _middlewareStack) - { - await middleware.InvokeAsync(context); - } - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/Pipeline/PipelineContext.cs b/src/c#/GeneralUpdate.Common/Internal/Pipeline/PipelineContext.cs deleted file mode 100644 index 8a85686f..00000000 --- a/src/c#/GeneralUpdate.Common/Internal/Pipeline/PipelineContext.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Collections.Concurrent; - -namespace GeneralUpdate.Common.Internal.Pipeline; - -public class PipelineContext -{ - private ConcurrentDictionary _context = new(); - - public TValue? Get(string key) - { - if (_context.TryGetValue(key, out var value)) - { - return value is TValue typedValue ? typedValue : default; - } - return default; - } - - public void Add(string key, TValue? value) - { - if (string.IsNullOrWhiteSpace(key)) - { - throw new ArgumentException("Key cannot be null or whitespace.", nameof(key)); - } - - _context[key] = value; - } - - public bool Remove(string key) => _context.TryRemove(key, out _); - - public bool ContainsKey(string key) => _context.ContainsKey(key); -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/Strategy/AbstractStrategy.cs b/src/c#/GeneralUpdate.Common/Internal/Strategy/AbstractStrategy.cs deleted file mode 100644 index dc52f927..00000000 --- a/src/c#/GeneralUpdate.Common/Internal/Strategy/AbstractStrategy.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; -using GeneralUpdate.Common.FileBasic; -using GeneralUpdate.Common.Internal.Event; -using GeneralUpdate.Common.Internal.Pipeline; -using GeneralUpdate.Common.Shared; -using GeneralUpdate.Common.Shared.Object; -using GeneralUpdate.Common.Shared.Object.Enum; -using GeneralUpdate.Common.Shared.Service; - -namespace GeneralUpdate.Common.Internal.Strategy -{ - public abstract class AbstractStrategy : IStrategy - { - private const string Patchs = "patchs"; - protected GlobalConfigInfo _configinfo = new(); - - public virtual void Execute() => throw new NotImplementedException(); - - public virtual void StartApp() => throw new NotImplementedException(); - - public virtual async Task ExecuteAsync() - { - try - { - var status = ReportType.None; - var patchPath = StorageManager.GetTempDirectory(Patchs); - foreach (var version in _configinfo.UpdateVersions) - { - try - { - var context = CreatePipelineContext(version, patchPath); - var pipelineBuilder = BuildPipeline(context); - await pipelineBuilder.Build(); - status = ReportType.Success; - } - catch (Exception e) - { - status = ReportType.Failure; - HandleExecuteException(e); - } - finally - { - await VersionService.Report(_configinfo.ReportUrl - , version.RecordId - , status - , version.AppType - , _configinfo.Scheme - , _configinfo.Token); - } - } - - Clear(patchPath); - Clear(_configinfo.TempPath); - OnExecuteComplete(); - } - catch (Exception e) - { - HandleExecuteException(e); - } - } - - public virtual void Create(GlobalConfigInfo parameter) => _configinfo = parameter; - - /// - /// Creates the pipeline context with common and platform-specific parameters. - /// Override this method to add platform-specific context parameters. - /// - protected virtual PipelineContext CreatePipelineContext(VersionInfo version, string patchPath) - { - var context = new PipelineContext(); - // Common parameters - context.Add("ZipFilePath", Path.Combine(_configinfo.TempPath, $"{version.Name}{_configinfo.Format}")); - // Hash middleware - context.Add("Hash", version.Hash); - // Zip middleware - context.Add("Format", _configinfo.Format); - context.Add("Name", version.Name); - context.Add("Encoding", _configinfo.Encoding); - // Patch middleware - context.Add("SourcePath", _configinfo.InstallPath); - context.Add("PatchPath", patchPath); - context.Add("PatchEnabled", _configinfo.PatchEnabled); - - return context; - } - - /// - /// Builds the pipeline with middleware components. - /// Override this method to customize the pipeline for specific platforms. - /// - protected abstract PipelineBuilder BuildPipeline(PipelineContext context); - - /// - /// Called after ExecuteAsync completes successfully. - /// Override this method to add platform-specific post-execution logic. - /// - protected virtual void OnExecuteComplete() - { - // Default implementation does nothing - } - - /// - /// Handles exceptions during execution. - /// Override this method to customize error handling. - /// - protected virtual void HandleExecuteException(Exception e) - { - GeneralTracer.Error($"Strategy execution exception.", e); - EventManager.Instance.Dispatch(this, new ExceptionEventArgs(e, e.Message)); - } - - /// - /// Checks if a file exists at the specified path. - /// - protected static string CheckPath(string path, string name) - { - if (string.IsNullOrWhiteSpace(path) || string.IsNullOrWhiteSpace(name)) - return string.Empty; - var tempPath = Path.Combine(path, name); - return File.Exists(tempPath) ? tempPath : string.Empty; - } - - private static void Clear(string path) - { - if (Directory.Exists(path)) - StorageManager.DeleteDirectory(path); - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Internal/Strategy/IStrategy.cs b/src/c#/GeneralUpdate.Common/Internal/Strategy/IStrategy.cs deleted file mode 100644 index bc583b71..00000000 --- a/src/c#/GeneralUpdate.Common/Internal/Strategy/IStrategy.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Threading.Tasks; -using GeneralUpdate.Common.Shared.Object; - -namespace GeneralUpdate.Common.Internal.Strategy -{ - /// - /// Update the strategy, if you need to extend it, you need to inherit this interface. - /// - public interface IStrategy - { - /// - /// Execution strategy. - /// - void Execute(); - - /// - /// After the update is complete. - /// - void StartApp(); - - /// - /// Execution strategy. - /// - Task ExecuteAsync(); - - /// - /// Create a strategy. - /// - void Create(GlobalConfigInfo parameter); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/BaseConfigInfo.cs b/src/c#/GeneralUpdate.Common/Shared/Object/BaseConfigInfo.cs deleted file mode 100644 index 681c6096..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/BaseConfigInfo.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace GeneralUpdate.Common.Shared.Object -{ - /// - /// Base configuration class containing common fields shared across all configuration objects. - /// This class serves as the foundation for user-facing configuration (Configinfo), - /// internal runtime state (GlobalConfigInfo), and inter-process communication (ProcessInfo). - /// - public abstract class BaseConfigInfo - { - /// - /// The name of the application that needs to be started after update. - /// This is the executable name without extension (e.g., "MyApp" for MyApp.exe). - /// Default value is "Update.exe". - /// - public string AppName { get; set; } = "Update.exe"; - - /// - /// The name of the main application without file extension. - /// Used to identify the primary application process that will be updated. - /// - public string MainAppName { get; set; } - - /// - /// The installation path where application files are located. - /// This is the root directory used for update file operations. - /// Default value is the current program's running directory. - /// - public string InstallPath { get; set; } = AppDomain.CurrentDomain.BaseDirectory; - - /// - /// The URL address for the update log webpage. - /// Users can view detailed changelog information at this address. - /// - public string UpdateLogUrl { get; set; } - - /// - /// The application secret key used for authentication. - /// This key is validated when requesting update information from the server. - /// - public string AppSecretKey { get; set; } - - /// - /// The current version of the client application. - /// Format should follow semantic versioning (e.g., "1.0.0"). - /// - public string ClientVersion { get; set; } - - /// - /// List of specific files that should be excluded from the update process. - /// Files in this blacklist will be skipped during update operations. - /// - public List BlackFiles { get; set; } - - /// - /// List of file format extensions that should be excluded from the update process. - /// For example: [".log", ".tmp", ".cache"] will skip all files with these extensions. - /// - public List BlackFormats { get; set; } - - /// - /// List of directory paths that should be skipped during the update process. - /// Entire directories in this list will be ignored during update operations. - /// - public List SkipDirectorys { get; set; } - - /// - /// The API endpoint URL for reporting update status and results. - /// Update progress and completion status will be sent to this URL. - /// - public string ReportUrl { get; set; } - - /// - /// The process name that should be terminated before starting the update. - /// This is typically used to close conflicting processes (e.g., "Bowl" process). - /// - public string Bowl { get; set; } - - /// - /// The URL scheme used for update requests (e.g., "http" or "https"). - /// This determines the protocol used for server communication. - /// - public string Scheme { get; set; } - - /// - /// The authentication token used for API requests. - /// This token is included in HTTP headers when communicating with the update server. - /// - public string Token { get; set; } - - /// - /// Shell script content used to grant file permissions on Linux/Unix systems. - /// This script is executed after update to ensure proper file permissions. - /// - public string Script { get; set; } - - /// - /// The directory path containing driver files for driver update functionality. - /// Used when DriveEnabled is true to locate and install driver files during updates. - /// - public string DriverDirectory { get; set; } - } -} diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/Configinfo.cs b/src/c#/GeneralUpdate.Common/Shared/Object/Configinfo.cs deleted file mode 100644 index 855d17d0..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/Configinfo.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace GeneralUpdate.Common.Shared.Object -{ - /// - /// User-facing configuration class for update parameters. - /// This class is designed for external API consumers to configure update behavior. - /// Inherits common fields from BaseConfigInfo to reduce duplication and improve maintainability. - /// - public class Configinfo : BaseConfigInfo - { - /// - /// The API endpoint URL for checking available updates. - /// The client queries this URL to determine if new versions are available. - /// - public string UpdateUrl { get; set; } - - /// - /// The current version of the upgrade application (the updater itself). - /// This allows the updater tool to be updated separately from the main application. - /// - public string UpgradeClientVersion { get; set; } - - /// - /// The unique product identifier used for tracking and update management. - /// Multiple products can share the same update infrastructure using different IDs. - /// - public string ProductId { get; set; } - - public void Validate() - { - if (string.IsNullOrWhiteSpace(UpdateUrl) || !Uri.IsWellFormedUriString(UpdateUrl, UriKind.Absolute)) - throw new ArgumentException("Invalid UpdateUrl"); - - if (!string.IsNullOrWhiteSpace(UpdateLogUrl) && !Uri.IsWellFormedUriString(UpdateLogUrl, UriKind.Absolute)) - throw new ArgumentException("Invalid UpdateLogUrl"); - - if (string.IsNullOrWhiteSpace(AppName)) - throw new ArgumentException("AppName cannot be empty"); - - if (string.IsNullOrWhiteSpace(MainAppName)) - throw new ArgumentException("MainAppName cannot be empty"); - - if (string.IsNullOrWhiteSpace(AppSecretKey)) - throw new ArgumentException("AppSecretKey cannot be empty"); - - if (string.IsNullOrWhiteSpace(ClientVersion)) - throw new ArgumentException("ClientVersion cannot be empty"); - - if (string.IsNullOrWhiteSpace(InstallPath)) - throw new ArgumentException("InstallPath cannot be empty"); - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder-Example.cs b/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder-Example.cs deleted file mode 100644 index bda8fac9..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder-Example.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using GeneralUpdate.Common.Shared.Object; - -namespace ConfiginfoBuilderExample -{ - /// - /// Example demonstrating the ConfiginfoBuilder usage with JSON configuration - /// - class Program - { - static void Main(string[] args) - { - Console.WriteLine("=== ConfiginfoBuilder Usage Examples ===\n"); - - // Example 1: Load configuration from JSON file (recommended) - Console.WriteLine("Example 1: Loading from update_config.json file"); - Console.WriteLine("This example requires an update_config.json file in the running directory."); - Console.WriteLine("The configuration file has the highest priority and must contain all required settings.\n"); - - try - { - // Create update_config.json for demonstration - CreateExampleConfigFile(); - - // Simply call Create() with no parameters - it loads from update_config.json - var config = ConfiginfoBuilder.Create().Build(); - - Console.WriteLine($" UpdateUrl: {config.UpdateUrl}"); - Console.WriteLine($" Token: {config.Token}"); - Console.WriteLine($" Scheme: {config.Scheme}"); - Console.WriteLine($" InstallPath: {config.InstallPath}"); - Console.WriteLine($" AppName: {config.AppName}"); - Console.WriteLine($" ClientVersion: {config.ClientVersion}"); - Console.WriteLine(); - } - catch (FileNotFoundException ex) - { - Console.WriteLine($" Error: {ex.Message}"); - Console.WriteLine(" Please create update_config.json in the running directory."); - Console.WriteLine(); - } - finally - { - CleanupExampleConfigFile(); - } - - // Example 2: Customizing configuration after loading from file - Console.WriteLine("Example 2: Loading from JSON and customizing with method chaining"); - try - { - CreateExampleConfigFile(); - - var customConfig = ConfiginfoBuilder.Create() - .SetAppName("CustomApp.exe") - .SetInstallPath("/custom/path") - .Build(); - - Console.WriteLine($" AppName: {customConfig.AppName}"); - Console.WriteLine($" InstallPath: {customConfig.InstallPath}"); - Console.WriteLine(); - } - catch (FileNotFoundException ex) - { - Console.WriteLine($" Error: {ex.Message}"); - Console.WriteLine(); - } - finally - { - CleanupExampleConfigFile(); - } - - // Example 3: Error handling when config file is missing - Console.WriteLine("Example 3: Error Handling - Missing Configuration File"); - try - { - var config = ConfiginfoBuilder.Create().Build(); - } - catch (FileNotFoundException ex) - { - Console.WriteLine($" Caught expected error: {ex.Message}"); - Console.WriteLine(" This is expected when update_config.json doesn't exist."); - } - Console.WriteLine(); - - Console.WriteLine("\n=== All Examples Completed! ==="); - Console.WriteLine("\nNote: ConfiginfoBuilder now requires update_config.json file."); - Console.WriteLine("See update_config.example.json for a complete example."); - } - - private static void CreateExampleConfigFile() - { - var configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "update_config.json"); - var exampleConfig = @"{ - ""UpdateUrl"": ""https://api.example.com/updates"", - ""Token"": ""example-auth-token"", - ""Scheme"": ""https"", - ""AppName"": ""Update.exe"", - ""MainAppName"": ""MyApplication.exe"", - ""ClientVersion"": ""1.0.0"", - ""UpgradeClientVersion"": ""1.0.0"", - ""AppSecretKey"": ""example-secret-key"", - ""ProductId"": ""example-product-id"" -}"; - File.WriteAllText(configPath, exampleConfig); - } - - private static void CleanupExampleConfigFile() - { - var configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "update_config.json"); - if (File.Exists(configPath)) - { - File.Delete(configPath); - } - } - } -} diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder-Usage.md b/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder-Usage.md deleted file mode 100644 index 9e8a0dfc..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder-Usage.md +++ /dev/null @@ -1,366 +0,0 @@ -# ConfiginfoBuilder Usage Guide - -The `ConfiginfoBuilder` class provides a simple and convenient way to create `Configinfo` objects for the GeneralUpdate system. It supports both JSON-based configuration and programmatic configuration. - -**Design Philosophy**: Inspired by zero-configuration patterns from projects like [Velopack](https://github.com/velopack/velopack), this builder minimizes required configuration while maintaining flexibility through optional fluent setters. - -## Configuration Methods - -There are two main ways to configure the update system: - -### 1. JSON Configuration File (Recommended) - -Place an `update_config.json` file in your application's running directory. When this file exists, ConfiginfoBuilder automatically loads all settings from it, giving the configuration file the highest priority. - -**Example `update_config.json`:** -```json -{ - "UpdateUrl": "https://api.example.com/updates", - "Token": "your-authentication-token", - "Scheme": "https", - "AppName": "Update.exe", - "MainAppName": "MyApplication.exe", - "ClientVersion": "1.0.0", - "InstallPath": "/path/to/installation", - "BlackFormats": [".log", ".tmp", ".cache"], - "SkipDirectorys": ["/temp", "/logs"] -} -``` - -See [update_config.example.json](update_config.example.json) for a complete example with all available options. - -**Usage:** -```csharp -// The Create method will automatically load from update_config.json if it exists -var config = ConfiginfoBuilder - .Create("fallback-url", "fallback-token", "https") - .Build(); -// If update_config.json exists, all values come from the file -// Parameters are only used as fallback if file doesn't exist -``` - -### 2. Programmatic Configuration - -Configure the update system entirely through code using the fluent API: - -## Automatic Configuration Detection - -The ConfiginfoBuilder implements intelligent zero-configuration by automatically extracting information from your project: - -### Comprehensive Project Metadata Extraction - -The builder automatically attempts to read multiple fields from your project file (`.csproj`): - -1. **Application Name** (maps to `AppName`, `MainAppName`) - - **Extracts** the `` property if specified - - **Falls back** to the csproj file name if `AssemblyName` is not defined - - **Applies** platform-specific extensions (`.exe` on Windows, none on Linux/macOS) - -2. **Version Number** (maps to `ClientVersion`, `UpgradeClientVersion`) - - **Reads** the `` property from csproj - - **Falls back** to default "1.0.0" if not specified - -3. **Publisher Information** (maps to `ProductId`) - - **Prioritizes** the `` property - - **Falls back** to `` property if Company not specified - - **Uses** default value if neither is available - -**Example:** -```xml - - - - MyApplication - 2.1.5 - MyCompany - Development Team - - -``` - -When the builder runs, it will automatically extract: -- **App Name**: `MyApplication.exe` (Windows) or `MyApplication` (Linux/macOS) -- **Version**: `2.1.5` -- **Product ID**: `MyCompany` - -All automatic with zero configuration needed! - -## Basic Usage - -### Minimal Configuration - -The simplest way to create a `Configinfo` object is to provide just the three required parameters: - -```csharp -using GeneralUpdate.Common.Shared.Object; - -// Method 1: Direct constructor (traditional) -var config = new ConfiginfoBuilder( - updateUrl: "https://api.example.com/updates", - token: "your-auth-token", - scheme: "https" -).Build(); - -// Method 2: Factory method (recommended, more fluent) -var config2 = ConfiginfoBuilder - .Create("https://api.example.com/updates", "your-auth-token", "https") - .Build(); - -// The config object now has all necessary defaults set based on the platform -// Application name is automatically detected from your project file! -``` - -## Platform-Specific Defaults - -The builder automatically detects the runtime platform and sets appropriate defaults: - -### Windows Platform -- **Install Path**: Current application's base directory (via `AppDomain.CurrentDomain.BaseDirectory`) -- **App Names**: Auto-detected from csproj + `.exe` extension (e.g., `MyApp.exe`) -- **Script**: Empty (Windows doesn't typically need permission scripts) -- **Path Separator**: Backslash (`\`) - handled automatically by .NET -- **Black Formats**: `.log`, `.tmp` (from `ConfiginfoBuilder.DefaultBlackFormats`) - -### Linux Platform -- **Install Path**: Current application's base directory (via `AppDomain.CurrentDomain.BaseDirectory`) -- **App Names**: Auto-detected from csproj, no `.exe` extension (e.g., `myapp`) -- **Script**: Default chmod script for granting execution permissions -- **Path Separator**: Forward slash (`/`) - handled automatically by .NET -- **Black Formats**: `.log`, `.tmp` (from `ConfiginfoBuilder.DefaultBlackFormats`) - -### macOS Platform -- **Install Path**: Current application's base directory (via `AppDomain.CurrentDomain.BaseDirectory`) -- **App Names**: Auto-detected from csproj, no `.exe` extension (e.g., `myapp`) -- **Script**: Default chmod script for granting execution permissions -- **Path Separator**: Forward slash (`/`) - handled automatically by .NET -- **Black Formats**: `.log`, `.tmp` (from `ConfiginfoBuilder.DefaultBlackFormats`) - -**Note**: The install path defaults to the current application's running directory, which does not require administrator privileges and automatically extracts the location from the host program. - -## Customizing Configuration - -You can override any default value using the fluent API: - -```csharp -var config = new ConfiginfoBuilder( - "https://api.example.com/updates", - "your-auth-token", - "https" -) -.SetAppName("MyApplication.exe") -.SetMainAppName("MyApplication.exe") -.SetClientVersion("1.5.0") -.SetInstallPath("/opt/myapp") -.SetAppSecretKey("my-secret-key") -.SetProductId("product-123") -.Build(); -``` - -## Advanced Configuration - -### Setting Update URLs - -```csharp -var config = new ConfiginfoBuilder(updateUrl, token, scheme) - .SetUpdateLogUrl("https://example.com/changelog") - .SetReportUrl("https://api.example.com/report") - .Build(); -``` - -### Configuring File Filters - -You can customize which files should be excluded from updates. By default, `.log` and `.tmp` files are excluded: - -```csharp -// Use default black formats -var config1 = new ConfiginfoBuilder(updateUrl, token, scheme).Build(); -// config1.BlackFormats will contain ConfiginfoBuilder.DefaultBlackFormats (.log, .tmp) - -// Override with custom filters -var config2 = new ConfiginfoBuilder(updateUrl, token, scheme) - .SetBlackFiles(new List { "config.json", "user.dat" }) - .SetBlackFormats(new List { ".log", ".tmp", ".cache", ".bak" }) - .SetSkipDirectorys(new List { "/temp", "/logs" }) - .Build(); -``` - -### Setting Process and Script Options - -```csharp -var config = new ConfiginfoBuilder(updateUrl, token, scheme) - .SetBowl("Bowl.exe") // Process to terminate before update - .SetScript("#!/bin/bash\nchmod +x \"$1\"") // Custom permission script - .SetDriverDirectory("/opt/myapp/drivers") - .Build(); -``` - -## Complete Example - -Here's a comprehensive example showing all available options: - -```csharp -using GeneralUpdate.Common.Shared.Object; -using System.Collections.Generic; - -public class UpdateConfigExample -{ - public static Configinfo CreateUpdateConfig() - { - var config = new ConfiginfoBuilder( - updateUrl: "https://api.example.com/updates", - token: "Bearer abc123xyz", - scheme: "https" - ) - // Application Info - .SetAppName("MyApp.exe") - .SetMainAppName("MyApp.exe") - .SetClientVersion("2.1.0") - .SetUpgradeClientVersion("1.0.0") - .SetProductId("myapp-001") - .SetAppSecretKey("secure-secret-key-789") - - // Paths - .SetInstallPath("/opt/myapp") - .SetDriverDirectory("/opt/myapp/drivers") - - // URLs - .SetUpdateLogUrl("https://myapp.example.com/changelog") - .SetReportUrl("https://api.example.com/report") - - // File Filters - .SetBlackFiles(new List - { - "config.json", - "user-settings.dat" - }) - .SetBlackFormats(new List - { - ".log", - ".tmp", - ".cache", - ".bak" - }) - .SetSkipDirectorys(new List - { - "/temp", - "/logs", - "/cache" - }) - - // Process Options - .SetBowl("Bowl.exe") - .SetScript("#!/bin/bash\nchmod +x \"$1\"\n") - - .Build(); - - // Validate the configuration - config.Validate(); - - return config; - } -} -``` - -## Error Handling - -The builder performs validation at two stages: - -### Construction Time -The constructor validates the three required parameters: - -```csharp -try -{ - var builder = new ConfiginfoBuilder( - null, // Invalid: null UpdateUrl - "token", - "https" - ); -} -catch (ArgumentException ex) -{ - Console.WriteLine($"Error: {ex.Message}"); - // Output: UpdateUrl cannot be null or empty. -} -``` - -### Build Time -The `Build()` method validates the complete configuration: - -```csharp -try -{ - var config = new ConfiginfoBuilder(updateUrl, token, scheme) - .SetAppName("") // Invalid: empty app name - .Build(); -} -catch (InvalidOperationException ex) -{ - Console.WriteLine($"Build Error: {ex.Message}"); - // Output: Failed to build valid Configinfo: AppName cannot be empty -} -``` - -## Best Practices - -1. **Use Minimal Configuration**: Only override defaults when necessary -2. **Validate Early**: Let the builder validate parameters immediately -3. **Use Method Chaining**: Take advantage of the fluent API for clean code -4. **Platform Awareness**: Let the builder handle platform-specific defaults -5. **Secure Tokens**: Never hardcode authentication tokens in production code - -## Migration from Manual Construction - -### Before (Manual Construction) -```csharp -var config = new Configinfo -{ - UpdateUrl = "https://api.example.com/updates", - Token = "token", - Scheme = "https", - AppName = "App.exe", - MainAppName = "App.exe", - ClientVersion = "1.0.0", - UpgradeClientVersion = "1.0.0", - InstallPath = Thread.GetDomain().BaseDirectory, - AppSecretKey = "secret", - ProductId = "product", - BlackFiles = new List(), - BlackFormats = new List { ".log", ".tmp" }, - SkipDirectorys = new List() -}; -``` - -### After (Using Builder) -```csharp -var config = new ConfiginfoBuilder( - "https://api.example.com/updates", - "token", - "https" -).Build(); // All defaults are set automatically! -``` - -## Platform Detection Example - -The builder automatically adapts to the runtime environment: - -```csharp -var config = new ConfiginfoBuilder(updateUrl, token, scheme).Build(); - -if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) -{ - Console.WriteLine($"Windows config: {config.InstallPath}"); - // Output: Windows config: C:\MyApp\ (current application directory) -} -else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) -{ - Console.WriteLine($"Linux config: {config.InstallPath}"); - // Output: Linux config: /opt/myapp/ (current application directory) -} -``` - -## See Also - -- `Configinfo` class documentation -- `BaseConfigInfo` class documentation -- GeneralUpdate main documentation diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder.cs b/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder.cs deleted file mode 100644 index 924da8f5..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/ConfiginfoBuilder.cs +++ /dev/null @@ -1,413 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text.Json; - -namespace GeneralUpdate.Common.Shared.Object -{ - /// - /// Universal ConfigInfo builder class that simplifies creation of update configurations. - /// Only requires three essential parameters (UpdateUrl, Token, Scheme) while automatically - /// generating platform-appropriate defaults for all other configuration items. - /// Inspired by zero-configuration design patterns from projects like Velopack. - /// - public class ConfiginfoBuilder - { - // Configurable default values - // Note: AppName and InstallPath defaults are set in Configinfo class itself - // These are ConfiginfoBuilder-specific defaults to support the builder pattern - private string _updateUrl; - private string _token; - private string _scheme; - private string _appName = "Update.exe"; - private string _mainAppName; - private string _clientVersion; - private string _upgradeClientVersion; - private string _appSecretKey; - private string _productId; - private string _installPath; - private string _updateLogUrl; - private string _reportUrl; - private string _bowl; - private string _script; - private string _driverDirectory; - private List _blackFiles; - private List _blackFormats; - private List _skipDirectorys; - - /// - /// Creates a new ConfiginfoBuilder instance by loading configuration from update_config.json file. - /// The configuration file must exist in the running directory and contain all required settings. - /// Configuration file has the highest priority - all settings must be specified in the JSON file. - /// - /// A new ConfiginfoBuilder instance with settings loaded from the configuration file. - /// Thrown when update_config.json is not found. - /// Thrown when the configuration file is invalid or cannot be loaded. - public static ConfiginfoBuilder Create() - { - // Try to load from configuration file - var configFromFile = LoadFromConfigFile(); - if (configFromFile != null) - { - // Configuration file loaded successfully - return configFromFile; - } - - // If no config file exists, throw an exception - throw new FileNotFoundException("Configuration file 'update_config.json' not found in the running directory. Please create this file with the required settings."); - } - - /// - /// Loads configuration from update_config.json file in the running directory. - /// - /// ConfiginfoBuilder with settings from file, or null if file doesn't exist or is invalid. - private static ConfiginfoBuilder LoadFromConfigFile() - { - try - { - var configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "update_config.json"); - if (!File.Exists(configPath)) - { - return null; - } - - var json = File.ReadAllText(configPath); - var config = JsonSerializer.Deserialize(json, new JsonSerializerOptions - { - PropertyNameCaseInsensitive = true - }); - - if (config == null) - { - return null; - } - - // Create a builder with the loaded configuration - var builder = new ConfiginfoBuilder(); - - // Apply all loaded settings - if (!string.IsNullOrWhiteSpace(config.UpdateUrl)) - builder.SetUpdateUrl(config.UpdateUrl); - if (!string.IsNullOrWhiteSpace(config.Token)) - builder.SetToken(config.Token); - if (!string.IsNullOrWhiteSpace(config.Scheme)) - builder.SetScheme(config.Scheme); - if (!string.IsNullOrWhiteSpace(config.AppName)) - builder.SetAppName(config.AppName); - if (!string.IsNullOrWhiteSpace(config.MainAppName)) - builder.SetMainAppName(config.MainAppName); - if (!string.IsNullOrWhiteSpace(config.ClientVersion)) - builder.SetClientVersion(config.ClientVersion); - if (!string.IsNullOrWhiteSpace(config.UpgradeClientVersion)) - builder.SetUpgradeClientVersion(config.UpgradeClientVersion); - if (!string.IsNullOrWhiteSpace(config.AppSecretKey)) - builder.SetAppSecretKey(config.AppSecretKey); - if (!string.IsNullOrWhiteSpace(config.ProductId)) - builder.SetProductId(config.ProductId); - if (!string.IsNullOrWhiteSpace(config.InstallPath)) - builder.SetInstallPath(config.InstallPath); - if (!string.IsNullOrWhiteSpace(config.UpdateLogUrl)) - builder.SetUpdateLogUrl(config.UpdateLogUrl); - if (!string.IsNullOrWhiteSpace(config.ReportUrl)) - builder.SetReportUrl(config.ReportUrl); - if (!string.IsNullOrWhiteSpace(config.Bowl)) - builder.SetBowl(config.Bowl); - if (!string.IsNullOrWhiteSpace(config.Script)) - builder.SetScript(config.Script); - if (!string.IsNullOrWhiteSpace(config.DriverDirectory)) - builder.SetDriverDirectory(config.DriverDirectory); - if (config.BlackFiles != null) - builder.SetBlackFiles(config.BlackFiles); - if (config.BlackFormats != null) - builder.SetBlackFormats(config.BlackFormats); - if (config.SkipDirectorys != null) - builder.SetSkipDirectorys(config.SkipDirectorys); - - builder.SetInstallPath(string.IsNullOrWhiteSpace(config.InstallPath) ? AppDomain.CurrentDomain.BaseDirectory : config.InstallPath); - return builder; - } - catch (System.Text.Json.JsonException) - { - // Invalid JSON format, fall back to parameters - return null; - } - catch (IOException) - { - // File read error, fall back to parameters - return null; - } - catch (UnauthorizedAccessException) - { - // Permission denied, fall back to parameters - return null; - } - catch - { - // Any other unexpected error, fall back to parameters - return null; - } - } - - public ConfiginfoBuilder SetUpdateUrl(string updateUrl) - { - if (string.IsNullOrWhiteSpace(updateUrl)) - throw new ArgumentException("updateUrl cannot be null or empty.", nameof(updateUrl)); - - _updateUrl = updateUrl; - return this; - } - - public ConfiginfoBuilder SetToken(string token) - { - if (string.IsNullOrWhiteSpace(token)) - throw new ArgumentException("token cannot be null or empty.", nameof(token)); - - _token = token; - return this; - } - - public ConfiginfoBuilder SetScheme(string scheme) - { - if (string.IsNullOrWhiteSpace(scheme)) - throw new ArgumentException("scheme cannot be null or empty.", nameof(scheme)); - - _scheme = scheme; - return this; - } - - /// - /// Sets the application name (executable to start after update). - /// - /// The name of the application executable. - /// The current ConfiginfoBuilder instance for method chaining. - public ConfiginfoBuilder SetAppName(string appName) - { - if (string.IsNullOrWhiteSpace(appName)) - throw new ArgumentException("AppName cannot be null or empty.", nameof(appName)); - - _appName = appName; - return this; - } - - /// - /// Sets the main application name. - /// - /// The name of the main application without file extension. - /// The current ConfiginfoBuilder instance for method chaining. - public ConfiginfoBuilder SetMainAppName(string mainAppName) - { - if (string.IsNullOrWhiteSpace(mainAppName)) - throw new ArgumentException("MainAppName cannot be null or empty.", nameof(mainAppName)); - - _mainAppName = mainAppName; - return this; - } - - /// - /// Sets the client version. - /// - /// The current version of the client application. - /// The current ConfiginfoBuilder instance for method chaining. - public ConfiginfoBuilder SetClientVersion(string clientVersion) - { - if (string.IsNullOrWhiteSpace(clientVersion)) - throw new ArgumentException("ClientVersion cannot be null or empty.", nameof(clientVersion)); - - _clientVersion = clientVersion; - return this; - } - - /// - /// Sets the upgrade client version. - /// - /// The current version of the upgrade application. - /// The current ConfiginfoBuilder instance for method chaining. - public ConfiginfoBuilder SetUpgradeClientVersion(string upgradeClientVersion) - { - if (string.IsNullOrWhiteSpace(upgradeClientVersion)) - throw new ArgumentException("UpgradeClientVersion cannot be null or empty.", nameof(upgradeClientVersion)); - - _upgradeClientVersion = upgradeClientVersion; - return this; - } - - /// - /// Sets the application secret key. - /// - /// The secret key used for authentication. - /// The current ConfiginfoBuilder instance for method chaining. - public ConfiginfoBuilder SetAppSecretKey(string appSecretKey) - { - if (string.IsNullOrWhiteSpace(appSecretKey)) - throw new ArgumentException("AppSecretKey cannot be null or empty.", nameof(appSecretKey)); - - _appSecretKey = appSecretKey; - return this; - } - - /// - /// Sets the product identifier. - /// - /// The unique product identifier. - /// The current ConfiginfoBuilder instance for method chaining. - public ConfiginfoBuilder SetProductId(string productId) - { - if (string.IsNullOrWhiteSpace(productId)) - throw new ArgumentException("ProductId cannot be null or empty.", nameof(productId)); - - _productId = productId; - return this; - } - - /// - /// Sets the installation path. - /// - /// The installation path where application files are located. - /// The current ConfiginfoBuilder instance for method chaining. - public ConfiginfoBuilder SetInstallPath(string installPath) - { - if (string.IsNullOrWhiteSpace(installPath)) - throw new ArgumentException("InstallPath cannot be null or empty.", nameof(installPath)); - - _installPath = installPath; - return this; - } - - /// - /// Sets the update log URL. - /// - /// The URL address for the update log webpage. - /// The current ConfiginfoBuilder instance for method chaining. - public ConfiginfoBuilder SetUpdateLogUrl(string updateLogUrl) - { - if (!string.IsNullOrWhiteSpace(updateLogUrl) && !Uri.IsWellFormedUriString(updateLogUrl, UriKind.Absolute)) - throw new ArgumentException("UpdateLogUrl must be a valid absolute URI.", nameof(updateLogUrl)); - - _updateLogUrl = updateLogUrl; - return this; - } - - /// - /// Sets the report URL. - /// - /// The API endpoint URL for reporting update status and results. - /// The current ConfiginfoBuilder instance for method chaining. - public ConfiginfoBuilder SetReportUrl(string reportUrl) - { - if (!string.IsNullOrWhiteSpace(reportUrl) && !Uri.IsWellFormedUriString(reportUrl, UriKind.Absolute)) - throw new ArgumentException("ReportUrl must be a valid absolute URI.", nameof(reportUrl)); - - _reportUrl = reportUrl; - return this; - } - - /// - /// Sets the bowl process name. - /// - /// The process name that should be terminated before starting the update. - /// The current ConfiginfoBuilder instance for method chaining. - public ConfiginfoBuilder SetBowl(string bowl) - { - _bowl = bowl; - return this; - } - - /// - /// Sets the shell script content. - /// - /// Shell script content used to grant file permissions on Linux/Unix systems. - /// The current ConfiginfoBuilder instance for method chaining. - public ConfiginfoBuilder SetScript(string script) - { - _script = script; - return this; - } - - /// - /// Sets the driver directory. - /// - /// The directory path containing driver files for driver update functionality. - /// The current ConfiginfoBuilder instance for method chaining. - public ConfiginfoBuilder SetDriverDirectory(string driverDirectory) - { - _driverDirectory = driverDirectory; - return this; - } - - /// - /// Sets the list of blacklisted files. - /// - /// List of specific files that should be excluded from the update process. - /// The current ConfiginfoBuilder instance for method chaining. - public ConfiginfoBuilder SetBlackFiles(List blackFiles) - { - _blackFiles = blackFiles ?? new List(); - return this; - } - - /// - /// Sets the list of blacklisted file formats. - /// - /// List of file format extensions that should be excluded from the update process. - /// The current ConfiginfoBuilder instance for method chaining. - public ConfiginfoBuilder SetBlackFormats(List blackFormats) - { - _blackFormats = blackFormats ?? new List(); - return this; - } - - /// - /// Sets the list of directories to skip. - /// - /// List of directory paths that should be skipped during the update process. - /// The current ConfiginfoBuilder instance for method chaining. - public ConfiginfoBuilder SetSkipDirectorys(List skipDirectorys) - { - _skipDirectorys = skipDirectorys ?? new List(); - return this; - } - - /// - /// Builds and returns a complete Configinfo object with all configured and default values. - /// - /// A fully configured Configinfo instance. - /// Thrown when the builder is in an invalid state. - public Configinfo Build() - { - // Create the Configinfo object with all values - var configinfo = new Configinfo - { - UpdateUrl = _updateUrl, - Token = _token, - Scheme = _scheme, - AppName = _appName, - MainAppName = _mainAppName, - ClientVersion = _clientVersion, - UpgradeClientVersion = _upgradeClientVersion, - AppSecretKey = _appSecretKey, - ProductId = _productId, - InstallPath = _installPath, - UpdateLogUrl = _updateLogUrl, - ReportUrl = _reportUrl, - Bowl = _bowl, - Script = _script, - DriverDirectory = _driverDirectory, - BlackFiles = _blackFiles ?? new List(), - BlackFormats = _blackFormats ?? new List(), - SkipDirectorys = _skipDirectorys ?? new List() - }; - - // Validate the built configuration - try - { - configinfo.Validate(); - } - catch (ArgumentException ex) - { - throw new InvalidOperationException($"Failed to build valid Configinfo: {ex.Message}", ex); - } - - return configinfo; - } - } -} diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/ConfigurationMapper.cs b/src/c#/GeneralUpdate.Common/Shared/Object/ConfigurationMapper.cs deleted file mode 100644 index 45e98d66..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/ConfigurationMapper.cs +++ /dev/null @@ -1,135 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace GeneralUpdate.Common.Shared.Object -{ - /// - /// Provides centralized mapping utilities for converting between configuration objects. - /// This class ensures consistent field mapping across Configinfo, GlobalConfigInfo, and ProcessInfo, - /// reducing the risk of missing or incorrectly mapped fields during maintenance. - /// - public static class ConfigurationMapper - { - /// - /// Maps user-provided configuration (Configinfo) to internal runtime configuration (GlobalConfigInfo). - /// This method performs a one-to-one field mapping for all shared configuration properties. - /// - /// The user-provided configuration object containing initial settings. - /// The internal configuration object to be populated. If null, a new instance is created. - /// A GlobalConfigInfo object populated with values from the source Configinfo. - public static GlobalConfigInfo MapToGlobalConfigInfo(Configinfo source, GlobalConfigInfo target = null) - { - // Create new instance if both source and target are not provided - if (target == null) - target = new GlobalConfigInfo(); - - // Return empty target if source is null - if (source == null) - return target; - - // Map common fields from base configuration - target.AppName = source.AppName; - target.MainAppName = source.MainAppName; - target.ClientVersion = source.ClientVersion; - target.InstallPath = source.InstallPath; - target.UpdateLogUrl = source.UpdateLogUrl; - target.AppSecretKey = source.AppSecretKey; - target.BlackFiles = source.BlackFiles; - target.BlackFormats = source.BlackFormats; - target.SkipDirectorys = source.SkipDirectorys; - target.ReportUrl = source.ReportUrl; - target.Bowl = source.Bowl; - target.Scheme = source.Scheme; - target.Token = source.Token; - target.Script = source.Script; - target.DriverDirectory = source.DriverDirectory; - - // Map GlobalConfigInfo-specific fields - target.UpdateUrl = source.UpdateUrl; - target.UpgradeClientVersion = source.UpgradeClientVersion; - target.ProductId = source.ProductId; - - return target; - } - - /// - /// Maps internal runtime configuration (GlobalConfigInfo) to process transfer parameters (ProcessInfo). - /// This method consolidates the complex parameter passing logic previously scattered in bootstrap code. - /// - /// The internal configuration object containing all runtime state. - /// List of version information objects from the update server response. - /// List of blacklisted file formats from the BlackListManager. - /// List of blacklisted files from the BlackListManager. - /// List of directories to skip from the BlackListManager. - /// A ProcessInfo object ready for serialization and inter-process communication. - /// Thrown when source is null - public static ProcessInfo MapToProcessInfo( - GlobalConfigInfo source, - List updateVersions, - List blackFileFormats, - List blackFiles, - List skipDirectories) - { - if (source == null) - 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 - return new ProcessInfo( - appName: source.MainAppName, // Maps MainAppName to ProcessInfo.AppName - installPath: source.InstallPath, - currentVersion: source.ClientVersion, // Maps ClientVersion to ProcessInfo.CurrentVersion - lastVersion: source.LastVersion, // Computed value set before calling this method - updateLogUrl: source.UpdateLogUrl, - compressEncoding: source.Encoding, // Computed value set before calling this method - compressFormat: source.Format, // Computed value set before calling this method - downloadTimeOut: source.DownloadTimeOut, // Computed value set before calling this method - appSecretKey: source.AppSecretKey, - updateVersions: updateVersions, // From API response - reportUrl: source.ReportUrl, - backupDirectory: source.BackupDirectory, // Computed value set before calling this method - bowl: source.Bowl, - scheme: source.Scheme, - token: source.Token, - script: source.Script, - driverDirectory: source.DriverDirectory, // Driver directory for driver updates - blackFileFormats: blackFileFormats, // From BlackListManager - blackFiles: blackFiles, // From BlackListManager - skipDirectories: skipDirectories // From BlackListManager - ); - } - - /// - /// Copies common configuration fields from a base configuration object to another. - /// This utility method helps maintain consistency when transferring configuration data. - /// - /// The source configuration type (must inherit from BaseConfigInfo). - /// The target configuration type (must inherit from BaseConfigInfo). - /// The source configuration object to copy from. - /// The target configuration object to copy to. - public static void CopyBaseFields(TSource source, TTarget target) - where TSource : BaseConfigInfo - where TTarget : BaseConfigInfo - { - if (source == null || target == null) - return; - - target.AppName = source.AppName; - target.MainAppName = source.MainAppName; - target.InstallPath = source.InstallPath; - target.UpdateLogUrl = source.UpdateLogUrl; - target.AppSecretKey = source.AppSecretKey; - target.ClientVersion = source.ClientVersion; - target.BlackFiles = source.BlackFiles; - target.BlackFormats = source.BlackFormats; - target.SkipDirectorys = source.SkipDirectorys; - target.ReportUrl = source.ReportUrl; - target.Bowl = source.Bowl; - target.Scheme = source.Scheme; - target.Token = source.Token; - target.Script = source.Script; - target.DriverDirectory = source.DriverDirectory; - } - } -} diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/DTO/BaseResponseDTO.cs b/src/c#/GeneralUpdate.Common/Shared/Object/DTO/BaseResponseDTO.cs deleted file mode 100644 index dfa9b49a..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/DTO/BaseResponseDTO.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Text.Json.Serialization; - -namespace GeneralUpdate.Common.Shared.Object -{ - public class BaseResponseDTO - { - [JsonPropertyName("code")] - public int Code { get; set; } - - [JsonPropertyName("body")] - public TBody Body { get; set; } - - [JsonPropertyName("message")] - public string Message { get; set; } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/DTO/VersionRespDTO.cs b/src/c#/GeneralUpdate.Common/Shared/Object/DTO/VersionRespDTO.cs deleted file mode 100644 index d1c9eca6..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/DTO/VersionRespDTO.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Collections.Generic; - -namespace GeneralUpdate.Common.Shared.Object; -public class VersionRespDTO : BaseResponseDTO>; \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/Enum/AppType.cs b/src/c#/GeneralUpdate.Common/Shared/Object/Enum/AppType.cs deleted file mode 100644 index 18648695..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/Enum/AppType.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace GeneralUpdate.Common.Shared.Object -{ - public class AppType - { - /// - /// main program - /// - public const int ClientApp = 1; - - /// - /// upgrade program. - /// - public const int UpgradeApp = 2; - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/Enum/Format.cs b/src/c#/GeneralUpdate.Common/Shared/Object/Enum/Format.cs deleted file mode 100644 index abb8efdd..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/Enum/Format.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace GeneralUpdate.Common.Shared.Object -{ - public class Format - { - public const string ZIP = ".zip"; - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/Enum/PlatformType.cs b/src/c#/GeneralUpdate.Common/Shared/Object/Enum/PlatformType.cs deleted file mode 100644 index 1382a881..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/Enum/PlatformType.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace GeneralUpdate.Common.Shared.Object.Enum; - -public class PlatformType -{ - public const int Windows = 1; - - public const int Linux = 2; -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/Enum/ReportType.cs b/src/c#/GeneralUpdate.Common/Shared/Object/Enum/ReportType.cs deleted file mode 100644 index c792ba6b..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/Enum/ReportType.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace GeneralUpdate.Common.Shared.Object.Enum; - -public class ReportType -{ - public const int None = 0; - - public const int Success = 2; - - public const int Failure = 3; -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/Enum/UpdateMode.cs b/src/c#/GeneralUpdate.Common/Shared/Object/Enum/UpdateMode.cs deleted file mode 100644 index cd05d00a..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/Enum/UpdateMode.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace GeneralUpdate.Common.Shared.Object.Enum; - -public enum UpdateMode -{ - Default = 0, - Scripts = 1 -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/GlobalConfigInfo.cs b/src/c#/GeneralUpdate.Common/Shared/Object/GlobalConfigInfo.cs deleted file mode 100644 index cb9bfc69..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/GlobalConfigInfo.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System.Collections.Generic; -using System.Text; - -namespace GeneralUpdate.Common.Shared.Object; - -/// -/// Internal runtime configuration class that combines user settings with computed state. -/// This class serves as the central configuration holder during the update workflow execution. -/// Inherits common fields from BaseConfigInfo and adds runtime-specific properties. -/// -/// Responsibilities: -/// - Stores user-provided configuration from Configinfo -/// - Maintains computed runtime values (encoding, format, paths, versions) -/// - Tracks update workflow state (IsMainUpdate, IsUpgradeUpdate) -/// -public class GlobalConfigInfo : BaseConfigInfo -{ - // User-provided configuration fields (mapped from Configinfo) - - /// - /// The API endpoint URL for checking available updates. - /// Inherited from user configuration, used for version validation requests. - /// - public string UpdateUrl { get; set; } - - /// - /// The current version of the upgrade application (the updater itself). - /// Used separately from ClientVersion to manage updater upgrades. - /// - public string UpgradeClientVersion { get; set; } - - /// - /// The unique product identifier for this application. - /// Used to distinguish between multiple products sharing the same update server. - /// - public string ProductId { get; set; } - - // Runtime computed fields (calculated during workflow execution) - - - // Runtime computed fields (calculated during workflow execution) - - /// - /// The compression format of update packages (e.g., "ZIP", "7Z"). - /// Computed from UpdateOption.Format or defaults to ZIP. - /// - public string Format { get; set; } - - /// - /// Indicates whether the upgrade application itself needs to be updated. - /// Computed by comparing UpgradeClientVersion with server response. - /// - public bool IsUpgradeUpdate { get; set; } - - /// - /// Indicates whether the main application needs to be updated. - /// Computed by comparing ClientVersion with server response. - /// - public bool IsMainUpdate { get; set; } - - /// - /// List of version information objects to be updated. - /// Populated from the update server response based on IsUpgradeUpdate/IsMainUpdate flags. - /// - public List UpdateVersions { get; set; } - - /// - /// The encoding format used for file operations (e.g., UTF-8, ASCII). - /// Computed from UpdateOption.Encoding or defaults to system default encoding. - /// - public Encoding Encoding { get; set; } - - /// - /// Timeout duration in seconds for download operations. - /// Computed from UpdateOption.DownloadTimeOut or defaults to 60 seconds. - /// - public int DownloadTimeOut { get; set; } - - /// - /// The latest available version from the update server. - /// Extracted from the server response body after version validation. - /// - public string LastVersion { get; set; } - - /// - /// Temporary directory path for downloading and extracting update files. - /// Computed using StorageManager.GetTempDirectory("main_temp"). - /// - public string TempPath { get; set; } - - /// - /// Serialized JSON string of ProcessInfo object for inter-process communication. - /// Contains all parameters needed by the upgrade process. - /// - public string ProcessInfo { get; set; } - - /// - /// Indicates whether driver update functionality is enabled. - /// Computed from UpdateOption.Drive or defaults to false. - /// - public bool? DriveEnabled { get; set; } - - /// - /// Directory path containing driver files for update. - /// Used when DriveEnabled is true to locate driver files for installation. - /// - public string DriverDirectory { get; set; } - - /// - /// Indicates whether differential patch update is enabled. - /// Computed from UpdateOption.Patch or defaults to true. - /// - public bool? PatchEnabled { get; set; } - - /// - /// Directory path where the current version files are backed up before update. - /// Computed by combining InstallPath with a versioned directory name. - /// - public string BackupDirectory { get; set; } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/GlobalConfigInfoOSS.cs b/src/c#/GeneralUpdate.Common/Shared/Object/GlobalConfigInfoOSS.cs deleted file mode 100644 index 1bd152ba..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/GlobalConfigInfoOSS.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Text.Json.Serialization; - -namespace GeneralUpdate.Common.Shared.Object -{ - public class GlobalConfigInfoOSS - { - [JsonPropertyName("Url")] - public string Url { get; set; } - - [JsonPropertyName("AppName")] - public string AppName { get; set; } - - [JsonPropertyName("CurrentVersion")] - public string CurrentVersion { get; set; } - - [JsonPropertyName("VersionFileName")] - public string VersionFileName { get; set; } - - [JsonPropertyName("Encoding")] - public string Encoding { get; set; } - - public GlobalConfigInfoOSS() - { - } - - public GlobalConfigInfoOSS(string url, string appName, string currentVersion, string versionFileName) - { - Url = url ?? throw new ArgumentNullException(nameof(url)); - AppName = appName ?? throw new ArgumentNullException(nameof(appName)); - CurrentVersion = currentVersion ?? throw new ArgumentNullException(nameof(currentVersion)); - VersionFileName = versionFileName ?? "versions.json"; - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/ObjectTranslator.cs b/src/c#/GeneralUpdate.Common/Shared/Object/ObjectTranslator.cs deleted file mode 100644 index 28f55cbf..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/ObjectTranslator.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace GeneralUpdate.Common.Shared.Object; - -public sealed class ObjectTranslator -{ - public static string GetPacketHash(object version) => - !GeneralTracer.IsTracingEnabled() ? string.Empty : $"[PacketHash]:{(version as VersionInfo).Hash} "; -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/Packet.cs b/src/c#/GeneralUpdate.Common/Shared/Object/Packet.cs deleted file mode 100644 index 19fa1f4b..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/Packet.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Text.Json.Serialization; - -namespace GeneralUpdate.Common.Shared.Object; - -/// -/// Currently used only for upgrade push. -/// -public class Packet -{ - [JsonPropertyName("Name")] - public string? Name { get; set; } - - [JsonPropertyName("Hash")] - public string Hash { get; set; } - - [JsonPropertyName("ReleaseDate")] - public DateTime? ReleaseDate { get; set; } - - [JsonPropertyName("Url")] - public string? Url { get; set; } - - [JsonPropertyName("Version")] - public string? Version { get; set; } - - [JsonPropertyName("AppType")] - public int? AppType { get; set; } - - [JsonPropertyName("Platform")] - public int? Platform { get; set; } - - [JsonPropertyName("ProductId")] - public string? ProductId { get; set; } - - [JsonPropertyName("IsForcibly")] - public bool? IsForcibly { get; set; } - - [JsonPropertyName("IsFreeze")] - public bool? IsFreeze { get; set; } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/ProcessInfo.cs b/src/c#/GeneralUpdate.Common/Shared/Object/ProcessInfo.cs deleted file mode 100644 index 8b8f6932..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/ProcessInfo.cs +++ /dev/null @@ -1,243 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using System.Text.Json.Serialization; - -namespace GeneralUpdate.Common.Shared.Object -{ - /// - /// Inter-process communication parameter object. - /// This class is serialized to JSON and passed to the upgrade process, enabling - /// the separate upgrade application to perform updates with the correct configuration. - /// - /// Design Notes: - /// - All fields are serialized using [JsonPropertyName] attributes - /// - Constructor performs validation to ensure required parameters are provided - /// - Field naming differs slightly from other config classes for backward compatibility - /// - public class ProcessInfo - { - /// - /// Default constructor for deserialization. - /// - public ProcessInfo() { } - - /// - /// Parameterized constructor with validation for creating ProcessInfo instances. - /// All parameters are validated to ensure the upgrade process receives valid configuration. - /// - /// The name of the application to start after update (maps from MainAppName) - /// The installation directory path (must exist) - /// The current version before update - /// The target version after update - /// The URL for viewing update logs - /// The encoding used for compressed files - /// The compression format (ZIP, 7Z, etc.) - /// The download timeout in seconds (must be > 0) - /// The application secret key for authentication - /// List of version information to update (must not be empty) - /// The URL for reporting update status - /// The directory path for backup files - /// The process name to terminate before updating - /// The URL scheme for update requests - /// The authentication token - /// The Linux permission script - /// The directory path containing driver files - /// List of file format extensions to skip - /// List of specific files to skip - /// List of directories to skip - /// Thrown when required parameters are null - /// Thrown when parameters fail validation - public ProcessInfo(string appName - , string installPath - , string currentVersion - , string lastVersion - , string updateLogUrl - , Encoding compressEncoding - , string compressFormat - , int downloadTimeOut - , string appSecretKey - , List updateVersions - , string reportUrl - , string backupDirectory - , string bowl - , string scheme - , string token - , string script - , string driverDirectory - , List blackFileFormats - , List blackFiles - , List skipDirectories) - { - // Validate required string parameters - AppName = appName ?? throw new ArgumentNullException(nameof(appName)); - if (!Directory.Exists(installPath)) throw new ArgumentException($"{nameof(installPath)} path does not exist ! {installPath}."); - InstallPath = installPath ?? throw new ArgumentNullException(nameof(installPath)); - CurrentVersion = currentVersion ?? throw new ArgumentNullException(nameof(currentVersion)); - LastVersion = lastVersion ?? throw new ArgumentNullException(nameof(lastVersion)); - UpdateLogUrl = updateLogUrl; - - // Validate and set compression parameters - CompressEncoding = compressEncoding.WebName; - CompressFormat = compressFormat; - if (downloadTimeOut < 0) throw new ArgumentException("Timeout must be greater than 0 !"); - DownloadTimeOut = downloadTimeOut; - - // Validate authentication parameters - AppSecretKey = appSecretKey ?? throw new ArgumentNullException(nameof(appSecretKey)); - - // Validate update versions collection - if (updateVersions == null || updateVersions.Count == 0) throw new ArgumentException("Collection cannot be null or has 0 elements !"); - UpdateVersions = updateVersions; - - // Set reporting and backup parameters - ReportUrl = reportUrl ?? throw new ArgumentNullException(nameof(reportUrl)); - BackupDirectory = backupDirectory ?? throw new ArgumentNullException(nameof(backupDirectory)); - - // Set optional parameters - Bowl = bowl; - Scheme = scheme; - Token = token; - Script = script; - DriverDirectory = driverDirectory; - - // Set blacklist parameters - BlackFileFormats = blackFileFormats; - BlackFiles = blackFiles; - SkipDirectorys = skipDirectories; - } - - /// - /// The name of the application to start after the update completes. - /// Note: In ProcessInfo, this field holds the MainAppName value from other config classes. - /// - [JsonPropertyName("AppName")] - public string AppName { get; set; } - - /// - /// The installation directory where files will be updated. - /// All update operations are performed relative to this path. - /// - [JsonPropertyName("InstallPath")] - public string InstallPath { get; set; } - - /// - /// The current version of the application before the update. - /// Note: Maps from GlobalConfigInfo.ClientVersion. - /// - [JsonPropertyName("CurrentVersion")] - public string CurrentVersion { get; set; } - - /// - /// The target version after the update completes. - /// This is the latest version available from the update server. - /// - [JsonPropertyName("LastVersion")] - public string LastVersion { get; set; } - - /// - /// The URL where users can view detailed update logs and changelogs. - /// - [JsonPropertyName("UpdateLogUrl")] - public string UpdateLogUrl { get; set; } - - /// - /// The text encoding used for compressing/decompressing update packages. - /// Stored as WebName string (e.g., "utf-8", "ascii"). - /// - [JsonPropertyName("CompressEncoding")] - public string CompressEncoding { get; set; } - - /// - /// The compression format of update packages (e.g., "ZIP", "7Z"). - /// - [JsonPropertyName("CompressFormat")] - public string CompressFormat { get; set; } - - /// - /// The timeout duration in seconds for downloading update packages. - /// Download operations will fail if they exceed this duration. - /// - [JsonPropertyName("DownloadTimeOut")] - public int DownloadTimeOut { get; set; } - - /// - /// The application secret key used for authenticating update requests. - /// - [JsonPropertyName("AppSecretKey")] - public string AppSecretKey { get; set; } - - /// - /// List of version information objects describing all versions to be updated. - /// Can contain multiple versions for incremental updates. - /// - [JsonPropertyName("UpdateVersions")] - public List UpdateVersions { get; set; } - - /// - /// The API endpoint URL for reporting update progress and completion status. - /// - [JsonPropertyName("ReportUrl")] - public string ReportUrl { get; set; } - - /// - /// The directory path where current version files are backed up before updating. - /// Used for rollback if the update fails. - /// - [JsonPropertyName("BackupDirectory")] - public string BackupDirectory { get; set; } - - /// - /// The name of a process that should be terminated before starting the update. - /// Typically used to close conflicting background processes. - /// - [JsonPropertyName("Bowl")] - public string Bowl { get; set; } - - /// - /// The URL scheme for update server communication (e.g., "http", "https"). - /// - [JsonPropertyName("Scheme")] - public string Scheme { get; set; } - - /// - /// The authentication token included in HTTP headers for API requests. - /// - [JsonPropertyName("Token")] - public string Token { get; set; } - - /// - /// List of file format extensions that should be excluded from updates. - /// Note: Different property name (BlackFileFormats) than in other config classes (BlackFormats). - /// - [JsonPropertyName("BlackFileFormats")] - public List BlackFileFormats { get; set; } - - /// - /// List of specific file names that should be excluded from updates. - /// - [JsonPropertyName("BlackFiles")] - public List BlackFiles { get; set; } - - /// - /// List of directory paths that should be skipped during update operations. - /// - [JsonPropertyName("SkipDirectorys")] - public List SkipDirectorys { get; set; } - - /// - /// Shell script content for granting file permissions on Linux/Unix systems. - /// Executed after update to ensure updated files have correct permissions. - /// - [JsonPropertyName("Script")] - public string Script { get; set; } - - /// - /// The directory path containing driver files for driver update functionality. - /// Used when DriveEnabled is true to locate and install driver files. - /// - [JsonPropertyName("DriverDirectory")] - public string DriverDirectory { get; set; } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/README-ConfiginfoBuilder.md b/src/c#/GeneralUpdate.Common/Shared/Object/README-ConfiginfoBuilder.md deleted file mode 100644 index 83790f6d..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/README-ConfiginfoBuilder.md +++ /dev/null @@ -1,263 +0,0 @@ -# ConfiginfoBuilder - Universal Configuration Builder - -## Overview - -The `ConfiginfoBuilder` class provides a simple, fluent API for creating `Configinfo` objects with minimal effort. It automatically handles platform-specific defaults and only requires three essential parameters. - -**NEW**: ConfiginfoBuilder now supports loading configuration from a JSON file (`update_config.json`) placed in the running directory. When this file exists, it takes the highest priority, overriding any parameters passed to the builder. - -**Design Inspiration**: The zero-configuration approach is inspired by projects like [Velopack](https://github.com/velopack/velopack), focusing on sensible defaults extracted from the running application with minimal user input required. - -## Configuration Priority - -The ConfiginfoBuilder follows this priority order: - -1. **JSON Configuration File** (`update_config.json`) - **HIGHEST PRIORITY** -2. **Builder Setter Methods** (via `.SetXXX()` methods) -3. **Default Values** (platform-specific defaults) - -## JSON Configuration File Support - -Place an `update_config.json` file in your application's running directory to configure all update settings. When this file is present, ConfiginfoBuilder will automatically load settings from it, ignoring parameters passed to the `Create()` method. - -**Example `update_config.json`:** -```json -{ - "UpdateUrl": "https://api.example.com/updates", - "Token": "your-authentication-token", - "Scheme": "https", - "AppName": "Update.exe", - "MainAppName": "MyApplication.exe", - "ClientVersion": "1.0.0", - "InstallPath": "/path/to/installation" -} -``` - -See [update_config.example.json](update_config.example.json) for a complete example with all available options. - -## Auto-Configuration Features - -🔍 **Application Name Detection**: Automatically reads `` from `.csproj` -📊 **Version Extraction**: Reads `` field for `ClientVersion` -🏢 **Publisher Info**: Extracts `` or `` for `ProductId` -📂 **Path Extraction**: Uses host program's base directory -🖥️ **Platform Detection**: Adapts to Windows, Linux, and macOS - -## Quick Start - -```csharp -using GeneralUpdate.Common.Shared.Object; - -// Method 1: With JSON configuration file (RECOMMENDED) -// Place update_config.json in your app's running directory -// The Create method will automatically load from the file -var config = ConfiginfoBuilder - .Create("https://fallback.com/updates", "fallback-token", "https") - .Build(); -// If update_config.json exists, those values are used instead of the parameters - -// Method 2: Using code configuration only (no JSON file) -var config2 = ConfiginfoBuilder - .Create("https://api.example.com/updates", "your-auth-token", "https") - .Build(); - -// Method 3: Code configuration with custom overrides -var config3 = ConfiginfoBuilder - .Create("https://api.example.com/updates", "your-auth-token", "https") - .SetAppName("MyApp.exe") - .SetInstallPath("/custom/path") - .Build(); -``` - -## Key Features - -✅ **JSON Configuration Support**: Load settings from `update_config.json` with highest priority -✅ **Minimal Parameters**: Only 3 required parameters (UpdateUrl, Token, Scheme) -✅ **Cross-Platform**: Automatically detects and adapts to Windows/Linux/macOS -✅ **Smart Defaults**: Platform-appropriate paths, separators, and configurations -✅ **Fluent API**: Clean, readable method chaining -✅ **Type-Safe**: Compile-time parameter validation -✅ **Well-Tested**: 39 comprehensive unit tests including JSON configuration scenarios - -## Platform Detection - -The builder automatically adapts based on your runtime environment: - -| Aspect | Windows | Linux | macOS | -|--------|---------|-------|-------| -| Install Path | Current app directory | Current app directory | Current app directory | -| App Names | Auto from csproj + `.exe` | Auto from csproj | Auto from csproj | -| Script | Empty | chmod script | chmod script | -| Path Separator | `\` (automatic) | `/` (automatic) | `/` (automatic) | - -## Documentation - -- **[Usage Guide](ConfiginfoBuilder-Usage.md)** - Comprehensive documentation with examples -- **[Example Code](ConfiginfoBuilder-Example.cs)** - Runnable examples demonstrating all features - -## Examples - -### Using JSON Configuration File -```csharp -// Create update_config.json in your app directory: -// { -// "UpdateUrl": "https://api.example.com/updates", -// "Token": "my-token", -// "Scheme": "https", -// "AppName": "MyApp.exe", -// "ClientVersion": "2.0.0" -// } - -// The builder will automatically load from the file -var config = ConfiginfoBuilder - .Create("ignored", "ignored", "ignored") - .Build(); -// Values come from update_config.json! -``` - -### Basic Usage (No JSON File) -```csharp -var config = ConfiginfoBuilder - .Create(updateUrl, token, scheme) - .Build(); -``` - -### Custom Configuration -```csharp -var config = ConfiginfoBuilder - .Create(updateUrl, token, scheme) - .SetAppName("MyApp.exe") - .SetClientVersion("2.0.0") - .SetInstallPath("/opt/myapp") - .Build(); -``` - -### With File Filters -```csharp -var config = ConfiginfoBuilder - .Create(updateUrl, token, scheme) - .SetBlackFormats(new List { ".log", ".tmp", ".cache" }) - .SetSkipDirectorys(new List { "/temp", "/logs" }) - .Build(); -``` - -## Default Values - -The builder and `Configinfo` class provide these defaults: - -### Configinfo Class Defaults (Property Initializers) -- **AppName**: "Update.exe" -- **InstallPath**: Current program's running directory (`AppDomain.CurrentDomain.BaseDirectory`) - -### ConfiginfoBuilder Defaults (for Builder Pattern) -- **ClientVersion**: "1.0.0" -- **UpgradeClientVersion**: "1.0.0" -- **AppSecretKey**: "default-secret-key" -- **ProductId**: "default-product-id" -- **MainAppName**: "App.exe" -- **BlackFormats**: `.log`, `.tmp`, `.cache`, `.bak` (via `ConfiginfoBuilder.DefaultBlackFormats`) -- **BlackFiles**: Empty list -- **SkipDirectorys**: Empty list - -All defaults can be overridden using: -1. JSON configuration file (`update_config.json`) - highest priority -2. Builder setter methods (`.SetXXX()`) -3. Direct property assignment on `Configinfo` objects - -## Error Handling - -The builder validates parameters at two stages: - -1. **Construction Time**: Validates required parameters (UpdateUrl, Token, Scheme) -2. **Build Time**: Validates the complete configuration before returning - -```csharp -try { - var config = new ConfiginfoBuilder(invalidUrl, token, scheme).Build(); -} catch (ArgumentException ex) { - Console.WriteLine($"Invalid parameter: {ex.Message}"); -} catch (InvalidOperationException ex) { - Console.WriteLine($"Build failed: {ex.Message}"); -} -``` - -## Testing - -The implementation includes 39 comprehensive unit tests covering: -- Constructor validation -- Default value generation -- Platform-specific behavior -- Method chaining -- Error handling -- JSON configuration file loading -- Fallback behavior when JSON is invalid -- Complete integration scenarios - -Run tests with: -```bash -dotnet test CoreTest/CoreTest.csproj --filter "FullyQualifiedName~ConfiginfoBuilderTests" -``` - -## Security - -✅ No security vulnerabilities detected by CodeQL -✅ Input validation on all parameters -✅ No hardcoded secrets or credentials - -## Compatibility - -- **.NET Standard 2.0** and above -- **.NET 10.0** and above -- **Cross-platform**: Windows, Linux (and other Unix-like systems) - -## Migration from Manual Construction - -**Before:** -```csharp -var config = new Configinfo -{ - UpdateUrl = url, - Token = token, - Scheme = scheme, - AppName = "App.exe", - MainAppName = "App.exe", - ClientVersion = "1.0.0", - // ... 15+ more properties -}; -``` - -**After (with JSON configuration):** -```json -// update_config.json -{ - "UpdateUrl": "https://api.example.com/updates", - "Token": "my-token", - "Scheme": "https", - "AppName": "MyApp.exe", - "ClientVersion": "1.0.0" -} -``` -```csharp -var config = ConfiginfoBuilder - .Create("fallback", "fallback", "https") - .Build(); -``` - -**After (with code only):** -```csharp -var config = ConfiginfoBuilder - .Create(url, token, scheme) - .Build(); -``` - -## Contributing - -This implementation follows the repository's coding standards and includes: -- Comprehensive XML documentation -- Extensive unit tests -- Usage examples -- Error handling - -## License - -Part of the GeneralUpdate project. See the main LICENSE file for details. diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/VersionInfo.cs b/src/c#/GeneralUpdate.Common/Shared/Object/VersionInfo.cs deleted file mode 100644 index 4a7144ed..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/VersionInfo.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Text.Json.Serialization; - -namespace GeneralUpdate.Common.Shared.Object; - -public class VersionInfo -{ - [JsonPropertyName("recordId")] - public int RecordId { get; set; } - - [JsonPropertyName("name")] - public string? Name { get; set; } - - [JsonPropertyName("hash")] - public string? Hash { get; set; } - - [JsonPropertyName("releaseDate")] - public DateTime? ReleaseDate { get; set; } - - [JsonPropertyName("url")] - public string? Url { get; set; } - - [JsonPropertyName("version")] - public string? Version { get; set; } - - [JsonPropertyName("appType")] - public int? AppType { get; set; } - - [JsonPropertyName("platform")] - public int? Platform { get; set; } - - [JsonPropertyName("productId")] - public string? ProductId { get; set; } - - [JsonPropertyName("isForcibly")] - public bool? IsForcibly { get; set; } - - [JsonPropertyName("format")] - public string? Format { get; set; } - - [JsonPropertyName("size")] - public long? Size { get; set; } - - /// - /// HTTP authentication scheme (e.g., "Bearer", "Basic") for download requests. - /// - [JsonPropertyName("authScheme")] - public string? AuthScheme { get; set; } - - /// - /// HTTP authentication token for download requests. - /// - [JsonPropertyName("authToken")] - public string? AuthToken { get; set; } - - /// - /// Update log or release notes for this version. - /// - [JsonPropertyName("updateLog")] - public string? UpdateLog { get; set; } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/VersionOSS.cs b/src/c#/GeneralUpdate.Common/Shared/Object/VersionOSS.cs deleted file mode 100644 index 6fbcf120..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/VersionOSS.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Text.Json.Serialization; - -namespace GeneralUpdate.Common.Shared.Object -{ - /// - /// Version data persistence. - /// - public class VersionOSS - { - /// - /// Update package release time. - /// - - [JsonPropertyName("PubTime")] - public DateTime PubTime { get; set; } - - /// - /// Update package name. - /// - [JsonPropertyName("PacketName")] - public string PacketName { get; set; } - - /// - /// Compare and verify with the downloaded update package. - /// - [JsonPropertyName("Hash")] - public string Hash { get; set; } - - /// - /// The version number. - /// - [JsonPropertyName("Version")] - public string Version { get; set; } - - /// - /// Remote service url address. - /// - [JsonPropertyName("Url")] - public string Url { get; set; } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/update_config.example.json b/src/c#/GeneralUpdate.Common/Shared/Object/update_config.example.json deleted file mode 100644 index ce6b7797..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Object/update_config.example.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "UpdateUrl": "https://api.example.com/updates", - "Token": "your-authentication-token-here", - "Scheme": "https", - "AppName": "Update.exe", - "MainAppName": "MyApplication.exe", - "ClientVersion": "1.0.0", - "UpgradeClientVersion": "1.0.0", - "AppSecretKey": "your-secret-key-here", - "ProductId": "your-product-id", - "InstallPath": "/path/to/installation", - "UpdateLogUrl": "https://example.com/changelog", - "ReportUrl": "https://api.example.com/report", - "Bowl": "Bowl.exe", - "Script": "#!/bin/bash\nchmod +x *", - "DriverDirectory": "/path/to/drivers", - "BlackFiles": [ - "config.json", - "user.dat" - ], - "BlackFormats": [ - ".log", - ".tmp", - ".cache", - ".bak" - ], - "SkipDirectorys": [ - "/temp", - "/logs" - ] -} diff --git a/src/c#/GeneralUpdate.Common/Shared/Service/VersionService.cs b/src/c#/GeneralUpdate.Common/Shared/Service/VersionService.cs deleted file mode 100644 index 3bcfd10b..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Service/VersionService.cs +++ /dev/null @@ -1,116 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Net.Http; -using System.Security.Cryptography.X509Certificates; -using System.Net.Security; -using System.Text; -using System.Text.Json; -using System.Text.Json.Serialization.Metadata; -using System.Threading.Tasks; -using GeneralUpdate.Common.Internal; -using GeneralUpdate.Common.Internal.JsonContext; -using GeneralUpdate.Common.Shared.Object; - -namespace GeneralUpdate.Common.Shared.Service -{ - public class VersionService - { - private VersionService() { } - - /// - /// Report the result of this update: whether it was successful. - /// - /// - /// - /// - /// - /// - public static async Task Report(string httpUrl - , int recordId - , int status - , int? type - , string scheme = null - , string token = null) - { - var parameters = new Dictionary - { - { "RecordId", recordId }, - { "Status", status }, - { "Type", type } - }; - await PostTaskAsync>(httpUrl, parameters, ReportRespJsonContext.Default.BaseResponseDTOBoolean, scheme, token); - } - - /// - /// Verify whether the current version needs an update. - /// - /// - /// - /// - /// - /// - /// - /// - public static async Task Validate(string httpUrl - , string version - , int appType - , string appKey - , int platform - , string productId - , string scheme = null - , string token = null) - { - var parameters = new Dictionary - { - { "Version", version }, - { "AppType", appType }, - { "AppKey", appKey }, - { "Platform", platform }, - { "ProductId", productId } - }; - return await PostTaskAsync(httpUrl, parameters, VersionRespJsonContext.Default.VersionRespDTO, scheme, token); - } - - private static async Task PostTaskAsync(string httpUrl, Dictionary parameters, JsonTypeInfo? typeInfo = null, string scheme = null, string token = null) - { - try - { - var uri = new Uri(httpUrl); - using var httpClient = new HttpClient(new HttpClientHandler - { - ServerCertificateCustomValidationCallback = CheckValidationResult - }); - httpClient.Timeout = TimeSpan.FromSeconds(15); - httpClient.DefaultRequestHeaders.Accept.ParseAdd("text/html, application/xhtml+xml, */*"); - - if (!string.IsNullOrEmpty(scheme) && !string.IsNullOrEmpty(token)) - { - httpClient.DefaultRequestHeaders.Authorization = - new System.Net.Http.Headers.AuthenticationHeaderValue(scheme, token); - } - - var parametersJson = - JsonSerializer.Serialize(parameters, HttpParameterJsonContext.Default.DictionaryStringObject); - var stringContent = new StringContent(parametersJson, Encoding.UTF8, "application/json"); - var result = await httpClient.PostAsync(uri, stringContent); - var reseponseJson = await result.Content.ReadAsStringAsync(); - return typeInfo == null - ? JsonSerializer.Deserialize(reseponseJson) - : JsonSerializer.Deserialize(reseponseJson, typeInfo); - } - catch (Exception e) - { - GeneralTracer.Error("The PostTaskAsync method in the VersionService class throws an exception.", e); - throw e; - } - } - - private static bool CheckValidationResult( - HttpRequestMessage message, - X509Certificate2 certificate, - X509Chain chain, - SslPolicyErrors sslPolicyErrors - ) => true; - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Trace/GeneralTracer.cs b/src/c#/GeneralUpdate.Common/Shared/Trace/GeneralTracer.cs deleted file mode 100644 index 4fbd1bf3..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Trace/GeneralTracer.cs +++ /dev/null @@ -1,163 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Runtime.InteropServices; - -namespace GeneralUpdate.Common.Shared; - -public static class GeneralTracer -{ - private static readonly object _lockObj = new(); - private static bool _isTracingEnabled; - private static string _currentLogDate; - private static TextTraceListener _fileListener; - - static GeneralTracer() - { - Trace.Listeners.Clear(); - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - Trace.Listeners.Add(new WindowsOutputDebugListener()); - } - - Trace.Listeners.Add(new TextWriterTraceListener(Console.Out) { Name = "ConsoleListener" }); - - InitializeFileListener(); - - if (Debugger.IsAttached) - Trace.Listeners.Add(new DefaultTraceListener()); - - Trace.AutoFlush = true; - _isTracingEnabled = true; - } - - private static void InitializeFileListener() - { - //Ensure that log files are rotated on a daily basis - var today = DateTime.Now.ToString("yyyy-MM-dd"); - if (today == _currentLogDate && _fileListener != null) - return; - - if (_fileListener != null) - { - Trace.Listeners.Remove(_fileListener); - _fileListener.Flush(); - _fileListener.Close(); - _fileListener.Dispose(); - } - - var logDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs"); - Directory.CreateDirectory(logDir); - - var logFileName = Path.Combine(logDir, $"generalupdate-trace {today}.log"); - _fileListener = new TextTraceListener(logFileName); - - Trace.Listeners.Add(_fileListener); - _currentLogDate = today; - } - - public static void Debug(string message) => WriteTraceMessage(TraceLevel.Verbose, message); - - public static void Info(string message) => WriteTraceMessage(TraceLevel.Info, message); - - public static void Warn(string message) => WriteTraceMessage(TraceLevel.Warning, message); - - public static void Error(string message) => WriteTraceMessage(TraceLevel.Error, message); - - public static void Fatal(string message) => WriteTraceMessage(TraceLevel.Off, message); - - public static void Error(string message, Exception ex) - { - var fullMessage = $"{message}{Environment.NewLine} Exception Details: {ex}"; - WriteTraceMessage(TraceLevel.Error, fullMessage); - } - - public static void Fatal(string message, Exception ex) - { - var fullMessage = $"{message}{Environment.NewLine} Exception Details: {ex}"; - WriteTraceMessage(TraceLevel.Off, fullMessage); - } - - public static void SetTracingEnabled(bool enabled) - { - lock (_lockObj) - { - Trace.AutoFlush = enabled; - _isTracingEnabled = enabled; - foreach (TraceListener listener in Trace.Listeners) - { - listener.Filter = enabled ? null : new EventTypeFilter(SourceLevels.Off); - } - } - } - - public static bool IsTracingEnabled() - { - lock (_lockObj) - { - return _isTracingEnabled; - } - } - - private static void WriteTraceMessage(TraceLevel level, string message) - { - if(!IsTracingEnabled()) - return; - - InitializeFileListener(); - var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); - var levelName = GetLevelName(level); - var fullMessage = string.Empty; - - try - { - var stackFrame = new StackFrame(2, true); - var method = stackFrame.GetMethod(); - var className = method.DeclaringType?.Name ?? "UnknownType"; - var methodName = method.Name; - var lineNumber = stackFrame.GetFileLineNumber(); - var lineInfo = lineNumber > 0 ? $"Line {lineNumber}" : "Line N/A (Line numbers may not be displayed in Release mode)"; - fullMessage = $"[{timestamp}] [{levelName}] {className}.{methodName} ({lineInfo}): {message}"; - } - catch - { - fullMessage = $"[{timestamp}] [{levelName}] : {message}"; - } - - Trace.WriteLine(fullMessage); - } - - private static string GetLevelName(TraceLevel level) => level switch - { - TraceLevel.Verbose => "DEBUG", - TraceLevel.Info => "INFO", - TraceLevel.Warning => "WARN", - TraceLevel.Error => "ERROR", - TraceLevel.Off => "FATAL", - _ => "UNKNOWN" - }; - - public static void Dispose() - { - try - { - lock (_lockObj) - { - if (_fileListener is not null) - { - _fileListener.Flush(); - _fileListener.Close(); - _fileListener.Dispose(); - _fileListener = null; - } - - Trace.Listeners.Clear(); - } - } - catch - { - // ignored - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Trace/TextTraceListener.cs b/src/c#/GeneralUpdate.Common/Shared/Trace/TextTraceListener.cs deleted file mode 100644 index 835f04ab..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Trace/TextTraceListener.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Collections.Concurrent; -using System.Threading; - -public class TextTraceListener : TraceListener, IDisposable -{ - private readonly string _filePath; - private readonly BlockingCollection _messageQueue; - private readonly Thread _loggingThread; - private volatile bool _isDisposed; - - public TextTraceListener(string filePath) - { - _filePath = filePath; - _messageQueue = new BlockingCollection(); - _loggingThread = new Thread(ProcessQueue); - _loggingThread.IsBackground = true; - _loggingThread.Start(); - } - - public override void Write(string? message) - { - QueueMessage(message); - } - - public override void WriteLine(string? message) - { - QueueMessage(message + Environment.NewLine); - } - - private void QueueMessage(string? message) - { - if (!_isDisposed && message != null) - { - _messageQueue.Add(message); - } - } - - private void ProcessQueue() - { - foreach (var message in _messageQueue.GetConsumingEnumerable()) - { - using (var fileStream = new FileStream(_filePath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite)) - using (var writer = new StreamWriter(fileStream)) - { - writer.Write(message); - } - } - } - - public void Dispose() - { - if (!_isDisposed) - { - _isDisposed = true; - _messageQueue.CompleteAdding(); - _loggingThread.Join(); - _messageQueue.Dispose(); - } - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Common/Shared/Trace/WindowsOutputDebugListener.cs b/src/c#/GeneralUpdate.Common/Shared/Trace/WindowsOutputDebugListener.cs deleted file mode 100644 index f7455a32..00000000 --- a/src/c#/GeneralUpdate.Common/Shared/Trace/WindowsOutputDebugListener.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace GeneralUpdate.Common.Shared; - -public class WindowsOutputDebugListener : TraceListener -{ - /// - /// Does not affect .NET AOT compilation and runtime on the Windows platform, provided that the following conditions are met: - /// The target platform is restricted to Windows (due to the dependency on kernel32.dll); - /// The function declaration is static (not dynamically generated). - /// This syntax is safe in an AOT environment and can properly work with Dbgview.exe to capture logs. - /// - /// - [DllImport("kernel32.dll", CharSet = CharSet.Auto)] - private static extern void OutputDebugString(string lpOutputString); - - public override void Write(string message) - { - if (!string.IsNullOrEmpty(message)) - { - OutputDebugString(message); - } - } - - public override void WriteLine(string message) - { - Write($"{message}{Environment.NewLine}"); - } -} \ No newline at end of file diff --git a/src/c#/GeneralUpdate.Core/GeneralUpdate.Core.csproj b/src/c#/GeneralUpdate.Core/GeneralUpdate.Core.csproj index de6d0919..e93ee2a2 100644 --- a/src/c#/GeneralUpdate.Core/GeneralUpdate.Core.csproj +++ b/src/c#/GeneralUpdate.Core/GeneralUpdate.Core.csproj @@ -12,6 +12,9 @@ upgrade,update,client 10.0.0-preview netstandard2.0 + + true + true diff --git a/src/c#/GeneralUpdate.Drivelution/Core/DriverUpdaterFactory.cs b/src/c#/GeneralUpdate.Drivelution/Core/DriverUpdaterFactory.cs index b65af1b9..ef8b8a59 100644 --- a/src/c#/GeneralUpdate.Drivelution/Core/DriverUpdaterFactory.cs +++ b/src/c#/GeneralUpdate.Drivelution/Core/DriverUpdaterFactory.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -using GeneralUpdate.Common.Shared; +using GeneralUpdate.Core; using GeneralUpdate.Drivelution.Abstractions; using GeneralUpdate.Drivelution.Abstractions.Configuration; using GeneralUpdate.Drivelution.Core.Execution; diff --git a/src/c#/GeneralUpdate.Drivelution/Core/Execution/CommandRunner.cs b/src/c#/GeneralUpdate.Drivelution/Core/Execution/CommandRunner.cs index 85dbce29..21c72e24 100644 --- a/src/c#/GeneralUpdate.Drivelution/Core/Execution/CommandRunner.cs +++ b/src/c#/GeneralUpdate.Drivelution/Core/Execution/CommandRunner.cs @@ -1,6 +1,6 @@ using System.Diagnostics; using System.Text; -using GeneralUpdate.Common.Shared; +using GeneralUpdate.Core; namespace GeneralUpdate.Drivelution.Core.Execution; diff --git a/src/c#/GeneralUpdate.Drivelution/Core/Pipeline/BaseDriverUpdater.cs b/src/c#/GeneralUpdate.Drivelution/Core/Pipeline/BaseDriverUpdater.cs index 70702027..4853c642 100644 --- a/src/c#/GeneralUpdate.Drivelution/Core/Pipeline/BaseDriverUpdater.cs +++ b/src/c#/GeneralUpdate.Drivelution/Core/Pipeline/BaseDriverUpdater.cs @@ -1,4 +1,4 @@ -using GeneralUpdate.Common.Shared; +using GeneralUpdate.Core; using GeneralUpdate.Drivelution.Abstractions; using GeneralUpdate.Drivelution.Abstractions.Configuration; using GeneralUpdate.Drivelution.Abstractions.Exceptions; diff --git a/src/c#/GeneralUpdate.Drivelution/Core/Pipeline/DefaultPipelineSteps.cs b/src/c#/GeneralUpdate.Drivelution/Core/Pipeline/DefaultPipelineSteps.cs index 3b04d02f..f20e8fc8 100644 --- a/src/c#/GeneralUpdate.Drivelution/Core/Pipeline/DefaultPipelineSteps.cs +++ b/src/c#/GeneralUpdate.Drivelution/Core/Pipeline/DefaultPipelineSteps.cs @@ -1,4 +1,4 @@ -using GeneralUpdate.Common.Shared; +using GeneralUpdate.Core; using GeneralUpdate.Drivelution.Abstractions; using GeneralUpdate.Drivelution.Abstractions.Models; using GeneralUpdate.Drivelution.Core.Utilities; diff --git a/src/c#/GeneralUpdate.Drivelution/GeneralDrivelution.cs b/src/c#/GeneralUpdate.Drivelution/GeneralDrivelution.cs index 2b58ab25..1b848880 100644 --- a/src/c#/GeneralUpdate.Drivelution/GeneralDrivelution.cs +++ b/src/c#/GeneralUpdate.Drivelution/GeneralDrivelution.cs @@ -1,4 +1,4 @@ -using GeneralUpdate.Common.Shared; +using GeneralUpdate.Core; using GeneralUpdate.Drivelution.Abstractions; using GeneralUpdate.Drivelution.Abstractions.Configuration; using GeneralUpdate.Drivelution.Abstractions.Models; diff --git a/src/c#/GeneralUpdate.Drivelution/GeneralUpdate.Drivelution.csproj b/src/c#/GeneralUpdate.Drivelution/GeneralUpdate.Drivelution.csproj index 7b3594ca..7c72c449 100644 --- a/src/c#/GeneralUpdate.Drivelution/GeneralUpdate.Drivelution.csproj +++ b/src/c#/GeneralUpdate.Drivelution/GeneralUpdate.Drivelution.csproj @@ -1,4 +1,4 @@ - + net10.0 @@ -28,11 +28,9 @@ true - + - - - + @@ -48,6 +46,7 @@ ./ + diff --git a/src/c#/GeneralUpdate.Drivelution/Linux/Implementation/LinuxDriverBackup.cs b/src/c#/GeneralUpdate.Drivelution/Linux/Implementation/LinuxDriverBackup.cs index 0fda85e8..4cc2901c 100644 --- a/src/c#/GeneralUpdate.Drivelution/Linux/Implementation/LinuxDriverBackup.cs +++ b/src/c#/GeneralUpdate.Drivelution/Linux/Implementation/LinuxDriverBackup.cs @@ -1,5 +1,5 @@ using System.Runtime.Versioning; -using GeneralUpdate.Common.Shared; +using GeneralUpdate.Core; using GeneralUpdate.Drivelution.Abstractions; using GeneralUpdate.Drivelution.Abstractions.Exceptions; diff --git a/src/c#/GeneralUpdate.Drivelution/Linux/Implementation/LinuxDriverValidator.cs b/src/c#/GeneralUpdate.Drivelution/Linux/Implementation/LinuxDriverValidator.cs index aed8cc49..1e1a6416 100644 --- a/src/c#/GeneralUpdate.Drivelution/Linux/Implementation/LinuxDriverValidator.cs +++ b/src/c#/GeneralUpdate.Drivelution/Linux/Implementation/LinuxDriverValidator.cs @@ -1,5 +1,5 @@ using System.Runtime.Versioning; -using GeneralUpdate.Common.Shared; +using GeneralUpdate.Core; using GeneralUpdate.Drivelution.Abstractions; using GeneralUpdate.Drivelution.Abstractions.Models; using GeneralUpdate.Drivelution.Core.Utilities; diff --git a/src/c#/GeneralUpdate.Drivelution/Linux/Implementation/LinuxGeneralDrivelution.cs b/src/c#/GeneralUpdate.Drivelution/Linux/Implementation/LinuxGeneralDrivelution.cs index 0de6387a..af73c40a 100644 --- a/src/c#/GeneralUpdate.Drivelution/Linux/Implementation/LinuxGeneralDrivelution.cs +++ b/src/c#/GeneralUpdate.Drivelution/Linux/Implementation/LinuxGeneralDrivelution.cs @@ -1,5 +1,5 @@ using System.Runtime.Versioning; -using GeneralUpdate.Common.Shared; +using GeneralUpdate.Core; using GeneralUpdate.Drivelution.Abstractions; using GeneralUpdate.Drivelution.Abstractions.Configuration; using GeneralUpdate.Drivelution.Abstractions.Exceptions; diff --git a/src/c#/GeneralUpdate.Drivelution/MacOS/Implementation/MacOsGeneralDrivelution.cs b/src/c#/GeneralUpdate.Drivelution/MacOS/Implementation/MacOsGeneralDrivelution.cs index 6e01d098..e8c4a6a5 100644 --- a/src/c#/GeneralUpdate.Drivelution/MacOS/Implementation/MacOsGeneralDrivelution.cs +++ b/src/c#/GeneralUpdate.Drivelution/MacOS/Implementation/MacOsGeneralDrivelution.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; using System.Runtime.Versioning; -using GeneralUpdate.Common.Shared; +using GeneralUpdate.Core; using GeneralUpdate.Drivelution.Abstractions; using GeneralUpdate.Drivelution.Abstractions.Configuration; using GeneralUpdate.Drivelution.Abstractions.Exceptions; diff --git a/src/c#/GeneralUpdate.Drivelution/Windows/Implementation/WindowsDriverBackup.cs b/src/c#/GeneralUpdate.Drivelution/Windows/Implementation/WindowsDriverBackup.cs index 40f88f42..530ad80f 100644 --- a/src/c#/GeneralUpdate.Drivelution/Windows/Implementation/WindowsDriverBackup.cs +++ b/src/c#/GeneralUpdate.Drivelution/Windows/Implementation/WindowsDriverBackup.cs @@ -1,5 +1,5 @@ using System.Runtime.Versioning; -using GeneralUpdate.Common.Shared; +using GeneralUpdate.Core; using GeneralUpdate.Drivelution.Abstractions; using GeneralUpdate.Drivelution.Abstractions.Exceptions; diff --git a/src/c#/GeneralUpdate.Drivelution/Windows/Implementation/WindowsDriverValidator.cs b/src/c#/GeneralUpdate.Drivelution/Windows/Implementation/WindowsDriverValidator.cs index d3cff48c..9997a972 100644 --- a/src/c#/GeneralUpdate.Drivelution/Windows/Implementation/WindowsDriverValidator.cs +++ b/src/c#/GeneralUpdate.Drivelution/Windows/Implementation/WindowsDriverValidator.cs @@ -1,5 +1,5 @@ using System.Runtime.Versioning; -using GeneralUpdate.Common.Shared; +using GeneralUpdate.Core; using GeneralUpdate.Drivelution.Abstractions; using GeneralUpdate.Drivelution.Abstractions.Exceptions; using GeneralUpdate.Drivelution.Abstractions.Models; diff --git a/src/c#/GeneralUpdate.Drivelution/Windows/Implementation/WindowsGeneralDrivelution.cs b/src/c#/GeneralUpdate.Drivelution/Windows/Implementation/WindowsGeneralDrivelution.cs index cd45cb59..59693570 100644 --- a/src/c#/GeneralUpdate.Drivelution/Windows/Implementation/WindowsGeneralDrivelution.cs +++ b/src/c#/GeneralUpdate.Drivelution/Windows/Implementation/WindowsGeneralDrivelution.cs @@ -1,5 +1,5 @@ using System.Runtime.Versioning; -using GeneralUpdate.Common.Shared; +using GeneralUpdate.Core; using GeneralUpdate.Drivelution.Abstractions; using GeneralUpdate.Drivelution.Abstractions.Configuration; using GeneralUpdate.Drivelution.Abstractions.Exceptions; diff --git a/src/c#/GeneralUpdate.Extension/Core/GeneralExtensionHost.cs b/src/c#/GeneralUpdate.Extension/Core/GeneralExtensionHost.cs index 62521da0..c1f0246f 100644 --- a/src/c#/GeneralUpdate.Extension/Core/GeneralExtensionHost.cs +++ b/src/c#/GeneralUpdate.Extension/Core/GeneralExtensionHost.cs @@ -7,7 +7,7 @@ using GeneralUpdate.Extension.Dependencies; using GeneralUpdate.Extension.Communication; using GeneralUpdate.Extension.Common.Models; -using GeneralUpdate.Common.Shared; +using GeneralUpdate.Core; using Newtonsoft.Json; using System; diff --git a/src/c#/GeneralUpdate.Extension/Download/DownloadQueueManager.cs b/src/c#/GeneralUpdate.Extension/Download/DownloadQueueManager.cs index 55ad81e8..0ebc8068 100644 --- a/src/c#/GeneralUpdate.Extension/Download/DownloadQueueManager.cs +++ b/src/c#/GeneralUpdate.Extension/Download/DownloadQueueManager.cs @@ -7,7 +7,7 @@ using GeneralUpdate.Extension.Dependencies; using GeneralUpdate.Extension.Communication; using GeneralUpdate.Extension.Common.Models; -using GeneralUpdate.Common.Shared; +using GeneralUpdate.Core; using System; using System.Collections.Generic; diff --git a/src/c#/GeneralUpdate.Extension/GeneralUpdate.Extension.csproj b/src/c#/GeneralUpdate.Extension/GeneralUpdate.Extension.csproj index fa075471..a2677d11 100644 --- a/src/c#/GeneralUpdate.Extension/GeneralUpdate.Extension.csproj +++ b/src/c#/GeneralUpdate.Extension/GeneralUpdate.Extension.csproj @@ -23,22 +23,19 @@ - - - + + + + + + + - - - - - - -