using System; using System.Collections.Generic; using Dapper; using System.Data; using System.Linq; using System.Threading.Tasks; using System.Text; using System.Net; using Repository.Models; using Microsoft.Extensions.Options; using System.IO; using System.Xml; using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace Repository.Services.Implement { public class ObixApiConfig { public string ApiBase { get; set; } public string UserName { get; set; } public string Password { get; set; } } public class Variable { public string System_type { get; set; } public string System_key { get; set; } public string system_value { get; set; } } public class DeviceSubscrip { public string building_guid { get; set; } public string main_system_guid { get; set; } public string sub_system_guid { get; set; } public string device_number { get; set; } } public class OntimeDeviceSubscripService { private readonly IDbConnection conn; private readonly IDbTransaction trans; private readonly IOptions _obixApiConfig; public OntimeDeviceSubscripService(IDbConnection conn, IDbTransaction trans, IOptions _obixApiConfig) { this.conn = conn; this.trans = trans; this._obixApiConfig = _obixApiConfig; } private string InsertGenerateString(List properties, string table_name) { var insertQuery = new StringBuilder($"INSERT INTO {table_name} "); insertQuery.Append("("); properties.ForEach(prop => { insertQuery.Append($"{table_name}.{prop.Replace("@", "")},"); }); insertQuery .Remove(insertQuery.Length - 1, 1) .Append(") VALUES ("); properties.ForEach(prop => { insertQuery.Append($"{prop},"); }); insertQuery .Remove(insertQuery.Length - 1, 1) .Append(");"); return insertQuery.ToString(); } public void MaintainOntimeDeviceSubscription(string targetTable, string mode, Dictionary targetData, string origData = null) { List> final_device_subscrip = new List>(); List tempDeviceSubscrips = new List(); //判斷來源是什麼資料表 if ("device" == targetTable) { //設備表格 switch (mode) { case "delete": //軟刪除 //直接刪除該設備 object device_guid = null; var has_device_guid = targetData.TryGetValue("device_guid", out device_guid); var sql_device = $@"SELECT device_number FROM device WHERE device_guid = @device_guid"; var device_number = conn.QueryFirstOrDefault(sql_device, new { device_guid = device_guid.ToString() }, trans); if (!string.IsNullOrEmpty(device_number)) { var purge_for_delete_sql = $@"DELETE FROM ontime_device_subscription WHERE device_number = @device_number"; conn.Execute(purge_for_delete_sql, new { device_number = device_number }, trans); } break; } } else if ("device_item" == targetTable) { //點位表格 List deviceSubscrips = new List(); // step 1 找出所有該系統小類的設備 if (mode != "delete") { var sql_device = $@"SELECT building_guid, main_system_guid, sub_system_guid, device_number FROM device WHERE deleted = 0 AND sub_system_guid = @sub_system_guid"; object sub_system_guid = null; var has_value = targetData.TryGetValue("@sub_system_guid", out sub_system_guid); deviceSubscrips = conn.Query(sql_device, new { sub_system_guid = sub_system_guid.ToString() }).ToList(); tempDeviceSubscrips = deviceSubscrips; } else { //需先找出該點位的sub_system_guid object device_item_guid = null; var has_value = targetData.TryGetValue("device_item_guid", out device_item_guid); if (has_value) { var sql_device_item = $@"SELECT sub_system_guid FROM device_item WHERE device_item_guid = @device_item_guid"; var sub_system_guid = conn.QueryFirstOrDefault(sql_device_item, new { device_item_guid = device_item_guid.ToString() }); var sql_device = $@"SELECT building_guid, main_system_guid, sub_system_guid, device_number FROM device WHERE deleted = 0 AND sub_system_guid = @sub_system_guid"; deviceSubscrips = conn.Query(sql_device, new { sub_system_guid = sub_system_guid.ToString() }).ToList(); tempDeviceSubscrips = deviceSubscrips; } } //判斷是什麼模式,ex:insert、insert_list、update...等 switch (mode) { case "insert": //新增 List> insertDics = new List>(); object point_name = null; var has_point_value = targetData.TryGetValue("@points", out point_name); if (has_point_value) { foreach (var deviceSubscrip in deviceSubscrips) { Dictionary insertDic = new Dictionary() { { "@building_guid", deviceSubscrip.building_guid }, { "@main_system_guid", deviceSubscrip.main_system_guid }, { "@sub_system_guid", deviceSubscrip.sub_system_guid }, { "@device_number", deviceSubscrip.device_number }, { "@name", point_name} }; insertDics.Add(insertDic); } } List properties = insertDics.First().Keys.ToList(); string sql = InsertGenerateString(properties, "ontime_device_subscription"); conn.Execute(sql, insertDics, trans); final_device_subscrip = insertDics; break; case "update": //更新 if (origData != null) { var device_point_name = origData; //刪除訂閱表的資料 var purge_sql = $@"DELETE FROM ontime_device_subscription WHERE name=@name AND device_number IN @device_number"; conn.Execute(purge_sql, new { name = device_point_name, device_number = deviceSubscrips.Select(x => x.device_number).ToList() }, trans); } //新增訂閱表的資料 List> insertDics2 = new List>(); object point_name2 = null; var has_point_value2 = targetData.TryGetValue("@points", out point_name); if (has_point_value2) { foreach (var deviceSubscrip in deviceSubscrips) { Dictionary insertDic = new Dictionary() { { "@building_guid", deviceSubscrip.building_guid }, { "@main_system_guid", deviceSubscrip.main_system_guid }, { "@sub_system_guid", deviceSubscrip.sub_system_guid }, { "@device_number", deviceSubscrip.device_number }, { "@name", point_name} }; insertDics2.Add(insertDic); } } List properties2 = insertDics2.First().Keys.ToList(); string sql2 = InsertGenerateString(properties2, "ontime_device_subscription"); conn.Execute(sql2, insertDics2, trans); final_device_subscrip = insertDics2; break; case "delete": //軟刪除 //找出原本的 object delete_device_item_guid = null; var has_delete_device_item_guid = targetData.TryGetValue("device_item_guid", out delete_device_item_guid); if (has_delete_device_item_guid) { var sql_device_item = $@"SELECT points FROM device_item WHERE device_item_guid = @device_item_guid"; var delete_device_point_name = conn.QueryFirst(sql_device_item, new { device_item_guid = delete_device_item_guid.ToString() }); //刪除訂閱表的資料 var purge_for_delete_sql = $@"DELETE FROM ontime_device_subscription WHERE name=@name AND device_number IN @device_number"; conn.Execute(purge_for_delete_sql, new { name = delete_device_point_name, device_number = deviceSubscrips.Select(x => x.device_number).ToList() }, trans); } break; } } #region step 2 設定要訂閱的設備點位 var subscripUriFormat = @" "; List subscripStrings = new List(); foreach (var deviceSubscrip in final_device_subscrip) { List devicePaths = new List(); object device_number = null; var has_device_number = deviceSubscrip.TryGetValue("@device_number", out device_number); //拆解設備編號來組出路徑 var deviceSubscripSplit = device_number.ToString().Split("_"); foreach (var temp in deviceSubscripSplit) { if (temp[0].ToString().All(char.IsDigit)) { devicePaths.Add($"$3{temp}"); } else { devicePaths.Add(temp); } } //剔除最後一個,因為是設備名稱 devicePaths.RemoveAt(devicePaths.Count() - 1); object point_name = null; var has_point_name = deviceSubscrip.TryGetValue("@name", out point_name); subscripStrings.Add(string.Format(subscripUriFormat, string.Join('/', devicePaths), device_number.ToString(), point_name.ToString())); } #endregion step 2 設定要訂閱的設備點位 #region step 3 訂閱設備點位,並將回傳的值新增至資料庫 EDFunction ed = new EDFunction(); string userName = ed.AESDecrypt(_obixApiConfig.Value.UserName); string password = ed.AESDecrypt(_obixApiConfig.Value.Password); String encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(userName + ":" + password)); var sql_watch = $@"SELECT * FROM variable WHERE deleted = 0 AND system_type = @system_type AND system_key = @system_key"; var watch = conn.QueryFirstOrDefault(sql_watch, new { system_type = "obixConfig", system_key = "watch_id" }); HttpWebRequest addWatchServiceRequest = (HttpWebRequest)WebRequest.Create($"{_obixApiConfig.Value.ApiBase}obix/watchService/watch{watch.system_value}/add/"); addWatchServiceRequest.Method = "POST"; addWatchServiceRequest.Headers.Add("Authorization", "Basic " + encoded); addWatchServiceRequest.PreAuthenticate = true; var subscripFullString = $@" {string.Join(null, subscripStrings)} "; byte[] byteArray = Encoding.UTF8.GetBytes(subscripFullString); using (Stream reqStream = addWatchServiceRequest.GetRequestStream()) { reqStream.Write(byteArray, 0, byteArray.Length); } HttpWebResponse addWatchServiceResponse = (HttpWebResponse)addWatchServiceRequest.GetResponse(); var addWatchServiceResponseContent = new StreamReader(addWatchServiceResponse.GetResponseStream()).ReadToEnd(); XmlDocument xmlDocument = new XmlDocument(); xmlDocument.LoadXml(addWatchServiceResponseContent); string addWatchServiceJson = JsonConvert.SerializeXmlNode(xmlDocument); JObject addWatchServiceJsonResult = (JObject)JsonConvert.DeserializeObject(addWatchServiceJson); if (addWatchServiceJsonResult.ContainsKey("err")) //抓取錯誤 { throw new NotImplementedException("設備點位訂閱失敗"); //logger.LogError("【OnTimeDeviceRawDataJob】【設備點位訂閱失敗】"); //logger.LogError("【OnTimeDeviceRawDataJob】【設備點位訂閱失敗】[錯誤內容]:{0}", addWatchServiceJsonResult); } if (addWatchServiceJsonResult.ContainsKey("obj")) //表示可以讀取到內容 { List> ontimeRawDatas = new List>(); var ontimeList = addWatchServiceJsonResult["obj"]["list"]; if (ontimeList["real"] != null && ontimeList["real"].HasValues) { //讀取數值型 foreach (var real in ontimeList["real"]) { var valueSplit = real["@display"].ToString().Split(); var value = valueSplit[0]; var href = real["@href"].ToString(); var hrefSplit = href.Split("/"); var findOutIndex = 0; var outIndex = 0; foreach (var tempHref in hrefSplit) //找出out的Index { if (tempHref == "out") { outIndex = findOutIndex; } findOutIndex++; } var device_number = hrefSplit[outIndex - 2]; //透過outIndex找出設備編號 var name = hrefSplit[outIndex - 1];//透過outIndex找出點位 var selectDevice = tempDeviceSubscrips.Where(x => x.device_number == device_number).FirstOrDefault(); Dictionary ontimeRawData = new Dictionary() { { "@building_guid", selectDevice.building_guid }, { "@main_system_guid", selectDevice.main_system_guid }, { "@sub_system_guid", selectDevice.sub_system_guid }, { "@device_number", device_number}, { "@name", name}, { "@value", value}, { "@is_bool", 0}, }; ontimeRawDatas.Add(ontimeRawData); } } if (ontimeList["bool"] != null && ontimeList["bool"].HasValues) { //讀取布林型 foreach (var real in ontimeList["bool"]) { var valueSplit = real["@display"].ToString().Split(); var value = valueSplit[0]; var href = real["@href"].ToString(); var hrefSplit = href.Split("/"); var findOutIndex = 0; var outIndex = 0; foreach (var tempHref in hrefSplit) //找出out的Index { if (tempHref == "out") { outIndex = findOutIndex; } findOutIndex++; } var device_number = hrefSplit[outIndex - 2]; //透過outIndex找出設備編號 var name = hrefSplit[outIndex - 1];//透過outIndex找出點位 var selectDevice = tempDeviceSubscrips.Where(x => x.device_number == device_number).FirstOrDefault(); Dictionary ontimeRawData = new Dictionary() { { "@building_guid", selectDevice.building_guid }, { "@main_system_guid", selectDevice.main_system_guid }, { "@sub_system_guid", selectDevice.sub_system_guid }, { "@device_number", device_number}, { "@name", name}, { "@value", value}, { "@is_bool", 1}, }; ontimeRawDatas.Add(ontimeRawData); } } if (ontimeRawDatas.Count() > 0) { try { var insert_update_sql = $@"INSERT INTO ontime_device_rawdata (building_guid, main_system_guid, sub_system_guid, device_number, name, value, is_bool) VALUES(@building_guid, @main_system_guid, @sub_system_guid, @device_number, @name, @value, @is_bool) ON DUPLICATE KEY UPDATE value=@value, is_bool = @is_bool"; conn.Execute(insert_update_sql, ontimeRawDatas); } catch (Exception exception) { throw new NotImplementedException("新增設備點位原始資料失敗", exception); //logger.LogError("【OnTimeDeviceSubscriptionJob】【新增設備點位原始資料失敗】"); //logger.LogError("【OnTimeDeviceSubscriptionJob】【新增設備點位原始資料失敗】[Exception]:{0}", exception.ToString()); } } //logger.LogInformation("【OnTimeDeviceSubscriptionJob】【任務完成】"); } #endregion step 3 訂閱設備點位,並將回傳的值新增至資料庫 } /// /// 維護多筆的設備點位訂閱表 /// /// /// /// public void MaintainMutiOntimeDeviceSubscription(string targetTable, List> targetDataList) { //只有新增設備時,會有多筆 if (targetTable == "device") { List points = new List(); // step 1 找出所有該系統小類的點位 var sql_points = $@"SELECT points FROM device_item WHERE deleted = 0 AND sub_system_guid = @sub_system_guid"; object sub_system_guid = null; var has_value = targetDataList.First().TryGetValue("@sub_system_guid", out sub_system_guid); points = conn.Query(sql_points, new { sub_system_guid = sub_system_guid.ToString() }).ToList(); List> insertDics = new List>(); List tempDeviceSubscrips = new List(); foreach (var targetData in targetDataList) { object device_number = null; var has_device_number_value = targetData.TryGetValue("@device_number", out device_number); if (has_device_number_value) { object building_guid = null; targetData.TryGetValue("@building_guid", out building_guid); object main_system_guid = null; targetData.TryGetValue("@main_system_guid", out main_system_guid); object local_sub_system_guid = null; targetData.TryGetValue("@sub_system_guid", out local_sub_system_guid); foreach (var point in points) { Dictionary insertDic = new Dictionary() { { "@building_guid", building_guid }, { "@main_system_guid", main_system_guid }, { "@sub_system_guid", local_sub_system_guid }, { "@device_number", device_number }, { "@name", point} }; insertDics.Add(insertDic); DeviceSubscrip deviceSubscrip = new DeviceSubscrip() { building_guid = building_guid.ToString(), main_system_guid = main_system_guid.ToString(), sub_system_guid = local_sub_system_guid.ToString(), device_number = device_number.ToString(), }; tempDeviceSubscrips.Add(deviceSubscrip); } } } List properties = insertDics.First().Keys.ToList(); string sql = InsertGenerateString(properties, "ontime_device_subscription"); conn.Execute(sql, insertDics, trans); #region step 2 設定要訂閱的設備點位 var subscripUriFormat = @" "; List subscripStrings = new List(); foreach (var deviceSubscrip in insertDics) { List devicePaths = new List(); object device_number = null; var has_device_number = deviceSubscrip.TryGetValue("@device_number", out device_number); //拆解設備編號來組出路徑 var deviceSubscripSplit = device_number.ToString().Split("_"); foreach (var temp in deviceSubscripSplit) { if (temp[0].ToString().All(char.IsDigit)) { devicePaths.Add($"$3{temp}"); } else { devicePaths.Add(temp); } } //剔除最後一個,因為是設備名稱 devicePaths.RemoveAt(devicePaths.Count() - 1); object point_name = null; var has_point_name = deviceSubscrip.TryGetValue("@name", out point_name); subscripStrings.Add(string.Format(subscripUriFormat, string.Join('/', devicePaths), device_number.ToString(), point_name.ToString())); } #endregion step 2 設定要訂閱的設備點位 #region step 3 訂閱設備點位,並將回傳的值新增至資料庫 EDFunction ed = new EDFunction(); string userName = ed.AESDecrypt(_obixApiConfig.Value.UserName); string password = ed.AESDecrypt(_obixApiConfig.Value.Password); String encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(userName + ":" + password)); var sql_watch = $@"SELECT * FROM variable WHERE deleted = 0 AND system_type = @system_type AND system_key = @system_key"; var watch = conn.QueryFirstOrDefault(sql_watch, new { system_type = "obixConfig", system_key = "watch_id" }); HttpWebRequest addWatchServiceRequest = (HttpWebRequest)WebRequest.Create($"{_obixApiConfig.Value.ApiBase}obix/watchService/watch{watch.system_value}/add/"); addWatchServiceRequest.Method = "POST"; addWatchServiceRequest.Headers.Add("Authorization", "Basic " + encoded); addWatchServiceRequest.PreAuthenticate = true; var subscripFullString = $@" {string.Join(null, subscripStrings)} "; byte[] byteArray = Encoding.UTF8.GetBytes(subscripFullString); using (Stream reqStream = addWatchServiceRequest.GetRequestStream()) { reqStream.Write(byteArray, 0, byteArray.Length); } HttpWebResponse addWatchServiceResponse = (HttpWebResponse)addWatchServiceRequest.GetResponse(); var addWatchServiceResponseContent = new StreamReader(addWatchServiceResponse.GetResponseStream()).ReadToEnd(); XmlDocument xmlDocument = new XmlDocument(); xmlDocument.LoadXml(addWatchServiceResponseContent); string addWatchServiceJson = JsonConvert.SerializeXmlNode(xmlDocument); JObject addWatchServiceJsonResult = (JObject)JsonConvert.DeserializeObject(addWatchServiceJson); if (addWatchServiceJsonResult.ContainsKey("err")) //抓取錯誤 { throw new NotImplementedException("設備點位訂閱失敗"); //logger.LogError("【OnTimeDeviceRawDataJob】【設備點位訂閱失敗】"); //logger.LogError("【OnTimeDeviceRawDataJob】【設備點位訂閱失敗】[錯誤內容]:{0}", addWatchServiceJsonResult); } if (addWatchServiceJsonResult.ContainsKey("obj")) //表示可以讀取到內容 { List> ontimeRawDatas = new List>(); var ontimeList = addWatchServiceJsonResult["obj"]["list"]; if (ontimeList["real"] != null && ontimeList["real"].HasValues) { //讀取數值型 foreach (var real in ontimeList["real"]) { var valueSplit = real["@display"].ToString().Split(); var value = valueSplit[0]; var href = real["@href"].ToString(); var hrefSplit = href.Split("/"); var findOutIndex = 0; var outIndex = 0; foreach (var tempHref in hrefSplit) //找出out的Index { if (tempHref == "out") { outIndex = findOutIndex; } findOutIndex++; } var device_number = hrefSplit[outIndex - 2]; //透過outIndex找出設備編號 var name = hrefSplit[outIndex - 1];//透過outIndex找出點位 var selectDevice = tempDeviceSubscrips.Where(x => x.device_number == device_number).FirstOrDefault(); Dictionary ontimeRawData = new Dictionary() { { "@building_guid", selectDevice.building_guid }, { "@main_system_guid", selectDevice.main_system_guid }, { "@sub_system_guid", selectDevice.sub_system_guid }, { "@device_number", device_number}, { "@name", name}, { "@value", value}, { "@is_bool", 0}, }; ontimeRawDatas.Add(ontimeRawData); } } if (ontimeList["bool"] != null && ontimeList["bool"].HasValues) { //讀取布林型 foreach (var real in ontimeList["bool"]) { var valueSplit = real["@display"].ToString().Split(); var value = valueSplit[0]; var href = real["@href"].ToString(); var hrefSplit = href.Split("/"); var findOutIndex = 0; var outIndex = 0; foreach (var tempHref in hrefSplit) //找出out的Index { if (tempHref == "out") { outIndex = findOutIndex; } findOutIndex++; } var device_number = hrefSplit[outIndex - 2]; //透過outIndex找出設備編號 var name = hrefSplit[outIndex - 1];//透過outIndex找出點位 var selectDevice = tempDeviceSubscrips.Where(x => x.device_number == device_number).FirstOrDefault(); Dictionary ontimeRawData = new Dictionary() { { "@building_guid", selectDevice.building_guid }, { "@main_system_guid", selectDevice.main_system_guid }, { "@sub_system_guid", selectDevice.sub_system_guid }, { "@device_number", device_number}, { "@name", name}, { "@value", value}, { "@is_bool", 1}, }; ontimeRawDatas.Add(ontimeRawData); } } if (ontimeRawDatas.Count() > 0) { try { var insert_update_sql = $@"INSERT INTO ontime_device_rawdata (building_guid, main_system_guid, sub_system_guid, device_number, name, value, is_bool) VALUES(@building_guid, @main_system_guid, @sub_system_guid, @device_number, @name, @value, @is_bool) ON DUPLICATE KEY UPDATE value=@value, is_bool = @is_bool"; conn.Execute(insert_update_sql, ontimeRawDatas); } catch (Exception exception) { throw new NotImplementedException("新增設備點位原始資料失敗", exception); //logger.LogError("【OnTimeDeviceSubscriptionJob】【新增設備點位原始資料失敗】"); //logger.LogError("【OnTimeDeviceSubscriptionJob】【新增設備點位原始資料失敗】[Exception]:{0}", exception.ToString()); } } //logger.LogInformation("【OnTimeDeviceSubscriptionJob】【任務完成】"); } #endregion step 3 訂閱設備點位,並將回傳的值新增至資料庫 } } } }