From fb4938cdc1ebaebb873471a79700e4316c304309 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 19 Jan 2026 06:50:04 +0000 Subject: [PATCH 1/5] Initial plan From ec3f69463e5fbf9fa3daa22534d9b52451e11851 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 19 Jan 2026 07:03:50 +0000 Subject: [PATCH 2/5] Convert GeneralClientBootstrap.cs to UTF-8 and use ConfigurationMapper - Converted GeneralClientBootstrap.cs from UTF-16BE to UTF-8 encoding - Updated SetConfig method to use ConfigurationMapper.MapToGlobalConfigInfo() instead of manual field mapping - Updated ExecuteWorkflowAsync to use ConfigurationMapper.MapToProcessInfo() instead of manual parameter passing - Added explanatory comments documenting the use of ConfigurationMapper Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com> --- .../GeneralClientBootstrap.cs | Bin 34772 -> 16288 bytes .../Shared/Object/BaseConfigInfo.cs | 96 +++++++++++++ .../Shared/Object/Configinfo.cs | 76 ++--------- .../Shared/Object/ConfigurationMapper.cs | 128 ++++++++++++++++++ .../Shared/Object/GlobalConfigInfo.cs | 124 ++++++++--------- .../Shared/Object/ProcessInfo.cs | 106 +++++++++++++-- 6 files changed, 381 insertions(+), 149 deletions(-) create mode 100644 src/c#/GeneralUpdate.Common/Shared/Object/BaseConfigInfo.cs create mode 100644 src/c#/GeneralUpdate.Common/Shared/Object/ConfigurationMapper.cs diff --git a/src/c#/GeneralUpdate.ClientCore/GeneralClientBootstrap.cs b/src/c#/GeneralUpdate.ClientCore/GeneralClientBootstrap.cs index cfa902155af90d6eb6accba5b5c880068596503a..542555701d0705c2408324ab3eab481526232e4b 100644 GIT binary patch literal 16288 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 UvTK*mp&kBEw<*Q#;P(B00B}?2LI3~& literal 34772 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 + /// 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). + /// + public string AppName { get; set; } + + /// + /// 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. + /// + public string InstallPath { get; set; } + + /// + /// 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; } + } +} diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/Configinfo.cs b/src/c#/GeneralUpdate.Common/Shared/Object/Configinfo.cs index 0f4c41b0..855d17d0 100644 --- a/src/c#/GeneralUpdate.Common/Shared/Object/Configinfo.cs +++ b/src/c#/GeneralUpdate.Common/Shared/Object/Configinfo.cs @@ -4,86 +4,30 @@ namespace GeneralUpdate.Common.Shared.Object { /// - /// Global update parameters. + /// 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 + public class Configinfo : BaseConfigInfo { /// - /// Update check api address. + /// 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; } /// - /// API address for reporting update status. - /// - public string ReportUrl { get; set; } - - /// - /// Need to start the name of the app. - /// - public string AppName { get; set; } - - /// - /// The name of the main application, without .exe. - /// - public string MainAppName { get; set; } - - /// - /// Update log web address. - /// - public string UpdateLogUrl { get; set; } - - /// - /// application key - /// - public string AppSecretKey { get; set; } - - /// - /// Client current version. - /// - public string ClientVersion { get; set; } - - /// - /// Upgrade Client current version. + /// 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; } /// - /// installation path (for update file logic). - /// - public string InstallPath { get; set; } - - /// - /// Files in the blacklist will skip the update. - /// - public List BlackFiles { get; set; } - - /// - /// File formats in the blacklist will skip the update. - /// - public List BlackFormats { get; set; } - - /// - /// SkipDirectorys - /// - public List SkipDirectorys { get; set; } - - /// - /// Product ID. + /// 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 string Bowl { get; set; } - - public string Scheme { get; set; } - - public string Token { get; set; } - - /// - /// Script to grant permissions to a specified file on Linux - /// - public string Script { get; set; } - public void Validate() { if (string.IsNullOrWhiteSpace(UpdateUrl) || !Uri.IsWellFormedUriString(UpdateUrl, UriKind.Absolute)) diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/ConfigurationMapper.cs b/src/c#/GeneralUpdate.Common/Shared/Object/ConfigurationMapper.cs new file mode 100644 index 00000000..0511665c --- /dev/null +++ b/src/c#/GeneralUpdate.Common/Shared/Object/ConfigurationMapper.cs @@ -0,0 +1,128 @@ +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) + { + if (source == null) + return target; + + if (target == null) + target = new GlobalConfigInfo(); + + // 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; + + // 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. + public static ProcessInfo MapToProcessInfo( + GlobalConfigInfo source, + List updateVersions, + List blackFileFormats, + List blackFiles, + List skipDirectories) + { + if (source == null) + return 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, + 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; + } + } +} diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/GlobalConfigInfo.cs b/src/c#/GeneralUpdate.Common/Shared/Object/GlobalConfigInfo.cs index a214137a..62c6d0f3 100644 --- a/src/c#/GeneralUpdate.Common/Shared/Object/GlobalConfigInfo.cs +++ b/src/c#/GeneralUpdate.Common/Shared/Object/GlobalConfigInfo.cs @@ -3,134 +3,118 @@ namespace GeneralUpdate.Common.Shared.Object; -public class GlobalConfigInfo +/// +/// 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) + /// - /// Update check api address. + /// The API endpoint URL for checking available updates. + /// Inherited from user configuration, used for version validation requests. /// public string UpdateUrl { get; set; } /// - /// API address for reporting update status. + /// The current version of the upgrade application (the updater itself). + /// Used separately from ClientVersion to manage updater upgrades. /// - public string ReportUrl { get; set; } + public string UpgradeClientVersion { get; set; } /// - /// Need to start the name of the app. + /// The unique product identifier for this application. + /// Used to distinguish between multiple products sharing the same update server. /// - public string AppName { get; set; } + public string ProductId { get; set; } - /// - /// The name of the main application, without .exe. - /// - public string MainAppName { get; set; } + // Runtime computed fields (calculated during workflow execution) + + + // Runtime computed fields (calculated during workflow execution) /// - /// Update package file format(Defult format is Zip). + /// The compression format of update packages (e.g., "ZIP", "7Z"). + /// Computed from UpdateOption.Format or defaults to ZIP. /// public string Format { get; set; } /// - /// Whether an update is required to upgrade the application. + /// Indicates whether the upgrade application itself needs to be updated. + /// Computed by comparing UpgradeClientVersion with server response. /// public bool IsUpgradeUpdate { get; set; } /// - /// Whether the main application needs to be updated. + /// Indicates whether the main application needs to be updated. + /// Computed by comparing ClientVersion with server response. /// public bool IsMainUpdate { get; set; } /// - /// Update log web address. - /// - public string UpdateLogUrl { get; set; } - - /// - /// Version information that needs to be updated. + /// 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 for file operations. + /// 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; } /// - /// Time-out event for file download. + /// Timeout duration in seconds for download operations. + /// Computed from UpdateOption.DownloadTimeOut or defaults to 60 seconds. /// public int DownloadTimeOut { get; set; } /// - /// application key - /// - public string AppSecretKey { get; set; } - - /// - /// Client current version. - /// - public string ClientVersion { get; set; } - - /// - /// Upgrade Client current version. - /// - public string UpgradeClientVersion { get; set; } - - /// - /// The main program latest version. + /// The latest available version from the update server. + /// Extracted from the server response body after version validation. /// public string LastVersion { get; set; } /// - /// installation path (for update file logic). - /// - public string InstallPath { get; set; } - - /// - /// Download file temporary storage path (for update file logic). + /// Temporary directory path for downloading and extracting update files. + /// Computed using StorageManager.GetTempDirectory("main_temp"). /// public string TempPath { get; set; } /// - /// Configuration parameters for upgrading the terminal program. + /// Serialized JSON string of ProcessInfo object for inter-process communication. + /// Contains all parameters needed by the upgrade process. /// public string ProcessInfo { get; set; } /// - /// Files in the blacklist will skip the update. + /// Indicates whether driver update functionality is enabled. + /// Computed from UpdateOption.Drive or defaults to false. /// - public List BlackFiles { get; set; } - - /// - /// File formats in the blacklist will skip the update. - /// - public List BlackFormats { get; set; } + public bool? DriveEnabled { get; set; } /// - /// SkipDirectorys + /// Indicates whether differential patch update is enabled. + /// Computed from UpdateOption.Patch or defaults to true. /// - public List SkipDirectorys { get; set; } + public bool? PatchEnabled { get; set; } /// - /// Whether to enable the driver upgrade function. + /// Dictionary for custom field name mappings. + /// Used for flexible configuration transformations in specific scenarios. /// - public bool? DriveEnabled { get; set; } - - public bool? PatchEnabled { get; set; } - - public string ProductId { get; set; } - public Dictionary FieldMappings { get; set; } - public string BackupDirectory { get; set; } - - public string Bowl { get; set; } - - public string Scheme { get; set; } - - public string Token { get; set; } - /// - /// Script to grant permissions to a specified file on Linux + /// Directory path where the current version files are backed up before update. + /// Computed by combining InstallPath with a versioned directory name. /// - public string Script { get; set; } + public string BackupDirectory { 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 index 68710749..047beef8 100644 --- a/src/c#/GeneralUpdate.Common/Shared/Object/ProcessInfo.cs +++ b/src/c#/GeneralUpdate.Common/Shared/Object/ProcessInfo.cs @@ -6,10 +6,48 @@ 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 + /// 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 @@ -30,122 +68,164 @@ public ProcessInfo(string appName , 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; + + // Set blacklist parameters BlackFileFormats = blackFileFormats; BlackFiles = blackFiles; SkipDirectorys = skipDirectories; } /// - /// Need to start the name of the app. + /// 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; } /// - /// Installation directory (the path where the update package is decompressed). + /// The installation directory where files will be updated. + /// All update operations are performed relative to this path. /// [JsonPropertyName("InstallPath")] public string InstallPath { get; set; } /// - /// Current version. + /// The current version of the application before the update. + /// Note: Maps from GlobalConfigInfo.ClientVersion. /// [JsonPropertyName("CurrentVersion")] public string CurrentVersion { get; set; } /// - /// The version of the last update. + /// The target version after the update completes. + /// This is the latest version available from the update server. /// [JsonPropertyName("LastVersion")] public string LastVersion { get; set; } /// - /// Update log web address. + /// The URL where users can view detailed update logs and changelogs. /// [JsonPropertyName("UpdateLogUrl")] public string UpdateLogUrl { get; set; } /// - /// The encoding type of the update package. + /// 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 the update package. + /// The compression format of update packages (e.g., "ZIP", "7Z"). /// [JsonPropertyName("CompressFormat")] public string CompressFormat { get; set; } /// - /// The timeout of the download. + /// 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; } /// - /// application key + /// The application secret key used for authenticating update requests. /// [JsonPropertyName("AppSecretKey")] public string AppSecretKey { get; set; } /// - /// One or more version update information. + /// 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; } /// - /// update report web address + /// The API endpoint URL for reporting update progress and completion status. /// [JsonPropertyName("ReportUrl")] public string ReportUrl { get; set; } /// - /// Back up the current version files that have not been updated. + /// 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; } /// - /// Script to grant permissions to a specified file on Linux + /// 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; } From ec89d92fa3cda8f5f7b5c180e1206994d17edfd9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 19 Jan 2026 07:08:25 +0000 Subject: [PATCH 3/5] Add BaseConfigInfo and ConfigurationMapper to project references Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com> --- src/c#/GeneralUpdate.Bowl/GeneralUpdate.Bowl.csproj | 2 ++ src/c#/GeneralUpdate.ClientCore/GeneralUpdate.ClientCore.csproj | 2 ++ src/c#/GeneralUpdate.Core/GeneralUpdate.Core.csproj | 2 ++ 3 files changed, 6 insertions(+) diff --git a/src/c#/GeneralUpdate.Bowl/GeneralUpdate.Bowl.csproj b/src/c#/GeneralUpdate.Bowl/GeneralUpdate.Bowl.csproj index 2b03c3a8..9657975a 100644 --- a/src/c#/GeneralUpdate.Bowl/GeneralUpdate.Bowl.csproj +++ b/src/c#/GeneralUpdate.Bowl/GeneralUpdate.Bowl.csproj @@ -59,6 +59,8 @@ + + diff --git a/src/c#/GeneralUpdate.ClientCore/GeneralUpdate.ClientCore.csproj b/src/c#/GeneralUpdate.ClientCore/GeneralUpdate.ClientCore.csproj index 9907131b..175194a4 100644 --- a/src/c#/GeneralUpdate.ClientCore/GeneralUpdate.ClientCore.csproj +++ b/src/c#/GeneralUpdate.ClientCore/GeneralUpdate.ClientCore.csproj @@ -57,6 +57,8 @@ + + diff --git a/src/c#/GeneralUpdate.Core/GeneralUpdate.Core.csproj b/src/c#/GeneralUpdate.Core/GeneralUpdate.Core.csproj index ac296dd1..1bc304aa 100644 --- a/src/c#/GeneralUpdate.Core/GeneralUpdate.Core.csproj +++ b/src/c#/GeneralUpdate.Core/GeneralUpdate.Core.csproj @@ -62,6 +62,8 @@ + + From 1095f6a185a5419a634fbb70d2f99121841fc646 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 19 Jan 2026 07:10:19 +0000 Subject: [PATCH 4/5] Address code review feedback: improve null handling in ConfigurationMapper Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com> --- .../Shared/Object/ConfigurationMapper.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/c#/GeneralUpdate.Common/Shared/Object/ConfigurationMapper.cs b/src/c#/GeneralUpdate.Common/Shared/Object/ConfigurationMapper.cs index 0511665c..05b352d6 100644 --- a/src/c#/GeneralUpdate.Common/Shared/Object/ConfigurationMapper.cs +++ b/src/c#/GeneralUpdate.Common/Shared/Object/ConfigurationMapper.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Text; @@ -19,12 +20,14 @@ public static class ConfigurationMapper /// A GlobalConfigInfo object populated with values from the source Configinfo. public static GlobalConfigInfo MapToGlobalConfigInfo(Configinfo source, GlobalConfigInfo target = null) { - if (source == null) - return target; - + // 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; @@ -59,6 +62,7 @@ public static GlobalConfigInfo MapToGlobalConfigInfo(Configinfo source, GlobalCo /// 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, @@ -67,7 +71,7 @@ public static ProcessInfo MapToProcessInfo( List skipDirectories) { if (source == null) - return 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 From 5a0d9b56ab161f2856ca611b574492ebe0c8481b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 19 Jan 2026 08:34:15 +0000 Subject: [PATCH 5/5] Apply ConfigurationMapper to GeneralUpdateBootstrap in Core project Co-authored-by: JusterZhu <11714536+JusterZhu@users.noreply.github.com> --- .../GeneralUpdateBootstrap.cs | 48 ++++++------------- 1 file changed, 15 insertions(+), 33 deletions(-) diff --git a/src/c#/GeneralUpdate.Core/GeneralUpdateBootstrap.cs b/src/c#/GeneralUpdate.Core/GeneralUpdateBootstrap.cs index 5756151d..7382da5c 100644 --- a/src/c#/GeneralUpdate.Core/GeneralUpdateBootstrap.cs +++ b/src/c#/GeneralUpdate.Core/GeneralUpdateBootstrap.cs @@ -64,41 +64,23 @@ public override async Task LaunchAsync() #region Configuration + /// + /// Configure the update bootstrap with user-provided configuration. + /// Uses ConfigurationMapper to ensure consistent field mapping and reduce maintenance burden. + /// + /// User-provided configuration containing update parameters + /// This bootstrap instance for method chaining public GeneralUpdateBootstrap SetConfig(Configinfo configInfo) { - _configInfo = new GlobalConfigInfo - { - MainAppName = configInfo.MainAppName, - InstallPath = configInfo.InstallPath, - ClientVersion = configInfo.ClientVersion, - UpdateLogUrl = configInfo.UpdateLogUrl, - AppSecretKey = configInfo.AppSecretKey, - TempPath = StorageManager.GetTempDirectory("upgrade_temp"), - ReportUrl = configInfo.ReportUrl, - UpdateUrl = configInfo.UpdateUrl, - Scheme = configInfo.Scheme, - Token = configInfo.Token, - ProductId = configInfo.ProductId, - DriveEnabled = GetOption(UpdateOption.Drive) ?? false, - PatchEnabled = GetOption(UpdateOption.Patch) ?? true, - Script = configInfo.Script - }; - - // Copy blacklist-related configuration if explicitly provided. - if (configInfo.BlackFiles != null) - { - _configInfo.BlackFiles = configInfo.BlackFiles; - } - - if (configInfo.BlackFormats != null) - { - _configInfo.BlackFormats = configInfo.BlackFormats; - } - - if (configInfo.SkipDirectorys != null) - { - _configInfo.SkipDirectorys = configInfo.SkipDirectorys; - } + // Use ConfigurationMapper instead of manual field mapping + // This ensures all fields are consistently mapped and reduces maintenance burden + _configInfo = ConfigurationMapper.MapToGlobalConfigInfo(configInfo); + + // Set runtime-specific values that are not part of user configuration + _configInfo.TempPath = StorageManager.GetTempDirectory("upgrade_temp"); + _configInfo.DriveEnabled = GetOption(UpdateOption.Drive) ?? false; + _configInfo.PatchEnabled = GetOption(UpdateOption.Patch) ?? true; + InitBlackList(); return this; }