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.

969 lines
47KB

  1. using GpsCardGatewayPosition.Common.Helper;
  2. using GpsCardGatewayPosition.Model.Cache;
  3. using GpsCardGatewayPosition.Model.Config;
  4. using GpsCardGatewayPosition.Model.Enum;
  5. using GpsCardGatewayPosition.Service.Biz.Iot;
  6. using GpsCardGatewayPosition.Service.Biz.Location.Dto.Wayz;
  7. using GpsCardGatewayPosition.Service.Cache;
  8. using Microsoft.Extensions.Caching.Memory;
  9. using Microsoft.Extensions.Logging;
  10. using Microsoft.Extensions.Options;
  11. using Newtonsoft.Json;
  12. using System;
  13. using System.Collections.Generic;
  14. using System.Linq;
  15. using System.Security.Cryptography;
  16. using System.Text;
  17. using System.Threading.Tasks;
  18. using static GpsCardGatewayPosition.Service.Biz.Location.Dto.Wayz.WayzResponseInfo;
  19. namespace GpsCardGatewayPosition.Service.Biz.Location
  20. {
  21. public class WayzService
  22. {
  23. private const string CACHE_KEY_WAYZ = "Wayz_";
  24. /// <summary>
  25. /// 兼容高德缓存
  26. /// </summary>
  27. // private const string CACHE_KEY_GAODE = "Gaode_";
  28. private const string CACHE_HASH_KEY_LOCATION_SINGLE_WIFI = "#LOCATION_WIFI_INFO_HASH";
  29. public static readonly string[] WAYZ_POI_TYPES =
  30. { "Airport", "Campus", "Education",
  31. "Finance", "Food", "Government",
  32. "Health", "Hospital", "Hotel",
  33. "Institute", "Mall", "Hotel",
  34. "Market", "Office", "Port",
  35. "Residential", "Scenic", "Station" ,
  36. "Tower", "Venue","Entity"};
  37. private readonly DeviceCacheManager _deviceCacheMgr;
  38. private readonly AppsettingsConfig _configAppSettings;
  39. private readonly WayzServicesConfig _configWayzServices;
  40. private readonly HttpHelper _httpHelper;
  41. private readonly DeviceIotOpenService _serviceDeviceIot;
  42. private readonly ILogger<WayzService> _logger;
  43. private readonly IMemoryCache _localCache;
  44. private static object _syncLocker = new object();
  45. private MD5 _md5;
  46. private int _idx = 0; //轮询索引
  47. private int _count = 1; //高德服务接口key组数量
  48. private int WayzDurationSeconds { get; }
  49. public WayzService(DeviceCacheManager deviceCacheMgr,
  50. IOptions<AppsettingsConfig> optConfigAppSettings, IOptions<WayzServicesConfig> optConfigWayzServices,
  51. HttpHelper httpHelper, DeviceIotOpenService serviceDeviceIot, ILogger<WayzService> logger)
  52. {
  53. _deviceCacheMgr = deviceCacheMgr;
  54. _configAppSettings = optConfigAppSettings.Value;
  55. _httpHelper = httpHelper;
  56. _serviceDeviceIot = serviceDeviceIot;
  57. _logger = logger;
  58. _md5 = MD5.Create();
  59. _localCache = new MemoryCache(new MemoryCacheOptions());
  60. //维智接口
  61. _configWayzServices = optConfigWayzServices.Value;
  62. _configWayzServices.Items = _configWayzServices.Items.Where(e => e.EnableConfig == true).ToList();
  63. _count = _configWayzServices.Items.Count;
  64. WayzDurationSeconds = _configAppSettings.WayzDurationSeconds;
  65. }
  66. /// <summary>
  67. /// wifi解析
  68. /// </summary>
  69. /// <param name="serialno"></param>
  70. /// <param name="model"></param>
  71. /// <returns></returns>
  72. public async Task<GetWayzPositionServiceResult> GetWayzWifiAddressAsync(string serialno, WayzWifiRequest model)
  73. {
  74. int wifiCount = model.Location.Wifis.Count;
  75. string wifiMacs = string.Empty;
  76. for (int i = 0; i < wifiCount; i++)
  77. {
  78. wifiMacs += model.Location.Wifis[i].MacAddress;
  79. }
  80. var hashModel = new
  81. {
  82. wifiMacs
  83. };
  84. //model.Asset.Id = serialno;
  85. //var hash = ComputeHash(model);
  86. var hash = ComputeHash(hashModel);
  87. var serviceResult = new GetWayzPositionServiceResult
  88. {
  89. HashParam = hash
  90. };
  91. var cacheKey = CACHE_KEY_WAYZ + $"{hash}";
  92. lock (_syncLocker)
  93. {
  94. var value = _localCache.Get(cacheKey);
  95. if (value != null)
  96. {
  97. _logger.LogWarning($"击中本地缓存 {nameof(_localCache)} 维智地址解析异常(404 position not found),GetWayzWifiAddress wifi解析失败, 参数: {JsonConvert.SerializeObject(value)}");
  98. serviceResult.Flag = false;
  99. serviceResult.CanRetry = false;
  100. return serviceResult;
  101. }
  102. }
  103. // var info = await RedisHelper.GetAsync<WayzWifiResponseInfo>(cacheKey).ConfigureAwait(false);
  104. var info = await RedisHelperWayz.GetAsync<WayzWifiResponseInfo>(cacheKey).ConfigureAwait(false);
  105. //var cacheKey = CACHE_KEY_GAODE + $"{hash}";
  106. //var info = await RedisHelper.GetAsync<GaodeWifiResponseInfo>(cacheKey).ConfigureAwait(false);
  107. var wayzOriginalInputLog = string.Empty;
  108. var wayzOriginalOutputLog = string.Empty;
  109. string result;
  110. try
  111. {
  112. //优先判断查询参数是否有效
  113. if (
  114. model.Location.Wifis.Count == 1
  115. &&
  116. model.Location.Wifis[0].MacAddress.Equals("00:00:00:00:00:00")
  117. )
  118. //if (
  119. // model.Location.Wifis.Count == 1
  120. // ||
  121. // model.Location.Wifis[0].MacAddress.Equals("00:00:00:00:00:00")
  122. // )
  123. {
  124. _logger.LogWarning($"GetWayzWifiAddressAsync wifi解析失败, 定位参数无效: {JsonConvert.SerializeObject(model)}");
  125. serviceResult.CanRetry = false;
  126. return serviceResult;
  127. }
  128. // 判断单wifi
  129. else if (
  130. model.Location.Wifis.Count == 1
  131. &&
  132. !model.Location.Wifis[0].MacAddress.Equals("00:00:00:00:00:00")
  133. )
  134. {
  135. // 通过读取 redis 获取地址
  136. var infoDb7SingleWifi = await RedisHelperDb7.HGetAsync<SingleWifiLocation>(CACHE_HASH_KEY_LOCATION_SINGLE_WIFI, model.Location.Wifis[0].MacAddress).ConfigureAwait(false);
  137. if (infoDb7SingleWifi == null)
  138. {
  139. serviceResult.CanRetry = false;
  140. return serviceResult;
  141. }
  142. _logger.LogInformation($"单 wifi 定位,从 Redis Db7 中读取 KEY: {CACHE_HASH_KEY_LOCATION_SINGLE_WIFI}, FIELD: {model.Location.Wifis[0].MacAddress}");
  143. // infoDb7SingleWifi 的 olat和olng 是 经纬度
  144. var lat = infoDb7SingleWifi.Latitude;//info.Location.Position.Point.Latitude; //
  145. var lng = infoDb7SingleWifi.Longitude;//info.Location.Position.Point.Longitude;
  146. // 地球系 --> 火星系
  147. GeoConvert.Transform(lat, lng, out double mgLat, out double mgLon);
  148. GeoConvert.G2Gps((double)mgLat, (double)mgLon, out double gLat, out double gLng);
  149. serviceResult.Accuracy = 50;
  150. serviceResult.AdCode = "";
  151. serviceResult.Flag = true;
  152. serviceResult.Lat = (decimal)gLat;
  153. serviceResult.Lon = (decimal)gLng;
  154. serviceResult.Poi = "";
  155. serviceResult.Province = infoDb7SingleWifi.Province;
  156. serviceResult.City = infoDb7SingleWifi.City;
  157. serviceResult.CityCode = infoDb7SingleWifi.CityCode;
  158. serviceResult.District = infoDb7SingleWifi.District;
  159. serviceResult.Address = infoDb7SingleWifi.Address;
  160. serviceResult.FullAddress = string.Format("{0}|{1}", "SingleWifi", infoDb7SingleWifi.Address);
  161. return serviceResult;
  162. }
  163. _idx = (_idx + 1) % _count;
  164. string accessKey = _configWayzServices.Items[_idx].AccessKey; //智能硬件解析接口key:wifi解析,lbs解析
  165. string positionBaseUrl = _configWayzServices.Items[_idx].PositionUrl; //高德wifi,lbs解析地址
  166. if (info == null
  167. || info.Location.Address == null
  168. || string.IsNullOrEmpty(info.Location.Address.Name)
  169. || info.Location.Place == null
  170. || string.IsNullOrEmpty(info.Location.Place.Name)
  171. )
  172. // debug
  173. // if (info = null)
  174. {
  175. var url = string.Format(positionBaseUrl, accessKey);
  176. // result = await _httpHelper.HttpToGetAsync(url).ConfigureAwait(false);
  177. //result = await _httpHelper.HttpToPostAsync(url, model).ConfigureAwait(false);
  178. //_logger.LogInformation($"{nameof(GetWayzWifiAddressAsync)}维智请求原始报文: {JsonConvert.SerializeObject(model)}");
  179. //result = await _httpHelper.HttpToPostAsync(url, model).ConfigureAwait(false);
  180. //_logger.LogInformation($"{nameof(GetWayzWifiAddressAsync)}维智返回原始报文: {result}");
  181. wayzOriginalInputLog = $"{nameof(GetWayzWifiAddressAsync)}维智请求原始报文: {JsonConvert.SerializeObject(model)}";
  182. _logger.LogInformation(wayzOriginalInputLog);
  183. result = await _httpHelper.HttpToPostAsync(url, model).ConfigureAwait(false);
  184. var resultText = result.Length >= 2000 ? result.Substring(0, 2000) : result;
  185. wayzOriginalOutputLog = $"{nameof(GetWayzWifiAddressAsync)}维智返回原始报文: {resultText}";
  186. _logger.LogInformation(wayzOriginalOutputLog);
  187. if (!string.IsNullOrWhiteSpace(result))
  188. {
  189. info = JsonConvert.DeserializeObject<WayzWifiResponseInfo>(result);
  190. // 返回原始相应的数据
  191. // serviceResult.OriginalResponse = result;
  192. //if (info != null && info.Status + "" == "1") RedisHelper.SetAsync(cacheKey, info, WayzDurationSeconds);
  193. //if (info != null) RedisHelper.SetAsync(cacheKey, info, WayzDurationSeconds);
  194. Random random = new Random(); // 随机1-2天
  195. if (info != null) await RedisHelperWayz.SetAsync(cacheKey, info, random.Next(7200, 14400));
  196. }
  197. // 没有返回结果,使用本地缓存记录
  198. else
  199. {
  200. _localCache.Set(cacheKey, model, DateTimeOffset.Now.AddMinutes(120));
  201. _logger.LogInformation($"本地缓存 {nameof(_localCache)} 储存维智Wifi地址解析异常(404 position not found),参数: {JsonConvert.SerializeObject(model)}");
  202. }
  203. }
  204. else _logger.LogInformation($"{nameof(GetWayzWifiAddressAsync)}维智Wifi请求击中缓存 {cacheKey}|{JsonConvert.SerializeObject(model.Location.Wifis)}");
  205. //if (info == null || info.Result == null || info.Info + "" != "OK" || info.Status + "" != "1")
  206. if (info == null)
  207. {
  208. serviceResult.Flag = false;
  209. }
  210. else
  211. {
  212. int contextCont = info.Location.Address.Context.Count;
  213. //if (info.Location.Address.Context.Count > 0)
  214. if (contextCont > 0)
  215. {
  216. // 解析地址
  217. int radius;
  218. var accuracy = info.Location.Position.Accuracy.ToString();
  219. _logger.LogInformation($"wayz wifi精度:{accuracy}");
  220. radius = int.TryParse(accuracy, out radius) && radius > 50 ? radius : 50;
  221. // 经纬度
  222. var loc = string.Format("{0},{1}", info.Location.Position.Point.Longitude, info.Location.Position.Point.Latitude) + "";
  223. var poi = info.Location.Place == null ? string.Empty : info.Location.Place.Name;
  224. var adCode = "";
  225. var lat = info.Location.Position.Point.Latitude;
  226. var lng = info.Location.Position.Point.Longitude;
  227. double gLat, gLng;
  228. GeoConvert.G2Gps((double)lat, (double)lng, out gLat, out gLng);
  229. serviceResult.Accuracy = radius;
  230. serviceResult.AdCode = adCode;
  231. serviceResult.Flag = true;
  232. serviceResult.Lat = (decimal)gLat;
  233. serviceResult.Lon = (decimal)gLng;
  234. serviceResult.Poi = poi;
  235. //地址解析
  236. string county = string.Empty;
  237. string province = string.Empty;
  238. string city = string.Empty;
  239. string district = string.Empty;
  240. string addr = string.Empty;
  241. /**
  242. info.Location.Address.Context.ForEach((item) =>
  243. {
  244. switch (item.Type)
  245. {
  246. case "Country":
  247. county = item.Name;
  248. break;
  249. case "Province":
  250. province = item.Name;
  251. break;
  252. case "City":
  253. city = item.Name;
  254. adCode = item.Code;
  255. break;
  256. case "District":
  257. district = item.Name;
  258. break;
  259. default:
  260. addr += item.Name;
  261. break;
  262. }
  263. });
  264. */
  265. for (int i = 0; i < contextCont; i++)
  266. {
  267. switch (info.Location.Address.Context[i].Type)
  268. {
  269. case "Country":
  270. county = info.Location.Address.Context[i].Name;
  271. break;
  272. case "Province":
  273. province = info.Location.Address.Context[i].Name;
  274. break;
  275. case "City":
  276. city = info.Location.Address.Context[i].Name;
  277. adCode = info.Location.Address.Context[i].Code;
  278. break;
  279. case "District":
  280. district = info.Location.Address.Context[i].Name;
  281. break;
  282. default:
  283. addr += info.Location.Address.Context[i].Name;
  284. break;
  285. }
  286. }
  287. // 判断poi是否在分配中显示
  288. // addr = WAYZ_POI_TYPES.Contains(info.Location.Place.Type)?addr+info.Location.Place.Name:addr;
  289. // addr += info.Location.Place == null ? string.Empty : info.Location.Place.Name;//info.Location.Place.Name; // 开放poi
  290. addr += GetFinalPlace(info);
  291. serviceResult.Province = province;
  292. serviceResult.City = city;
  293. serviceResult.CityCode = adCode;
  294. serviceResult.AdCode = adCode;
  295. serviceResult.District = district;
  296. serviceResult.Address = addr;
  297. serviceResult.FullAddress = string.Format("{0}|{1}", info.Location.Place == null ? string.Empty : info.Location.Place.Type, info.Location.Address.Name);
  298. return serviceResult;
  299. }
  300. else
  301. {
  302. serviceResult.Flag = false;
  303. }
  304. }
  305. if (!serviceResult.Flag)
  306. {
  307. _logger.LogWarning($"维智地址解析异常,GetWayzWifiAddressAsync wifi解析失败, 参数: {JsonConvert.SerializeObject(model)}| \n{wayzOriginalInputLog}| \n{wayzOriginalOutputLog}");
  308. }
  309. }
  310. catch (Exception ex)
  311. {
  312. serviceResult.Flag = false;
  313. _logger.LogError($"维智地址解析异常,GetWayzWifiAddressAsync wifi解析异常, 参数: {JsonConvert.SerializeObject(model)}| \n{wayzOriginalInputLog}| \n{wayzOriginalOutputLog}| \n {ex.Message}, {ex.StackTrace}");
  314. }
  315. return serviceResult;
  316. }
  317. /// <summary>
  318. /// lbs解析
  319. /// </summary>
  320. /// <param name="serialno"></param>
  321. /// <param name="model"></param>
  322. /// <returns></returns>
  323. public async Task<GetWayzPositionServiceResult> GetWayzLbsAddressAsync(string serialno, WayzLbsRequest model)
  324. {
  325. /**
  326. * CellId = int.Parse(bts[3]),
  327. //RadioType = "lte",
  328. MobileCountryCode = int.Parse(bts[0]),
  329. MobileNetworkCode = int.Parse(bts[1]),
  330. LocationAreaCode = int.Parse(bts[2]),
  331. */
  332. int lbsCount = model.Location.Cellulars.Count;
  333. string lbsBts = model.Location.Cellulars[0].MobileCountryCode.ToString()
  334. + model.Location.Cellulars[0].MobileCountryCode.ToString()
  335. + model.Location.Cellulars[0].LocationAreaCode.ToString()
  336. + model.Location.Cellulars[0].CellId.ToString()
  337. ;
  338. //for (int i = 0; i < lbsCount; i++)
  339. //{
  340. // lbsBts += model.Location.Cellulars[i].MobileCountryCode.;
  341. //}
  342. var wayzOriginalInputLog = string.Empty;
  343. var wayzOriginalOutputLog = string.Empty;
  344. var hashModel = new
  345. {
  346. lbsBts
  347. //LBSBts = model.Location.Cellulars
  348. };
  349. var hash = ComputeHash(hashModel);
  350. // model.Asset.Id = serialno;
  351. // var hash = ComputeHash(model);
  352. var serviceResult = new GetWayzPositionServiceResult
  353. {
  354. HashParam = hash
  355. };
  356. var cacheKey = CACHE_KEY_WAYZ + $"{hash}";
  357. // var info = await RedisHelper.GetAsync<WayzLbsResponseInfo>(cacheKey).ConfigureAwait(false);
  358. lock (_syncLocker)
  359. {
  360. var value = _localCache.Get(cacheKey);
  361. if (value != null)
  362. {
  363. _logger.LogWarning($"击中本地缓存 {nameof(_localCache)} 维智地址解析异常(404 position not found),GetWayzLbsAddress lbs解析失败, 参数: {JsonConvert.SerializeObject(value)}");
  364. serviceResult.Flag = false;
  365. serviceResult.CanRetry = false;
  366. return serviceResult;
  367. }
  368. }
  369. var info = await RedisHelperWayz.GetAsync<WayzLbsResponseInfo>(cacheKey).ConfigureAwait(false);
  370. string result;
  371. try
  372. {
  373. _idx = (_idx + 1) % _count;
  374. string accessKey = _configWayzServices.Items[_idx].AccessKey;
  375. string positionBaseUrl = _configWayzServices.Items[_idx].PositionUrl;
  376. if (info == null
  377. || info.Location.Address == null
  378. || string.IsNullOrEmpty(info.Location.Address.Name)
  379. || info.Location.Place == null
  380. || string.IsNullOrEmpty(info.Location.Place.Name)
  381. )
  382. {
  383. var url = string.Format(positionBaseUrl, accessKey);
  384. url += "&poi_search_radius=500"; // LBS 要 500 米的 poi 半径
  385. // result = await _httpHelper.HttpToGetAsync(url).ConfigureAwait(false);
  386. //result = await _httpHelper.HttpToPostAsync(url, model).ConfigureAwait(false);
  387. //_logger.LogInformation($"{nameof(GetWayzLbsAddressAsync)}维智请求原始报文: {JsonConvert.SerializeObject(model)}");
  388. //result = await _httpHelper.HttpToPostAsync(url, model).ConfigureAwait(false);
  389. //_logger.LogInformation($"{nameof(GetWayzLbsAddressAsync)}维智返回原始报文: {result}");
  390. wayzOriginalInputLog = $"{nameof(GetWayzLbsAddressAsync)}维智请求原始报文: {JsonConvert.SerializeObject(model)}";
  391. _logger.LogInformation(wayzOriginalInputLog);
  392. result = await _httpHelper.HttpToPostAsync(url, model).ConfigureAwait(false);
  393. var resultText = result.Length >= 2000 ? result.Substring(0, 2000) + "..." : result;
  394. wayzOriginalOutputLog = $"{nameof(GetWayzLbsAddressAsync)}维智返回原始报文: {resultText}";
  395. _logger.LogInformation(wayzOriginalOutputLog);
  396. if (!string.IsNullOrWhiteSpace(result))
  397. {
  398. info = JsonConvert.DeserializeObject<WayzLbsResponseInfo>(result);
  399. // 返回原始相应的数据
  400. // serviceResult.OriginalResponse = result;
  401. //if (info != null && info.Status + "" == "1") RedisHelper.SetAsync(cacheKey, info, WayzDurationSeconds);
  402. //if (info != null) RedisHelper.SetAsync(cacheKey, info, WayzDurationSeconds);
  403. Random random = new Random(); // 随机1-2天
  404. if (info != null) await RedisHelperWayz.SetAsync(cacheKey, info, random.Next(7200, 14400));
  405. }
  406. // 没有返回结果,使用本地缓存记录
  407. else
  408. {
  409. _localCache.Set(cacheKey, model, DateTimeOffset.Now.AddMinutes(120));
  410. _logger.LogInformation($"本地缓存 {nameof(_localCache)} 储存维智lbs地址解析异常(404 position not found),参数: {JsonConvert.SerializeObject(model)}");
  411. }
  412. }
  413. else _logger.LogInformation($"{nameof(GetWayzLbsAddressAsync)}维智LBS请求击中缓存 {cacheKey}|{JsonConvert.SerializeObject(model.Location.Cellulars)}");
  414. if (info == null)
  415. {
  416. serviceResult.Flag = false;
  417. }
  418. else
  419. {
  420. int contextCont = info.Location.Address.Context.Count;
  421. if (contextCont > 0)
  422. {
  423. // 解析地址
  424. int radius;
  425. var accuracy = info.Location.Position.Accuracy.ToString();
  426. _logger.LogInformation($"wayz lbs精度:{accuracy}");
  427. radius = int.TryParse(accuracy, out radius) && radius > 500 ? radius : 500;
  428. // 经纬度
  429. var loc = string.Format("{0},{1}", info.Location.Position.Point.Longitude, info.Location.Position.Point.Latitude) + "";
  430. var poi = info.Location.Place == null ? string.Empty : info.Location.Place.Name;
  431. var adCode = "";
  432. var lat = info.Location.Position.Point.Latitude;
  433. var lng = info.Location.Position.Point.Longitude;
  434. double gLat, gLng;
  435. GeoConvert.G2Gps((double)lat, (double)lng, out gLat, out gLng);
  436. serviceResult.Accuracy = radius;
  437. // serviceResult.AdCode = adCode;
  438. serviceResult.Flag = true;
  439. serviceResult.Lat = (decimal)gLat;
  440. serviceResult.Lon = (decimal)gLng;
  441. serviceResult.Poi = poi;
  442. // 地址解析
  443. string county = string.Empty;
  444. string province = string.Empty;
  445. string city = string.Empty;
  446. string district = string.Empty;
  447. string addr = string.Empty;
  448. /**
  449. info.Location.Address.Context.ForEach((item) =>
  450. {
  451. switch (item.Type)
  452. {
  453. case "Country":
  454. county = item.Name;
  455. break;
  456. case "Province":
  457. province = item.Name;
  458. break;
  459. case "City":
  460. city = item.Name;
  461. adCode = item.Code;
  462. break;
  463. case "District":
  464. district = item.Name;
  465. break;
  466. default:
  467. addr += item.Name;
  468. break;
  469. }
  470. });
  471. */
  472. //int contextCont = info.Location.Address.Context.Count;
  473. for (int i = 0; i < contextCont; i++)
  474. {
  475. switch (info.Location.Address.Context[i].Type)
  476. {
  477. case "Country":
  478. county = info.Location.Address.Context[i].Name;
  479. break;
  480. case "Province":
  481. province = info.Location.Address.Context[i].Name;
  482. break;
  483. case "City":
  484. city = info.Location.Address.Context[i].Name;
  485. adCode = info.Location.Address.Context[i].Code;
  486. break;
  487. case "District":
  488. district = info.Location.Address.Context[i].Name;
  489. break;
  490. default:
  491. addr += info.Location.Address.Context[i].Name;
  492. break;
  493. }
  494. }
  495. // 判断poi是否在分配中显示
  496. // addr = WAYZ_POI_TYPES.Contains(info.Location.Place.Type)?addr+info.Location.Place.Name:addr;
  497. //addr += info.Location.Place == null ? string.Empty : info.Location.Place.Name;//info.Location.Place.Name; // 开放poi
  498. addr += GetFinalPlace(info);
  499. serviceResult.Province = province;
  500. serviceResult.City = city;
  501. serviceResult.CityCode = adCode;
  502. serviceResult.AdCode = adCode;
  503. serviceResult.District = district;
  504. serviceResult.Address = addr;
  505. serviceResult.FullAddress = string.Format("{0}|{1}", info.Location.Place == null ? string.Empty : info.Location.Place.Type, info.Location.Address.Name);
  506. return serviceResult;
  507. }
  508. else
  509. {
  510. serviceResult.Flag = false;
  511. }
  512. }
  513. if (!serviceResult.Flag)
  514. {
  515. _logger.LogWarning($"维智地址解析异常,GetWayzLbsAddress lbs解析失败, 参数: {JsonConvert.SerializeObject(model)}| \n{wayzOriginalInputLog}| \n{wayzOriginalOutputLog}");
  516. }
  517. }
  518. catch (Exception ex)
  519. {
  520. serviceResult.Flag = false;
  521. _logger.LogError($"维智地址解析异常,GetWayzLbsAddress lbs解析异常, 参数: {JsonConvert.SerializeObject(model)}| \n{wayzOriginalInputLog}| \n{wayzOriginalOutputLog}| \n {ex.Message}, {ex.StackTrace}");
  522. }
  523. return serviceResult;
  524. }
  525. /// <summary>
  526. /// gps解析
  527. /// </summary>
  528. /// <param name="serialno">设备imei</param>
  529. /// <param name="model">经纬度</param>
  530. /// <returns></returns>
  531. public async Task<GetWayzPositionServiceResult> GetWayzReGeoAddressAsync(string serialno, WayzGpsRequest model)
  532. {
  533. //model.Asset.Id = serialno;
  534. //var hash = ComputeHash(model);
  535. var serviceResult = new GetWayzPositionServiceResult();
  536. var hash = string.Empty;
  537. var logModelStr = string.Empty;
  538. var wayzOriginalInputLog = string.Empty;
  539. var wayzOriginalOutputLog = string.Empty;
  540. if (model.Location.Gnss != null)
  541. {
  542. var Gnss = model.Location.Gnss.Point.Latitude.ToString() + model.Location.Gnss.Point.Longitude.ToString();
  543. var hashModel = new
  544. {
  545. Gnss
  546. };
  547. hash = ComputeHash(hashModel);
  548. logModelStr = "地球系坐标: " + JsonConvert.SerializeObject(model.Location.Gnss);
  549. }
  550. if (model.Location.Position != null)
  551. {
  552. var Position = model.Location.Position.Point.Latitude.ToString() + model.Location.Position.Point.Longitude.ToString();
  553. var hashModel = new
  554. {
  555. Position
  556. };
  557. hash = ComputeHash(hashModel);
  558. logModelStr = "火星系坐标: " + JsonConvert.SerializeObject(model.Location.Position);
  559. }
  560. serviceResult = new GetWayzPositionServiceResult
  561. {
  562. HashParam = hash
  563. };
  564. var cacheKey = CACHE_KEY_WAYZ + $"{hash}";
  565. lock (_syncLocker)
  566. {
  567. var value = _localCache.Get(cacheKey);
  568. if (value != null)
  569. {
  570. _logger.LogWarning($"击中本地缓存 {nameof(_localCache)} 维智地址解析异常(404 position not found),GetWayzReGeoAddressAddress 逆地理解析失败, 参数: {JsonConvert.SerializeObject(value)}");
  571. serviceResult.Flag = false;
  572. serviceResult.CanRetry = false;
  573. return serviceResult;
  574. }
  575. }
  576. //var info = await RedisHelper.GetAsync<WayzGpsResponseInfo>(cacheKey).ConfigureAwait(false);
  577. var info = await RedisHelperWayz.GetAsync<WayzGpsResponseInfo>(cacheKey).ConfigureAwait(false);
  578. //var info = new WayzGpsResponseInfo();
  579. string result;
  580. try
  581. {
  582. _idx = (_idx + 1) % _count;
  583. string accessKey = _configWayzServices.Items[_idx].AccessKey;
  584. string positionBaseUrl = _configWayzServices.Items[_idx].PositionUrl;
  585. if (info == null
  586. || info.Location.Address == null
  587. || string.IsNullOrEmpty(info.Location.Address.Name)
  588. || info.Location.Place == null
  589. || string.IsNullOrEmpty(info.Location.Place.Name)
  590. )
  591. {
  592. var url = string.Format(positionBaseUrl, accessKey);
  593. // result = await _httpHelper.HttpToGetAsync(url).ConfigureAwait(false);
  594. wayzOriginalInputLog = $"{nameof(GetWayzReGeoAddressAsync)}维智请求原始报文: {JsonConvert.SerializeObject(model)}";
  595. _logger.LogInformation(wayzOriginalInputLog);
  596. result = await _httpHelper.HttpToPostAsync(url, model).ConfigureAwait(false);
  597. var resultText = result.Length >= 2000 ? result.Substring(0, 2000) + "..." : result;
  598. wayzOriginalOutputLog = $"{nameof(GetWayzReGeoAddressAsync)}维智返回原始报文: {resultText}";
  599. _logger.LogInformation(wayzOriginalOutputLog);
  600. if (!string.IsNullOrWhiteSpace(result))
  601. {
  602. info = JsonConvert.DeserializeObject<WayzGpsResponseInfo>(result);
  603. // 返回原始相应的数据
  604. // serviceResult.OriginalResponse = result;
  605. //if (info != null && info.Status + "" == "1") RedisHelper.SetAsync(cacheKey, info, WayzDurationSeconds);
  606. //if (info != null) RedisHelper.SetAsync(cacheKey, info, WayzDurationSeconds);
  607. Random random = new Random(); // 随机1-2天
  608. if (info != null) await RedisHelperWayz.SetAsync(cacheKey, info, random.Next(7200, 14400));
  609. }// 没有返回结果,使用本地缓存记录
  610. else
  611. {
  612. _localCache.Set(cacheKey, model, DateTimeOffset.Now.AddMinutes(120));
  613. _logger.LogInformation($"本地缓存 {nameof(_localCache)} 储存维智GPS逆地址解析异常(404 position not found),参数: {JsonConvert.SerializeObject(model)}");
  614. }
  615. }
  616. else _logger.LogInformation($"{nameof(GetWayzReGeoAddressAsync)}维智GPS击中缓存 {cacheKey}|{logModelStr}");
  617. if (info == null)
  618. {
  619. serviceResult.Flag = false;
  620. }
  621. else
  622. {
  623. int contextCont = info.Location.Address.Context.Count;
  624. if (contextCont > 0)
  625. {
  626. // 解析地址
  627. int radius;
  628. var accuracy = info.Location.Position.Accuracy.ToString();
  629. radius = int.TryParse(accuracy, out radius) ? radius : 50;
  630. // 经纬度
  631. var loc = string.Format("{0},{1}", info.Location.Position.Point.Longitude, info.Location.Position.Point.Latitude) + "";
  632. var poi = info.Location.Place == null ? string.Empty : info.Location.Place.Name;
  633. var adCode = "";
  634. var lat = info.Location.Position.Point.Latitude;
  635. var lng = info.Location.Position.Point.Longitude;
  636. //double gLat, gLng;
  637. //GeoConvert.G2Gps((double)lat, (double)lng, out gLat, out gLng);
  638. serviceResult.Accuracy = radius;
  639. serviceResult.AdCode = adCode;
  640. serviceResult.Flag = true;
  641. serviceResult.Lat = (decimal)lat;
  642. serviceResult.Lon = (decimal)lng;
  643. serviceResult.Poi = poi;
  644. //地址解析
  645. string county = string.Empty;
  646. string province = string.Empty;
  647. string city = string.Empty;
  648. string district = string.Empty;
  649. string addr = string.Empty;
  650. /**
  651. info.Location.Address.Context.ForEach((item) =>
  652. {
  653. switch (item.Type)
  654. {
  655. case "Country":
  656. county = item.Name;
  657. break;
  658. case "Province":
  659. province = item.Name;
  660. break;
  661. case "City":
  662. city = item.Name;
  663. adCode = item.Code;
  664. break;
  665. case "District":
  666. district = item.Name;
  667. break;
  668. default:
  669. addr += item.Name;
  670. break;
  671. }
  672. });
  673. */
  674. for (int i = 0; i < contextCont; i++)
  675. {
  676. switch (info.Location.Address.Context[i].Type)
  677. {
  678. case "Country":
  679. county = info.Location.Address.Context[i].Name;
  680. break;
  681. case "Province":
  682. province = info.Location.Address.Context[i].Name;
  683. break;
  684. case "City":
  685. city = info.Location.Address.Context[i].Name;
  686. adCode = info.Location.Address.Context[i].Code;
  687. break;
  688. case "District":
  689. district = info.Location.Address.Context[i].Name;
  690. break;
  691. default:
  692. addr += info.Location.Address.Context[i].Name;
  693. break;
  694. }
  695. }
  696. // 判断poi是否在分配中显示
  697. // addr = WAYZ_POI_TYPES.Contains(info.Location.Place.Type)?addr+info.Location.Place.Name:addr;
  698. // addr += info.Location.Place == null ? string.Empty : info.Location.Place.Name;//info.Location.Place.Name; // 开放poi
  699. addr += GetFinalPlace(info);
  700. /**
  701. var finalPlace = string.Empty;
  702. if (info.Location.Place == null)
  703. {
  704. if (info.Location.NearbyPlaces != null)
  705. {
  706. foreach (var item in info.Location.NearbyPlaces)
  707. {
  708. var isSchool = item.Name.Contains("小学") || item.Name.Contains("中学");
  709. if (item.Type.Equals("Education")&& isSchool)
  710. {
  711. finalPlace=item.Name;
  712. break;
  713. }
  714. }
  715. }
  716. }
  717. else
  718. {
  719. finalPlace = info.Location.Place.Name;
  720. var isSchool = info.Location.Place.Name.Contains("小学") || info.Location.Place.Name.Contains("中学");
  721. if (info.Location.Place.Type.Equals("Education") && isSchool)
  722. {
  723. }
  724. else
  725. {
  726. if (info.Location.NearbyPlaces != null)
  727. {
  728. foreach (var item in info.Location.NearbyPlaces)
  729. {
  730. isSchool = item.Name.Contains("小学") || item.Name.Contains("中学");
  731. if (item.Type.Equals("Education") && isSchool)
  732. {
  733. finalPlace = item.Name;
  734. break;
  735. }
  736. }
  737. }
  738. }
  739. }
  740. addr += finalPlace;
  741. */
  742. serviceResult.Province = province;
  743. serviceResult.City = city;
  744. serviceResult.CityCode = adCode;
  745. serviceResult.AdCode = adCode;
  746. serviceResult.District = district;
  747. serviceResult.Address = addr;
  748. serviceResult.FullAddress = string.Format("{0}|{1}", info.Location.Place == null ? string.Empty : info.Location.Place.Type, info.Location.Address.Name);
  749. return serviceResult;
  750. }
  751. else
  752. {
  753. serviceResult.Flag = false;
  754. }
  755. }
  756. if (!serviceResult.Flag)
  757. {
  758. _logger.LogWarning($"维智地址解析异常,GetWayzGpsAddressAsync 逆地理解析失败, 参数: {JsonConvert.SerializeObject(model)}| \n{wayzOriginalInputLog}| \n{wayzOriginalOutputLog}");
  759. }
  760. }
  761. catch (Exception ex)
  762. {
  763. serviceResult.Flag = false;
  764. // _logger.LogError($"GetWayzGpsAddressAsync 逆地理解析异常, ({model.Location.Gnss.Point.Longitude},{model.Location.Gnss.Point.Latitude}) \n{ex.Message}, {ex.StackTrace}");
  765. _logger.LogError($"维智地址解析异常,GetWayzGpsAddressAsync 逆地理解析异常, ({logModelStr})| \n{wayzOriginalInputLog}| \n{wayzOriginalOutputLog}| \n{ex.Message}, {ex.StackTrace}");
  766. }
  767. return serviceResult;
  768. }
  769. /// <summary>
  770. /// 从poi和nearbyPlaces 中获取小学和中学优先地址
  771. /// </summary>
  772. /// <param name="info"></param>
  773. /// <returns></returns>
  774. private string GetFinalPlace(WayzResponseInfo info)
  775. {
  776. string finalPlace;
  777. try
  778. {
  779. string GetEducationPlaceName(List<NearbyPlace> nearbyPlaces)
  780. {
  781. if (nearbyPlaces != null)
  782. {
  783. foreach (var item in nearbyPlaces)
  784. {
  785. var isSchool = item.Name.Contains("小学") || item.Name.Contains("中学");
  786. if (item.Type.Equals("Education") && isSchool)
  787. {
  788. return item.Name;
  789. }
  790. }
  791. }
  792. return info.Location.Place == null ? string.Empty : info.Location.Place.Name;
  793. }
  794. if (info.Location.Place == null)
  795. {
  796. finalPlace = GetEducationPlaceName(info.Location.NearbyPlaces);
  797. }
  798. else
  799. {
  800. var isSchool = info.Location.Place.Name.Contains("小学") || info.Location.Place.Name.Contains("中学");
  801. if (info.Location.Place.Type.Equals("Education") && isSchool)
  802. {
  803. finalPlace = info.Location.Place.Name;
  804. }
  805. else
  806. {
  807. finalPlace = GetEducationPlaceName(info.Location.NearbyPlaces);
  808. }
  809. }
  810. }
  811. catch (Exception ex)
  812. {
  813. _logger.LogError($"{nameof(WayzResponseInfo)} 地址解析出错\n{JsonConvert.SerializeObject(info)},\n{ex.Message}\n{ex.StackTrace}");
  814. return info.Location.Place == null ? string.Empty : info.Location.Place.Name;
  815. }
  816. return finalPlace;
  817. }
  818. public async Task SendRealtimeLocationAsync(string imei, DateTime time, RealtimeLocationTypeFlag type = RealtimeLocationTypeFlag.None)
  819. {
  820. var now = DateTime.Now;
  821. //定位信息的时间早于平台当前时间4分钟的,则不进行下发实时定位指令的处理
  822. if (now.Subtract(time).TotalMinutes >= 4) return;
  823. //在30分钟内,只发起一次实时定位给设备
  824. var status = await _deviceCacheMgr.GetPositionStatusCacheAsync(imei);
  825. if (status?.SendGetLocationTime != null && now.Subtract(status.SendGetLocationTime.Value).TotalMinutes < 30) return;
  826. var flags = new List<string>();
  827. if ((type & RealtimeLocationTypeFlag.Gps) == RealtimeLocationTypeFlag.Gps) flags.Add("GPS");
  828. if ((type & RealtimeLocationTypeFlag.Lbs) == RealtimeLocationTypeFlag.Lbs) flags.Add("LBS");
  829. if ((type & RealtimeLocationTypeFlag.Wifi) == RealtimeLocationTypeFlag.Wifi) flags.Add("WIFI");
  830. if (flags.Count == 0) throw new ArgumentException($"请提供有效的实时定位类型{nameof(type)}");
  831. //DeviceOpenApi api = new DeviceOpenApi(_configIot,_serviceGuardMq, _logger);
  832. string args = "{\"command\":\"getLocation\",\"parameter\":\"" + string.Join("|", flags.ToArray()) + "\"}";
  833. var bResult = await _serviceDeviceIot.InvokeThingServiceAsync(imei, "getGeoLocation", args).ConfigureAwait(false);
  834. _logger.LogInformation($"定位解析失败[{imei}],下发立即定位指令,结果: {bResult}");
  835. if (status == null) status = new DevicePositionStatus();
  836. status.SendGetLocationTime = DateTime.Now;
  837. _deviceCacheMgr.SetPositionStatusCache(imei, status);
  838. }
  839. private string ComputeHash(object data)
  840. {
  841. lock (_syncLocker)
  842. {
  843. var value = JsonConvert.SerializeObject(data);
  844. value = Convert.ToBase64String(_md5.ComputeHash(Encoding.UTF8.GetBytes(value)));
  845. return value;
  846. }
  847. }
  848. /// <summary>
  849. /// 维智纠偏
  850. /// </summary>
  851. /// <returns></returns>
  852. public async Task WayzWifiCalbration(WayzWifiRequest request)
  853. {
  854. try
  855. {
  856. var model = new
  857. {
  858. Location = new
  859. {
  860. request.Location.Wifis
  861. }
  862. };
  863. var url = $"https://lotboard-dev.newayz.com/wifis?force=true";
  864. var res = await _httpHelper.HttpToPostAsync(url, model).ConfigureAwait(false);
  865. _logger.LogInformation($"维智纠偏结果{JsonConvert.SerializeObject(res)}");
  866. }
  867. catch (Exception ex)
  868. {
  869. _logger.LogError($"请求纠偏出错\n{ex.Message}\n{ex.StackTrace}");
  870. }
  871. }
  872. }
  873. }