diff --git a/src/MaaWpfGui/Configuration/ConfigFactory.cs b/src/MaaWpfGui/Configuration/ConfigFactory.cs index 6111ac5b46..2b3be13b20 100644 --- a/src/MaaWpfGui/Configuration/ConfigFactory.cs +++ b/src/MaaWpfGui/Configuration/ConfigFactory.cs @@ -49,6 +49,7 @@ namespace MaaWpfGui.Configuration private static readonly JsonSerializerOptions _options = new() { WriteIndented = true, Converters = { new JsonStringEnumConverter() }, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }; + // TODO: 参考 ConfigurationHelper ,拆几个函数出来 private static readonly Lazy _rootConfig = new Lazy(() => { lock (_lock) @@ -64,6 +65,11 @@ namespace MaaWpfGui.Configuration try { parsed = JsonSerializer.Deserialize(File.ReadAllText(_configurationFile), _options); + if (parsed is null) + { + _logger.Warning("Failed to load configuration file, copying configuration file to error file"); + File.Copy(_configurationFile, _configurationFile + ".err", true); + } } catch (Exception e) { @@ -71,20 +77,27 @@ namespace MaaWpfGui.Configuration } } - if (parsed is null) + if (parsed is null && File.Exists(_configurationBakFile)) { - if (File.Exists(_configurationBakFile)) + _logger.Information("trying to use backup file"); + try { - File.Copy(_configurationBakFile, _configurationFile, true); - try + parsed = JsonSerializer.Deserialize(File.ReadAllText(_configurationBakFile), _options); + if (parsed is not null) { - parsed = JsonSerializer.Deserialize(File.ReadAllText(_configurationFile), _options); + _logger.Information("Backup file loaded successfully, copying backup file to configuration file"); + File.Copy(_configurationBakFile, _configurationFile, true); } - catch (Exception e) + else { - _logger.Information("Failed to parse configuration file: " + e); + _logger.Warning("Failed to load backup file, copying backup file to error file"); + File.Copy(_configurationBakFile, _configurationBakFile + ".err", true); } } + catch (Exception e) + { + _logger.Information("Failed to parse configuration file: " + e); + } } if (parsed is null) @@ -241,8 +254,23 @@ namespace MaaWpfGui.Configuration { lock (_lock) { - Save(); - Save(_configurationBakFile); + if (Save()) + { + _logger.Information($"{_configurationFile} saved"); + } + else + { + _logger.Warning($"{_configurationFile} save failed"); + } + + if (Save(_configurationBakFile)) + { + _logger.Information($"{_configurationBakFile} saved"); + } + else + { + _logger.Warning($"{_configurationBakFile} save failed"); + } } } diff --git a/src/MaaWpfGui/Helper/ConfigurationHelper.cs b/src/MaaWpfGui/Helper/ConfigurationHelper.cs index 453c85265e..cb5a388569 100644 --- a/src/MaaWpfGui/Helper/ConfigurationHelper.cs +++ b/src/MaaWpfGui/Helper/ConfigurationHelper.cs @@ -12,6 +12,7 @@ // using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; @@ -26,15 +27,16 @@ namespace MaaWpfGui.Helper { private static readonly string _configurationFile = Path.Combine(Environment.CurrentDirectory, "config/gui.json"); private static readonly string _configurationBakFile = Path.Combine(Environment.CurrentDirectory, "config/gui.json.bak"); - private static Dictionary> _kvsMap; + private static readonly string _configurationErrorFile = Path.Combine(Environment.CurrentDirectory, "config/gui.error.json"); + private static ConcurrentDictionary> _kvsMap; private static string _current = ConfigurationKeys.DefaultConfiguration; - private static Dictionary _kvs; - private static Dictionary _globalKvs; - - private static readonly ILogger _logger = Log.ForContext(); + private static ConcurrentDictionary _kvs; + private static ConcurrentDictionary _globalKvs; private static readonly object _lock = new(); + private static readonly ILogger _logger = Log.ForContext(); + public delegate void ConfigurationUpdateEventHandler(string key, string oldValue, string newValue); public static event ConfigurationUpdateEventHandler ConfigurationUpdateEvent; @@ -77,6 +79,7 @@ namespace MaaWpfGui.Helper { _logger.Information("Read global configuration key {Key} with current configuration value {Value}, configuration hit: {HasValue}, configuration value {Value}", key, value, true, value); SetGlobalValue(key, value); + DeleteValue(key); return value; } @@ -93,54 +96,48 @@ namespace MaaWpfGui.Helper /// The return value of public static bool SetValue(string key, string value) { - lock (_lock) + var old = string.Empty; + if (!_kvs.TryAdd(key, value)) { - var old = string.Empty; - if (!_kvs.TryAdd(key, value)) - { - old = _kvs[key]; - _kvs[key] = value; - } - - var result = Save(); - if (result) - { - ConfigurationUpdateEvent?.Invoke(key, old, value); - _logger.Debug("Configuration {Key} has been set to {Value}", key, value); - } - else - { - _logger.Warning("Failed to save configuration {Key} to {Value}", key, value); - } - - return result; + old = _kvs[key]; + _kvs[key] = value; } + + var result = Save(); + if (result) + { + ConfigurationUpdateEvent?.Invoke(key, old, value); + _logger.Debug("Configuration {Key} has been set to {Value}", key, value); + } + else + { + _logger.Warning("Failed to save configuration {Key} to {Value}", key, value); + } + + return result; } public static bool SetGlobalValue(string key, string value) { - lock (_lock) + var old = string.Empty; + if (!_globalKvs.TryAdd(key, value)) { - var old = string.Empty; - if (!_globalKvs.TryAdd(key, value)) - { - old = _globalKvs[key]; - _globalKvs[key] = value; - } - - var result = Save(); - if (result) - { - ConfigurationUpdateEvent?.Invoke(key, old, value); - _logger.Debug("Global configuration {Key} has been set to {Value}", key, value); - } - else - { - _logger.Warning("Failed to save global configuration {Key} to {Value}", key, value); - } - - return result; + old = _globalKvs[key]; + _globalKvs[key] = value; } + + var result = Save(); + if (result) + { + ConfigurationUpdateEvent?.Invoke(key, old, value); + _logger.Debug("Global configuration {Key} has been set to {Value}", key, value); + } + else + { + _logger.Warning("Failed to save global configuration {Key} to {Value}", key, value); + } + + return result; } /// @@ -151,28 +148,25 @@ namespace MaaWpfGui.Helper // ReSharper disable once UnusedMember.Global public static bool DeleteValue(string key) { - lock (_lock) + var old = string.Empty; + if (_kvs.TryGetValue(key, out var kv)) { - var old = string.Empty; - if (_kvs.TryGetValue(key, out var kv)) - { - old = kv; - } - - _kvs.Remove(key); - var result = Save(); - if (result) - { - ConfigurationUpdateEvent?.Invoke(key, old, string.Empty); - _logger.Debug("Configuration {Key} has been deleted", key); - } - else - { - _logger.Warning("Failed to save configuration file when deleted {Key}", key); - } - - return result; + old = kv; } + + _kvs.Remove(key, out _); + var result = Save(); + if (result) + { + ConfigurationUpdateEvent?.Invoke(key, old, string.Empty); + _logger.Debug("Configuration {Key} has been deleted", key); + } + else + { + _logger.Warning("Failed to save configuration file when deleted {Key}", key); + } + + return result; } private static void EnsureConfigDirectoryExists() @@ -186,29 +180,37 @@ namespace MaaWpfGui.Helper private static bool ParseConfig(out JObject parsed) { parsed = ParseJsonFile(_configurationFile); - if (parsed is null && File.Exists(_configurationBakFile)) + if (parsed is not null) { - _logger.Warning("Failed to load configuration file, trying to use backup file"); - parsed = ParseJsonFile(_configurationFile); + return true; + } + + if (File.Exists(_configurationFile)) + { + _logger.Warning("Failed to load configuration file, copying configuration file to error file"); + File.Copy(_configurationFile, _configurationErrorFile, true); + } + + if (File.Exists(_configurationBakFile)) + { + _logger.Information("trying to use backup file"); + parsed = ParseJsonFile(_configurationBakFile); if (parsed is not null) { + _logger.Information("Backup file loaded successfully, copying backup file to configuration file"); File.Copy(_configurationBakFile, _configurationFile, true); + return true; } } - if (parsed is null) - { - _logger.Warning("Failed to load configuration file and/or backup file, using default settings"); + _logger.Warning("Failed to load configuration file and/or backup file, using default settings"); - _kvsMap = new Dictionary>(); - _current = ConfigurationKeys.DefaultConfiguration; - _kvsMap[_current] = new Dictionary(); - _kvs = _kvsMap[_current]; - _globalKvs = new Dictionary(); - return false; - } - - return true; + _kvsMap = []; + _current = ConfigurationKeys.DefaultConfiguration; + _kvsMap[_current] = []; + _kvs = _kvsMap[_current]; + _globalKvs = []; + return false; } /// @@ -217,51 +219,46 @@ namespace MaaWpfGui.Helper /// True if success, false if failed public static bool Load() { - lock (_lock) + EnsureConfigDirectoryExists(); + + // Load configuration file + if (!ParseConfig(out var parsed)) { - EnsureConfigDirectoryExists(); - - // Load configuration file - if (!ParseConfig(out var parsed)) - { - return false; - } - - - SetKvOrMigrate(parsed); - - return true; + return false; } + + SetKvOrMigrate(parsed); + + return true; } private static void SetKvOrMigrate(JObject parsed) { - bool hasConfigMap = parsed.ContainsKey(ConfigurationKeys.ConfigurationMap); - bool hasCurrentConfig = parsed.ContainsKey(ConfigurationKeys.CurrentConfiguration); + bool hasGlobalConfig = parsed.ContainsKey(ConfigurationKeys.GlobalConfiguration); if (hasConfigMap) { // new version - _kvsMap = parsed[ConfigurationKeys.ConfigurationMap]?.ToObject>>() - ?? new Dictionary>(); + _kvsMap = parsed[ConfigurationKeys.ConfigurationMap]?.ToObject>>() + ?? []; _current = parsed[ConfigurationKeys.CurrentConfiguration]?.ToString() ?? ConfigurationKeys.DefaultConfiguration; - _kvs = _kvsMap[_current]; } else { // old version _logger.Information("Configuration file is in old version, migrating to new version"); - _kvsMap = new Dictionary>(); + _kvsMap = []; _current = ConfigurationKeys.DefaultConfiguration; - _kvsMap[_current] = parsed.ToObject>(); - _kvs = _kvsMap[_current]; + _kvsMap[_current] = parsed.ToObject>(); } - _globalKvs = hasCurrentConfig - ? parsed[ConfigurationKeys.GlobalConfiguration]?.ToObject>() - : new Dictionary(); + _kvs = _kvsMap[_current]; + + _globalKvs = hasGlobalConfig + ? parsed[ConfigurationKeys.GlobalConfiguration]?.ToObject>() + : new ConcurrentDictionary(); } /// @@ -270,27 +267,35 @@ namespace MaaWpfGui.Helper /// The result of saving process private static bool Save(string file = null) { - if (Released) + lock (_lock) { - _logger.Warning("Attempting to save configuration file after release, this is not allowed"); - return false; - } + if (Released) + { + _logger.Warning("Attempting to save configuration file after release, this is not allowed"); + return false; + } - try - { - var jsonStr = JsonConvert.SerializeObject( - new Dictionary { { ConfigurationKeys.ConfigurationMap, _kvsMap }, { ConfigurationKeys.CurrentConfiguration, _current }, { ConfigurationKeys.GlobalConfiguration, _globalKvs }, }, - Formatting.Indented); + try + { + var jsonStr = JsonConvert.SerializeObject( + new Dictionary + { + { ConfigurationKeys.ConfigurationMap, _kvsMap }, + { ConfigurationKeys.CurrentConfiguration, _current }, + { ConfigurationKeys.GlobalConfiguration, _globalKvs }, + }, + Formatting.Indented); - File.WriteAllText(file ?? _configurationFile, jsonStr); - } - catch (Exception e) - { - _logger.Error(e, "Failed to save configuration file."); - return false; - } + File.WriteAllText(file ?? _configurationFile, jsonStr); + } + catch (Exception e) + { + _logger.Error(e, "Failed to save configuration file."); + return false; + } - return true; + return true; + } } public static string GetCheckedStorage(string storageKey, string name, string defaultValue) @@ -367,10 +372,31 @@ namespace MaaWpfGui.Helper { lock (_lock) { - Save(); - Save(_configurationBakFile); - Released = true; + if (Released) + { + return; + } + + if (Save()) + { + _logger.Information($"{_configurationFile} saved"); + } + else + { + _logger.Warning($"{_configurationFile} save failed"); + } + + if (Save(_configurationBakFile)) + { + _logger.Information($"{_configurationBakFile} saved"); + } + else + { + _logger.Warning($"{_configurationBakFile} save failed"); + } } + + Released = true; } private static JObject ParseJsonFile(string filePath) @@ -423,7 +449,7 @@ namespace MaaWpfGui.Helper if (copyFrom is null) { - _kvsMap[configName] = new Dictionary(); + _kvsMap[configName] = []; } else { @@ -433,7 +459,7 @@ namespace MaaWpfGui.Helper return false; } - _kvsMap[configName] = new Dictionary(_kvsMap[copyFrom]); + _kvsMap[configName] = new ConcurrentDictionary(_kvsMap[copyFrom]); } return true; @@ -453,7 +479,7 @@ namespace MaaWpfGui.Helper return false; } - _kvsMap.Remove(configName); + _kvsMap.Remove(configName, out _); return true; } diff --git a/src/MaaWpfGui/Main/Bootstrapper.cs b/src/MaaWpfGui/Main/Bootstrapper.cs index 1507e872af..5537562260 100644 --- a/src/MaaWpfGui/Main/Bootstrapper.cs +++ b/src/MaaWpfGui/Main/Bootstrapper.cs @@ -108,10 +108,10 @@ namespace MaaWpfGui.Main // Bootstrap serilog var loggerConfiguration = new LoggerConfiguration() .WriteTo.Debug( - outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] <{ThreadId}><{ThreadName}> {Message:lj}{NewLine}{Exception}") + outputTemplate: "[{Timestamp:HH:mm:ss}][{Level:u3}] <{ThreadId}><{ThreadName}> {Message:lj}{NewLine}{Exception}") .WriteTo.File( LogFilename, - outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}] <{ThreadId}><{ThreadName}> {Message:lj}{NewLine}{Exception}") + outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff}][{Level:u3}] <{ThreadId}><{ThreadName}> {Message:lj}{NewLine}{Exception}") .Enrich.FromLogContext() .Enrich.WithThreadId() .Enrich.WithThreadName(); @@ -122,7 +122,8 @@ namespace MaaWpfGui.Main var maaEnv = Environment.GetEnvironmentVariable("MAA_ENVIRONMENT") == "Debug" ? "Debug" : "Production"; - loggerConfiguration = maaEnv == "Debug" + var withDebugFile = File.Exists("DEBUG") || File.Exists("DEBUG.txt"); + loggerConfiguration = (maaEnv == "Debug" || withDebugFile) ? loggerConfiguration.MinimumLevel.Verbose() : loggerConfiguration.MinimumLevel.Information(); @@ -134,6 +135,11 @@ namespace MaaWpfGui.Main _logger.Information($"Built at {builtDate:O}"); _logger.Information($"Maa ENV: {maaEnv}"); _logger.Information($"User Dir {Directory.GetCurrentDirectory()}"); + if (withDebugFile) + { + _logger.Information("Start with DEBUG file"); + } + if (IsUserAdministrator()) { _logger.Information("Run as Administrator"); diff --git a/src/MaaWpfGui/Services/Web/HttpService.cs b/src/MaaWpfGui/Services/Web/HttpService.cs index 2574b14f3b..959b02159d 100755 --- a/src/MaaWpfGui/Services/Web/HttpService.cs +++ b/src/MaaWpfGui/Services/Web/HttpService.cs @@ -37,13 +37,13 @@ namespace MaaWpfGui.Services.Web { get { - var p = ConfigurationHelper.GetGlobalValue(ConfigurationKeys.UpdateProxy, string.Empty); - if (string.IsNullOrEmpty(p)) + var proxy = Instances.SettingsViewModel.Proxy; + if (string.IsNullOrEmpty(proxy)) { return string.Empty; } - return p.Contains("://") ? p : ConfigurationHelper.GetGlobalValue(ConfigurationKeys.ProxyType, "http") + $"://{p}"; + return proxy.Contains("://") ? proxy : Instances.SettingsViewModel.ProxyType + $"://{proxy}"; } }