#define DEBUG using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Xml; 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 MECF.Framework.Common.Equipment; using MECF.Framework.Common.FAServices; namespace MECF.Framework.Common.SCCore { public class SystemConfigManager : Singleton, ISCManager { #region Variables private readonly Dictionary _items; private readonly Dictionary>> _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."; #endregion #region Constructors public SystemConfigManager() { _items = new Dictionary(StringComparer.OrdinalIgnoreCase); _dicValueChangedCallback = new Dictionary>>(); } #endregion #region Methods public List VidConfigList { get { var list = new List(); 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); SC.Manager = this; Singleton.Instance.StartDataCleaner(); } 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(); HandleValueChanged(scName, _items[scName].Value); EV.PostInfoLog("System", $"SC {scName} value changed from {configValueAsObject} to {parameters[1]}"); } return 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") }; 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(); 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(""); 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(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(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 GetItemList() { return _items.Values.ToList(); } public void SetItemValueFromString(string name, string value) { if (InitializeItemValue(_items[name], value)) { GenerateDataFile(); HandleValueChanged(name, value); } } private bool InitializeItemValue(SCConfigItem scItem, object value) { var result = false; switch (scItem.Type) { case "Bool": { if (bool.TryParse(value.ToString(), out var result2) && result2 != scItem.BoolValue) { scItem.BoolValue = result2; result = true; } break; } case "Integer": { if (int.TryParse(value.ToString(), out var result6) && result6 != scItem.IntValue) { int.TryParse(scItem.Min, out var result7); int.TryParse(scItem.Max, out var result8); if (result6 < result7 || result6 > result8) { EV.PostWarningLog("System", $"SC {scItem.PathName} value {result6} out of setting range ({scItem.Min}, {scItem.Max})"); } else { scItem.IntValue = result6; result = true; } } break; } case "Double": { if (double.TryParse(value.ToString(), out var result3) && Math.Abs(result3 - scItem.DoubleValue) > 0.0001) { double.TryParse(scItem.Min, out var result4); double.TryParse(scItem.Max, out var result5); if (result3 < result4 || result3 > result5) { EV.PostWarningLog("System", $"SC {scItem.PathName} value {result3} out of setting range ({scItem.Min}, {scItem.Max})"); } else { scItem.DoubleValue = result3; result = true; } } break; } case "String": if (value.ToString() != scItem.StringValue) { scItem.StringValue = value.ToString(); result = true; } break; } return result; } 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(); HandleValueChanged(name, value); } } public void SetItemValueStringFormat(string name, string value) { Debug.Assert(_items.ContainsKey(name), "can not find sc name, " + name); if (!_items.ContainsKey(name)) { return; } var isChanged = false; switch (_items[name].Type) { case "Bool": { var flag2 = Convert.ToBoolean(value); if (flag2 != _items[name].BoolValue) { _items[name].BoolValue = flag2; isChanged = true; } break; } case "Integer": { var num = Convert.ToInt32(value); if (num != _items[name].IntValue) { _items[name].IntValue = num; isChanged = true; } break; } case "Double": { var num2 = Convert.ToDouble(value); if (Math.Abs(num2 - _items[name].DoubleValue) > 0.0001) { _items[name].DoubleValue = num2; isChanged = true; } break; } case "String": if (value != _items[name].StringValue) { _items[name].StringValue = value; isChanged = true; } break; } if (isChanged) { GenerateDataFile(); HandleValueChanged(name, value); } } 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 (value != _items[name].BoolValue) { _items[name].BoolValue = value; GenerateDataFile(); HandleValueChanged(name, value); } } 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 (value != _items[name].IntValue) { _items[name].IntValue = value; GenerateDataFile(); HandleValueChanged(name, value); } } 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 (Math.Abs(value - _items[name].DoubleValue) > 0.0001) { _items[name].DoubleValue = value; GenerateDataFile(); HandleValueChanged(name, value); } } public void SetItemValue(string name, string value) { Debug.Assert(_items.ContainsKey(name), "can not find sc name, " + name); if (value != _items[name].StringValue) { _items[name].StringValue = value; GenerateDataFile(); HandleValueChanged(name, value); } } /// /// 注册一个回调函数,当指定的配置项发生变化时,调用此函数。 /// /// /// public void RegisterValueChangedCallback(string name, Action callback) { if (_dicValueChangedCallback.TryGetValue(name, out var actions)) actions.Add(callback); else _dicValueChangedCallback.Add(name, new List>(new[] { callback })); } private void HandleValueChanged(string name, T newValue) { if (_dicValueChangedCallback.TryGetValue(name, out var actions)) { actions.ForEach(a => { try { a.Invoke(newValue); } catch (Exception ex) { LOG.Error(ex.Message, ex); EV.PostWarningLog(ModuleName.System.ToString(), $"Callback function for '{name}' error"); } }); } } #endregion } }