You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

264 lines
10KB

  1. using GpsCardGatewayPosition.Model.Config;
  2. using GpsCardGatewayPosition.Service.Cache;
  3. using GpsCardGatewayPosition.Service.MqProducer;
  4. using Microsoft.Extensions.DependencyInjection;
  5. using Microsoft.Extensions.Logging;
  6. using Microsoft.Extensions.Options;
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Linq;
  10. using System.Text;
  11. using System.Threading.Tasks;
  12. using TelpoDataService.Util.Clients;
  13. using TelpoDataService.Util.Entities.GpsLocationHistory;
  14. namespace GpsCardGatewayPosition.Service.Biz.Sos
  15. {
  16. public class SosLogic
  17. {
  18. public enum SosStatusType : int
  19. {
  20. /// <summary>
  21. /// 不存在
  22. /// </summary>
  23. NotExisted = 0,
  24. /// <summary>
  25. /// 不完整,已填写内容
  26. /// </summary>
  27. FilledContent = 1,
  28. /// <summary>
  29. /// 不完整,已填写地址
  30. /// </summary>
  31. FilledAddress = 2,
  32. /// <summary>
  33. /// 信息已完整
  34. /// </summary>
  35. Complete = 3,
  36. /// <summary>
  37. ///
  38. /// </summary>
  39. Reserved
  40. }
  41. private const string KEY_CACHE_SOS_STATUS = "Sos_Status";
  42. private const int KEY_CACHE_SECONDS = 600;
  43. private const string TEMPLATE_SOS_TOPIC = "/{0}/{1}/thing/event/SOS/post";
  44. private const string TEMPLATE_SOS_BODY = "{{\"deviceType\":\"CustomCategory\",\"identifier\":\"SOS\",\"iotId\":\"{0}\",\"requestId\":\"666\",\"name\":\"SOS求救报警\",\"time\":{1},\"type\":\"alert\",\"productKey\":\"{2}\",\"deviceName\":\"{3}\",\"value\":{{\"SOSID\":\"{4}\",\"state\":-5,\"info\":\"求救!\"}}}}";
  45. private readonly PersonCacheManager _personCacheMgr;
  46. private readonly MqProcessLogic _serviceMqProcess;
  47. private readonly GpsLocationHistoryAccessorClient<HisGpsAlarm> _alarmApiClient;
  48. // private readonly EventResolverFactory _resolverFactory;
  49. private readonly IServiceProvider _services;
  50. private readonly IotConfig _configIot;
  51. private readonly ILogger<SosLogic> _logger;
  52. //private static MsgQueueManager _queueManager = null;
  53. //private MsgQueueManager QueueManager
  54. //{
  55. // get
  56. // {
  57. // if (_queueManager == null) _queueManager = _services.GetRequiredService<MsgQueueManager>();
  58. // return _queueManager;
  59. // }
  60. //}
  61. public SosLogic(PersonCacheManager personCacheMgr, MqProcessLogic serviceMqProcess,
  62. GpsLocationHistoryAccessorClient<HisGpsAlarm> alarmApiClient,
  63. //EventResolverFactory resolverFactory,
  64. IServiceProvider services, IOptions<IotConfig> optConfigIot, ILogger<SosLogic> logger)
  65. {
  66. _personCacheMgr = personCacheMgr;
  67. _serviceMqProcess = serviceMqProcess;
  68. _alarmApiClient = alarmApiClient;
  69. //_resolverFactory = resolverFactory;
  70. _services = services;
  71. _configIot = optConfigIot.Value;
  72. _logger = logger;
  73. }
  74. private async Task<SosStatusType> GetSosStatusAsync(string sosId)
  75. {
  76. var key = $"{KEY_CACHE_SOS_STATUS}_{sosId}";
  77. var result = await RedisHelper.GetAsync<SosStatusType?>(key);
  78. if (result == null) return SosStatusType.NotExisted;
  79. if (result > SosStatusType.Reserved || result < SosStatusType.NotExisted) return SosStatusType.NotExisted;
  80. return result.Value;
  81. }
  82. /// <summary>
  83. /// 处理sos事件消息
  84. /// </summary>
  85. /// <param name="messageId"></param>
  86. /// <param name="sosId"></param>
  87. /// <param name="factoryToAdd">返回告警对象用于插入数据库</param>
  88. /// <param name="factoryToUpdate">返回告警对象用于更新数据库</param>
  89. /// <param name="handleFollowup">后续处理</param>
  90. /// <returns></returns>
  91. public async Task<bool> HandleSosContent(string messageId, string sosId,
  92. Func<HisGpsAlarm> factoryToAdd, Func<HisGpsAlarm, HisGpsAlarm> factoryToUpdate,
  93. Action handleFollowup = null)
  94. {
  95. if (factoryToAdd == null || factoryToUpdate == null) throw new ArgumentNullException();
  96. HisGpsAlarm alarm = null;
  97. var status = await GetSosStatusAsync(sosId).ConfigureAwait(false);
  98. if (status == SosLogic.SosStatusType.Complete || status == SosLogic.SosStatusType.FilledContent)
  99. {
  100. _logger.LogWarning($"SOS事件[{sosId}]已处理(内容)");
  101. return false;
  102. }
  103. if (status == SosStatusType.NotExisted)
  104. {
  105. alarm = factoryToAdd.Invoke();
  106. await AddSosAlarmAsync(messageId, alarm).ConfigureAwait(false);
  107. SetSosStatus(sosId, SosLogic.SosStatusType.FilledContent);
  108. }
  109. else
  110. {
  111. alarm = await GetSosAlarmAsync(messageId, sosId).ConfigureAwait(false);
  112. if (alarm != null)
  113. {
  114. alarm = factoryToUpdate.Invoke(alarm);
  115. await UpdateSosAlarmAsync(messageId, alarm).ConfigureAwait(false);
  116. SetSosStatus(sosId, SosLogic.SosStatusType.Complete);
  117. }
  118. }
  119. if (alarm != null)
  120. {
  121. //推送微信公众号
  122. if (alarm.TypeId >= 1 && alarm.TypeId <= 5)
  123. {
  124. await _serviceMqProcess.ProcessWxAlarmAsync(alarm);
  125. }
  126. }
  127. handleFollowup?.Invoke();
  128. return true;
  129. }
  130. public async Task<bool> HandleSosAddressAsync(string messageId, string sosId, long timestamp,
  131. Func<HisGpsAlarm> factoryToAdd, Func<HisGpsAlarm, HisGpsAlarm> factoryToUpdate,
  132. Action handleFollowup = null)
  133. {
  134. if (factoryToAdd == null || factoryToUpdate == null) throw new ArgumentNullException();
  135. HisGpsAlarm alarm = null;
  136. var status = await GetSosStatusAsync(sosId).ConfigureAwait(false);
  137. if (status == SosStatusType.Complete || status == SosStatusType.FilledAddress)
  138. {
  139. _logger.LogWarning($"SOS事件[{sosId}]已处理(地址)");
  140. return false;
  141. }
  142. if (status == SosStatusType.NotExisted)
  143. {
  144. alarm = factoryToAdd.Invoke();
  145. await AddSosAlarmAsync(messageId, alarm).ConfigureAwait(false);
  146. SetSosStatus(sosId, SosLogic.SosStatusType.FilledAddress);
  147. //为预防sos事件丢失的情况,这里主动构建sos事件消息并入队列
  148. var topic = string.Format(TEMPLATE_SOS_TOPIC, _configIot.ProductKey, alarm.Serialno);
  149. var body = string.Format(TEMPLATE_SOS_BODY,
  150. Guid.NewGuid().ToString(),
  151. //new DateTimeOffset(alarm.DeviceUtcTime ?? DateTime.UtcNow).ToUnixTimeMilliseconds(),
  152. timestamp,
  153. _configIot.ProductKey,
  154. alarm.Serialno,
  155. sosId);
  156. //var msg = _resolverFactory.ParseAndWrap(new ReceiveMessageModel(messageId, topic, body));
  157. //if (msg == null) _logger.LogError("模拟sos事件消息失败");
  158. //else QueueManager.EnqueueMsg(msg);
  159. }
  160. else
  161. {
  162. alarm = await GetSosAlarmAsync(messageId, sosId).ConfigureAwait(false);
  163. if (alarm != null)
  164. {
  165. alarm = factoryToUpdate.Invoke(alarm);
  166. await UpdateSosAlarmAsync(messageId, alarm).ConfigureAwait(false);
  167. SetSosStatus(sosId, SosLogic.SosStatusType.Complete);
  168. }
  169. }
  170. handleFollowup?.Invoke();
  171. return true;
  172. }
  173. private void SetSosStatus(string sosId, SosStatusType status)
  174. {
  175. var key = $"{KEY_CACHE_SOS_STATUS}_{sosId}";
  176. RedisHelper.SetAsync(key, (int)status, KEY_CACHE_SECONDS);
  177. }
  178. private async Task<HisGpsAlarm> GetSosAlarmAsync(string messageId, string sosId)
  179. {
  180. try
  181. {
  182. var alarm = await _alarmApiClient.GetByIdAsync(sosId, header: new RequestHeader { RequestId = messageId }).ConfigureAwait(false);
  183. return alarm;
  184. }
  185. catch (Exception ex)
  186. {
  187. _logger.LogError($"根据{sosId}获取指定SOS告警信息失败, {ex.Message}, {ex.StackTrace}");
  188. return null;
  189. }
  190. }
  191. /// <summary>
  192. ///
  193. /// </summary>
  194. /// <param name="messageId"></param>
  195. /// <param name="alarm"></param>
  196. /// <returns></returns>
  197. private async Task<bool> AddSosAlarmAsync(string messageId, HisGpsAlarm alarm)
  198. {
  199. try
  200. {
  201. var person = await _personCacheMgr.GetPersonBySerialNoAsync(messageId, alarm.Serialno).ConfigureAwait(false);
  202. if (person == null)
  203. alarm.DeviceName = alarm.Serialno;
  204. else
  205. alarm.DeviceName = person.NickName;
  206. if (string.IsNullOrWhiteSpace(alarm.MessageId)) alarm.MessageId = Guid.NewGuid().ToString("D");
  207. await _alarmApiClient.AddAsync(alarm, header: new RequestHeader { RequestId = messageId }).ConfigureAwait(false);
  208. return true;
  209. }
  210. catch (Exception ex)
  211. {
  212. _logger.LogError($"新增SOS报警信息发生异常:{ex.Message}, {ex.StackTrace}");
  213. }
  214. return false;
  215. }
  216. private async Task<bool> UpdateSosAlarmAsync(string messageId, HisGpsAlarm alarm)
  217. {
  218. try
  219. {
  220. await _alarmApiClient.UpdateAsync(alarm, header: new RequestHeader { RequestId = messageId }).ConfigureAwait(false);
  221. return true;
  222. }
  223. catch (Exception ex)
  224. {
  225. _logger.LogError($"更新SOS报警信息发生异常:{ex.Message}, {ex.StackTrace}");
  226. }
  227. return false;
  228. }
  229. }
  230. }