mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-15 17:30:27 +08:00
fix: 配置问题 (#10601)
* fix: _configurationBakFile 不生效 * chore: HttpService 使用 SettingsViewModel 属性 * chore: GetValue 增加同步锁 * chore: 备份有错误的配置文件 * chore: 使用 ConcurrentDictionary * style: 减少缩进 * chore: 移除未使用变量 * chore: 目录下存在 DEBUG/DEBUG.txt 的情况下输出更低等级的日志信息 * fix: 无配置文件时报错 * chore: gui.log 输出日志等级 * chore: 给写入文件的时候加锁 * perf: 减少重复检查 * fix: omit --------- Co-authored-by: status102 <102887808+status102@users.noreply.github.com>
This commit is contained in:
@@ -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<Root> _rootConfig = new Lazy<Root>(() =>
|
||||
{
|
||||
lock (_lock)
|
||||
@@ -64,6 +65,11 @@ namespace MaaWpfGui.Configuration
|
||||
try
|
||||
{
|
||||
parsed = JsonSerializer.Deserialize<Root>(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<Root>(File.ReadAllText(_configurationBakFile), _options);
|
||||
if (parsed is not null)
|
||||
{
|
||||
parsed = JsonSerializer.Deserialize<Root>(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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
// </copyright>
|
||||
|
||||
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<string, Dictionary<string, string>> _kvsMap;
|
||||
private static readonly string _configurationErrorFile = Path.Combine(Environment.CurrentDirectory, "config/gui.error.json");
|
||||
private static ConcurrentDictionary<string, ConcurrentDictionary<string, string>> _kvsMap;
|
||||
private static string _current = ConfigurationKeys.DefaultConfiguration;
|
||||
private static Dictionary<string, string> _kvs;
|
||||
private static Dictionary<string, string> _globalKvs;
|
||||
|
||||
private static readonly ILogger _logger = Log.ForContext<ConfigurationHelper>();
|
||||
private static ConcurrentDictionary<string, string> _kvs;
|
||||
private static ConcurrentDictionary<string, string> _globalKvs;
|
||||
|
||||
private static readonly object _lock = new();
|
||||
|
||||
private static readonly ILogger _logger = Log.ForContext<ConfigurationHelper>();
|
||||
|
||||
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
|
||||
/// <returns>The return value of <see cref="Save"/></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -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<string, Dictionary<string, string>>();
|
||||
_current = ConfigurationKeys.DefaultConfiguration;
|
||||
_kvsMap[_current] = new Dictionary<string, string>();
|
||||
_kvs = _kvsMap[_current];
|
||||
_globalKvs = new Dictionary<string, string>();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
_kvsMap = [];
|
||||
_current = ConfigurationKeys.DefaultConfiguration;
|
||||
_kvsMap[_current] = [];
|
||||
_kvs = _kvsMap[_current];
|
||||
_globalKvs = [];
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -217,51 +219,46 @@ namespace MaaWpfGui.Helper
|
||||
/// <returns>True if success, false if failed</returns>
|
||||
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<Dictionary<string, Dictionary<string, string>>>()
|
||||
?? new Dictionary<string, Dictionary<string, string>>();
|
||||
_kvsMap = parsed[ConfigurationKeys.ConfigurationMap]?.ToObject<ConcurrentDictionary<string, ConcurrentDictionary<string, string>>>()
|
||||
?? [];
|
||||
_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<string, Dictionary<string, string>>();
|
||||
_kvsMap = [];
|
||||
_current = ConfigurationKeys.DefaultConfiguration;
|
||||
_kvsMap[_current] = parsed.ToObject<Dictionary<string, string>>();
|
||||
_kvs = _kvsMap[_current];
|
||||
_kvsMap[_current] = parsed.ToObject<ConcurrentDictionary<string, string>>();
|
||||
}
|
||||
|
||||
_globalKvs = hasCurrentConfig
|
||||
? parsed[ConfigurationKeys.GlobalConfiguration]?.ToObject<Dictionary<string, string>>()
|
||||
: new Dictionary<string, string>();
|
||||
_kvs = _kvsMap[_current];
|
||||
|
||||
_globalKvs = hasGlobalConfig
|
||||
? parsed[ConfigurationKeys.GlobalConfiguration]?.ToObject<ConcurrentDictionary<string, string>>()
|
||||
: new ConcurrentDictionary<string, string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -270,27 +267,35 @@ namespace MaaWpfGui.Helper
|
||||
/// <returns>The result of saving process</returns>
|
||||
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<string, object> { { ConfigurationKeys.ConfigurationMap, _kvsMap }, { ConfigurationKeys.CurrentConfiguration, _current }, { ConfigurationKeys.GlobalConfiguration, _globalKvs }, },
|
||||
Formatting.Indented);
|
||||
try
|
||||
{
|
||||
var jsonStr = JsonConvert.SerializeObject(
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
{ 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<string, string>();
|
||||
_kvsMap[configName] = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -433,7 +459,7 @@ namespace MaaWpfGui.Helper
|
||||
return false;
|
||||
}
|
||||
|
||||
_kvsMap[configName] = new Dictionary<string, string>(_kvsMap[copyFrom]);
|
||||
_kvsMap[configName] = new ConcurrentDictionary<string, string>(_kvsMap[copyFrom]);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -453,7 +479,7 @@ namespace MaaWpfGui.Helper
|
||||
return false;
|
||||
}
|
||||
|
||||
_kvsMap.Remove(configName);
|
||||
_kvsMap.Remove(configName, out _);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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}";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user