|
- using GpsCardGatewayPosition.Common;
- using GpsCardGatewayPosition.Model.Cache;
- using GpsCardGatewayPosition.Model.Config;
- using GpsCardGatewayPosition.Model.Enum;
- using GpsCardGatewayPosition.Service.Biz.Location.Dto.Wayz;
- using GpsCardGatewayPosition.Service.Cache;
- using GpsCardGatewayPosition.Service.MqProducer;
- using Microsoft.Extensions.Logging;
- using Microsoft.Extensions.Options;
- using Newtonsoft.Json;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using TelpoDataService.Util.Clients;
- using TelpoDataService.Util.Entities.GpsCard;
- using TelpoDataService.Util.Entities.GpsLocationHistory;
- using TelpoDataService.Util;
- using GpsCardGatewayPosition.Service.Dto;
- using GpsCardGatewayPosition.Service.MqProducer.Model;
- using GpsCardGatewayPosition.Service.Biz.Location.Dto;
-
- namespace GpsCardGatewayPosition.Service.Biz.Location
- {
- public class LocationLogic
- {
- private readonly ServiceConfig _configService;
- private readonly MqProcessLogic _serviceMqProcess;
- private readonly DeviceCacheManager _deviceCacheMgr;
- private readonly GpsCardAccessorClient<GpsDeviceStatus> _deviceStatusApiClient;
- private readonly GpsLocationHistoryAccessorClient<HisGpsDeviceData> _hisDeviceDataApiClient;
- private readonly GpsLocationHistoryAccessorClient<History> _hisApiClient;
-
- private readonly ILogger<LocationLogic> _logger;
-
- private readonly int DEFAULT_LBS_ACCEPT_DISTANCE = 2000; // 默认IOT LBS经纬度与缓存经纬度
-
- public LocationLogic(IOptions<ServiceConfig> optConfigService, MqProcessLogic serviceMqProcess, DeviceCacheManager deviceCacheMgr,
- GpsCardAccessorClient<GpsDeviceStatus> deviceStatusApiClient, GpsLocationHistoryAccessorClient<HisGpsDeviceData> hisDeviceDataApiClient, GpsLocationHistoryAccessorClient<History> hisApiClient,
- ILogger<LocationLogic> logger)
- {
- _configService = optConfigService.Value;
- _serviceMqProcess = serviceMqProcess;
- _deviceCacheMgr = deviceCacheMgr;
-
- _deviceStatusApiClient = deviceStatusApiClient;
- _hisDeviceDataApiClient = hisDeviceDataApiClient;
- _hisApiClient = hisApiClient;
-
- _logger = logger;
- }
-
-
- #region 更新设备最后位置信息状态
- public async Task<GeneralResult> UpdateDeviceStatusAsync(string messageId, GpsDeviceStatus deviceStatus)
- {
- var result = new GeneralResult();
- try
- {
- var sn = deviceStatus.Serialno;
-
- var url = _configService.TelpoDataUrl;
- if (await _deviceCacheMgr.GetDeviceStatusBySerialNoAsync(messageId, sn) != null)
- {
- await _deviceStatusApiClient.UpdateAsync(deviceStatus, new RequestHeader { RequestId = messageId }).ConfigureAwait(false);
- }
- else
- {
- await _deviceStatusApiClient.AddAsync(deviceStatus, new RequestHeader { RequestId = messageId }).ConfigureAwait(false);
- }
-
- //更新DeviceStatus缓存
- _deviceCacheMgr.SetDeviceStatus(deviceStatus);
- result.IsSuccess = true;
- }
- catch (Exception ex)
- {
- result.Message = $"更新设备最后位置信息状态发生异常:{ex.Message}, {ex.StackTrace}";
- }
-
- return result;
- }
- #endregion
-
- #region 电子围栏处理
- public async void ProcessGeofence(LocationInfo loc, string messageId)
- {
- var fence = new FenceLocationPlus()
- {
- DeviceId = loc.DeviceId,
- imei = loc.SerialNo,
- address = loc.Address,
- baiduLatitude = loc.BaiduLat,
- baiduLongitude = loc.BaiduLng,
- gaodeLatitude = loc.GLat,
- gaodeLongitude = loc.GLng,
- originalLatitude = loc.OLat,
- originalLongitude = loc.OLng,
- LastUpdate = loc.LastUpdate!.Value.ToString("yyyy-MM-dd HH:mm:ss"), //LastUpdate = datetime,
- UtcDate = loc.UtcDate!.Value.ToString("yyyy-MM-dd HH:mm:ss"), //UtcDate =
- Radius = SafeType.SafeInt(loc.DeviceStatus),
- };
- await _serviceMqProcess.ProcessFencePlusAsync(fence, loc.LastUpdate.Value.ToString("yyyy-MM-dd HH:mm:ss"), messageId);
- }
- public async Task ProcessGeofenceAsync(LocationInfo loc, string messageId)
- {
- var fence = new FenceLocationPlus()
- {
- DeviceId = loc.DeviceId,
- imei = loc.SerialNo,
- address = loc.Address,
- baiduLatitude = loc.BaiduLat,
- baiduLongitude = loc.BaiduLng,
- gaodeLatitude = loc.GLat,
- gaodeLongitude = loc.GLng,
- originalLatitude = loc.OLat,
- originalLongitude = loc.OLng,
- LastUpdate = loc.LastUpdate!.Value.ToString("yyyy-MM-dd HH:mm:ss"), //LastUpdate = datetime,
- UtcDate = loc.UtcDate!.Value.ToString("yyyy-MM-dd HH:mm:ss"), //UtcDate =
- Radius = SafeType.SafeInt(loc.DeviceStatus),
- };
- await _serviceMqProcess.ProcessFencePlusAsync(fence, loc.LastUpdate.Value.ToString("yyyy-MM-dd HH:mm:ss"), messageId);
- }
- #endregion
-
- #region 保存原始数据包
- public async Task<GeneralResult> SavePackageAsync(string messageId, HisGpsDeviceData data)
- {
- var result = new GeneralResult();
- try
- {
- await _hisDeviceDataApiClient.AddAsync(data, header: new RequestHeader { RequestId = messageId }).ConfigureAwait(false);
-
- result.Message = $"保存原始数据包成功!";
- result.IsSuccess = true;
- }
- catch (Exception ex)
- {
- result.Message = $"保存原始数据包发生异常:{ex.Message}, {ex.StackTrace}!";
- }
- return result;
- }
- #endregion
-
- #region 保存历史位置
- /// <summary>
- ///
- /// </summary>
- /// <param name="loc"></param>
- /// <param name="positionStatus">定位状态缓存</param>
- /// <param name="sentTicks">设备上报消息到IOT的时间戳</param>
- /// <param name="cityCode">城市行政编码</param>
- /// <param name="steps">IOT上报步数(选填,暂时只有wifi2有)</param> // 2022/11/23 定位缓存需要增加步数字段实现前端“静止/行走”状态展示
- /// <returns></returns>
- public async Task<LocationServiceResult> AddLocationAsync(string messageId, LocationInfo loc, DevicePositionStatus positionStatus, long sentTicks, string cityCode = "", int? steps = default, object requestPostionData = default)
- {
- var result = new LocationServiceResult();
-
- var requestPostionVar = string.Empty;
- var requestPostionVarObj = new object(); ;
- if (requestPostionData is RequestLocationInfo<WayzWifiRequest> requestPostion && loc.LocationType == 3)
- {
- requestPostionVarObj = new
- {
- Location = new
- {
- Wifis = requestPostion.RequestData.Location.Wifis.Select(i => new { i.MacAddress, i.SignalStrength }).ToList()
- }
- };
- requestPostionVar = JsonConvert.SerializeObject(requestPostionVarObj);
- }
- else
- {
- requestPostionVar = null;
- }
-
- try
- {
- var url = _configService.TelpoDataUrl;
- var model = new History
- {
- LocationId = Guid.NewGuid().ToString("D"),
- DeviceId = loc.DeviceId,
- Serialno = loc.SerialNo,
- Utctime = loc.UtcDate,
- LastUpdate = loc.LastUpdate,
- IsStop = loc.IsStop ?? false,
- IsRedressed = loc.IsRedressed,
- Speed = loc.Speed,
- Course = loc.Course,
- LocationType = loc.LocationType,
- Olat = loc.OLat,
- Olng = loc.OLng,
- BaiduLat = loc.BaiduLat,
- BaiduLng = loc.BaiduLng,
- Glat = loc.GLat,
- Glng = loc.GLng,
- DeviceStatus = loc.DeviceStatus,
- Address = loc.Address,
- Remarks = $"{loc.Remarks}#{messageId}#{DateTime.Now}", //记录messageId方便查询异常的定位,系统保存时间
- RequestPosition = requestPostionVar,
- //RequestPosition =
- //loc.LocationType == 3 && requestPostionData. ? JsonConvert.SerializeObject(requestPostionData)
- };
- await _hisApiClient.AddAsync(model, model.Serialno, header: new RequestHeader { RequestId = messageId }).ConfigureAwait(false);
-
- result.Message = "保存历史位置成功!";
- result.IsSuccess = true;
- }
- catch (Exception ex)
- {
- result.Message = $"保存历史位置发生异常: message:{ex.Message}, {ex.StackTrace}";
- }
-
- if (positionStatus == null) positionStatus = new DevicePositionStatus();
-
- var cache = positionStatus.LastPosition;
- if (cache == null || cache.SentTicks < sentTicks)
- {
- //更新设备的坐标缓存
- // 2022/11/15 关于定位信息缓存更新机制的优化说明(实时定位场景):
- /**
- * // 2022/11/15 关于定位信息缓存更新机制的优化说明(实时定位场景):
- * 具体需求
- * 关于定位信息缓存更新机制的优化说明(实时定位场景):
- 1、缓存需要增加一个字段“原始有效定位时间”,该字段用于填写覆盖LBS定位数据的有效定位数据的定位时间。
- 2、缓存更新需要基于缓存的数据定位时间(last_update)与“原始有效定位时间”进行比较判定更新机制。
- 3、有效定位数据定位时间(非LBS IOT上报时间)>缓存的定位时间,直接用有效定位数据更新缓存,同时,有效定位数据的“原始有效定位时间”是当前数据的定位时间。
- 4、LBS定位数据定位时间(LBS IOT上报时间)>缓存的定位时间,则更新缓存的定位时间,定数数据还是原有缓存的定位数据,“原始有效定位时间”不变还是原有的缓存数据的时间。LBS定位数据定位时间<缓存的定位时间(不可能有这个情况),直接不处理。
- 5、有效定位数据时间(非LBS IOT上报时间)>缓存的“原始有效定位时间”,同时,有效定位数据时间<缓存的的定位时间的情况(就是之前有LBS定位更新了缓存定位时间),则更新缓存的定位数据内容及“原始有效定位时间”,“原始有效定位时间”为当前有效定位的定位时间,定位时间还是不变。
- ===================
- 注:原有定位数据不变都是直接入库。此缓存主要应用于实时定位数据获取。
-
- y: 原始有效定位;
- y_time:原始有效定位的时间;
- l_time: LBS有效定位的时间
- h: 缓存的定位
- h_time:缓存的定位时间(last_update)
-
-
- 1、定位数据
- y: 定位数据:区分有效定位数据(y_data)与LBS定位数据(w_data)。
- l_time: 定位的时间
-
- 2、缓存数据
- h: 缓存的定位
- h_time:缓存的定位时间(字段last_update)
- y_time:有效定位的时间(新增字段,取y_data的l_time);
- h_time>=y_time
-
- 3、y_data:l_time > h_time,则用y更新h、用l_time更新h_time、y_time。
- 4、w_data:l_time > h_time,则用y不更新h、用l_time更新h_time,y_time不变。
- 5、y_data:l_time < h_time & l_time > y_time, 则用y更新h、用l_time更新y_time
- */
-
- // 2022/12/2 所有定位类型都要生成缓存。
- var now = DateTime.Now;
- var positionCache = new DevicePositionStatus.PositionCache
- {
- Address = loc.Address,
- BaiduLat = loc.BaiduLat,
- BaiduLon = loc.BaiduLng,
- CityCode = cityCode,
- GaodeLat = loc.GLat,
- GaodeLon = loc.GLng,
- OriginalLat = loc.OLat,
- OriginalLon = loc.OLng,
- LocationType = loc.LocationType,
- //UpdateTime = loc.LastUpdate ?? DateTime.Now, //DateTime.Now,
- Steps = steps,
- // 2022/11/15 关于定位信息缓存更新机制的优化说明(实时定位场景):
- // 3、有效定位数据定位时间>缓存的定位时间,直接用有效定位数据更新缓存,同时,有效定位数据的“原始有效定位时间”是当前数据的定位时间。
- OriginalTime = loc.LastUpdate ?? now,
- UpdateTime = loc.LastUpdate ?? now, //DateTime.Now,
- ExpiredTime = DateTime.Now.AddHours(1),
- Radius = Convert.ToInt32(loc.DeviceStatus),
- SentTicks = sentTicks,
- Province = loc.Province,
- City = loc.City,
- District = loc.District
- };
-
- // 更新设备的坐标缓存(非LBS IOT)
- if (loc.LocationType != (int)LocationType.LBS) //此缓存值用于通过gps或者wifi类型来校对lbs的偏移
- {
-
- // 2022/11/15 关于定位信息缓存更新机制的优化说明(实时定位场景):
- /** 非LBS 定位缓存
- *
- //var now = DateTime.Now;
- //var positionCache = new DevicePositionStatus.PositionCache
- //{
- // Address = loc.Address,
- // BaiduLat = loc.BaiduLat,
- // BaiduLon = loc.BaiduLng,
- // CityCode = cityCode,
- // GaodeLat = loc.GLat,
- // GaodeLon = loc.GLng,
- // OriginalLat = loc.OLat,
- // OriginalLon = loc.OLng,
- // LocationType = loc.LocationType,
- // //UpdateTime = loc.LastUpdate ?? DateTime.Now, //DateTime.Now,
- // Steps = steps,
- // // 2022/11/15 关于定位信息缓存更新机制的优化说明(实时定位场景):
- // // 3、有效定位数据定位时间>缓存的定位时间,直接用有效定位数据更新缓存,同时,有效定位数据的“原始有效定位时间”是当前数据的定位时间。
- // OriginalTime = loc.LastUpdate ?? now,
- // UpdateTime = loc.LastUpdate ?? now, //DateTime.Now,
- // ExpiredTime = DateTime.Now.AddHours(1),
- // Radius = Convert.ToInt32(loc.DeviceStatus),
- // SentTicks = sentTicks,
- // Province = loc.Province,
- // City = loc.City,
- // District = loc.District
- //};
- */
-
- if (cache != null)
- {
- positionCache.ExpiredTime = cache.ExpiredTime;
- // 5、有效定位数据时间>缓存的“原始有效定位时间”,同时,有效定位数据时间<缓存的的定位时间的情况(就是之前有LBS定位更新了缓存定位时间),
- // 则更新缓存的定位数据内容及“原始有效定位时间”,“原始有效定位时间”为当前有效定位的定位时间,定位时间还是不变。
-
- if (
- Utils.ConvertToLocalDateTime(sentTicks) > cache.OriginalTime
- && Utils.ConvertToLocalDateTime(sentTicks) < cache.UpdateTime
- )
- {
- // “原始有效定位时间”为当前有效定位的定位时间
- positionCache.OriginalTime = Utils.ConvertToLocalDateTime(sentTicks);
-
- // 2022/11/23 定位缓存需要增加步数字段实现前端“静止/行走”状态展示
- positionCache.Steps = steps;
- }
- }
-
-
- // 更新缓存的定位数据内容
- positionStatus.LastPosition = positionCache;
- positionStatus.RequestPosition = loc.LocationType == 3 ? requestPostionVarObj : null;
- _deviceCacheMgr.SetPositionStatusCache(loc.SerialNo, positionStatus);
- _logger.LogInformation($"设备{loc.SerialNo},设备上报消息到IOT设备时间:{Utils.ConvertToLocalDateTime(sentTicks)},更新缓存时间:{DateTime.Now}|{JsonConvert.SerializeObject(positionStatus)}|实际定位类型:{loc.LocationType}");
-
- }
- //更新设备的坐标缓存(LBS IOT)
- else
- {
- //LBS 定位数据不写入缓存
-
- // 存在非LBS 缓存
- if (cache != null)
- {
- /**
- // 2023/04/12 当LBS定位处理优化:
- // 就是基于LBS与上次有效定位的距离进行分析,
- // 在一个合理的距离则判定LBS有效,
- // 也是需更新缓存并显示。
- // 这个距离可设置,默认大于2000米
-
- **/
- if (false) // 临时开发LBS
- {
- var distance = GeoUtils.GetDistance2((double)cache.GaodeLon, (double)cache.GaodeLat, (double)positionCache.GaodeLon, (double)positionCache.GaodeLat);
- if (distance >= DEFAULT_LBS_ACCEPT_DISTANCE) // 临时开放LBS(false) 说明可能关机下走了很远,此时IOT的定位是LBS,生成的定位缓存也是LBS
- {
- // 使用最新的IOT LBS数据更新定位缓存
- positionStatus.LastPosition = positionCache;
- positionStatus.RequestPosition = loc.LocationType == 3 ? requestPostionVarObj : null;
- _deviceCacheMgr.SetPositionStatusCache(loc.SerialNo, positionStatus);
- _logger.LogInformation($"设备{loc.SerialNo},设备上报消息到IOT设备时间:{Utils.ConvertToLocalDateTime(sentTicks)},更新缓存时间:{DateTime.Now}|缓存内容:{JsonConvert.SerializeObject(positionStatus)}|基于LBS与上次有效定位的距离超过{DEFAULT_LBS_ACCEPT_DISTANCE}米,生成新的LBS定位缓存");
-
- }
- else if (cache.LocationType == (int)LocationType.LBS) // 否则在2000米内,缓存中有LBS的,使用新的IOT LBS数据
- {
- ////LBS定位缓存中原始有效定位与IOT的LBS定位时间差大于1小时更新LBS定位缓存所有数据
- //if (Utils.ConvertToLocalDateTime(sentTicks).Subtract((DateTime)cache.OriginalTime).TotalHours > 1)
- //{
- // positionStatus.LastPosition = positionCache;
- // _deviceCacheMgr.SetPositionStatusCache(loc.SerialNo, positionStatus);
- // _logger.LogInformation($"设备{loc.SerialNo},设备上报消息到IOT设备时间:{Utils.ConvertToLocalDateTime(sentTicks)},更新缓存时间:{DateTime.Now}|缓存内容:{JsonConvert.SerializeObject(positionStatus)}|LBS定位缓存中原始有效定位与IOT的LBS定位时间差小于1小时更新LBS定位缓存所有数据");
- //}
- positionStatus.LastPosition = positionCache;
- positionStatus.RequestPosition = loc.LocationType == 3 ? requestPostionVarObj : null;
- _deviceCacheMgr.SetPositionStatusCache(loc.SerialNo, positionStatus);
- _logger.LogInformation($"设备{loc.SerialNo},设备上报消息到IOT设备时间:{Utils.ConvertToLocalDateTime(sentTicks)},更新缓存时间:{DateTime.Now}|缓存内容:{JsonConvert.SerializeObject(positionStatus)}定位缓存类型是LBS且定位缓存经纬度与 IOT LBS 经纬度直线少于2000米,生成新的LBS定位缓存");
- }
-
- // 4、LBS定位数据定位时间>缓存的定位时间,则更新缓存的定位时间,定数数据还是原有缓存的定位数据,
- //“原始有效定位时间”不变还是原有的缓存数据的时间。
-
- //// LBS定位数据定位时间<缓存的定位时间,直接不处理。
- //if (Utils.ConvertToLocalDateTime(sentTicks) > cache.OriginalTime)
-
- // LBS无效定位只更新时间和步数
- else
- {
- // 更新缓存的定位时间
- cache.UpdateTime = Utils.ConvertToLocalDateTime(sentTicks);
-
- // 定数数据还是原有缓存的定位数据,“原始有效定位时间”不变还是原有的缓存数据的时间。
- positionStatus.LastPosition = cache;
- // 2022/11/23 定位缓存需要增加步数字段实现前端“静止/行走”状态展示
- positionStatus.LastPosition.Steps = steps;
- positionStatus.RequestPosition = loc.LocationType == 3 ? requestPostionVarObj : null;
- _deviceCacheMgr.SetPositionStatusCache(loc.SerialNo, positionStatus);
- _logger.LogInformation($"设备{loc.SerialNo},设备上报消息到IOT设备时间:{Utils.ConvertToLocalDateTime(sentTicks)},更新缓存时间:{DateTime.Now}|缓存内容:{JsonConvert.SerializeObject(positionStatus)}|无效 IOT LBS经纬度|实际IOT定位类型:{loc.LocationType}");
-
- }
-
- }
- else
- {
- positionStatus.LastPosition = positionCache;
- positionStatus.LastPosition.Steps = steps;
- positionStatus.RequestPosition = loc.LocationType == 3 ? requestPostionVarObj : null;
- _deviceCacheMgr.SetPositionStatusCache(loc.SerialNo, positionStatus);
- _logger.LogInformation($"设备{loc.SerialNo},设备上报消息到IOT设备时间:{Utils.ConvertToLocalDateTime(sentTicks)},更新缓存时间:{DateTime.Now}|缓存内容:{JsonConvert.SerializeObject(positionStatus)} 临时开放LBS (覆盖原来有缓存)");
-
- }
-
- }
- // 2022/12/2 若是没有缓存,且一开始定位是LBS,还是要生成缓存(LBS数据)
- else
- {
- // 生成缓存(LBS数据)
- positionStatus.LastPosition = positionCache;
- positionStatus.RequestPosition = loc.LocationType == 3 ? requestPostionVarObj : null;
- _deviceCacheMgr.SetPositionStatusCache(loc.SerialNo, positionStatus);
- _logger.LogInformation($"设备{loc.SerialNo},设备上报消息到IOT设备时间:{Utils.ConvertToLocalDateTime(sentTicks)},更新缓存时间:{DateTime.Now}|缓存内容:{JsonConvert.SerializeObject(positionStatus)}|设备首次定位且是IOT LBS,生成首次LBS数据的定位缓存");
-
- }
-
- }
-
- }
- else
- {
- result.IsHistoryLocation = true;
- }
-
- return result;
- }
- #endregion
- }
- }
|