ibms-dome/FrontendWorkerService/Quartz/Jobs/OnTimeDeviceSubscriptionJob.cs

584 lines
31 KiB
C#
Raw Normal View History

2022-10-14 16:08:54 +08:00
using FrontendWorkerService.Models;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Quartz;
using Repository.FrontendRepository.Interface;
using Repository.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace FrontendWorkerService.Quartz.Jobs
{
[DisallowConcurrentExecution]
public class OnTimeDeviceSubscriptionJob : IJob
{
private readonly ILogger<OnTimeDeviceSubscriptionJob> logger;
private readonly IFrontendRepository frontendRepository;
public OnTimeDeviceSubscriptionJob(
ILogger<OnTimeDeviceSubscriptionJob> logger,
IFrontendRepository frontendRepository)
{
this.logger = logger;
this.frontendRepository = frontendRepository;
}
public async Task Execute(IJobExecutionContext context)
{
try
{
string watch_id = string.Empty; //紀錄watch id的編號
XmlDocument xmlDocument = new XmlDocument();
logger.LogInformation("【OnTimeDeviceSubscriptionJob】【任務開始】");
EDFunction ed = new EDFunction();
var obixApiConfig = new ObixApiConfig();
var sqlObix = $@"SELECT system_value as Value, system_key as Name FROM variable WHERE deleted = 0 AND system_type = 'obixConfig'";
var variable = await frontendRepository.GetAllAsync<KeyValue>(sqlObix);
obixApiConfig.ApiBase = variable.Where(x => x.Name == "ApiBase").Select(x => x.Value).FirstOrDefault();
obixApiConfig.UserName = ed.AESDecrypt(variable.Where(x => x.Name == "UserName").Select(x => x.Value).FirstOrDefault());
obixApiConfig.Password = ed.AESDecrypt(variable.Where(x => x.Name == "Password").Select(x => x.Value).FirstOrDefault());
String encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(obixApiConfig.UserName + ":" + obixApiConfig.Password));
var sWhere = @$"deleted = 0 AND system_type = @system_type AND system_key = @system_key";
var watch = await frontendRepository.GetOneAsync<Variable>("variable", sWhere, new { system_type = "obixConfig", system_key = "watch_id" });
#region step 1 watch id是否存活
HttpWebRequest watchServiceRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/watchService/");
watchServiceRequest.Method = "GET";
watchServiceRequest.Headers.Add("Authorization", "Basic " + encoded);
watchServiceRequest.PreAuthenticate = true;
HttpWebResponse watchServiceResponse = (HttpWebResponse)watchServiceRequest.GetResponse();
var watchServiceResponseContent = new StreamReader(watchServiceResponse.GetResponseStream()).ReadToEnd();
xmlDocument.LoadXml(watchServiceResponseContent);
string watchServiceJson = JsonConvert.SerializeXmlNode(xmlDocument);
JObject watchServiceJsonResult = (JObject)JsonConvert.DeserializeObject(watchServiceJson);
if (watchServiceJsonResult.ContainsKey("err")) //抓取錯誤
{
logger.LogError("【OnTimeDeviceSubscriptionJob】【檢查watch service失敗】");
logger.LogError("【OnTimeDeviceSubscriptionJob】【檢查watch service失敗】[錯誤內容]{0}", watchServiceJson);
return;
}
if (watchServiceJsonResult.ContainsKey("obj")) //表示可以讀取到內容
{
if (watchServiceJsonResult["obj"]["ref"] != null && watchServiceJsonResult["obj"]["ref"].HasValues)
{
var watchServices = watchServiceJsonResult["obj"]["ref"];
var temp_name_count = 0; //用來計算總共有幾個name
foreach (var watchService in watchServices.Children())
{
var tempKeyValue = watchService.ToString();
if (tempKeyValue.Contains("@name"))
{
temp_name_count++;
}
}
if (temp_name_count > 1)
{ //有多個watch
foreach (var watchService in watchServices.Children())
{
var tempKeyValue = watchService.ToString();
if (tempKeyValue.Contains("@name"))
{
var name = watchService["@name"].ToString();
watch_id = name.Replace("watch", "");
if (watch_id == watch.system_value)
{ //表示有找到id
break;
}
watch_id = string.Empty;
}
}
}
else
{ //單一個watch
var tempKeyValue = watchServices.ToString();
if (tempKeyValue.Contains("@name"))
{
var name = watchServices["@name"].ToString();
watch_id = name.Replace("watch", "");
if (watch_id != watch.system_value)
{
watch_id = string.Empty;
}
}
}
}
}
if (string.IsNullOrEmpty(watch_id))
{ //建立watch service
HttpWebRequest makeWatchServiceRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/watchService/make/");
makeWatchServiceRequest.Method = "POST";
makeWatchServiceRequest.Headers.Add("Authorization", "Basic " + encoded);
makeWatchServiceRequest.PreAuthenticate = true;
HttpWebResponse makeWatchServiceResponse = (HttpWebResponse)makeWatchServiceRequest.GetResponse();
var makeWatchServiceResponseContent = new StreamReader(makeWatchServiceResponse.GetResponseStream()).ReadToEnd();
xmlDocument.LoadXml(makeWatchServiceResponseContent);
string makeWatchServiceJson = JsonConvert.SerializeXmlNode(xmlDocument);
JObject makeWatchServiceJsonResult = (JObject)JsonConvert.DeserializeObject(makeWatchServiceJson);
if (makeWatchServiceJsonResult.ContainsKey("err")) //抓取錯誤
{
logger.LogError("【OnTimeDeviceSubscriptionJob】【重新建立watch service失敗】");
logger.LogError("【OnTimeDeviceSubscriptionJob】【重新建立watch service失敗】[錯誤內容]{0}", makeWatchServiceJson);
return;
}
if (makeWatchServiceJsonResult.ContainsKey("obj")) //表示可以讀取到內容
{
var makeSplit = makeWatchServiceJsonResult["obj"]["@href"].ToString().Split("/");
watch_id = makeSplit[makeSplit.Length - 2].Replace("watch", "");
}
if (!string.IsNullOrEmpty(watch_id))
{
//儲存至variable
Dictionary<string, object> updateWatchId = new Dictionary<string, object>()
{
{ "@system_value", watch_id}
};
await frontendRepository.UpdateOneByCustomTable(updateWatchId, "variable", "system_type = 'obixConfig' AND system_key = 'watch_id'");
//修改watch service 存活時間
HttpWebRequest changeWatchServiceRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/watchService/watch{watch_id}/lease/");
changeWatchServiceRequest.Method = "PUT";
changeWatchServiceRequest.Headers.Add("Authorization", "Basic " + encoded);
changeWatchServiceRequest.PreAuthenticate = true;
var realTime = $@"<reltime val='PT24H0S' />";
byte[] realTimeByteArray = Encoding.UTF8.GetBytes(realTime);
using (Stream reqStream = changeWatchServiceRequest.GetRequestStream())
{
reqStream.Write(realTimeByteArray, 0, realTimeByteArray.Length);
}
HttpWebResponse changeWatchServiceResponse = (HttpWebResponse)changeWatchServiceRequest.GetResponse();
var changeWatchServiceResponseContent = new StreamReader(changeWatchServiceResponse.GetResponseStream()).ReadToEnd();
xmlDocument.LoadXml(changeWatchServiceResponseContent);
string changeWatchServiceJson = JsonConvert.SerializeXmlNode(xmlDocument);
JObject changeWatchServiceJsonResult = (JObject)JsonConvert.DeserializeObject(changeWatchServiceJson);
if (changeWatchServiceJsonResult.ContainsKey("err")) //抓取錯誤
{
logger.LogError("【OnTimeDeviceSubscriptionJob】【修改watch service存活時間失敗】");
logger.LogError("【OnTimeDeviceSubscriptionJob】【修改watch service存活時間失敗】[錯誤內容]{0}", changeWatchServiceJsonResult);
return;
}
}
}
#endregion step 1 watch id是否存活
#region step 2
var deviceSubscrips = await frontendRepository.GetAllAsync<OntimeSubscrip>("ontime_device_subscription", string.Empty);
var subscripUriFormat = @" <uri val='/obix/config/Arena/{0}/{1}/{2}/{3}/' />";
List<string> subscripStrings = new List<string>();
foreach (var deviceSubscrip in deviceSubscrips)
{
List<string> devicePaths = new List<string>();
//拆解設備編號來組出路徑
var deviceSubscripSplit = deviceSubscrip.device_number.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);
//查詢是否有做為狀態設定(device_kind)
var sql_device_kind = $@"SELECT dk.* FROM device d
JOIN device_kind dk ON
d.device_building_tag = dk.device_building_tag
AND d.device_system_tag = dk.device_system_tag
AND d.device_name_tag = dk.device_name_tag
WHERE d.deleted = 0
AND d.device_number = @device_number";
var deviceKind = await frontendRepository.GetOneAsync<DeviceKind>(sql_device_kind, new { device_number = deviceSubscrip.device_number });
if (deviceKind != null)
{ //表示該設備有特別設定點位
if ((deviceSubscrip.name == deviceKind.Device_normal_point_name ||
deviceSubscrip.name == deviceKind.Device_close_point_name ||
deviceSubscrip.name == deviceKind.Device_error_point_name) &&
deviceSubscrip.name != "ER")
{
subscripStrings.Add(string.Format(subscripUriFormat, string.Join('/', devicePaths), deviceSubscrip.device_number, deviceSubscrip.name, "facets"));
subscripStrings.Add(string.Format(subscripUriFormat, string.Join('/', devicePaths), deviceSubscrip.device_number, deviceSubscrip.name, "out"));
}
else
{ //並未符合指定的點位
subscripStrings.Add(string.Format(subscripUriFormat, string.Join('/', devicePaths), deviceSubscrip.device_number, deviceSubscrip.name, "out"));
}
}
else
{
subscripStrings.Add(string.Format(subscripUriFormat, string.Join('/', devicePaths), deviceSubscrip.device_number, deviceSubscrip.name, "out"));
}
}
#endregion step 2
#region step 3
HttpWebRequest addWatchServiceRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/watchService/watch{watch_id}/add/");
addWatchServiceRequest.Method = "POST";
addWatchServiceRequest.Headers.Add("Authorization", "Basic " + encoded);
addWatchServiceRequest.PreAuthenticate = true;
var subscripFullString = $@"<obj is='obix: WatchIn'>
<list names = 'hrefs'>
{string.Join(null, subscripStrings)}
</list>
</obj>";
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.LoadXml(addWatchServiceResponseContent);
string addWatchServiceJson = JsonConvert.SerializeXmlNode(xmlDocument);
JObject addWatchServiceJsonResult = (JObject)JsonConvert.DeserializeObject(addWatchServiceJson);
if (addWatchServiceJsonResult.ContainsKey("err")) //抓取錯誤
{
logger.LogError("【OnTimeDeviceRawDataJob】【設備點位訂閱失敗】");
logger.LogError("【OnTimeDeviceRawDataJob】【設備點位訂閱失敗】[錯誤內容]{0}", addWatchServiceJsonResult);
return;
}
if (addWatchServiceJsonResult.ContainsKey("obj")) //表示可以讀取到內容
{
List<Dictionary<string, object>> ontimeRawDatas = new List<Dictionary<string, object>>();
var ontimeList = addWatchServiceJsonResult["obj"]["list"];
if (ontimeList["real"] != null && ontimeList["real"].HasValues)
{ //讀取數值型
//判斷是否為多筆數值資料
var temp_real_count = 0; //用來計算總共有幾個name
foreach (var realVal in ontimeList["real"].Children())
{
var tempKeyValue = realVal.ToString();
if (tempKeyValue.Contains("@displayName"))
{
temp_real_count++;
}
}
if (temp_real_count > 1)
{ //多筆情況
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 = deviceSubscrips.Where(x => x.device_number == device_number).FirstOrDefault();
Dictionary<string, object> ontimeRawData = new Dictionary<string, object>()
{
{ "@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);
}
}
else
{ //單筆情況
var valueSplit = ontimeList["real"]["@display"].ToString().Split();
var value = valueSplit[0];
var href = ontimeList["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找出點位
Dictionary<string, object> ontimeRawData = new Dictionary<string, object>()
{
{ "device_number", device_number},
{ "name", name},
{ "@value", value},
{ "@is_bool", 0},
};
ontimeRawDatas.Add(ontimeRawData);
}
}
if (ontimeList["bool"] != null && ontimeList["bool"].HasValues)
{ //讀取布林型
//判斷是否為多筆bool資料
var temp_bool_count = 0; //用來計算總共有幾個name
foreach (var boolVal in ontimeList["bool"].Children())
{
var tempKeyValue = boolVal.ToString();
if (tempKeyValue.Contains("@displayName"))
{
temp_bool_count++;
}
}
if (temp_bool_count > 1)
{ //多筆情況
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找出點位
string finalFacetsValue = null;
var selectDevice = deviceSubscrips.Where(x => x.device_number == device_number).FirstOrDefault();
//判斷是否有facets
if (ontimeList["str"] != null && ontimeList["str"].HasValues)
{
var has_find = false;
foreach (var facet in ontimeList["str"])
{
var facet_href = facet["@href"].ToString();
var facet_href_split = facet_href.Split("/");
if (facet_href.Contains(device_number) && facet_href_split[facet_href_split.Length - 3] == name)
{ //表示有找到
finalFacetsValue = facet["@display"].ToString();
var facetValueSplit = facet["@display"].ToString().Split(",");
foreach (var facetValue in facetValueSplit)
{
if (facetValue.Contains(value))
{
var tempTextValue = facetValue.Split("=");
value = tempTextValue[0];
has_find = true;
break;
}
}
if (has_find)
{
break;
}
}
}
}
Dictionary<string, object> ontimeRawData = new Dictionary<string, object>()
{
{ "@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},
{ "@facets", finalFacetsValue},
};
ontimeRawDatas.Add(ontimeRawData);
}
}
else
{ //單筆情況
var valueSplit = ontimeList["bool"]["@display"].ToString().Split();
var value = valueSplit[0];
var href = ontimeList["bool"]["@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找出點位
string finalFacetsValue = null;
var selectDevice = deviceSubscrips.Where(x => x.device_number == device_number).FirstOrDefault();
//判斷是否有facets
if (ontimeList["str"] != null && ontimeList["str"].HasValues)
{
var has_find = false;
foreach (var facet in ontimeList["str"])
{
var facet_href = facet["@href"].ToString();
var facet_href_split = facet_href.Split("/");
if (facet_href.Contains(device_number) && facet_href_split[facet_href_split.Length - 3] == name)
{ //表示有找到
finalFacetsValue = facet["@display"].ToString();
var facetValueSplit = facet["@display"].ToString().Split(",");
foreach (var facetValue in facetValueSplit)
{
if (facetValue.Contains(value))
{
var tempTextValue = facetValue.Split("=");
value = tempTextValue[0];
has_find = true;
break;
}
}
if (has_find)
{
break;
}
}
}
}
else
{
//找出是否有存在facets如果有則須多加判斷
var sql = $@"SELECT facets FROM ontime_device_rawdata WHERE device_number = @device_number AND name = @name";
var facets = await frontendRepository.GetOneAsync<string>(sql, new { device_number = device_number, name = name });
finalFacetsValue = facets;
if (!string.IsNullOrEmpty(facets))
{
var facetValueSplit = facets.Split(",");
foreach (var facetValue in facetValueSplit)
{
if (facetValue.Contains(value))
{
var tempTextValue = facetValue.Split("=");
value = tempTextValue[0];
break;
}
}
}
}
Dictionary<string, object> ontimeRawData = new Dictionary<string, object>()
{
{ "@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},
{ "@facets", finalFacetsValue},
};
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, facets) VALUES(@building_guid, @main_system_guid, @sub_system_guid, @device_number, @name, @value, @is_bool, @facets)
ON DUPLICATE KEY UPDATE value=@value, is_bool = @is_bool, facets = @facets";
await frontendRepository.ExecuteSql(insert_update_sql, ontimeRawDatas);
}
catch (Exception exception)
{
logger.LogError("【OnTimeDeviceSubscriptionJob】【新增設備點位原始資料失敗】");
logger.LogError("【OnTimeDeviceSubscriptionJob】【新增設備點位原始資料失敗】[Exception]{0}", exception.ToString());
}
}
logger.LogInformation("【OnTimeDeviceSubscriptionJob】【任務完成】");
}
#endregion step 3
}
catch (Exception exception)
{
logger.LogError("【OnTimeDeviceSubscriptionJob】【任務失敗】");
logger.LogError("【OnTimeDeviceSubscriptionJob】【任務失敗】[Exception]{0}", exception.ToString());
}
}
}
}