ConnectService.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. using System;
  2. using System.Threading.Tasks;
  3. using JsonRpcLite.Services;
  4. using WingDeviceService.Common;
  5. using WingInterfaceLibrary.DTO.Authentication;
  6. using WingInterfaceLibrary.DTO.Device;
  7. using WingInterfaceLibrary.Enum;
  8. using WingInterfaceLibrary.Interface;
  9. using WingInterfaceLibrary.Request;
  10. using WingInterfaceLibrary.Request.Authentication;
  11. using WingInterfaceLibrary.Request.Device;
  12. using WingInterfaceLibrary.Request.Notification;
  13. using WingInterfaceLibrary.Result.Device;
  14. using WingServerCommon.Log;
  15. using WingServerCommon.Mapper;
  16. using WingServerCommon.Service;
  17. namespace WingDeviceService.Service
  18. {
  19. /// <summary>
  20. /// 鉴权服务
  21. /// </summary>
  22. public partial class DeviceService : JsonRpcService, IConnectService
  23. {
  24. private readonly string _sourceUrl = "cloud.xinglinghui.com";
  25. private readonly object _createShortCodeLocker = new object();
  26. /// <summary>设备连接云服务</summary>
  27. /// <param name="request">请求对象</param>
  28. /// <returns>授权响应</returns>
  29. /// <remarks>POST</remarks>
  30. public async Task<ConnectResult> Connect(ConnectRequest request)
  31. {
  32. try
  33. {
  34. #region Params Check
  35. if (string.IsNullOrWhiteSpace(request.DeviceUniqueCode))
  36. {
  37. throw new RpcException(1001, "DeviceUniqueCode empty error", "DeviceUniqueCode empty error");
  38. }
  39. if (string.IsNullOrWhiteSpace(request.DeviceModel))
  40. {
  41. throw new RpcException(1001, "DeviceModel empty error", "DeviceModel empty error");
  42. }
  43. if (string.IsNullOrWhiteSpace(request.DeviceType))
  44. {
  45. throw new RpcException(1001, "DeviceType empty error", "DeviceType empty error");
  46. }
  47. if (string.IsNullOrWhiteSpace(request.SoftwareVersion))
  48. {
  49. throw new RpcException(1001, "SoftwareVersion empty error", "SoftwareVersion empty error");
  50. }
  51. if (string.IsNullOrWhiteSpace(request.SystemVersion))
  52. {
  53. throw new RpcException(1001, "SystemVersion empty error", "SystemVersion empty error");
  54. }
  55. if (string.IsNullOrWhiteSpace(request.CPUModel))
  56. {
  57. throw new RpcException(1001, "CPUModel empty error", "CPUModel empty error");
  58. }
  59. if (string.IsNullOrWhiteSpace(request.SystemLanguage))
  60. {
  61. throw new RpcException(1001, "SystemLanguage empty error", "SystemLanguage empty error");
  62. }
  63. #endregion
  64. var deviceDto = await _deviceInfoDBServiceProxy.FindDeviceInfoBySerialNumberAsync(request.DeviceUniqueCode);
  65. var shortCode = deviceDto?.ShortCode;
  66. var deviceCode = deviceDto?.DeviceCode;
  67. if (string.IsNullOrWhiteSpace(shortCode))
  68. {
  69. shortCode = GenerateShortCode();
  70. }
  71. if (deviceDto == null)
  72. {
  73. var deviceInfoDB = new DeviceInfoDTO()
  74. {
  75. SerialNumber = request.DeviceUniqueCode,
  76. Name = request.Name,
  77. Description = request.Description,
  78. OrganizationCode = request.OrganizationCode,
  79. DeviceModel = request.DeviceModel,
  80. DeviceType = request.DeviceType,
  81. DeviceSoftwareVersion = request.SoftwareVersion,
  82. ShortCode = shortCode,
  83. SystemVersion = request.SystemVersion,
  84. CPUModel = request.CPUModel,
  85. SystemLanguage = request.SystemLanguage
  86. };
  87. deviceCode = await _deviceInfoDBServiceProxy.InsertDeviceInfoAsync(new WingInterfaceLibrary.DB.Request.CreateDeviceInfoDBRequest
  88. {
  89. Data = deviceInfoDB
  90. });
  91. }
  92. var now = DateTime.UtcNow;
  93. await _deviceInfoDBServiceProxy.UpdateLoginTimeAsync(new WingInterfaceLibrary.DB.Request.UpdateLoginTimeDBRequest
  94. {
  95. DeviceCode = deviceCode,
  96. LastLoginTime = now,
  97. ShortCode = shortCode,
  98. DeviceModel = request.DeviceModel,
  99. DeviceType = request.DeviceType,
  100. SoftwareVersion = request.SoftwareVersion,
  101. SystemVersion = request.SystemVersion,
  102. CPUModel = request.CPUModel,
  103. Description = request.Description,
  104. Name = request.Name,
  105. OrganizationCode = request.OrganizationCode,
  106. SystemLanguage = request.SystemLanguage,
  107. });
  108. var tokenId = await _authenticationServiceProxy.CreateAuthToken(new CreateAuthTokenRequest
  109. {
  110. Code = deviceCode,
  111. IssueTime = now,
  112. SourceUrl = _sourceUrl,
  113. });
  114. await SetDeviceOnlineAsync(deviceCode, true, true);
  115. //注册通知
  116. var subscribeNotifyRequest = new SubscribeNotifyRequest()
  117. {
  118. UserCode = deviceCode,
  119. Token = tokenId
  120. };
  121. var result = await _notificationService.SubscribeNotify(subscribeNotifyRequest);
  122. return new ConnectResult
  123. {
  124. Token = tokenId,
  125. UniqueCode = shortCode
  126. };
  127. }
  128. catch (RpcException)
  129. {
  130. throw;
  131. }
  132. catch (Exception ex)
  133. {
  134. throw new RpcException(1001, ex.Message, ex.InnerException?.Message);
  135. }
  136. }
  137. /// <summary>查询当前设备信息</summary>
  138. /// <param name="request">请求对象</param>
  139. /// <returns>设备信息</returns>
  140. /// <remarks>POST</remarks>
  141. public async Task<CacheDeviceDTO> GetDeviceByToken(TokenRequest request)
  142. {
  143. try
  144. {
  145. var deviceTokenDTO = await _authenticationServiceProxy.GetAuthToken(request);
  146. if (deviceTokenDTO == null || string.IsNullOrWhiteSpace(deviceTokenDTO.Code))
  147. {
  148. throw new RpcException(2004, "Permission validation error", "Permission validation error");
  149. }
  150. var cacheDeviceDTO = await GetDevice(deviceTokenDTO.Code);
  151. if (cacheDeviceDTO == null)
  152. {
  153. throw new RpcException(2004, "deviceInfo not find", "deviceInfo not find");
  154. }
  155. if (cacheDeviceDTO.LastLoginTime > deviceTokenDTO.IssueTime)
  156. {
  157. throw new RpcException(20041, "Permission validation error", "Permission validation error");
  158. }
  159. await SetDeviceOnlineAsync(deviceTokenDTO.Code, true);
  160. return cacheDeviceDTO;
  161. }
  162. catch (RpcException)
  163. {
  164. throw;
  165. }
  166. catch (Exception ex)
  167. {
  168. throw new RpcException(1001, ex.Message, ex.InnerException?.Message);
  169. }
  170. }
  171. /// <summary>设备与云服务断开连接</summary>
  172. /// <param name="request">请求对象</param>
  173. /// <returns>是否成功</returns>
  174. /// <value>true</value>
  175. public async Task<bool> DisConnect(TokenRequest request)
  176. {
  177. try
  178. {
  179. var deviceTokenDTO = await _authenticationServiceProxy.GetAuthToken(request);
  180. if (deviceTokenDTO == null || string.IsNullOrWhiteSpace(deviceTokenDTO.Code))
  181. {
  182. Logger.WriteLineWarn($"DisConnect: invalid token");
  183. }
  184. var cacheDeviceDTO = await GetDevice(deviceTokenDTO.Code);
  185. if (cacheDeviceDTO != null && cacheDeviceDTO.LastLoginTime <= deviceTokenDTO.IssueTime)
  186. {
  187. if (await UpdateLastLoginTime(cacheDeviceDTO))
  188. {
  189. _cacheDeviceManager.Remove(cacheDeviceDTO.DeviceCode);
  190. Logger.WriteLineInfo($"DisConnect: device disconnect success.");
  191. return true;
  192. }
  193. else
  194. {
  195. throw new RpcException(20041, "disconnect error", "disconnect error");
  196. }
  197. }
  198. return true;
  199. }
  200. catch (RpcException)
  201. {
  202. throw;
  203. }
  204. catch (Exception ex)
  205. {
  206. throw new RpcException(1001, ex.Message, ex.InnerException?.Message);
  207. }
  208. }
  209. /// <summary>生成唯一 shortCode</summary>
  210. /// <returns></returns>
  211. private string GenerateShortCode()
  212. {
  213. try
  214. {
  215. lock (_createShortCodeLocker)
  216. {
  217. var uniqueId = new byte[6];
  218. var rand = new Random((int)(DateTime.Now.Ticks % 1000000));
  219. for (int i = 0; i < 6; i++)
  220. {
  221. int randCode;
  222. do
  223. {
  224. randCode = rand.Next(50, 90);
  225. uniqueId[i] = Convert.ToByte(randCode);
  226. } while (randCode >= 58 && randCode <= 64 || randCode == 79 || randCode == 73);
  227. }
  228. return System.Text.Encoding.ASCII.GetString(uniqueId);
  229. }
  230. }
  231. catch (Exception ex)
  232. {
  233. Logger.WriteLineError($"GenerateShortCode error {ex}");
  234. }
  235. return string.Empty;
  236. }
  237. /// <summary>查询设备信息</summary>
  238. /// <param name="deviceCode"></param>
  239. /// <returns></returns>
  240. private async Task<CacheDeviceDTO> GetDevice(string deviceCode)
  241. {
  242. try
  243. {
  244. var cacheDTO = _cacheDeviceManager.Get(deviceCode);
  245. if (cacheDTO == null)
  246. {
  247. var deviceDTO = await _deviceInfoDBServiceProxy.FindDeviceInfoByCodeAsync(deviceCode);
  248. cacheDTO = deviceDTO.MappingTo<CacheDeviceDTO>();
  249. _cacheDeviceManager.AddOrUpdate(cacheDTO.DeviceCode, cacheDTO);
  250. }
  251. return cacheDTO;
  252. }
  253. catch (Exception ex)
  254. {
  255. Logger.WriteLineError($"GetDevice error {ex}");
  256. }
  257. return null;
  258. }
  259. /// <summary>更新设备在线状态</summary>
  260. /// <param name="deviceCode"></param>
  261. /// <param name="isOnline"></param>
  262. /// <param name="refresh"></param>
  263. /// <returns></returns>
  264. private async Task<CacheDeviceDTO> SetDeviceOnlineAsync(string deviceCode, bool isOnline, bool refresh = false)
  265. {
  266. try
  267. {
  268. var cacheDTO = _cacheDeviceManager.Get(deviceCode);
  269. if (cacheDTO == null || refresh)
  270. {
  271. var deviceDTO = await _deviceInfoDBServiceProxy.FindDeviceInfoByCodeAsync(deviceCode);
  272. cacheDTO = deviceDTO.MappingTo<CacheDeviceDTO>();
  273. cacheDTO.IsOnline = isOnline;
  274. cacheDTO.SourceUrl = _sourceUrl;
  275. _cacheDeviceManager.AddOrUpdate(cacheDTO.DeviceCode, cacheDTO);
  276. }
  277. else if (cacheDTO.IsOnline != isOnline)
  278. {
  279. cacheDTO.IsOnline = isOnline;
  280. _cacheDeviceManager.AddOrUpdate(cacheDTO.DeviceCode, cacheDTO);
  281. }
  282. return cacheDTO;
  283. }
  284. catch (Exception ex)
  285. {
  286. Logger.WriteLineError($"SetDeviceOnlineAsync error {ex}");
  287. }
  288. return null;
  289. }
  290. private async Task<bool> UpdateLastLoginTime(DeviceInfoDTO deviceInfo)
  291. {
  292. try
  293. {
  294. var result = await _deviceInfoDBServiceProxy.UpdateLoginTimeAsync(new WingInterfaceLibrary.DB.Request.UpdateLoginTimeDBRequest
  295. {
  296. DeviceCode = deviceInfo.DeviceCode,
  297. LastLoginTime = DateTime.UtcNow,
  298. ShortCode = deviceInfo.ShortCode,
  299. DeviceModel = deviceInfo.DeviceModel,
  300. DeviceType = deviceInfo.DeviceType,
  301. SoftwareVersion = deviceInfo.DeviceSoftwareVersion,
  302. SystemVersion = deviceInfo.SystemVersion,
  303. CPUModel = deviceInfo.CPUModel,
  304. Description = deviceInfo.Description,
  305. Name = deviceInfo.Name,
  306. OrganizationCode = deviceInfo.OrganizationCode,
  307. SystemLanguage = deviceInfo.SystemLanguage,
  308. });
  309. return result;
  310. }
  311. catch (Exception ex)
  312. {
  313. Logger.WriteLineError($"UpdateLastLoginTime err, {ex}");
  314. return false;
  315. }
  316. }
  317. }
  318. }