using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.IO; namespace Txgy.EWS.Client.Common { public static class BusinessConfigManager { private static readonly object SyncRoot = new object(); private static BusinessConfig _current; public static string ConfigPath => Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config", "client-settings.json"); public static BusinessConfig Current { get { lock (SyncRoot) { return _current ?? (_current = Read()); } } } public static BusinessConfig Read() { if (!File.Exists(ConfigPath)) { throw new FileNotFoundException("Business config file was not found.", ConfigPath); } var json = File.ReadAllText(ConfigPath); var config = JsonConvert.DeserializeObject(json); Validate(config); return config; } public static BusinessConfig Reload() { lock (SyncRoot) { _current = Read(); FreeSqlTencent.Reset(); FreeSqlLocalSqLite.Reset(); return _current; } } public static string GetConnectionString(string name) { var connections = Current.Database.Connections; if (connections == null || !connections.TryGetValue(name, out var value) || string.IsNullOrWhiteSpace(value)) { throw new InvalidOperationException($"Business config is missing database connection: {name}"); } return value; } public static string GetRequiredPath(string value, string name) { if (string.IsNullOrWhiteSpace(value)) { throw new InvalidOperationException($"Business config is missing path: {name}"); } return value; } public static string GetAppSetting(string key) { if (!GetLegacyAppSettings().TryGetValue(key, out var token)) { return null; } if (token == null || token.Type == JTokenType.Null) { return null; } return token.Type == JTokenType.String ? token.Value() : token.ToString(); } public static void UpdateAppSetting(string key, string value) { lock (SyncRoot) { var root = ReadRoot(); var appSettings = GetLegacyAppSettings(root); if (!appSettings.TryGetValue(key, out var token) || token == null) { throw new InvalidOperationException($"Business config does not support writing setting: {key}"); } token.Replace(ConvertValue(token, value)); SaveRoot(root); _current = root.ToObject(); Validate(_current); FreeSqlTencent.Reset(); FreeSqlLocalSqLite.Reset(); } } public static void UpdateRuntimeSettings(int loadDataTimeLenMins, int dataCacheTimeLenMins) { lock (SyncRoot) { var root = ReadRoot(); root["runtime"]["loadDataTimeLenMins"] = loadDataTimeLenMins; root["runtime"]["dataCacheTimeLenMins"] = dataCacheTimeLenMins; SaveRoot(root); _current = root.ToObject(); Validate(_current); } } private static JObject ReadRoot() { if (!File.Exists(ConfigPath)) { throw new FileNotFoundException("Business config file was not found.", ConfigPath); } return JObject.Parse(File.ReadAllText(ConfigPath)); } private static void SaveRoot(JObject root) { var serializer = JsonSerializer.Create(new JsonSerializerSettings { Formatting = Formatting.Indented, StringEscapeHandling = StringEscapeHandling.EscapeNonAscii }); string json; using (var writer = new StringWriter()) { serializer.Serialize(writer, root); json = writer.ToString(); } var tempPath = ConfigPath + ".tmp"; File.WriteAllText(tempPath, json); if (File.Exists(ConfigPath)) { File.Delete(ConfigPath); } File.Move(tempPath, ConfigPath); } private static Dictionary GetLegacyAppSettings() { return GetLegacyAppSettings(ReadRoot()); } private static Dictionary GetLegacyAppSettings(JObject root) { return new Dictionary { { "api_domain", root["endpoints"]?["apiDomain"] }, { "AlarmSetting", root["paths"]?["alarmSetting"] }, { "AlarmLevelConfig", root["paths"]?["alarmLevelConfig"] }, { "ReportEventLevelSetting", root["paths"]?["reportEventLevelSetting"] }, { "WorkAreaFilePath", root["paths"]?["workAreaFilePath"] }, { "StationsCsvFilePath", root["paths"]?["stationsCsvFilePath"] }, { "CadDwgFilePath", root["paths"]?["cadDwgFilePath"] }, { "DwgJsonSetting", root["paths"]?["dwgJsonSetting"] }, { "WavesMseedFilePath", root["paths"]?["wavesMseedFilePath"] }, { "WavesTxtFilePath", root["paths"]?["wavesTxtFilePath"] }, { "LocalSqLiteDb", root["paths"]?["localSqLiteDb"] }, { "DwgSettings", root["paths"]?["dwgSettings"] }, { "CadSettingsFileName", root["paths"]?["cadSettingsFileName"] }, { "IsDesign", root["runtime"]?["isDesign"] }, { "IsRealtime", root["runtime"]?["isRealtime"] }, { "RefreshInterval", root["runtime"]?["refreshInterval"] }, { "EventShowTotalSeconds", root["runtime"]?["eventShowTotalSeconds"] }, { "LoadDataTimeLenMins", root["runtime"]?["loadDataTimeLenMins"] }, { "DataCacheTimeLenMins", root["runtime"]?["dataCacheTimeLenMins"] }, { "RealtimeResultTable", root["database"]?["tables"]?["realtimeResultTable"] }, { "RealtimeWaveDataTable", root["database"]?["tables"]?["realtimeWaveDataTable"] }, { "RealtimeFocalmechanismTable", root["database"]?["tables"]?["realtimeFocalmechanismTable"] }, { "PostResultTable", root["database"]?["tables"]?["postResultTable"] }, { "PostWaveDataTable", root["database"]?["tables"]?["postWaveDataTable"] }, { "PostFocalmechanismTable", root["database"]?["tables"]?["postFocalmechanismTable"] }, { "CommpanyName", root["branding"]?["commpanyName"] }, { "SystemNameCn", root["branding"]?["systemNameCn"] }, { "SystemNameEn", root["branding"]?["systemNameEn"] }, { "WorkAreaName", root["branding"]?["workAreaName"] }, { "SystemShortName", root["branding"]?["systemShortName"] }, { "日报起始时间", root["report"]?["dailyReportStartTime"] }, { "日报平面图横向偏移", root["report"]?["dailyReportPlanOffsetX"] }, { "日报平面图纵向偏移", root["report"]?["dailyReportPlanOffsetY"] }, { "BaseX", root["coordinates"]?["baseX"] }, { "BaseY", root["coordinates"]?["baseY"] }, { "BaseZ", root["coordinates"]?["baseZ"] } }; } private static JToken ConvertValue(JToken currentValue, string value) { switch (currentValue.Type) { case JTokenType.Boolean: return bool.Parse(value); case JTokenType.Integer: return int.Parse(value); case JTokenType.Float: return double.Parse(value); default: return value; } } private static void Validate(BusinessConfig config) { if (config == null) { throw new InvalidOperationException("Business config file format is invalid."); } Require(config.Endpoints?.ApiDomain, "endpoints.apiDomain"); Require(config.Paths?.AlarmSetting, "paths.alarmSetting"); Require(config.Paths?.AlarmLevelConfig, "paths.alarmLevelConfig"); Require(config.Paths?.ReportEventLevelSetting, "paths.reportEventLevelSetting"); Require(config.Paths?.WorkAreaFilePath, "paths.workAreaFilePath"); Require(config.Paths?.StationsCsvFilePath, "paths.stationsCsvFilePath"); Require(config.Paths?.CadDwgFilePath, "paths.cadDwgFilePath"); Require(config.Paths?.DwgJsonSetting, "paths.dwgJsonSetting"); Require(config.Paths?.WavesMseedFilePath, "paths.wavesMseedFilePath"); Require(config.Paths?.WavesTxtFilePath, "paths.wavesTxtFilePath"); Require(config.Paths?.LocalSqLiteDb, "paths.localSqLiteDb"); Require(config.Branding?.CommpanyName, "branding.commpanyName"); Require(config.Branding?.SystemNameCn, "branding.systemNameCn"); Require(config.Branding?.SystemNameEn, "branding.systemNameEn"); Require(config.Branding?.WorkAreaName, "branding.workAreaName"); Require(config.Branding?.SystemShortName, "branding.systemShortName"); Require(config.Report?.DailyReportStartTime, "report.dailyReportStartTime"); Require(config.Database?.Tables?.RealtimeResultTable, "database.tables.realtimeResultTable"); Require(config.Database?.Tables?.RealtimeWaveDataTable, "database.tables.realtimeWaveDataTable"); Require(config.Database?.Tables?.RealtimeFocalmechanismTable, "database.tables.realtimeFocalmechanismTable"); Require(config.Database?.Tables?.PostResultTable, "database.tables.postResultTable"); Require(config.Database?.Tables?.PostWaveDataTable, "database.tables.postWaveDataTable"); Require(config.Database?.Tables?.PostFocalmechanismTable, "database.tables.postFocalmechanismTable"); GetConnectionStringFromConfig(config, "TencetnMySQL"); GetConnectionStringFromConfig(config, "NasMySQL"); } private static void Require(string value, string name) { if (string.IsNullOrWhiteSpace(value)) { throw new InvalidOperationException($"Business config is missing setting: {name}"); } } private static void GetConnectionStringFromConfig(BusinessConfig config, string name) { if (config.Database?.Connections == null || !config.Database.Connections.TryGetValue(name, out var value) || string.IsNullOrWhiteSpace(value)) { throw new InvalidOperationException($"Business config is missing database connection: {name}"); } } } }