using GpsCardGatewayPosition.Model.Config; using GpsCardGatewayPosition.Service.Cache; using GpsCardGatewayPosition.Service.MqProducer; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using TelpoDataService.Util.Clients; using TelpoDataService.Util.Entities.GpsLocationHistory; namespace GpsCardGatewayPosition.Service.Biz.Sos { public class SosLogic { public enum SosStatusType : int { /// /// 不存在 /// NotExisted = 0, /// /// 不完整,已填写内容 /// FilledContent = 1, /// /// 不完整,已填写地址 /// FilledAddress = 2, /// /// 信息已完整 /// Complete = 3, /// /// /// Reserved } private const string KEY_CACHE_SOS_STATUS = "Sos_Status"; private const int KEY_CACHE_SECONDS = 600; private const string TEMPLATE_SOS_TOPIC = "/{0}/{1}/thing/event/SOS/post"; 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\":\"求救!\"}}}}"; private readonly PersonCacheManager _personCacheMgr; private readonly MqProcessLogic _serviceMqProcess; private readonly GpsLocationHistoryAccessorClient _alarmApiClient; // private readonly EventResolverFactory _resolverFactory; private readonly IServiceProvider _services; private readonly IotConfig _configIot; private readonly ILogger _logger; //private static MsgQueueManager _queueManager = null; //private MsgQueueManager QueueManager //{ // get // { // if (_queueManager == null) _queueManager = _services.GetRequiredService(); // return _queueManager; // } //} public SosLogic(PersonCacheManager personCacheMgr, MqProcessLogic serviceMqProcess, GpsLocationHistoryAccessorClient alarmApiClient, //EventResolverFactory resolverFactory, IServiceProvider services, IOptions optConfigIot, ILogger logger) { _personCacheMgr = personCacheMgr; _serviceMqProcess = serviceMqProcess; _alarmApiClient = alarmApiClient; //_resolverFactory = resolverFactory; _services = services; _configIot = optConfigIot.Value; _logger = logger; } private async Task GetSosStatusAsync(string sosId) { var key = $"{KEY_CACHE_SOS_STATUS}_{sosId}"; var result = await RedisHelper.GetAsync(key); if (result == null) return SosStatusType.NotExisted; if (result > SosStatusType.Reserved || result < SosStatusType.NotExisted) return SosStatusType.NotExisted; return result.Value; } /// /// 处理sos事件消息 /// /// /// /// 返回告警对象用于插入数据库 /// 返回告警对象用于更新数据库 /// 后续处理 /// public async Task HandleSosContent(string messageId, string sosId, Func factoryToAdd, Func factoryToUpdate, Action handleFollowup = null) { if (factoryToAdd == null || factoryToUpdate == null) throw new ArgumentNullException(); HisGpsAlarm alarm = null; var status = await GetSosStatusAsync(sosId).ConfigureAwait(false); if (status == SosLogic.SosStatusType.Complete || status == SosLogic.SosStatusType.FilledContent) { _logger.LogWarning($"SOS事件[{sosId}]已处理(内容)"); return false; } if (status == SosStatusType.NotExisted) { alarm = factoryToAdd.Invoke(); await AddSosAlarmAsync(messageId, alarm).ConfigureAwait(false); SetSosStatus(sosId, SosLogic.SosStatusType.FilledContent); } else { alarm = await GetSosAlarmAsync(messageId, sosId).ConfigureAwait(false); if (alarm != null) { alarm = factoryToUpdate.Invoke(alarm); await UpdateSosAlarmAsync(messageId, alarm).ConfigureAwait(false); SetSosStatus(sosId, SosLogic.SosStatusType.Complete); } } if (alarm != null) { //推送微信公众号 if (alarm.TypeId >= 1 && alarm.TypeId <= 5) { await _serviceMqProcess.ProcessWxAlarmAsync(alarm); } } handleFollowup?.Invoke(); return true; } public async Task HandleSosAddressAsync(string messageId, string sosId, long timestamp, Func factoryToAdd, Func factoryToUpdate, Action handleFollowup = null) { if (factoryToAdd == null || factoryToUpdate == null) throw new ArgumentNullException(); HisGpsAlarm alarm = null; var status = await GetSosStatusAsync(sosId).ConfigureAwait(false); if (status == SosStatusType.Complete || status == SosStatusType.FilledAddress) { _logger.LogWarning($"SOS事件[{sosId}]已处理(地址)"); return false; } if (status == SosStatusType.NotExisted) { alarm = factoryToAdd.Invoke(); await AddSosAlarmAsync(messageId, alarm).ConfigureAwait(false); SetSosStatus(sosId, SosLogic.SosStatusType.FilledAddress); //为预防sos事件丢失的情况,这里主动构建sos事件消息并入队列 var topic = string.Format(TEMPLATE_SOS_TOPIC, _configIot.ProductKey, alarm.Serialno); var body = string.Format(TEMPLATE_SOS_BODY, Guid.NewGuid().ToString(), //new DateTimeOffset(alarm.DeviceUtcTime ?? DateTime.UtcNow).ToUnixTimeMilliseconds(), timestamp, _configIot.ProductKey, alarm.Serialno, sosId); //var msg = _resolverFactory.ParseAndWrap(new ReceiveMessageModel(messageId, topic, body)); //if (msg == null) _logger.LogError("模拟sos事件消息失败"); //else QueueManager.EnqueueMsg(msg); } else { alarm = await GetSosAlarmAsync(messageId, sosId).ConfigureAwait(false); if (alarm != null) { alarm = factoryToUpdate.Invoke(alarm); await UpdateSosAlarmAsync(messageId, alarm).ConfigureAwait(false); SetSosStatus(sosId, SosLogic.SosStatusType.Complete); } } handleFollowup?.Invoke(); return true; } private void SetSosStatus(string sosId, SosStatusType status) { var key = $"{KEY_CACHE_SOS_STATUS}_{sosId}"; RedisHelper.SetAsync(key, (int)status, KEY_CACHE_SECONDS); } private async Task GetSosAlarmAsync(string messageId, string sosId) { try { var alarm = await _alarmApiClient.GetByIdAsync(sosId, header: new RequestHeader { RequestId = messageId }).ConfigureAwait(false); return alarm; } catch (Exception ex) { _logger.LogError($"根据{sosId}获取指定SOS告警信息失败, {ex.Message}, {ex.StackTrace}"); return null; } } /// /// /// /// /// /// private async Task AddSosAlarmAsync(string messageId, HisGpsAlarm alarm) { try { var person = await _personCacheMgr.GetPersonBySerialNoAsync(messageId, alarm.Serialno).ConfigureAwait(false); if (person == null) alarm.DeviceName = alarm.Serialno; else alarm.DeviceName = person.NickName; if (string.IsNullOrWhiteSpace(alarm.MessageId)) alarm.MessageId = Guid.NewGuid().ToString("D"); await _alarmApiClient.AddAsync(alarm, header: new RequestHeader { RequestId = messageId }).ConfigureAwait(false); return true; } catch (Exception ex) { _logger.LogError($"新增SOS报警信息发生异常:{ex.Message}, {ex.StackTrace}"); } return false; } private async Task UpdateSosAlarmAsync(string messageId, HisGpsAlarm alarm) { try { await _alarmApiClient.UpdateAsync(alarm, header: new RequestHeader { RequestId = messageId }).ConfigureAwait(false); return true; } catch (Exception ex) { _logger.LogError($"更新SOS报警信息发生异常:{ex.Message}, {ex.StackTrace}"); } return false; } } }