ibms-dome/FrontendWorkerService/Quartz/Jobs/OnTimeDeviceSubscriptionJob.cs
2022-10-14 16:08:54 +08:00

584 lines
31 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.

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());
}
}
}
}