645 lines
17 KiB
C#
645 lines
17 KiB
C#
#define DEBUG
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Diagnostics;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using System.Xml;
|
||
using System.Xml.Linq;
|
||
using Aitex.Common.Util;
|
||
using Aitex.Core.RT.ConfigCenter;
|
||
using Aitex.Core.RT.DBCore;
|
||
using Aitex.Core.RT.Event;
|
||
using Aitex.Core.RT.Log;
|
||
using Aitex.Core.RT.OperationCenter;
|
||
using Aitex.Core.RT.SCCore;
|
||
using Aitex.Core.Util;
|
||
using DocumentFormat.OpenXml.Vml.Spreadsheet;
|
||
using DocumentFormat.OpenXml.Wordprocessing;
|
||
using MECF.Framework.Common.Equipment;
|
||
using MECF.Framework.Common.FAServices;
|
||
using MECF.Framework.Common.MECF.Framework.Common.SCCore;
|
||
|
||
namespace MECF.Framework.Common.SCCore
|
||
{
|
||
public class SystemConfigManager : Singleton<SystemConfigManager>, ISCManager
|
||
{
|
||
#region Variables
|
||
|
||
private readonly Dictionary<string, SCConfigItem> _items;
|
||
private readonly Dictionary<string, List<Action<object>>> _dicValueChangedCallback;
|
||
|
||
private object _itemLocker = new object();
|
||
|
||
private string _scConfigFile;
|
||
|
||
private readonly string _scDataFile = PathManager.GetCfgDir() + "_sc.data";
|
||
|
||
private readonly string _scDataBackupFile = PathManager.GetCfgDir() + "_sc.data.bak";
|
||
|
||
private readonly string _scDataErrorFile = PathManager.GetCfgDir() + "_sc.data.err.";
|
||
|
||
private readonly string _scConfigChangedBackupPath = PathManager.GetCfgDir() + "ConfigBackup\\";
|
||
|
||
public readonly List<ConfigChangedInfo> _itemsChanged; //ϵͳÅäÖñä¸üÏî¼Ç¼
|
||
|
||
#endregion
|
||
|
||
#region Constructors
|
||
|
||
public SystemConfigManager()
|
||
{
|
||
_items = new Dictionary<string, SCConfigItem>(StringComparer.OrdinalIgnoreCase);
|
||
_itemsChanged = new List<ConfigChangedInfo>();
|
||
_dicValueChangedCallback = new Dictionary<string, List<Action<object>>>();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Methods
|
||
|
||
public List<VIDItem> VidConfigList
|
||
{
|
||
get
|
||
{
|
||
var list = new List<VIDItem>();
|
||
foreach (var item in _items)
|
||
{
|
||
list.Add(new VIDItem
|
||
{
|
||
DataType = "",
|
||
Description = item.Value.Description,
|
||
Index = 0,
|
||
Name = item.Key,
|
||
Unit = ""
|
||
});
|
||
}
|
||
return list;
|
||
}
|
||
}
|
||
|
||
public void Initialize(string scConfigPathName)
|
||
{
|
||
_scConfigFile = scConfigPathName;
|
||
BuildItems(_scConfigFile);
|
||
BackupAndRecoverDataFile();
|
||
CustomData();
|
||
GenerateDataFile();
|
||
foreach (var item in _items)
|
||
{
|
||
CONFIG.Subscribe("", item.Key, () => item.Value.Value);
|
||
}
|
||
OP.Subscribe("System.SetConfig", InvokeSetConfig);
|
||
|
||
|
||
GetConfigChangedInfo();
|
||
CONFIG.Subscribe("SystemConfig", "DataChangedList", () => _itemsChanged);
|
||
OP.Subscribe("SystemConfig.Confirm", RemoveConfigChangedInfo);
|
||
OP.Subscribe("SystemConfig.Revert", RevertConfig);
|
||
|
||
SC.Manager = this;
|
||
}
|
||
|
||
/// <summary>
|
||
/// ½«±ä¸ü¹ýµÄÅäÖû¹Ô
|
||
/// </summary>
|
||
/// <param name="arg1"></param>
|
||
/// <param name="arg2"></param>
|
||
/// <returns></returns>
|
||
private bool RevertConfig(string arg1, object[] arg2)
|
||
{
|
||
foreach (var item in _itemsChanged)
|
||
{
|
||
if (_items.ContainsKey(item.Name))
|
||
{
|
||
if (InitializeItemValue(_items[item.Name], item.OldValue))
|
||
{
|
||
GenerateDataFile();
|
||
EV.PostInfoLog("System", $"SC {item.Name} value changed back to {item.OldValue}");
|
||
//DataChangedBackup(_items[item.Name], item.OldValue); //±éÀúʱ²»ÄܶÔlist½øÐвÙ×÷
|
||
}
|
||
}
|
||
}
|
||
//Èç¹ûÏîÄ¿ÖдæÔÚÇ°´Î¸Ä¶¯£¬ÔòÔٴα¸·ÝÎļþ
|
||
if (_itemsChanged.Exists(i=>!i.Enable))
|
||
{
|
||
RemoveConfigChangedInfo(null,null);
|
||
}
|
||
_itemsChanged.Clear();
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// ´Ó±¾µØ»ñÈ¡ÅäÖñä¸ü¼Ç¼
|
||
/// 1.»ñÈ¡×î½üÅäÖÃÎļþ£¨Éϴγõʼ»¯Ê±±£´æµÄbackup£©£¨ÅäÖÃvisible=falseÏî²»×ö¶Ô±È£©
|
||
/// 2.ºÍµ±Ç°ÅäÖÃ×ö¶Ô±È
|
||
/// </summary>
|
||
private void GetConfigChangedInfo()
|
||
{
|
||
if (!Directory.Exists(_scConfigChangedBackupPath))
|
||
{
|
||
Directory.CreateDirectory(_scConfigChangedBackupPath);
|
||
}
|
||
DirectoryInfo folder = new DirectoryInfo(@_scConfigChangedBackupPath);
|
||
List<FileInfo> files = folder.GetFiles("*.configbackup", SearchOption.TopDirectoryOnly).ToList();
|
||
var qry = from x in files
|
||
orderby x.LastWriteTime
|
||
select x;
|
||
string newestBackupPath = qry.Last()?.FullName;
|
||
if (!string.IsNullOrEmpty(newestBackupPath))
|
||
{
|
||
var xmlDocument = new XmlDocument();
|
||
xmlDocument.Load(newestBackupPath);
|
||
var xmlNodeList = xmlDocument.SelectNodes("root/scdata");
|
||
bool isConfigChanged = false;
|
||
foreach (XmlElement item in xmlNodeList)
|
||
{
|
||
var name = item.GetAttribute("name");
|
||
if (_items.ContainsKey(name))
|
||
{
|
||
if (!_items[name].ValueEquals(item.GetAttribute("value")) && _items[name].Visible)
|
||
{
|
||
isConfigChanged = true;
|
||
_itemsChanged.Add(new ConfigChangedInfo
|
||
{
|
||
Name = name,
|
||
OldValue = item.GetAttribute("value"),
|
||
Enable = false
|
||
});
|
||
}
|
||
}
|
||
}
|
||
//if (isConfigChanged)
|
||
//{
|
||
// File.Copy(_scDataFile, _scConfigChangedBackupPath + "\\config." +
|
||
// DateTime.Now.ToString().Replace(":", "").Replace("/", "").Replace(" ", "")+".backup");
|
||
//}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// ÅäÖÃÓб䶯ʱ£¬Ï´ÎÆô¶¯Èí¼þ»áµ¯´°È·ÈÏ°´Å¥°´Ïºó»á½«ÅäÖÃbackup£¬Ï´ÎÆô¶¯²»ÔÙÏÔʾ´Ë´Î±ä¸ü¼Ç¼
|
||
/// </summary>
|
||
/// <param name="arg1"></param>
|
||
/// <param name="arg2"></param>
|
||
/// <returns></returns>
|
||
private bool RemoveConfigChangedInfo(string arg1, object[] arg2)
|
||
{
|
||
try
|
||
{
|
||
File.Copy(_scDataFile, _scConfigChangedBackupPath + "\\" +
|
||
DateTime.Now.ToString().Replace(":", "").Replace("/", "").Replace(" ", "") + ".configbackup");
|
||
return true;
|
||
}
|
||
catch (Exception)
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
private bool InvokeSetConfig(string cmd, object[] parameters)
|
||
{
|
||
var scName = (string)parameters[0];
|
||
var scValue = parameters[1];
|
||
if (!ContainsItem(scName))
|
||
{
|
||
EV.PostWarningLog("System", $"Not find SC with name {scName}");
|
||
return false;
|
||
}
|
||
var configValueAsObject = GetConfigValueAsObject(scName);
|
||
if (InitializeItemValue(_items[scName], scValue))
|
||
{
|
||
GenerateDataFile();
|
||
EV.PostInfoLog("System", $"SC {scName} value changed from {configValueAsObject} to {parameters[1]}");
|
||
DataChangedBackup(_items[scName], configValueAsObject);
|
||
}
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
///
|
||
/// </summary>
|
||
/// <param name="item"></param>
|
||
/// <param name="oldvalue"></param>
|
||
private void DataChangedBackup(SCConfigItem item, object oldvalue)
|
||
{
|
||
bool isExist = false;
|
||
for (int i = _itemsChanged.Count - 1; i >= 0; i--)
|
||
{
|
||
if (_itemsChanged[i].Name == item.PathName)
|
||
{
|
||
isExist = true;
|
||
object newvalue = (item.Type switch
|
||
{
|
||
"Bool" => item.BoolValue,
|
||
"Integer" => item.IntValue,
|
||
"Double" => item.DoubleValue,
|
||
"String" => item.StringValue,
|
||
_ => null,
|
||
});
|
||
if (newvalue.ToString() == _itemsChanged[i].OldValue)
|
||
{
|
||
_itemsChanged.Remove(_itemsChanged[i]);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
if (!isExist)
|
||
{
|
||
_itemsChanged.Add(new ConfigChangedInfo
|
||
{
|
||
Name = item.PathName,
|
||
OldValue = oldvalue.ToString(),
|
||
Enable = true
|
||
});
|
||
}
|
||
|
||
}
|
||
|
||
public void Terminate()
|
||
{
|
||
}
|
||
|
||
public string GetFileContent()
|
||
{
|
||
if (!File.Exists(_scConfigFile))
|
||
{
|
||
return "";
|
||
}
|
||
var stringBuilder = new StringBuilder();
|
||
try
|
||
{
|
||
using var streamReader = new StreamReader(_scConfigFile);
|
||
while (!streamReader.EndOfStream)
|
||
{
|
||
stringBuilder.Append(streamReader.ReadLine());
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LOG.Write(ex);
|
||
return "";
|
||
}
|
||
return stringBuilder.ToString();
|
||
}
|
||
|
||
private void BuildItems(string xmlFile)
|
||
{
|
||
var xmlDocument = new XmlDocument();
|
||
try
|
||
{
|
||
xmlDocument.Load(xmlFile);
|
||
var xmlNodeList = xmlDocument.SelectNodes("root/configs");
|
||
foreach (XmlElement item in xmlNodeList)
|
||
{
|
||
BuildPathConfigs(item.GetAttribute("name"), item);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LOG.Write(ex);
|
||
}
|
||
}
|
||
|
||
private void BuildPathConfigs(string parentPath, XmlElement configElement)
|
||
{
|
||
var xmlNodeList = configElement.SelectNodes("configs");
|
||
foreach (XmlElement item in xmlNodeList)
|
||
{
|
||
if (string.IsNullOrEmpty(parentPath))
|
||
{
|
||
BuildPathConfigs(item.GetAttribute("name"), item);
|
||
}
|
||
else
|
||
{
|
||
BuildPathConfigs(parentPath + "." + item.GetAttribute("name"), item);
|
||
}
|
||
}
|
||
var xmlNodeList2 = configElement.SelectNodes("config");
|
||
foreach (XmlElement item2 in xmlNodeList2)
|
||
{
|
||
var sCConfigItem = new SCConfigItem
|
||
{
|
||
Default = item2.GetAttribute("default"),
|
||
Name = item2.GetAttribute("name"),
|
||
Description = item2.GetAttribute("description"),
|
||
Max = item2.GetAttribute("max"),
|
||
Min = item2.GetAttribute("min"),
|
||
Parameter = item2.GetAttribute("paramter"),
|
||
Path = parentPath,
|
||
Tag = item2.GetAttribute("tag"),
|
||
Type = item2.GetAttribute("type"),
|
||
Unit = item2.GetAttribute("unit")
|
||
};
|
||
|
||
bool visible;
|
||
if (bool.TryParse(item2.GetAttribute("visible"),out visible))
|
||
{
|
||
sCConfigItem.Visible = visible;
|
||
}
|
||
|
||
InitializeItemValue(sCConfigItem, sCConfigItem.Default);
|
||
if (_items.ContainsKey(sCConfigItem.PathName))
|
||
{
|
||
LOG.Error("Duplicated SC item, " + sCConfigItem.PathName);
|
||
}
|
||
_items[sCConfigItem.PathName] = sCConfigItem;
|
||
}
|
||
}
|
||
|
||
private void BackupAndRecoverDataFile()
|
||
{
|
||
try
|
||
{
|
||
if (File.Exists(_scDataFile) && IsXmlFileLoadable(_scDataFile))
|
||
{
|
||
File.Copy(_scDataFile, _scDataBackupFile, overwrite: true);
|
||
}
|
||
else if (File.Exists(_scDataBackupFile) && IsXmlFileLoadable(_scDataBackupFile))
|
||
{
|
||
if (File.Exists(_scDataFile))
|
||
{
|
||
File.Copy(_scDataFile, _scDataErrorFile + DateTime.Now.ToString("yyyyMMdd_HHmmss"), overwrite: true);
|
||
}
|
||
File.Copy(_scDataBackupFile, _scDataFile, overwrite: true);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LOG.Write(ex);
|
||
}
|
||
}
|
||
|
||
private void CustomData()
|
||
{
|
||
var dictionary = new Dictionary<string, string>();
|
||
try
|
||
{
|
||
if (!File.Exists(_scDataFile))
|
||
{
|
||
return;
|
||
}
|
||
var xmlDocument = new XmlDocument();
|
||
xmlDocument.Load(_scDataFile);
|
||
var xmlNodeList = xmlDocument.SelectNodes("root/scdata");
|
||
foreach (XmlElement item in xmlNodeList)
|
||
{
|
||
var attribute = item.GetAttribute("name");
|
||
if (_items.ContainsKey(attribute))
|
||
{
|
||
InitializeItemValue(_items[attribute], item.GetAttribute("value"));
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LOG.Write(ex);
|
||
}
|
||
}
|
||
|
||
private void GenerateDataFile()
|
||
{
|
||
try
|
||
{
|
||
var doc = new XmlDocument();
|
||
doc.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><root></root>");
|
||
var root = doc.SelectSingleNode("root") as XmlElement;
|
||
foreach (var item in _items)
|
||
{
|
||
var xmlElement2 = doc.CreateElement("scdata");
|
||
xmlElement2.SetAttribute("name", item.Key);
|
||
xmlElement2.SetAttribute("value", item.Value.Value.ToString());
|
||
root.AppendChild(xmlElement2);
|
||
}
|
||
if (File.Exists(_scDataFile) && IsXmlFileLoadable(_scDataFile))
|
||
{
|
||
File.Copy(_scDataFile, _scDataBackupFile, overwrite: true);
|
||
}
|
||
using var fileStream = new FileStream(_scDataFile, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, 1024, FileOptions.WriteThrough);
|
||
fileStream.SetLength(0L);
|
||
var xmlWriterSettings = new XmlWriterSettings();
|
||
xmlWriterSettings.Indent = true;
|
||
xmlWriterSettings.OmitXmlDeclaration = false;
|
||
using var w = XmlWriter.Create(fileStream, xmlWriterSettings);
|
||
doc.Save(w);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LOG.Write(ex);
|
||
}
|
||
}
|
||
|
||
private bool IsXmlFileLoadable(string file)
|
||
{
|
||
try
|
||
{
|
||
var xmlDocument = new XmlDocument();
|
||
xmlDocument.Load(file);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LOG.Write(ex);
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
public SCConfigItem GetConfigItem(string name)
|
||
{
|
||
if (!_items.ContainsKey(name))
|
||
{
|
||
return null;
|
||
}
|
||
return _items[name];
|
||
}
|
||
|
||
public bool ContainsItem(string name)
|
||
{
|
||
return _items.ContainsKey(name);
|
||
}
|
||
|
||
public object GetConfigValueAsObject(string name)
|
||
{
|
||
var configItem = GetConfigItem(name);
|
||
return configItem.Type switch
|
||
{
|
||
"Bool" => configItem.BoolValue,
|
||
"Integer" => configItem.IntValue,
|
||
"Double" => configItem.DoubleValue,
|
||
"String" => configItem.StringValue,
|
||
_ => null,
|
||
};
|
||
}
|
||
|
||
public T GetValue<T>(string name) where T : struct
|
||
{
|
||
try
|
||
{
|
||
if (typeof(T) == typeof(bool))
|
||
{
|
||
return (T)(object)_items[name].BoolValue;
|
||
}
|
||
if (typeof(T) == typeof(int))
|
||
{
|
||
return (T)(object)_items[name].IntValue;
|
||
}
|
||
if (typeof(T) == typeof(double))
|
||
{
|
||
return (T)(object)_items[name].DoubleValue;
|
||
}
|
||
}
|
||
catch (KeyNotFoundException)
|
||
{
|
||
EV.PostAlarmLog("System", "Can not find system config item " + name);
|
||
return default(T);
|
||
}
|
||
catch (Exception)
|
||
{
|
||
EV.PostAlarmLog("System", "Can not get valid system config item value " + name);
|
||
return default(T);
|
||
}
|
||
Debug.Assert(condition: false, "unsupported type");
|
||
return default(T);
|
||
}
|
||
|
||
public string GetStringValue(string name)
|
||
{
|
||
if (!_items.ContainsKey(name))
|
||
{
|
||
return null;
|
||
}
|
||
return _items[name].StringValue;
|
||
}
|
||
|
||
public T SafeGetValue<T>(string name, T defaultValue) where T : struct
|
||
{
|
||
try
|
||
{
|
||
if (typeof(T) == typeof(bool))
|
||
{
|
||
return (T)(object)_items[name].BoolValue;
|
||
}
|
||
if (typeof(T) == typeof(int))
|
||
{
|
||
return (T)(object)_items[name].IntValue;
|
||
}
|
||
if (typeof(T) == typeof(double))
|
||
{
|
||
return (T)(object)_items[name].DoubleValue;
|
||
}
|
||
}
|
||
catch (KeyNotFoundException)
|
||
{
|
||
return defaultValue;
|
||
}
|
||
catch (Exception)
|
||
{
|
||
return defaultValue;
|
||
}
|
||
Debug.Assert(condition: false, "unsupported type");
|
||
return defaultValue;
|
||
}
|
||
|
||
public string SafeGetStringValue(string name, string defaultValue)
|
||
{
|
||
if (!_items.ContainsKey(name))
|
||
{
|
||
return defaultValue;
|
||
}
|
||
return _items[name].StringValue;
|
||
}
|
||
|
||
public List<SCConfigItem> GetItemList()
|
||
{
|
||
return _items.Values.ToList();
|
||
}
|
||
|
||
private bool InitializeItemValue(SCConfigItem scItem, object value)
|
||
{
|
||
return scItem?.SafeSetValue(value) ?? false;
|
||
}
|
||
|
||
public void SetItemValue(string name, object value)
|
||
{
|
||
Debug.Assert(_items.ContainsKey(name), "can not find sc name, " + name);
|
||
if (!_items.ContainsKey(name))
|
||
return;
|
||
|
||
if (_items[name].SetValue(value))
|
||
{
|
||
GenerateDataFile();
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc/>
|
||
public void SetItemValue(string name, bool value)
|
||
{
|
||
Debug.Assert(_items.ContainsKey(name), "can not find sc name, " + name);
|
||
Debug.Assert(_items[name].Type == "Bool", "sc type not bool, defined as" + _items[name].Type);
|
||
|
||
if (_items[name].SetValue(value))
|
||
{
|
||
GenerateDataFile();
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc/>
|
||
public void SetItemValue(string name, int value)
|
||
{
|
||
Debug.Assert(_items.ContainsKey(name), "can not find sc name, " + name);
|
||
Debug.Assert(_items[name].Type == "Integer", "sc type not bool, defined as" + _items[name].Type);
|
||
if (_items[name].SetValue(value))
|
||
{
|
||
GenerateDataFile();
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc/>
|
||
public void SetItemValue(string name, double value)
|
||
{
|
||
Debug.Assert(_items.ContainsKey(name), "can not find sc name, " + name);
|
||
Debug.Assert(_items[name].Type == "Double", "sc type not bool, defined as" + _items[name].Type);
|
||
if (_items[name].SetValue(value))
|
||
{
|
||
GenerateDataFile();
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc/>
|
||
public void SetItemValue(string name, string value)
|
||
{
|
||
Debug.Assert(_items.ContainsKey(name), "can not find sc name, " + name);
|
||
if (_items[name].SetValue(value))
|
||
{
|
||
GenerateDataFile();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// <inheritdoc/>
|
||
/// </summary>
|
||
/// <param name="name"></param>
|
||
/// <param name="callback"></param>
|
||
public void RegisterValueChangedCallback(string name, Action<object> callback)
|
||
{
|
||
if (_items.TryGetValue(name, out var scItem))
|
||
{
|
||
scItem.OnValueChanged += (sender, newValue) =>
|
||
{
|
||
try
|
||
{
|
||
callback.Invoke(newValue);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LOG.Write(ex);
|
||
}
|
||
};
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
}
|