Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

413 lines
22KB

  1. using dotnet_etcd;
  2. using Etcdserverpb;
  3. using Google.Protobuf.WellKnownTypes;
  4. using HealthMonitor.Common;
  5. using HealthMonitor.Common.helper;
  6. using HealthMonitor.Core.Common.Extensions;
  7. using HealthMonitor.Model.Config;
  8. using HealthMonitor.Model.Service;
  9. using HealthMonitor.Service.Biz;
  10. using HealthMonitor.Service.Biz.db;
  11. using HealthMonitor.Service.Etcd;
  12. using HealthMonitor.Service.Sub;
  13. using Microsoft.AspNetCore.Mvc.RazorPages;
  14. using Microsoft.EntityFrameworkCore.Metadata.Internal;
  15. using Microsoft.Extensions.Options;
  16. using Newtonsoft.Json;
  17. using Newtonsoft.Json.Linq;
  18. using System.Reflection;
  19. using System.Threading.Channels;
  20. using TDengineDriver;
  21. using TDengineTMQ;
  22. namespace HealthMonitor.WebApi
  23. {
  24. public class Worker : BackgroundService
  25. {
  26. private readonly ILogger<Worker> _logger;
  27. private readonly IServiceProvider _services;
  28. private readonly TDengineDataSubcribe _tdEngineDataSubcribe;
  29. private readonly PackageProcess _processor;
  30. private readonly TDengineService _serviceTDengine;
  31. private readonly EtcdService _serviceEtcd;
  32. private readonly HttpHelper _httpHelper = default!;
  33. private readonly IotWebApiService _serviceIotWebApi;
  34. private readonly BoodPressResolverConfig _configBoodPressResolver;
  35. private CancellationTokenSource _tokenSource=default!;
  36. public Worker(ILogger<Worker> logger, IServiceProvider services, IotWebApiService iotWebApiService, IOptions<BoodPressResolverConfig> optionBoodPressResolver, PackageProcess processor,TDengineDataSubcribe tdEngineDataSubcribe, TDengineService serviceDengine, HttpHelper httpHelper, EtcdService serviceEtcd)
  37. {
  38. _logger = logger;
  39. _tdEngineDataSubcribe = tdEngineDataSubcribe;
  40. _services = services;
  41. _serviceIotWebApi = iotWebApiService;
  42. _processor = processor;
  43. _serviceEtcd = serviceEtcd;
  44. _serviceTDengine = serviceDengine;
  45. _httpHelper = httpHelper;
  46. _configBoodPressResolver = optionBoodPressResolver.Value;
  47. }
  48. public override Task StartAsync(CancellationToken cancellationToken)
  49. {
  50. _logger.LogInformation("------StartAsync");
  51. _tokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
  52. // 创建消费者
  53. // _tdEngineDataSubcribe.CreateConsumer();
  54. return base.StartAsync(cancellationToken);
  55. }
  56. public override Task StopAsync(CancellationToken cancellationToken)
  57. {
  58. _logger.LogInformation("------StopAsync");
  59. _tokenSource.Cancel(); //停止工作线程
  60. // 关闭消费者
  61. // _tdEngineDataSubcribe.CloseConsumer();
  62. return base.StopAsync(cancellationToken);
  63. }
  64. protected override Task ExecuteAsync(CancellationToken stoppingToken)
  65. {
  66. // var processor = _services.GetService<PackageProcess>();
  67. TaskFactory factory = new(_tokenSource.Token);
  68. factory.StartNew(async () =>
  69. {
  70. if (_tokenSource.IsCancellationRequested)
  71. _logger.LogWarning("Worker exit");
  72. _logger.LogInformation("------ResolveAsync");
  73. while (!_tokenSource.IsCancellationRequested)
  74. {
  75. //
  76. await _processor.ResolveAsync().ConfigureAwait(false);
  77. // await _tdEngineDataSubcribe.ProcessMsg();
  78. }
  79. }, TaskCreationOptions.LongRunning);
  80. factory.StartNew(() =>
  81. {
  82. _logger.LogInformation("------_tdEngineDataSubcribe");
  83. while (!_tokenSource.IsCancellationRequested)
  84. {
  85. _tdEngineDataSubcribe.BeginListen(_tokenSource.Token);
  86. }
  87. }, TaskCreationOptions.LongRunning);
  88. Task.Run(() =>
  89. _serviceEtcd.WacthKeysWithPrefixResponseAsync($"health_moniter/schedule_push", WatchEvents)
  90. , stoppingToken);
  91. // watch
  92. //factory.StartNew(() =>
  93. //{
  94. // while (!_tokenSource.IsCancellationRequested)
  95. // {
  96. // //_serviceEtcd.WacthKeysWithPrefixAsync($"health_moniter/schedule_push", watchEvents => WatchEvents(watchEvents));
  97. // _serviceEtcd.WacthKeysWithPrefixResponseAsync($"health_moniter/schedule_push", WatchEvents);
  98. // }
  99. //}, TaskCreationOptions.LongRunning);
  100. // _serviceEtcd.WacthKeysWithPrefixResponseAsync($"health_moniter/schedule_push", WatchEvents);
  101. return Task.Delay(1000, _tokenSource.Token);
  102. }
  103. private void WatchEvents(WatchEvent[] response)
  104. {
  105. foreach (WatchEvent e1 in response)
  106. {
  107. // Console.WriteLine($"{nameof(WatchEventsAsync)} --- {e1.Key}:{e1.Value}:{e1.Type}");
  108. switch (e1.Type.ToString())
  109. {
  110. //case "Put":
  111. // // 获取时间点计算TTL
  112. // break;
  113. case "Delete":
  114. // TTL到了重新计算TTL,下发
  115. Console.WriteLine($"--- {e1.Key}:{e1.Value}:{e1.Type}");
  116. break;
  117. }
  118. }
  119. }
  120. private void WatchEvents(WatchResponse response)
  121. {
  122. response.Events.ToList().ForEach(async e =>
  123. {
  124. switch (e.Type.ToString())
  125. {
  126. case "Put":
  127. // 获取时间点计算TTL
  128. Console.BackgroundColor = ConsoleColor.Blue;
  129. Console.WriteLine($"--- {e.Type}--{e.Kv.Key.ToStringUtf8()}--{e.Kv.Value.ToStringUtf8()}---{DateTime.Now}");
  130. Console.BackgroundColor = ConsoleColor.Black;
  131. break;
  132. case "Delete":
  133. // TTL到了重新计算TTL,下发
  134. Console.BackgroundColor = ConsoleColor.Green;
  135. Console.WriteLine($"--- {e.Type}--{e.Kv.Key.ToStringUtf8()}--{e.Kv.Value.ToStringUtf8()}---{DateTime.Now}");
  136. // var key = $"health_moniter/schedule_push/imei/{bp.Serialno}";
  137. var key = e.Kv.Key.ToStringUtf8();
  138. var imeiDel = key.Split('/')[3];
  139. var schedule_push = await _serviceEtcd.GetValAsync(key).ConfigureAwait(false);
  140. if (string.IsNullOrWhiteSpace(schedule_push))
  141. {
  142. var startTime =DateTime.Now;
  143. // 下发增量值
  144. #region 定时下发增量值
  145. var last= await _serviceTDengine.GetLastAsync("stb_hm_bloodpress_stats_inc", $"serialno='{imeiDel}' order by last_update desc");
  146. var ts = last?[0];
  147. if (DateTime.TryParse(ts?.ToString(),out DateTime newTs))
  148. {
  149. // 7 天有效数据
  150. if (newTs.AddDays(7) > DateTime.Now)
  151. {
  152. Console.WriteLine(ts);
  153. var systolic_ref_value = last?[5];
  154. var diastolic_ref_value = last?[12];
  155. var systolic_inc_value = last?[10];
  156. var diastolic_inc_value = last?[17];
  157. #region 判断是否初始化remark
  158. // 判断是否初始化remark
  159. /**
  160. *
  161. var imei = imeiDel;
  162. var last_push = await _serviceTDengine.GetLastAsync("stb_hm_bp_push_ref_inc_value", $"serialno='{imei}' order by ts desc");
  163. if (last_push?.Count == 0)
  164. {
  165. var dataServiceBaseUrl = $"https://id.ssjlai.com/data";
  166. var DataServicePersionGet = $"{dataServiceBaseUrl}/api/GpsCard/GpsPerson/GetFirst";
  167. List<KeyValuePair<string, string>> Dataheaders = new()
  168. {
  169. new KeyValuePair<string, string>("requestId", $"{imei}")
  170. };
  171. var dataPersion = new
  172. {
  173. filters = new List<object>() { new { key = "serialno", value = $"{imei}", valueType = "string", @operator = "Equal" } },
  174. orderBys = new List<object>() { new { key = "serialno", isDesc = true } }
  175. };
  176. var resRef = await _httpHelper.HttpToPostAsync(DataServicePersionGet, dataPersion, Dataheaders).ConfigureAwait(false);
  177. var resObj = JsonConvert.DeserializeObject(resRef!) as JToken;
  178. var remark = resObj?["remarks"]?.ToString();
  179. // 修改数据库
  180. if (string.IsNullOrWhiteSpace(remark))
  181. {
  182. var newRemarkData = new
  183. {
  184. imei,
  185. time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
  186. commandValue = new
  187. {
  188. systolicCalibrationValue = systolic_ref_value, //收缩压标定值,值为0 表示不生效
  189. diastolicCalibrationValue = diastolic_ref_value, //舒张压标定值,值为0表示不生效
  190. systolicIncValue = 0, //收缩压显示增量,值为0 表示不生效
  191. diastolicIncValue = 0 //舒张压显示增量,值为0 表示不生效
  192. }
  193. };
  194. resObj!["remarks"] = $"is_blood_press:{JsonConvert.SerializeObject(newRemarkData)}|";
  195. var DataServicePersionUpdate = $"{dataServiceBaseUrl}/api/GpsCard/GpsPerson/Update";
  196. var resUpdate = await _httpHelper.HttpToPostAsync(DataServicePersionUpdate, resObj, Dataheaders).ConfigureAwait(false);
  197. _logger.LogInformation($"更新Person数据库|{resUpdate}");
  198. //更新缓存
  199. List<KeyValuePair<string, string>> headersCache = new()
  200. {
  201. new KeyValuePair<string, string>("AuthKey", "key1")
  202. };
  203. var cacheUrl = $"http://id.ssjlai.com/webapi/api/Device/UpdatePersonInfoCache?imei={imei}";
  204. var updateCache = await _httpHelper.HttpToGetAsync(cacheUrl, headersCache);
  205. _logger.LogInformation($"更新Person缓存|{updateCache}");
  206. }
  207. }
  208. */
  209. #endregion
  210. //var bpData = new
  211. //{
  212. // imei = imeiDel,
  213. // //systolicCalibrationValue = last?[5], //收缩压标定值,值为0 表示不生效
  214. // //diastolicCalibrationValue = last?[12], //舒张压标定值,值为0表示不生效
  215. // //systolicIncValue = last?[10], //收缩压显示增量,值为0 表示不生效
  216. // //diastolicIncValue = last?[17] //舒张压显示增量,值为0 表示不生效
  217. // systolicCalibrationValue = systolic_ref_value, //收缩压标定值,值为0 表示不生效
  218. // diastolicCalibrationValue = diastolic_ref_value, //舒张压标定值,值为0表示不生效
  219. // systolicIncValue = systolic_inc_value, //收缩压显示增量,值为0 表示不生效
  220. // diastolicIncValue = diastolic_inc_value //舒张压显示增量,值为0 表示不生效
  221. //};
  222. //var str = JsonConvert.SerializeObject(bpData);
  223. //var url = $"http://id.ssjlai.com/webapi/api/Command/SetBloodPressCalibrationConfig";
  224. //List<KeyValuePair<string, string>> headers = new()
  225. //{
  226. // new KeyValuePair<string, string>("AuthKey", "key1")
  227. //};
  228. //var res = await _httpHelper.HttpToPostAsync(url, bpData, headers).ConfigureAwait(false);
  229. //_logger.LogInformation($"向{imeiDel}下发增量值数据:{str},响应:{res}");
  230. //var resJToken = JsonConvert.DeserializeObject(res!) as JToken;
  231. //if (resJToken!["message"]!.ToString().Equals("ok"))
  232. Console.WriteLine($"{nameof(Worker)} 开启血压标定值下发: {_configBoodPressResolver.EnableBPRefPush}");
  233. if (_configBoodPressResolver.EnableBPRefPush)
  234. {
  235. BloodPressCalibrationConfigModel bpIncData = new()
  236. {
  237. Imei = imeiDel,
  238. SystolicRefValue = SafeType.SafeInt(((int)systolic_ref_value!)), //收缩压标定值,值为0 表示不生效
  239. DiastolicRefValue = SafeType.SafeInt(((int)diastolic_ref_value!)), //舒张压标定值,值为0表示不生效
  240. SystolicIncValue = SafeType.SafeInt(((int)systolic_inc_value!)), //收缩压显示增量,值为0 表示不生效
  241. DiastolicIncValue = SafeType.SafeInt(((int)diastolic_inc_value!)) //舒张压显示增量,值为0 表示不生效
  242. };
  243. var pushedBP = await _serviceIotWebApi.SetBloodPressCalibrationConfigAsync(bpIncData).ConfigureAwait(false);
  244. if (pushedBP)
  245. {
  246. #region 保存下推记录 stb_hm_bp_push_ref_inc_value
  247. var sql = $"INSERT INTO health_monitor.hm_bp_push_ref_inc_value_{imeiDel.Substring(imeiDel.Length - 2)} " +
  248. $"USING health_monitor.stb_hm_bp_push_ref_inc_value " +
  249. $"TAGS ('{imeiDel.Substring(imeiDel.Length - 2)}') " +
  250. $"VALUES(" +
  251. $"'{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}'," +
  252. $"'{imeiDel}'," +
  253. $"{systolic_ref_value}," +
  254. $"{diastolic_ref_value}," +
  255. $"{systolic_inc_value}," +
  256. $"{diastolic_inc_value}," +
  257. $"{false})";
  258. _serviceTDengine.ExecuteInsertSQL(sql);
  259. #endregion
  260. // 注册下次下推
  261. var endTime = DateTime.Now;
  262. #if DEBUG
  263. //long ttl = (long)((60 * 1000-(endTime-startTime).TotalMilliseconds)/1000);
  264. //await _serviceEtcd.PutValAsync(key, imeiDel,ttl, false).ConfigureAwait(false);
  265. var interval = 0;
  266. // 获取当前时间
  267. DateTime now = DateTime.Now;
  268. // 计算距离下一个$interval天后的8点的时间间隔
  269. DateTime nextRunTime = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute + 2, 0).AddDays(interval);
  270. TimeSpan timeUntilNextRun = nextRunTime - now;
  271. // 如果当前时间已经超过了8点,将等待到明天后的8点
  272. if (timeUntilNextRun < TimeSpan.Zero)
  273. {
  274. timeUntilNextRun = timeUntilNextRun.Add(TimeSpan.FromMinutes(1));
  275. nextRunTime += timeUntilNextRun;
  276. }
  277. // var ttl = timeUntilNextRun.TotalMilliseconds;
  278. long ttl = (long)((timeUntilNextRun.TotalMilliseconds - (endTime - startTime).TotalMilliseconds) / 1000);
  279. var data = new
  280. {
  281. imei = imeiDel,
  282. create_time = now.ToString("yyyy-MM-dd HH:mm:ss"),
  283. ttl,
  284. next_run_time = nextRunTime.ToString("yyyy-MM-dd HH:mm:ss")
  285. };
  286. var result = JsonConvert.SerializeObject(data);
  287. await _serviceEtcd.PutValAsync(key, result, ttl, false).ConfigureAwait(false);
  288. #else
  289. // 每$interval天,晚上8点
  290. var interval = 1;
  291. // 获取当前时间
  292. DateTime now = DateTime.Now;
  293. // 计算距离下一个$interval天后的8点的时间间隔
  294. DateTime nextRunTime = new DateTime(now.Year, now.Month, now.Day, 20, 0, 0).AddDays(interval);
  295. TimeSpan timeUntilNextRun = nextRunTime - now;
  296. // 如果当前时间已经超过了8点,将等待到明天后的8点
  297. if (timeUntilNextRun < TimeSpan.Zero)
  298. {
  299. timeUntilNextRun = timeUntilNextRun.Add(TimeSpan.FromDays(1));
  300. nextRunTime += timeUntilNextRun;
  301. }
  302. // var ttl = timeUntilNextRun.TotalMilliseconds;
  303. long ttl = (long)((timeUntilNextRun.TotalMilliseconds-(endTime-startTime).TotalMilliseconds)/1000);
  304. var data = new
  305. {
  306. imei = imeiDel,
  307. create_time = now.ToString("yyyy-MM-dd HH:mm:ss"),
  308. ttl,
  309. next_run_time = nextRunTime.ToString("yyyy-MM-dd HH:mm:ss")
  310. };
  311. var result = JsonConvert.SerializeObject(data);
  312. await _serviceEtcd.PutValAsync(key, result, ttl, false).ConfigureAwait(false);
  313. #endif
  314. }
  315. else
  316. {
  317. _logger.LogInformation($"错误响应,没有下推数据");
  318. }
  319. }
  320. }
  321. }
  322. else
  323. {
  324. _logger.LogInformation($"向{imeiDel}准备下推的数据已经失效ts,{ts}");
  325. }
  326. #endregion
  327. //if (imeiDel.Equals("861281060086216"))
  328. //{
  329. // var result = await _httpHelper.HttpToPostAsync(url, data, headers).ConfigureAwait(false);
  330. // _logger.LogInformation($"向{imeiDel}下发增量值数据:{str},响应:{result}");
  331. // Console.WriteLine(str);
  332. //}
  333. //Console.BackgroundColor = ConsoleColor.Black;
  334. }
  335. break;
  336. }
  337. });
  338. //if (response.Events.Count == 0)
  339. //{
  340. // Console.WriteLine(response);
  341. //}
  342. //else
  343. //{
  344. // Console.WriteLine($"{response.Events[0].Kv.Key.ToStringUtf8()}:{response.Events.Kv.Value.ToStringUtf8()}");
  345. //}
  346. }
  347. }
  348. }