using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Data.SqlClient; using System.Diagnostics; using System.Linq; using System.Threading; using ClientDriver; using DatabaseLib; using DataService; namespace CoreTest { public sealed class DAServer : IDataServer, IAlarmServer, IHDAServer { int ALARMLIMIT = 1000; int CYCLE = 60000; const char SPLITCHAR = '.'; const string SERVICELOGSOURCE = "ClientService"; const string SERVICELOGNAME = "ClientService"; static EventLog Log; public ITag this[short id] { get { int index = GetItemProperties(id); if (index >= 0) { return this[_list[index].Name]; } return null; } } public ITag this[string name] { get { if (string.IsNullOrEmpty(name)) return null; ITag dataItem; _mapping.TryGetValue(name.ToUpper(), out dataItem); return dataItem; } } List _list; public IList MetaDataList { get { return _list; } } public IList ScalingList { get { return _scales; } } object _syncRoot; public object SyncRoot { get { if (this._syncRoot == null) { Interlocked.CompareExchange(ref this._syncRoot, new object(), null); } return this._syncRoot; } } Timer timer; Dictionary _mapping; List _scales; public IEnumerable Drivers { get { yield return reader; } } CompareCondBySource _compare; ClientReader reader = null; ClientGroup group = null; ExpressionEval reval; public ExpressionEval Eval { get { return reval; } } public DAServer() { /*hda = new HDAQueue(MAXHDACAP);历史数据均保存于服务器;本机如需查询,需复制历史数据文件到指定文件夹。 * 历史数据在服务器上分包(1024字节)发送,客户端每接收一条记录,异步附加或yield return*/ if (!EventLog.SourceExists(SERVICELOGSOURCE)) { EventLog.CreateEventSource(SERVICELOGSOURCE, SERVICELOGNAME); } Log = new EventLog(SERVICELOGNAME); Log.Source = SERVICELOGSOURCE; ALARMLIMIT = ConfigCache.AlarmLimit; CYCLE = ConfigCache.Cycle; _scales = new List(); _linkedList = new QueueCollection(ALARMLIMIT + 10); reval = new ExpressionEval(this); InitClient(); InitServerByDatabase(); InitConnection(); } void InitClient() { string sLine = DataHelper.HostName; AddDriver(1, "Client1", string.IsNullOrEmpty(sLine) ? Environment.MachineName : sLine, 20000, null, null, null, null); } void InitConnection() { reader.OnClose += new ShutdownRequestEventHandler(reader_OnClose); if (reader.IsClosed) { reader.Connect(); } if (group != null) { group.IsActive = true; timer = new Timer(OnTimer, null, CYCLE, CYCLE); } } void OnTimer(object o) { if (reader.IsClosed) { reader.Connect(); group.IsActive = true; } } void InitServerByDatabase() { try { using (var dataReader = DataHelper.ExecuteProcedureReader("InitServer", new SqlParameter("@TYPE", 1))) { if (dataReader == null) Environment.Exit(0); //dataReader.Read(); dataReader.Read(); int count = dataReader.GetInt32(0); _list = new List(count); _mapping = new Dictionary(count); dataReader.NextResult(); while (dataReader.Read()) { _list.Add(new TagMetaData(dataReader.GetInt16(0), dataReader.GetInt16(1), dataReader.GetString(2), dataReader.GetString(3), (DataType)dataReader.GetByte(4), (ushort)dataReader.GetInt16(5), dataReader.GetBoolean(6), dataReader.GetFloat(7), dataReader.GetFloat(8), dataReader.GetInt32(9))); //_list[i].Description = dataReader.GetSqlString(6).Value; } _list.Sort(); if (reader != null && group == null) { group = reader.AddGroup("Group1", 1, 0, 0, true) as ClientGroup; group.AddItems(_list); } dataReader.NextResult(); _conditions = new List(); _conditionList = new ObservableCollection(); while (dataReader.Read()) { int id = dataReader.GetInt32(0); AlarmType type = (AlarmType)dataReader.GetInt32(2); ICondition cond; string source = dataReader.GetString(1); if (_conditions.Count > 0) { cond = _conditions[_conditions.Count - 1]; if (cond.ID == id) { cond.AddSubCondition(new SubCondition((SubAlarmType)dataReader.GetInt32(9), dataReader.GetFloat(10), (Severity)dataReader.GetByte(11), dataReader.GetString(12), dataReader.GetBoolean(13))); continue; } } switch (type) { case AlarmType.Complex: cond = new ComplexCondition(id, source, dataReader.GetString(6), dataReader.GetFloat(7), dataReader.GetInt32(8)); break; case AlarmType.Level: cond = new LevelAlarm(id, source, dataReader.GetString(6), dataReader.GetFloat(7), dataReader.GetInt32(8)); break; case AlarmType.Dev: cond = new DevAlarm(id, (ConditionType)dataReader.GetByte(4), source, dataReader.GetString(6), dataReader.GetFloat(5), dataReader.GetFloat(7), dataReader.GetInt32(8)); break; case AlarmType.ROC: cond = new ROCAlarm(id, source, dataReader.GetString(6), dataReader.GetFloat(7), dataReader.GetInt32(8)); break; case AlarmType.Quality: cond = new QualitiesAlarm(id, source, dataReader.GetString(6)); break; default: cond = new DigitAlarm(id, source, dataReader.GetString(6), dataReader.GetInt32(8)); break; } cond.AddSubCondition(new SubCondition((SubAlarmType)dataReader.GetInt32(9), dataReader.GetFloat(10), (Severity)dataReader.GetByte(11), dataReader.GetString(12), dataReader.GetBoolean(13))); cond.IsEnabled = dataReader.GetBoolean(3); var simpcond = cond as SimpleCondition; if (simpcond != null) { simpcond.Tag = this[source]; } else { var complexcond = cond as ComplexCondition; if (complexcond != null) { var action = complexcond.SetFunction(reval.Eval(source)); if (action != null) { ValueChangedEventHandler handle = (s1, e1) => { action(); }; foreach (ITag tag in reval.TagList) { tag.ValueChanged += handle;// tag.Refresh(); } } } } cond.AlarmActive += new AlarmEventHandler(cond_SendAlarm); cond.AlarmAck += new EventHandler(cond_AckAlarm); //_conditions.Add(cond);// UpdateCondition(cond); _conditions.Add(cond); } dataReader.NextResult(); while (dataReader.Read()) { _scales.Add(new Scaling(dataReader.GetInt16(0), (ScaleType)dataReader.GetByte(1), dataReader.GetFloat(2), dataReader.GetFloat(3), dataReader.GetFloat(4), dataReader.GetFloat(5))); } } reval.Clear(); _scales.Sort(); _compare = new CompareCondBySource(); _conditions.Sort(_compare); } catch (Exception e) { App.AddErrorLog(e); Environment.Exit(0); } } public HistoryData[] BatchRead(DataSource source, bool sync, params ITag[] itemArray) { if (group == null) return null; return group.BatchRead(source, sync, itemArray); } public int BatchWrite(Dictionary tags, bool sync) { if (group == null) return -1; SortedDictionary dict = new SortedDictionary(); foreach (var item in tags) { var tag = this[item.Key]; if (tag != null) dict.Add(tag, item.Value); } return group.BatchWrite(dict, sync); } public IDriver AddDriver(short id, string name, string server, int timeOut, string assembly, string className, string spare1, string spare2) { if (reader == null) { reader = new ClientReader(this, id, name, server, timeOut);//server应为远程主机名/IP,从本地字符串解析获取 } return reader; } public bool RemoveDriver(IDriver device) { lock (SyncRoot) { if (device == reader) { device.Dispose(); device = null; return true; } return false; } } void reader_OnClose(object sender, ShutdownRequestEventArgs e) { App.AddErrorLog(new Exception((e.shutdownReason))); //AddErrorLog(new Exception(e.shutdownReason)); } public bool AddItemIndex(string key, ITag value) { key = key.ToUpper(); if (_mapping.ContainsKey(key)) return false; _mapping.Add(key, value); return true; } public bool RemoveItemIndex(string key) { return _mapping.Remove(key.ToUpper()); } object _asyncAlarm = new object(); void cond_SendAlarm(object sender, AlarmItem e) { lock (_asyncAlarm) { int index2 = _conditions.BinarySearch(new DigitAlarm(0, e.Source), _compare); if (index2 > -1) { var cond = _conditions[index2]; if (_conditionList.Contains(cond) && App.Current != null) { App.Current.Dispatcher.BeginInvoke(new Action(delegate { try { _conditionList.Remove(cond); } catch (Exception err) { } })); } if (e.SubAlarmType != SubAlarmType.None && App.Current != null) { App.Current.Dispatcher.BeginInvoke(new Action(delegate { try { _conditionList.Add(cond); } catch (Exception err) { } })); } } if (_linkedList.Count < ALARMLIMIT) { _linkedList.Enqueue(e); } else { _linkedList.Dequeue(); _linkedList.Enqueue(e); } } } void cond_AckAlarm(object sender, EventArgs e) { SystemLog.AddLog(new SystemLog(EventType.Simple, DateTime.Now, App.LogSource, "报警应答")); } string[] itemList = null; public IEnumerable BrowseItems(BrowseType browseType, string tagName, DataType dataType) { lock (SyncRoot) { if (_list.Count == 0) yield break; int len = _list.Count; if (itemList == null) { itemList = new string[len]; for (int i = 0; i < len; i++) { itemList[i] = _list[i].Name; } Array.Sort(itemList); } int ii = 0; bool hasTag = !string.IsNullOrEmpty(tagName); bool first = true; string str = hasTag ? tagName + SPLITCHAR : string.Empty; if (hasTag) { ii = Array.BinarySearch(itemList, tagName); if (ii < 0) first = false; //int strLen = str.Length; ii = Array.BinarySearch(itemList, str); if (ii < 0) ii = ~ii; } //while (++i < len && temp.Length >= strLen && temp.Substring(0, strLen) == str) do { if (first && hasTag) { first = false; yield return tagName; } string temp = itemList[ii]; if (hasTag && !temp.StartsWith(str, StringComparison.Ordinal)) break; if (dataType == DataType.NONE || _mapping[temp].Address.VarType == dataType) { bool b3 = true; if (browseType != BrowseType.Flat) { string curr = temp + SPLITCHAR; int index = Array.BinarySearch(itemList, ii, len - ii, curr); if (index < 0) index = ~index; b3 = itemList[index].StartsWith(curr, StringComparison.Ordinal); if (browseType == BrowseType.Leaf) b3 = !b3; } if (b3) yield return temp; } } while (++ii < len); } } public int GetScaleByID(short Id) { if (_scales == null || _scales.Count == 0) return -1; return _scales.BinarySearch(new Scaling { ID = Id }); } public IGroup GetGroupByName(string name) { return group; } public void ActiveItem(bool active, params ITag[] items) { Dictionary> dict = new Dictionary>(); for (int i = 0; i < items.Length; i++) { List list = null; ITag item = items[i]; dict.TryGetValue(item.Parent, out list); if (list != null) { list.Add(item.ID); } else dict.Add(item.Parent, new List { item.ID }); } foreach (var grp in dict) { grp.Key.SetActiveState(active, grp.Value.ToArray()); } } public int GetItemProperties(short id) { return _list.BinarySearch(new TagMetaData { ID = id }); } public IEnumerable ReadAtTime(params DateTime[] timeStamps) { return null;//待定 } public IEnumerable ReadAtTime(short ID, params DateTime[] timeStamps) { return null;//待定 } //考虑用异步Socket从服务器获取历史数据,命令包含起始时间和ID,以数组返回(要拆包) //对日期、时间如何分割?可返回任意时间段;合并;对于历史数据,如本地文件夹存在,则从本地读取;没有则当日从服务器读取,历史数据分离处理 public IEnumerable ReadRaw(DateTime start, DateTime end) { if (end < start) return null; try { if (HDAIOHelper.FindFile(end) && (DateTime.Today > end.Date)) { return ReadFromFile(start, end); } return group.SendHdaRequest(start, end); } catch (Exception exp) { App.AddErrorLog(exp); return null; } } public IEnumerable ReadRaw(DateTime start, DateTime end, short ID) { if (end < start) return null; try { if (HDAIOHelper.FindFile(end) && (DateTime.Today > end.Date)) { return ReadFromFile(start, end, ID); } return group.SendHdaRequest(start, end, ID); } catch (Exception exp) { App.AddErrorLog(exp); return null; } } private IEnumerable ReadFromFile(DateTime start, DateTime end, short ID) { int eyear = end.Year; int syear = start.Year; int emonth = end.Month; int smonth = start.Month; int year = syear; while (year <= eyear) { int month = (year == syear ? smonth : 1); while (month <= (year == eyear ? emonth : 12)) { var result = HDAIOHelper.LoadFromFile((year == syear && month == smonth ? start : new DateTime(year, month, 1)), (year == eyear && month == emonth ? end : new DateTime(year, month, 1).AddMonths(1).AddMilliseconds(-2)), ID);//考虑按月遍历 if (result != null) { foreach (var data in result) yield return data; } month++; } year++; } } private IEnumerable ReadFromFile(DateTime start, DateTime end) { int eyear = end.Year; int syear = start.Year; int emonth = end.Month; int smonth = start.Month; int year = syear; while (year <= eyear) { int month = (year == syear ? smonth : 1); while (month <= (year == eyear ? emonth : 12)) { var result = HDAIOHelper.LoadFromFile((year == syear && month == smonth ? start : new DateTime(year, month, 1)), (year == eyear && month == emonth ? end : new DateTime(year, month, 1).AddMonths(1).AddMilliseconds(-2)));//考虑按月遍历 if (result != null) { foreach (var data in result) yield return data; } month++; } year++; } } public int SendAlarmRequest(DateTime? start, DateTime? end) { return group.SendAlarmRequest(start, end); } public void Dispose() { lock (this) { if (timer != null) timer.Dispose(); group.SendResetRequest(); reader.OnClose -= this.reader_OnClose; reader.Dispose(); if (_conditionList != null) { foreach (var condition in _conditionList) { if (condition != null) condition.AlarmActive -= cond_SendAlarm; } } reval.Dispose(); } } List _conditions; ObservableCollection _conditionList; QueueCollection _linkedList; public IEnumerable AlarmList { get { return _linkedList; } } public IList ActivedConditionList { get { return _conditionList; } } public IList ConditionList { get { return _conditions; } } public ICondition GetCondition(string tagName, AlarmType type) { ITag tag = this[tagName]; if (tag == null) return null; short id = tag.ID; int index = _conditions.BinarySearch(new DigitAlarm(0, tagName)); if (index < 0) return null; int ind1 = index - 1; ICondition cond = _conditions[index]; while (index < _conditions.Count && cond.Source == tagName) { cond = _conditions[index++]; if (cond.AlarmType == type) { return cond; } } while (ind1 >= 0 && cond.Source == tagName) { cond = _conditions[ind1--]; if (cond.AlarmType == type) { return cond; } } return null; } public IList QueryConditions(string sourceName) { if (_conditions == null || sourceName == null) return null; ITag tag = this[sourceName]; if (tag == null) return null; int index = _conditions.BinarySearch(new DigitAlarm(0, sourceName)); if (index < 0) return null; List condList = new List(); ICondition cond = _conditions[index]; int ind1 = index - 1; while (cond.Source == sourceName) { condList.Add(cond); if (++index < _conditions.Count) cond = _conditions[index]; else break; } while (ind1 >= 0) { if (cond.Source == sourceName) condList.Add(cond); } return condList; } public int DisableCondition(string sourceName, AlarmType type) { var cond = GetCondition(sourceName, type); if (cond != null) { cond.IsEnabled = false; return 1; } return -1; } public int EnableCondition(string sourceName, AlarmType type) { var cond = GetCondition(sourceName, type); if (cond != null) { cond.IsEnabled = true; return 1; } return -1; } public int RemoveConditon(string sourceName, AlarmType type) { var cond = GetCondition(sourceName, type); if (cond != null) { _conditions.Remove(cond); return 1; } return -1; } public int RemoveConditons(string sourceName) { ITag tag = this[sourceName]; if (_conditions == null || tag == null) return -1; int index = _conditions.BinarySearch(new DigitAlarm(0, sourceName)); if (index < 0) return index; int ind1 = index - 1; ICondition cond = _conditions[index]; List li = new List(); while (cond.Source == sourceName) { li.Add(index); if (++index < _conditions.Count) cond = _conditions[index]; else break; } while (ind1 >= 0) { cond = _conditions[ind1--]; if (cond.Source == sourceName) li.Add(ind1); } if (li.Count == 0) return -1; for (int i = li.Count - 1; i >= 0; i--) { _conditions.RemoveAt(i); } return 1; } public int AckConditions(params ICondition[] conditions) { if (conditions == null || conditions.Length == 0) return -1; lock (_asyncAlarm) { foreach (ICondition cond in conditions) { cond.IsAcked = true; if (_conditionList.Contains(cond)) _conditionList.Remove(cond); } } return 1; } public int IgnoreConditions(params ICondition[] conditions) { if (conditions == null || conditions.Length == 0) return -1; lock (_asyncAlarm) { foreach (ICondition cond in conditions) { if (_conditionList.Contains(cond)) _conditionList.Remove(cond); } } return 1; } Dictionary _archiveList = null; public Dictionary ArchiveList { get { if (_archiveList == null) { var list = MetaDataList.Where(x => x.Archive).Select(y => y.ID);//&& x.DataType != DataType.BOOL if (list != null && list.Count() > 0) { string sql = "SELECT TAGID,DESCRIPTION FROM META_TAG WHERE TAGID IN(" + string.Join(",", list) + ");"; using (var reader = DataHelper.ExecuteReader(sql)) { if (reader != null) { _archiveList = new Dictionary(); while (reader.Read()) { _archiveList.Add(reader.GetInt16(0), reader.GetNullableString(1)); } } } } } return _archiveList; } } public void GetMinMax(short id, out float max, out float min) { int index = GetItemProperties(id); if (index >= 0) { var metadata = MetaDataList[index]; if (metadata.Maximum == metadata.Minimum && metadata.Maximum == 0) { switch (metadata.DataType) { case DataType.BOOL: max = 1; min = 0; break; case DataType.BYTE: max = byte.MaxValue; min = byte.MinValue; break; case DataType.WORD: max = ushort.MaxValue; min = ushort.MinValue; break; case DataType.SHORT: max = short.MaxValue; min = short.MinValue; break; case DataType.TIME: max = uint.MaxValue; min = 0; break; case DataType.INT: max = 100000; min = -100000; break; case DataType.FLOAT: max = 100000; min = -100000; break; default: max = min = 0f; break; } } else { max = metadata.Maximum; min = metadata.Minimum; } } else { max = 100000; min = 0; } } } }