You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

353 lines
14 KiB
C#

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
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<BusinessConfig>(json);
NormalizeRuntimeSettings(config);
Validate(config);
return config;
}
public static BusinessConfig Reload()
{
lock (SyncRoot)
{
_current = Read();
FreeSqlTencent.Reset();
FreeSqlLocalSqLite.Reset();
return _current;
}
}
public static BusinessConfig Save(BusinessConfig config)
{
lock (SyncRoot)
{
NormalizeRuntimeSettings(config);
Validate(config);
SaveConfig(config);
_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<string>() : 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<BusinessConfig>();
Validate(_current);
FreeSqlTencent.Reset();
FreeSqlLocalSqLite.Reset();
}
}
public static void UpdateRuntimeSettings(int loadDataTimeLenMins, int dataCacheTimeLenMins)
{
UpdateDataLookbackHours(loadDataTimeLenMins / 60.0);
}
public static void UpdateDataLookbackHours(double dataLookbackHours)
{
lock (SyncRoot)
{
if (dataLookbackHours <= 0)
{
throw new InvalidOperationException("runtime.dataLookbackHours must be greater than 0.");
}
var root = ReadRoot();
root["runtime"]["dataLookbackHours"] = dataLookbackHours;
root["runtime"]["dataCacheTimeLenMins"] = (int)Math.Round(dataLookbackHours * 60.0);
SaveRoot(root);
_current = root.ToObject<BusinessConfig>();
NormalizeRuntimeSettings(_current);
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 SaveConfig(BusinessConfig config)
{
var serializer = JsonSerializer.Create(new JsonSerializerSettings
{
Formatting = Formatting.Indented,
StringEscapeHandling = StringEscapeHandling.EscapeNonAscii,
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy
{
ProcessDictionaryKeys = false
}
}
});
string json;
using (var writer = new StringWriter())
{
serializer.Serialize(writer, config);
json = writer.ToString();
}
WriteJson(json);
}
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();
}
WriteJson(json);
}
private static void WriteJson(string json)
{
var directory = Path.GetDirectoryName(ConfigPath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
var tempPath = ConfigPath + ".tmp";
File.WriteAllText(tempPath, json, System.Text.Encoding.UTF8);
if (File.Exists(ConfigPath))
{
var backupPath = ConfigPath + ".bak";
if (File.Exists(backupPath))
{
File.Delete(backupPath);
}
File.Replace(tempPath, ConfigPath, backupPath, true);
if (File.Exists(backupPath))
{
File.Delete(backupPath);
}
return;
}
File.Move(tempPath, ConfigPath);
}
private static Dictionary<string, JToken> GetLegacyAppSettings()
{
return GetLegacyAppSettings(ReadRoot());
}
private static Dictionary<string, JToken> GetLegacyAppSettings(JObject root)
{
return new Dictionary<string, JToken>
{
{ "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"] },
{ "DataLookbackHours", root["runtime"]?["dataLookbackHours"] },
{ "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");
DateTime.Parse(config.Report.DailyReportStartTime);
}
private static void NormalizeRuntimeSettings(BusinessConfig config)
{
if (config?.Runtime == null)
{
return;
}
var runtime = config.Runtime;
if (runtime.DataLookbackHours <= 0)
{
throw new InvalidOperationException("runtime.dataLookbackHours must be greater than 0.");
}
runtime.DataCacheTimeLenMins = (int)Math.Round(runtime.DataLookbackHours * 60.0);
}
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}");
}
}
}
}