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.
354 lines
14 KiB
C#
354 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");
|
|
GetConnectionStringFromConfig(config, "NasMySQL");
|
|
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}");
|
|
}
|
|
}
|
|
}
|
|
}
|