From 2883f79972187d8f8600e9fa5002d4cad4a690c6 Mon Sep 17 00:00:00 2001 From: JusterZhu Date: Mon, 25 May 2026 19:16:53 +0800 Subject: [PATCH] refactor: migrate to DefaultBlackListMatcher, deprecate BlackListManager Replace BlackListManager singleton with DefaultBlackListMatcher injection via StorageManager.BlackListMatcher static property. - BlackListDefaults: new static class with built-in defaults - DefaultBlackListMatcher.FromConfigInfo(): factory from GlobalConfigInfo - StorageManager.BlackListMatcher: injectable matcher, fallback to old - All call sites use GlobalConfigInfo properties directly instead of BlackListManager.Instance for accumulation + ProcessInfo building - BlackListManager marked [Obsolete] Closes #412 --- .../Bootstrap/GeneralUpdateBootstrap.cs | 22 ++++++++++------ .../FileSystem/BlackListDefaults.cs | 25 +++++++++++++++++++ .../FileSystem/BlackListManager.cs | 3 ++- .../FileSystem/DefaultBlackListMatcher.cs | 10 ++++++++ .../FileSystem/StorageManager.cs | 11 ++++++-- .../Silent/SilentPollOrchestrator.cs | 19 ++++++++------ .../Strategy/ClientUpdateStrategy.cs | 17 +++++++------ 7 files changed, 81 insertions(+), 26 deletions(-) create mode 100644 src/c#/GeneralUpdate.Core/FileSystem/BlackListDefaults.cs diff --git a/src/c#/GeneralUpdate.Core/Bootstrap/GeneralUpdateBootstrap.cs b/src/c#/GeneralUpdate.Core/Bootstrap/GeneralUpdateBootstrap.cs index a9bdc513..80c52a54 100644 --- a/src/c#/GeneralUpdate.Core/Bootstrap/GeneralUpdateBootstrap.cs +++ b/src/c#/GeneralUpdate.Core/Bootstrap/GeneralUpdateBootstrap.cs @@ -261,10 +261,6 @@ private void InitializeFromEnvironment() var processInfo = new EncryptedFileProcessInfoProvider().Receive(); if (processInfo == null) return; - BlackListManager.Instance.AddBlackFormats(processInfo.BlackFileFormats); - BlackListManager.Instance.AddBlackFiles(processInfo.BlackFiles); - BlackListManager.Instance.AddSkipDirectorys(processInfo.SkipDirectorys); - _configInfo = new GlobalConfigInfo { MainAppName = processInfo.AppName, @@ -282,8 +278,13 @@ private void InitializeFromEnvironment() BackupDirectory = processInfo.BackupDirectory, Scheme = processInfo.Scheme, Token = processInfo.Token, - DriverDirectory = processInfo.DriverDirectory + DriverDirectory = processInfo.DriverDirectory, + BlackFiles = processInfo.BlackFiles ?? BlackListDefaults.DefaultBlackFiles, + BlackFormats = processInfo.BlackFileFormats ?? BlackListDefaults.DefaultBlackFormats, + SkipDirectorys = processInfo.SkipDirectorys ?? BlackListDefaults.DefaultSkipDirectories }; + + StorageManager.BlackListMatcher = DefaultBlackListMatcher.FromConfigInfo(_configInfo); } /// @@ -350,9 +351,14 @@ private async Task LaunchSilentAsync() private void InitBlackList() { - BlackListManager.Instance.AddBlackFiles(_configInfo.BlackFiles); - BlackListManager.Instance.AddBlackFormats(_configInfo.BlackFormats); - BlackListManager.Instance.AddSkipDirectorys(_configInfo.SkipDirectorys); + // Build blacklist matcher from GlobalConfigInfo and set on StorageManager. + // The matcher combines user config with system defaults. + var effectiveConfig = new BlackListConfig( + _configInfo.BlackFiles?.Count > 0 ? _configInfo.BlackFiles : BlackListDefaults.DefaultBlackFiles, + _configInfo.BlackFormats?.Count > 0 ? _configInfo.BlackFormats : BlackListDefaults.DefaultBlackFormats, + _configInfo.SkipDirectorys?.Count > 0 ? _configInfo.SkipDirectorys : BlackListDefaults.DefaultSkipDirectories + ); + StorageManager.BlackListMatcher = new DefaultBlackListMatcher(effectiveConfig); } private async Task CallSmallBowlHomeAsync(string processName) diff --git a/src/c#/GeneralUpdate.Core/FileSystem/BlackListDefaults.cs b/src/c#/GeneralUpdate.Core/FileSystem/BlackListDefaults.cs new file mode 100644 index 00000000..d5bd92a8 --- /dev/null +++ b/src/c#/GeneralUpdate.Core/FileSystem/BlackListDefaults.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +namespace GeneralUpdate.Core.FileSystem; + +/// Built-in default blacklist items — previously hardcoded in BlackListManager. +public static class BlackListDefaults +{ + /// Default blacklisted files (system DLLs that ship with the runtime). + public static readonly List DefaultBlackFiles = new() + { + "Microsoft.Bcl.AsyncInterfaces.dll", + "System.Collections.Immutable.dll", + "System.IO.Pipelines.dll", + "System.Text.Encodings.Web.dll", + "System.Text.Json.dll" + }; + + /// Default blacklisted file extensions. + public static readonly List DefaultBlackFormats = new() + { ".patch", ".pdb", ".rar", ".tar", ".json", Configuration.Format.ZIP }; + + /// Default skipped directory prefixes. + public static readonly List DefaultSkipDirectories = new() + { "app-", "fail" }; +} diff --git a/src/c#/GeneralUpdate.Core/FileSystem/BlackListManager.cs b/src/c#/GeneralUpdate.Core/FileSystem/BlackListManager.cs index 6e7d61e0..887a6f41 100644 --- a/src/c#/GeneralUpdate.Core/FileSystem/BlackListManager.cs +++ b/src/c#/GeneralUpdate.Core/FileSystem/BlackListManager.cs @@ -15,9 +15,10 @@ public interface IBlackListMatcher } /// -/// Thread-safe blacklist manager. Uses Lazy singleton. +/// Thread-safe blacklist manager. Uses Lazy<T> singleton. /// Matching is case-insensitive and supports prefix matching for skip directories. /// +[Obsolete("Use DefaultBlackListMatcher + StorageManager.BlackListMatcher instead. See #412.")] public class BlackListManager : IBlackListMatcher { private static readonly Lazy _lazy = new(() => new BlackListManager()); diff --git a/src/c#/GeneralUpdate.Core/FileSystem/DefaultBlackListMatcher.cs b/src/c#/GeneralUpdate.Core/FileSystem/DefaultBlackListMatcher.cs index 463fb605..76a2a113 100644 --- a/src/c#/GeneralUpdate.Core/FileSystem/DefaultBlackListMatcher.cs +++ b/src/c#/GeneralUpdate.Core/FileSystem/DefaultBlackListMatcher.cs @@ -13,6 +13,16 @@ public class DefaultBlackListMatcher : IBlackListMatcher public DefaultBlackListMatcher(BlackListConfig config) => _config = config ?? throw new ArgumentNullException(nameof(config)); + /// Create a matcher from GlobalConfigInfo blacklist properties. + public static DefaultBlackListMatcher FromConfigInfo(GlobalConfigInfo config) + { + var cfg = new BlackListConfig( + config.BlackFiles?.Count > 0 ? config.BlackFiles : null, + config.BlackFormats?.Count > 0 ? config.BlackFormats : null, + config.SkipDirectorys?.Count > 0 ? config.SkipDirectorys : null); + return new DefaultBlackListMatcher(cfg); + } + public bool IsBlacklisted(string relativeFilePath) { var fileName = Path.GetFileName(relativeFilePath); diff --git a/src/c#/GeneralUpdate.Core/FileSystem/StorageManager.cs b/src/c#/GeneralUpdate.Core/FileSystem/StorageManager.cs index ae45afd0..bb8b04a0 100644 --- a/src/c#/GeneralUpdate.Core/FileSystem/StorageManager.cs +++ b/src/c#/GeneralUpdate.Core/FileSystem/StorageManager.cs @@ -13,6 +13,9 @@ public sealed class StorageManager { private long _fileCount = 0; public const string DirectoryName = "app-"; + + /// Optional blacklist matcher. When set, takes precedence over BlackListManager. + public static IBlackListMatcher? BlackListMatcher { get; set; } private ComparisonResult ComparisonResult { get; set; } @@ -264,7 +267,9 @@ private IEnumerable ReadFileNode(string path, string rootPath = null) foreach (var subPath in Directory.EnumerateFiles(path)) { - if (BlackListManager.Instance.IsBlacklisted(subPath)) continue; +#pragma warning disable CS0618 // Obsolete fallback + if ((BlackListMatcher ?? BlackListManager.Instance).IsBlacklisted(subPath)) continue; +#pragma warning restore CS0618 var hashAlgorithm = new Sha256HashAlgorithm(); var hash = hashAlgorithm.ComputeHash(subPath); @@ -283,7 +288,9 @@ private IEnumerable ReadFileNode(string path, string rootPath = null) foreach (var subPath in Directory.EnumerateDirectories(path)) { - if (BlackListManager.Instance.ShouldSkipDirectory(subPath)) continue; +#pragma warning disable CS0618 // Obsolete fallback + if ((BlackListMatcher ?? BlackListManager.Instance).ShouldSkipDirectory(subPath)) continue; +#pragma warning restore CS0618 resultFiles.AddRange(ReadFileNode(subPath, rootPath)); } diff --git a/src/c#/GeneralUpdate.Core/Silent/SilentPollOrchestrator.cs b/src/c#/GeneralUpdate.Core/Silent/SilentPollOrchestrator.cs index fa47dbc5..bfddc675 100644 --- a/src/c#/GeneralUpdate.Core/Silent/SilentPollOrchestrator.cs +++ b/src/c#/GeneralUpdate.Core/Silent/SilentPollOrchestrator.cs @@ -147,10 +147,13 @@ private async Task PrepareUpdateIfNeededAsync(CancellationToken token) catch (Exception ex) { GeneralTracer.Warn($"Hook OnBeforeUpdateAsync failed: {ex.Message}"); } } - // Configure for update - BlackListManager.Instance?.AddBlackFiles(_configInfo.BlackFiles); - BlackListManager.Instance?.AddBlackFormats(_configInfo.BlackFormats); - BlackListManager.Instance?.AddSkipDirectorys(_configInfo.SkipDirectorys); + // Configure matcher from config with defaults + var effectiveConfig = new BlackListConfig( + _configInfo.BlackFiles?.Count > 0 ? _configInfo.BlackFiles : BlackListDefaults.DefaultBlackFiles, + _configInfo.BlackFormats?.Count > 0 ? _configInfo.BlackFormats : BlackListDefaults.DefaultBlackFormats, + _configInfo.SkipDirectorys?.Count > 0 ? _configInfo.SkipDirectorys : BlackListDefaults.DefaultSkipDirectories + ); + StorageManager.BlackListMatcher = new DefaultBlackListMatcher(effectiveConfig); _configInfo.LastVersion = latestVersion; _configInfo.UpdateVersions = new List(); // legacy compat @@ -160,14 +163,14 @@ private async Task PrepareUpdateIfNeededAsync(CancellationToken token) // Backup StorageManager.Backup(_configInfo.InstallPath, _configInfo.BackupDirectory, - BlackListManager.Instance.SkipDirectorys); + _configInfo.SkipDirectorys ?? BlackListDefaults.DefaultSkipDirectories); // Build ProcessInfo and store for IPC delivery on process exit _preparedProcessInfo = ConfigurationMapper.MapToProcessInfo( _configInfo, new List(), - BlackListManager.Instance.BlackFormats.ToList(), - BlackListManager.Instance.BlackFiles.ToList(), - BlackListManager.Instance.SkipDirectorys.ToList()); + _configInfo.BlackFormats ?? BlackListDefaults.DefaultBlackFormats, + _configInfo.BlackFiles ?? BlackListDefaults.DefaultBlackFiles, + _configInfo.SkipDirectorys ?? BlackListDefaults.DefaultSkipDirectories); _configInfo.ProcessInfo = JsonSerializer.Serialize(_preparedProcessInfo, ProcessInfoJsonContext.Default.ProcessInfo); // ═══ Reporter: update started ═══ diff --git a/src/c#/GeneralUpdate.Core/Strategy/ClientUpdateStrategy.cs b/src/c#/GeneralUpdate.Core/Strategy/ClientUpdateStrategy.cs index 122e4baa..f484273c 100644 --- a/src/c#/GeneralUpdate.Core/Strategy/ClientUpdateStrategy.cs +++ b/src/c#/GeneralUpdate.Core/Strategy/ClientUpdateStrategy.cs @@ -173,9 +173,9 @@ private async Task ExecuteStandardWorkflowAsync() var processInfo = ConfigurationMapper.MapToProcessInfo( _configInfo, downloadVersions, - BlackListManager.Instance.BlackFormats.ToList(), - BlackListManager.Instance.BlackFiles.ToList(), - BlackListManager.Instance.SkipDirectorys.ToList()); + _configInfo.BlackFormats ?? BlackListDefaults.DefaultBlackFormats, + _configInfo.BlackFiles ?? BlackListDefaults.DefaultBlackFiles, + _configInfo.SkipDirectorys ?? BlackListDefaults.DefaultSkipDirectories); // Keep JSON string for backward compatibility (GlobalConfigInfo.ProcessInfo) _configInfo.ProcessInfo = JsonSerializer.Serialize(processInfo, @@ -243,16 +243,19 @@ private static IStrategy ResolveOsStrategy() private void InitBlackList() { - BlackListManager.Instance.AddBlackFiles(_configInfo!.BlackFiles); - BlackListManager.Instance.AddBlackFormats(_configInfo.BlackFormats); - BlackListManager.Instance.AddSkipDirectorys(_configInfo.SkipDirectorys); + var effectiveConfig = new BlackListConfig( + _configInfo!.BlackFiles?.Count > 0 ? _configInfo.BlackFiles : BlackListDefaults.DefaultBlackFiles, + _configInfo.BlackFormats?.Count > 0 ? _configInfo.BlackFormats : BlackListDefaults.DefaultBlackFormats, + _configInfo.SkipDirectorys?.Count > 0 ? _configInfo.SkipDirectorys : BlackListDefaults.DefaultSkipDirectories + ); + StorageManager.BlackListMatcher = new DefaultBlackListMatcher(effectiveConfig); } private void Backup() { GeneralTracer.Info($"ClientUpdateStrategy: backing up {_configInfo!.InstallPath} -> {_configInfo.BackupDirectory}"); StorageManager.Backup(_configInfo.InstallPath, _configInfo.BackupDirectory, - BlackListManager.Instance.SkipDirectorys); + _configInfo.SkipDirectorys ?? BlackListDefaults.DefaultSkipDirectories); } private bool CanSkip(bool isForcibly, UpdateInfoEventArgs updateInfo)