|
- using GpsCardGatewayPosition.Common.Helper;
- using GpsCardGatewayPosition.Model.Cache;
- using GpsCardGatewayPosition.Model.Config;
- using GpsCardGatewayPosition.Model.Enum;
- using GpsCardGatewayPosition.Service.Biz.Iot;
- using GpsCardGatewayPosition.Service.Biz.Location.Dto.Gaode;
- using GpsCardGatewayPosition.Service.Cache;
- using Microsoft.Extensions.Logging;
- using Microsoft.Extensions.Options;
- using Newtonsoft.Json;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Security.Cryptography;
- using System.Text;
- using System.Text.RegularExpressions;
- using System.Threading.Tasks;
-
- namespace GpsCardGatewayPosition.Service.Biz.Location
- {
- public class GaodeService
- {
- private const string CACHE_KEY_GAODE = "Gaode_";
-
- private readonly DeviceCacheManager _deviceCacheMgr;
- private readonly AppsettingsConfig _configAppSettings;
- private readonly GaodeServicesConfig _configGaodeServices;
- private readonly HttpHelper _httpHelper;
- private readonly DeviceIotOpenService _serviceDeviceIot;
- private readonly ILogger<GaodeService> _logger;
-
- private static object _syncLocker = new object();
- private MD5 _md5;
-
- private int _idx = 0; //轮询索引
- private int _count = 1; //高德服务接口key组数量
-
- private int GaodeDurationSeconds { get; }
-
- public GaodeService(DeviceCacheManager deviceCacheMgr,
- IOptions<AppsettingsConfig> optConfigAppSettings, IOptions<GaodeServicesConfig> optConfigGaodeServices,
- HttpHelper httpHelper, DeviceIotOpenService serviceDeviceIot, ILogger<GaodeService> logger)
- {
- _deviceCacheMgr = deviceCacheMgr;
- _configAppSettings = optConfigAppSettings.Value;
- _httpHelper = httpHelper;
- _serviceDeviceIot = serviceDeviceIot;
- _logger = logger;
-
- _md5 = MD5.Create();
-
- //高德接口
- _configGaodeServices = optConfigGaodeServices.Value;
- _configGaodeServices.Items = _configGaodeServices.Items.Where(e => e.EnableConfig == true).ToList();
- _count = _configGaodeServices.Items.Count;
-
- GaodeDurationSeconds = _configAppSettings.GaodeDurationSeconds;
- }
-
- /// <summary>
- /// wifi解析
- /// </summary>
- /// <param name="serialno"></param>
- /// <param name="model"></param>
- /// <returns></returns>
- public async Task<GetGaodePositionServiceResult> GetGaodeWifiAddressAsync(string serialno, GaodeWifiRequest model)
- {
- var hash = ComputeHash(model);
- var serviceResult = new GetGaodePositionServiceResult
- {
- HashParam = hash
- };
-
- var cacheKey = CACHE_KEY_GAODE + $"{hash}";
- var info = await RedisHelper.GetAsync<GaodeWifiResponseInfo>(cacheKey).ConfigureAwait(false);
- string result;
-
- try
- {
- //优先判断查询参数是否有效
- if (model.Mmac.Equals("00:00:00:00:00:00,0,"))
- {
- _logger.LogWarning($"GetGaodeWifiAddress wifi解析失败, 定位参数无效: {JsonConvert.SerializeObject(model)}");
- serviceResult.CanRetry = false;
- return serviceResult;
- }
-
- _idx = (_idx + 1) % _count;
- string wifiLbsKey = _configGaodeServices.Items[_idx].GaodeWifiKey; //智能硬件解析接口key:wifi解析,lbs解析
- string wifiLbsBaseUrl = _configGaodeServices.Items[_idx].GaodeWifiUrl; //高德wifi,lbs解析地址
-
- if (info == null)
- {
- //http://apilocate.amap.com/position?accesstype={0}&cdma=0&network=gsm&macs={1}&key={2}
- var url = string.Format(wifiLbsBaseUrl, 1, model.Macs, wifiLbsKey);
- url += "&mmac=" + model.Mmac;
- result = await _httpHelper.HttpToGetAsync(url).ConfigureAwait(false);
-
- if (!string.IsNullOrWhiteSpace(result))
- {
- info = JsonConvert.DeserializeObject<GaodeWifiResponseInfo>(result);
- if (info != null && info.Status + "" == "1") RedisHelper.SetAsync(cacheKey, info, GaodeDurationSeconds);
- }
- }
- else _logger.LogInformation($"{nameof(GetGaodeWifiAddressAsync)}击中缓存 {cacheKey}");
-
- if (info == null || info.Result == null || info.Info + "" != "OK" || info.Status + "" != "1")
- {
- serviceResult.Flag = false;
- }
- else
- {
- if (info.Result.Type + "" == "0")
- {
- serviceResult.Flag = false;
- }
- else
- {
- int radius;
- var accuracy = info.Result.Radius + "";
- radius = int.TryParse(accuracy, out radius) ? radius : 35;
-
- var loc = info.Result.Location + "";
- var poi = info.Result.Poi + "";
- var adCode = info.Result.Adcode + "";
-
- var ll = loc.Split(',');
- if (ll.Length == 2)
- {
- var lat = Convert.ToDecimal(ll[1]);
- var lng = Convert.ToDecimal(ll[0]);
- double gLat, gLng;
- GeoConvert.G2Gps((double)lat, (double)lng, out gLat, out gLng);
-
- serviceResult.Accuracy = radius;
- serviceResult.AdCode = adCode;
- serviceResult.Flag = true;
- serviceResult.Lat = (decimal)gLat;
- serviceResult.Lon = (decimal)gLng;
- serviceResult.Poi = poi;
-
- //地址解析
- string province = info.Result.Province;
- string city = info.Result.City;
- string addr = info.Result.Desc;
- string county = null;
-
- var sectors = addr?.Split(" ".ToCharArray()) ?? new string[] { };
- if (sectors.Length > 4 && sectors[0] == province && sectors[1] == city)
- {
- county = sectors[2];
- addr = sectors[3] + sectors[4];
- }
-
- serviceResult.Province = province;
- serviceResult.City = city;
- serviceResult.District = county;
- serviceResult.Address = addr;
- return serviceResult;
- }
- else
- {
- serviceResult.Flag = false;
- }
- }
- }
-
- if (!serviceResult.Flag)
- {
- _logger.LogWarning($"GetGaodeWifiAddress wifi解析失败, 参数: {JsonConvert.SerializeObject(model)}");
- }
- }
- catch (Exception ex)
- {
- serviceResult.Flag = false;
- _logger.LogError($"GetGaodeWifiAddress wifi解析异常, 参数: {JsonConvert.SerializeObject(model)}\n {ex.Message}, {ex.StackTrace}");
- }
-
- return serviceResult;
- }
-
- /// <summary>
- /// lbs解析
- /// </summary>
- /// <param name="serialno"></param>
- /// <param name="model"></param>
- /// <returns></returns>
- public async Task<GetGaodePositionServiceResult> GetGaodeLbsAddressAsync(string serialno, GaodeLbsRequest model)
- {
- var hash = ComputeHash(model);
- var serviceResult = new GetGaodePositionServiceResult
- {
- HashParam = hash
- };
-
- var cacheKey = CACHE_KEY_GAODE + $"{hash}";
- var info = await RedisHelper.GetAsync<GaodeWifiResponseInfo>(cacheKey).ConfigureAwait(false);
- string result;
-
- try
- {
- _idx = (_idx + 1) % _count;
- string wifiLbsKey = _configGaodeServices.Items[_idx].GaodeWifiKey; //智能硬件解析接口key:wifi解析,lbs解析
- string wifiLbsBaseUrl = _configGaodeServices.Items[_idx].GaodeWifiUrl; //高德wifi,lbs解析地址
-
- if (info == null)
- {
- //http://apilocate.amap.com/position?accesstype={0}&cdma=0&network=gsm&macs={1}&key={2}
- var url = string.Format(wifiLbsBaseUrl, 0, "", wifiLbsKey);
- url += "&smac=" + model.Smac;
- url += "&imsi=" + model.Imsi;
- url += "&bts=" + model.Bts;
- if (!string.IsNullOrWhiteSpace(model.NearBts)) url += "&nearbts=" + model.NearBts;
-
- result = await _httpHelper.HttpToGetAsync(url).ConfigureAwait(false);
- if (!string.IsNullOrWhiteSpace(result))
- {
- info = JsonConvert.DeserializeObject<GaodeWifiResponseInfo>(result);
- if (info != null && info.Status + "" == "1") RedisHelper.SetAsync(cacheKey, info, GaodeDurationSeconds);
- }
- }
- else _logger.LogInformation($"{nameof(GetGaodeLbsAddressAsync)}击中缓存 {cacheKey}");
-
- if (info == null || info.Result == null || info.Info + "" != "OK" || info.Status + "" != "1")
- {
- serviceResult.Flag = false;
- }
- else
- {
- if (info.Result.Type + "" == "0")
- {
- serviceResult.Flag = false;
- }
- else
- {
- int radius;
- var accuracy = info.Result.Radius + "";
- radius = int.TryParse(accuracy, out radius) ? radius : 35;
-
- var loc = info.Result.Location + "";
- var poi = info.Result.Poi + "";
- var adCode = info.Result.Adcode + "";
-
- var ll = loc.Split(',');
- if (ll.Length == 2)
- {
- var lat = Convert.ToDecimal(ll[1]);
- var lng = Convert.ToDecimal(ll[0]);
- double gLat, gLng;
- GeoConvert.G2Gps((double)lat, (double)lng, out gLat, out gLng);
-
- serviceResult.Accuracy = radius;
- serviceResult.AdCode = adCode;
- serviceResult.Flag = true;
- serviceResult.Lat = (decimal)gLat;
- serviceResult.Lon = (decimal)gLng;
- serviceResult.Poi = poi;
-
- //地址解析
- string province = info.Result.Province;
- string city = info.Result.City;
- string addr = info.Result.Desc;
- string county = null;
-
- var sectors = addr?.Split(" ".ToCharArray()) ?? new string[] { };
- if (sectors.Length > 4 && sectors[0] == province && sectors[1] == city)
- {
- county = sectors[2];
- addr = sectors[3] + sectors[4];
- }
-
- serviceResult.Province = province;
- serviceResult.City = city;
- serviceResult.District = county;
- serviceResult.Address = addr;
- return serviceResult;
- }
- else
- {
- serviceResult.Flag = false;
- }
- }
- }
-
- if (!serviceResult.Flag)
- {
- _logger.LogWarning($"GetGaodeLbsAddress lbs解析失败, 参数: {JsonConvert.SerializeObject(model)}");
- }
- }
- catch (Exception ex)
- {
- serviceResult.Flag = false;
- _logger.LogError($"GetGaodeLbsAddress lbs解析异常, 参数: {JsonConvert.SerializeObject(model)}\n {ex.Message}, {ex.StackTrace}");
- }
-
- return serviceResult;
- }
-
- /// <summary>
- /// gps解析
- /// </summary>
- /// <param name="serialno">设备imei</param>
- /// <param name="model">高德经纬度</param>
- /// <returns></returns>
- public async Task<GetAddressServiceResult> GetGaodeReGeoAddressAsync(string serialno, GaodeGpsRequest model)
- {
- var hash = ComputeHash(model);
- var serviceResult = new GetAddressServiceResult
- {
- HashParam = hash
- };
-
- var cacheKey = CACHE_KEY_GAODE + $"{hash}";
- var info = await RedisHelper.GetAsync<GaodeGpsResponseInfo>(cacheKey).ConfigureAwait(false);
- string result;
-
- try
- {
- _idx = (_idx + 1) % _count;
- string geoCodeKey = _configGaodeServices.Items[_idx].GaodeRegeoKey; //基础功能解析接口key:gps解析
- string geoCodeBaseUrl = _configGaodeServices.Items[_idx].GaodeRegeoUrl; //高德gps解析地址
-
- if (info == null)
- {
- var url = string.Format(geoCodeBaseUrl, geoCodeKey, model.Longitude, model.Latitude);
- result = await _httpHelper.HttpToGetAsync(url).ConfigureAwait(false);
-
- if (!string.IsNullOrWhiteSpace(result))
- {
- info = JsonConvert.DeserializeObject<GaodeGpsResponseInfo>(result);
- if (info != null && info.Status + "" == "1") RedisHelper.SetAsync(cacheKey, info, GaodeDurationSeconds);
- }
- }
- else _logger.LogInformation($"{nameof(GetGaodeReGeoAddressAsync)}击中缓存 {cacheKey}");
-
- if (info == null || info.Regeocode == null || info.Info + "" != "OK" || info.Status + "" != "1")
- {
- serviceResult.Flag = false;
- }
- else
- {
- //广东省广州市海珠区龙凤街道怡雅苑(马涌直街)
- var tempAddress = info.Regeocode.FormattedAddress + "";
- //龙凤街道
- var townShip = info.Regeocode.AddressComponent.Township + "";
- //城市编码
- var cityCode = info.Regeocode.AddressComponent.Adcode + "";
- var city = info.Regeocode.AddressComponent.City + "";
- var province = info.Regeocode.AddressComponent.Province + "";
- var district = info.Regeocode.AddressComponent.District + "";
-
- if (!string.IsNullOrWhiteSpace(townShip)) //先通过townShip截取地址内容
- {
- var startIndex = tempAddress.IndexOf(townShip);
- tempAddress = tempAddress.Substring(startIndex);
- }
-
- var roads = info.Regeocode.Roads;
- if (roads != null && roads.Count() > 0)
- {
- var addresses = roads.Select(e =>
- {
- var road_name = e.Name + "";
- int idx = tempAddress.IndexOf(road_name);
- idx = idx >= 0 ? idx + road_name.Length : 0;
- return e.Name + tempAddress.Substring(idx);
- }).ToList();
-
- foreach (var addr in addresses)
- {
- if (addr.Length < tempAddress.Length) tempAddress = addr;
- }
- if (!string.IsNullOrWhiteSpace(townShip)) tempAddress = townShip + tempAddress;
-
- serviceResult.Address = tempAddress;
- //如果截取后剩余的字符都是符号(非中文、英文或数字),也当作没数据处理
- Regex reg = new Regex(@"^[\u4e00-\u9fa5a-zA-Z0-9]+$");
- if (!reg.Match(serviceResult.Address).Success)
- {
- serviceResult.Address = tempAddress;
- }
- }
-
- if (string.IsNullOrWhiteSpace(serviceResult.Address)) serviceResult.Address = info.Regeocode.FormattedAddress + "";
-
- serviceResult.Province = province;
- serviceResult.City = city;
- serviceResult.CityCode = cityCode;
- serviceResult.District = district;
- serviceResult.Flag = true;
-
- if (string.IsNullOrWhiteSpace(serviceResult.Address)) throw new Exception("无效地址");
-
- return serviceResult;
- }
-
- if (!serviceResult.Flag)
- {
- _logger.LogWarning($"GetGaodeReGeoAddress 逆地理解析失败, 参数: {JsonConvert.SerializeObject(model)}");
- }
- }
- catch (Exception ex)
- {
- serviceResult.Flag = false;
- _logger.LogError($"GetGaodeReGeoAddress 逆地理解析异常, ({model.Longitude},{model.Latitude}) \n{ex.Message}, {ex.StackTrace}");
- }
-
- return serviceResult;
- }
-
- public async Task SendRealtimeLocationAsync(string imei, DateTime time, RealtimeLocationTypeFlag type = RealtimeLocationTypeFlag.None)
- {
- var now = DateTime.Now;
-
- //定位信息的时间早于平台当前时间4分钟的,则不进行下发实时定位指令的处理
- if (now.Subtract(time).TotalMinutes >= 4) return;
-
- //在30分钟内,只发起一次实时定位给设备
- var status = await _deviceCacheMgr.GetPositionStatusCacheAsync(imei);
- if (status?.SendGetLocationTime != null && now.Subtract(status.SendGetLocationTime.Value).TotalMinutes < 30) return;
-
- var flags = new List<string>();
- if ((type & RealtimeLocationTypeFlag.Gps) == RealtimeLocationTypeFlag.Gps) flags.Add("GPS");
- if ((type & RealtimeLocationTypeFlag.Lbs) == RealtimeLocationTypeFlag.Lbs) flags.Add("LBS");
- if ((type & RealtimeLocationTypeFlag.Wifi) == RealtimeLocationTypeFlag.Wifi) flags.Add("WIFI");
-
- if (flags.Count == 0) throw new ArgumentException($"请提供有效的实时定位类型{nameof(type)}");
-
- //DeviceOpenApi api = new DeviceOpenApi(_configIot,_serviceGuardMq, _logger);
- string args = "{\"command\":\"getLocation\",\"parameter\":\"" + string.Join("|", flags.ToArray()) + "\"}";
- var bResult = await _serviceDeviceIot.InvokeThingServiceAsync(imei, "getGeoLocation", args).ConfigureAwait(false);
- _logger.LogInformation($"定位解析失败[{imei}],下发立即定位指令,结果: {bResult}");
-
- if (status == null) status = new DevicePositionStatus();
- status.SendGetLocationTime = DateTime.Now;
- _deviceCacheMgr.SetPositionStatusCache(imei, status);
- }
-
- private string ComputeHash(object data)
- {
- lock (_syncLocker)
- {
- var value = JsonConvert.SerializeObject(data);
- value = Convert.ToBase64String(_md5.ComputeHash(Encoding.UTF8.GetBytes(value)));
- return value;
- }
- }
- }
- }
|