Sic.Framework/MECF.Framework.Common/MECF/Framework/Common/SCCore/SystemConfigManager.cs

649 lines
18 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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();
if (files == null || files.Count() == 0) //ÕÒ²»µ½Îļþ
{
RemoveConfigChangedInfo(null, null);
return;
}
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
}
}