平安校园
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 
 
 

735 řádky
38 KiB

  1. using System.Drawing;
  2. using System.Drawing.Imaging;
  3. using System.Net.WebSockets;
  4. using System.Text;
  5. using MoYu.DataEncryption;
  6. using MoYu.RemoteRequest.Extensions;
  7. using Newtonsoft.Json;
  8. using Newtonsoft.Json.Linq;
  9. using SafeCampus.Application.Services.Business.AttendanceService;
  10. using SafeCampus.Application.Services.Business.ClassRoomCallService;
  11. using SafeCampus.Application.Services.Business.Warn.Dto;
  12. using SafeCampus.Application.Services.Business.Warn.Service;
  13. namespace SafeCampus.Application.Manager.DeepelephManager;
  14. /// <summary>
  15. /// 深象智能对接实现
  16. /// </summary>
  17. public class DeepelephManager : IDeepelephManager, IScoped
  18. {
  19. private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
  20. private bool _isConnected = false;
  21. private Timer _pingTimer;
  22. private List<ClientWebSocket> webScokets=new List<ClientWebSocket>();
  23. private readonly ISimpleCacheService _simpleCacheService;
  24. public DeepelephManager(ISimpleCacheService simpleCacheService)
  25. {
  26. _simpleCacheService = simpleCacheService;
  27. }
  28. //获取地址
  29. //建立请求,发送订阅参数
  30. //遍历等待接收消息
  31. public string GetToken()
  32. {
  33. var cacheToken = _simpleCacheService.Get<string>(AuthConstants.SXTOKEN);
  34. if (cacheToken != null) return cacheToken;
  35. return GenSXToken();
  36. }
  37. /// <summary>
  38. /// 获取深象智能Token
  39. /// </summary>
  40. /// <returns></returns>
  41. private string GenSXToken()
  42. {
  43. var token = "";
  44. var setting = App.GetOptionsMonitor<AppInfoOptions>();
  45. var nonce = Guid.NewGuid().ToString("N");
  46. var timestamp =DateTimeOffset.Now.ToUnixTimeMilliseconds();
  47. var list = $"{setting.SXAPIURL}/user/center/v1/login/client"
  48. .SetBody(new
  49. {
  50. appKey = setting.AppKey,
  51. appSecret = setting.AppSecret,
  52. nonce ,
  53. timestamp,
  54. sign = MD5Encryption.Encrypt($"{setting.AppSecret}appKey{setting.AppKey}nonce{nonce}timestamp{timestamp}{setting.AppSecret}",true)
  55. })
  56. .SetContentType("application/json")
  57. .PostAsAsync<string>().Result;
  58. var model = JsonConvert.DeserializeObject<JObject>(list);
  59. if (model["success"]!=null)
  60. {
  61. if ((bool)model["success"])
  62. {
  63. token = model["data"]["token"].ToString();
  64. //token有效期2小时,提前20分钟失效
  65. _simpleCacheService.Set(AuthConstants.SXTOKEN, token, 100*60);
  66. }
  67. else
  68. {
  69. LogHelper.WriteToLog("token请求失败", model["message"].ToString());
  70. }
  71. }
  72. return token;
  73. }
  74. /// <summary>
  75. /// 订阅预警更新
  76. /// </summary>
  77. /// <returns></returns>
  78. public async Task SubscribeAlarm()
  79. {
  80. var setting = App.GetOptionsMonitor<AppInfoOptions>();
  81. var timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds();
  82. var url = GetWebSocketUrl(AuthConstants.SXALARM, AuthConstants.SXALARM_Grpup);
  83. var subscribeJson = JsonConvert.SerializeObject(new
  84. {
  85. token = GetToken(),
  86. type = "subscribe",
  87. timestamp,
  88. payload = new
  89. {
  90. topic = AuthConstants.SXALARM, consumerGroup = AuthConstants.SXALARM_Grpup, tags = setting.TenantCode
  91. }
  92. });
  93. ClientWebSocket _webSocket = new ClientWebSocket();
  94. webScokets.Add(_webSocket);
  95. await _webSocket.ConnectAsync(new Uri(url), CancellationToken.None);
  96. //LogHelper.WriteToLog($"预警WebSocket 地址:{url}");
  97. await _webSocket.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(subscribeJson)), WebSocketMessageType.Text, true, CancellationToken.None);
  98. byte[] buffer = new byte[1024*8];
  99. while (_webSocket.State == WebSocketState.Open)
  100. {
  101. //try
  102. //{
  103. // var jsonstr =
  104. // "{\"body\":{\"extend\":\"{\\\"trackId\\\":\\\"7173252404809024768\\\",\\\"genderScore\\\":[0.0,1.0,0.0],\\\"faceSnapshot\\\":\\\"http://deepvision.oss-cn-zhangjiakou.aliyuncs.com/acp/quanjiang/DEMO00001/20240719/edge/group/SXT001_book_wm_1721360996798_55.jpg?Expires=1721368200&OSSAccessKeyId=STS.NSwBDiH7ZnNGS9m2ahE8XyuW6&Signature=dEBXyrWcz3FyXMqDueIkZL%2F9uhk%3D&security-token=CAIS0wN1q6Ft5B2yfSjIr5DCCf7dpeh72YysUR%2Fc1mE9Sbd0lrD81Dz2IHFMf3huCeodsv8%2BlGxS5%2FgelrpqVpZDR03Na8RHwrly1lv5O9KY4zJySB7g0s%2FLI3OaLjKm9hi7AYygPgK0GJqEb1TDiVUto9%2FTfimjWFqIKICAjYUdAP0cQgi%2Fa0gwZrJRPRAwh8IGEnHTOP2xUHvtmXGCNFd0nQB%2BhGhjk7TdpPeR8R3Dllb35%2FYIroDqWPieYtJrIY10XqWBvqx%2FfbGT1zVLuVoYtvV6gaFc5zbcv9abRFVf4hiCP6%2Ff6MBuNw5%2Fae94efZNp%2BOukuZj6K6B1db7xhtVI%2BBOUiPZA4mr2IzdBeqvNNcwc7m8F1no9YjXbsGs9EEGGStLaVgVI4F8dyAhWEd9FWjgR%2FX5qAyQUGCKULOY1aw6651xwmjz8MCCT1r1GOTBindGasVnMxh5Z0JMjDK9aNkKfgFUbVJ8BrGTCIh%2FYx0bsq7yowDIEyp71TRMo%2Bbu%2FDBhIifKpO4VN7AxMup1DPwu2wNCxKTpyjlP%2FAxd8uAx9DyyfH1x3TObqd7jjqzaKs3NYdtswV4BUlvK5CGWEjhzQEO8mJtNIDT39ay%2BVK8NrfsIeBqAATzzKDWbI1DbvfIwuHS6%2BX5i%2FQ0%2BgbpA87Kw%2BQiZxZdvjHXLLqQaYmTRXkuFPxUqNR8BckkEiPPkSs%2B9UQm3Cwq6rnEFeZty8FvEKds5Wo3H2QevhGwkKNImDp%2BmIjF2gzxOSfDv5rBvJWanWW0ewZdlFeiIR88SRvtr10jyoV4OIAA%3D\\\",\\\"faceSnapshotPath\\\":\\\"deepvision:acp/quanjiang/DEMO00001/20240719/edge/group/SXT001_book_wm_1721360996798_55.jpg\\\",\\\"faceScore\\\":30.105469}\",\"alarmType\":\"mask_detect\",\"func\":\"mask_detect\",\"cameraId\":\"SXT001\",\"alarmId\":\"1600d5874d854f1da54e663ae56c845f\",\"snapshotUrl\":\"http://deepvision.oss-cn-zhangjiakou.aliyuncs.com/acp/quanjiang/DEMO00001/20240719/edge/group/SXT001/SXT001_69bde610-a957-434b-a7ce-834aee148b2b_wm_56.jpg?Expires=1721368200&OSSAccessKeyId=STS.NSwBDiH7ZnNGS9m2ahE8XyuW6&Signature=hb6DQLWwZqukNQdel0TsUctAwAE%3D&security-token=CAIS0wN1q6Ft5B2yfSjIr5DCCf7dpeh72YysUR%2Fc1mE9Sbd0lrD81Dz2IHFMf3huCeodsv8%2BlGxS5%2FgelrpqVpZDR03Na8RHwrly1lv5O9KY4zJySB7g0s%2FLI3OaLjKm9hi7AYygPgK0GJqEb1TDiVUto9%2FTfimjWFqIKICAjYUdAP0cQgi%2Fa0gwZrJRPRAwh8IGEnHTOP2xUHvtmXGCNFd0nQB%2BhGhjk7TdpPeR8R3Dllb35%2FYIroDqWPieYtJrIY10XqWBvqx%2FfbGT1zVLuVoYtvV6gaFc5zbcv9abRFVf4hiCP6%2Ff6MBuNw5%2Fae94efZNp%2BOukuZj6K6B1db7xhtVI%2BBOUiPZA4mr2IzdBeqvNNcwc7m8F1no9YjXbsGs9EEGGStLaVgVI4F8dyAhWEd9FWjgR%2FX5qAyQUGCKULOY1aw6651xwmjz8MCCT1r1GOTBindGasVnMxh5Z0JMjDK9aNkKfgFUbVJ8BrGTCIh%2FYx0bsq7yowDIEyp71TRMo%2Bbu%2FDBhIifKpO4VN7AxMup1DPwu2wNCxKTpyjlP%2FAxd8uAx9DyyfH1x3TObqd7jjqzaKs3NYdtswV4BUlvK5CGWEjhzQEO8mJtNIDT39ay%2BVK8NrfsIeBqAATzzKDWbI1DbvfIwuHS6%2BX5i%2FQ0%2BgbpA87Kw%2BQiZxZdvjHXLLqQaYmTRXkuFPxUqNR8BckkEiPPkSs%2B9UQm3Cwq6rnEFeZty8FvEKds5Wo3H2QevhGwkKNImDp%2BmIjF2gzxOSfDv5rBvJWanWW0ewZdlFeiIR88SRvtr10jyoV4OIAA%3D\",\"rects\":[{\"top\":601,\"left\":1156,\"width\":235,\"height\":767}],\"poiId\":\"DEMO00001\",\"tenantCode\":\"quanjiang\",\"tick\":1721360953398},\"bornTimestamp\":1721361000758,\"consumerGroup\":\"GID_quanjiang_risk\",\"keys\":\"1600d5874d854f1da54e663ae56c845f\",\"messageId\":\"AC14058A00017A07C5B45F3C813680EC\",\"queueId\":4,\"queueOffset\":422853,\"tags\":\"quanjiang\",\"topic\":\"ECOLOGY_PAAS_RISK_ALARM\",\"type\":\"msg\"}";
  105. // var json = JsonConvert.DeserializeObject<JObject>(jsonstr);
  106. // if (json["type"].ToString() == "msg")
  107. // {
  108. // var body = json["body"];
  109. // if (body != null)
  110. // {
  111. // PersonType personEnum;
  112. // if (!Enum.TryParse(body["alarmType"].ToString(), out AlarmType dayEnum))
  113. // {
  114. // dayEnum = AlarmType.visual_fence;
  115. // }
  116. // if (body["extend"] != null)
  117. // {
  118. // var extend = JsonConvert.DeserializeObject<JObject>(body["extend"].ToString());
  119. // if (extend["personType"] != null)
  120. // {
  121. // if (!Enum.TryParse(body["extend"]?["personType"]?.ToString(), out personEnum))
  122. // {
  123. // personEnum = PersonType.unkonwn;
  124. // }
  125. // }
  126. // else
  127. // {
  128. // personEnum = PersonType.unkonwn;
  129. // }
  130. // }
  131. // else
  132. // {
  133. // personEnum = PersonType.unkonwn;
  134. // }
  135. // var model = new WarnInfoDto
  136. // {
  137. // TenantCode = body["tenantCode"]?.ToString(),
  138. // PoiId = body["poiId"]?.ToString(),
  139. // AlarmId = body["alarmId"]?.ToString(),
  140. // AlarmType = body["alarmType"]?.ToString(),
  141. // AlarmTypeDesc = dayEnum.GetDescription(),
  142. // CameraId = body["cameraId"]?.ToString(),
  143. // Tick = TimestampToDateTime(body["tick"].ToString()),
  144. // SnapshotUrl = body["snapshotUrl"]?.ToString(),
  145. // Rects = body["rects"]?.ToString(),
  146. // Tags = body["tags"]?.ToString(),
  147. // Extend = body["extend"]?.ToString(),
  148. // PersonType = personEnum.GetDescription(),
  149. // WarnHand = 0,
  150. // };
  151. // var signImg = Path.Combine(Directory.GetCurrentDirectory(), "Files", App.Configuration["AppInfo:AlarmImg"], model.AlarmId + ".jpg");
  152. // var steam = await model.SnapshotUrl.GetAsByteArrayAsync();
  153. // model.SnapshotUrl = $"http://192.168.10.186:8003/Files/alarmImg/{model.AlarmId}.jpg";
  154. // using (MemoryStream ms = new MemoryStream(steam))
  155. // {
  156. // using (Bitmap bmp = new Bitmap(ms))
  157. // {
  158. // using (Graphics g = Graphics.FromImage(bmp))
  159. // {
  160. // using (Pen pen = new Pen(Color.Red, 3))
  161. // {
  162. // foreach (var item in body["rects"])
  163. // {
  164. // Rectangle rect = new Rectangle((int)item["left"], (int)item["top"], (int)item["width"], (int)item["height"]);
  165. // g.DrawRectangle(pen, rect);
  166. // }
  167. // }
  168. // }
  169. // bmp.Save(signImg, ImageFormat.Jpeg);
  170. // }
  171. // }
  172. // //await model.SnapshotUrl.GetToSaveAsync(signImg);
  173. // Scoped.Create((_, scope) =>
  174. // {
  175. // var services = scope.ServiceProvider;
  176. // var _repository = services.GetService<IWarnInfoService>();
  177. // _repository.Add(model);
  178. // });
  179. // }
  180. // }
  181. //}
  182. //catch (Exception e)
  183. //{
  184. //}
  185. WebSocketReceiveResult result = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
  186. if (result.MessageType == WebSocketMessageType.Text)
  187. {
  188. try
  189. {
  190. string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
  191. var json = JsonConvert.DeserializeObject<JObject>(message);
  192. if (json["type"].ToString() == "msg")
  193. {
  194. //TODO 发送短信
  195. //TxySmsUtil.SendSms(new[] { "" }, new[] { "" });
  196. var body = json["body"];
  197. if (body != null)
  198. {
  199. var model = new WarnInfoDto
  200. {
  201. TenantCode = body["tenantCode"]?.ToString(),
  202. PoiId = body["poiId"]?.ToString(),
  203. AlarmId = body["alarmId"]?.ToString(),
  204. AlarmType = body["alarmType"]?.ToString(),
  205. //AlarmTypeDesc = dayEnum.GetDescription(),
  206. CameraId = body["cameraId"]?.ToString(),
  207. Tick = TimestampToDateTime(body["tick"].ToString()),
  208. SnapshotUrl = body["snapshotUrl"]?.ToString(),
  209. Rects = body["rects"]?.ToString(),
  210. Tags = body["tags"]?.ToString(),
  211. Extend = body["extend"]?.ToString(),
  212. //PersonType = personEnum.GetDescription(),
  213. WarnHand = 0,
  214. };
  215. PersonType personEnum;
  216. if (!Enum.TryParse(body["alarmType"].ToString(), out AlarmType dayEnum))
  217. {
  218. dayEnum = AlarmType.visual_fence;
  219. }
  220. if (body["extend"] != null)
  221. {
  222. var extend = JsonConvert.DeserializeObject<JObject>(body["extend"].ToString());
  223. model.PersonId = extend?["personId"]?.ToString();
  224. model.PersonSetId =extend?["personSetId"]?.ToString();
  225. model.ClothId =extend?["clothId"]?.ToString();
  226. model.ClothsSetId =extend?["clothsSetId"]?.ToString();
  227. model.Gender =extend?["genderScore"]?.ToString();
  228. model.TrackId =extend?["trackId"]?.ToString();
  229. model.SpeedLevel =extend?["speedLevel"]?.ToString();
  230. if (extend["clothSimilarity"] !=null)
  231. model.ClothSimilarity = extend?["clothSimilarity"]?.ParseToFloat();
  232. if (extend["count"] != null)
  233. model.Count = extend?["count"]?.ParseToInt();
  234. if (extend["duration"] != null)
  235. model.Duration = extend?["duration"]?.ParseToInt();
  236. if (extend["faceSimilarity"] != null)
  237. model.FaceSimilarity = extend?["faceSimilarity"]?.ParseToFloat();
  238. if (extend["maxAroundTracks"] != null)
  239. model.MaxAroundTracks = extend?["maxAroundTracks"]?.ParseToInt();
  240. if (extend["genderScore"] != null)
  241. {
  242. if ((float)extend["genderScore"][0] > 0.6)
  243. {
  244. model.Gender = "男性";
  245. }
  246. else if ((float)extend["genderScore"][1] > 0.6)
  247. {
  248. model.Gender = "女性";
  249. }
  250. else if ((float)extend["genderScore"][2] > 0.6)
  251. {
  252. model.Gender = "不确定";
  253. }
  254. }
  255. if (extend["personType"] != null)
  256. {
  257. if (!Enum.TryParse(extend?["personType"]?.ToString(), out personEnum))
  258. {
  259. personEnum = PersonType.unkonwn;
  260. }
  261. }
  262. else
  263. {
  264. personEnum = PersonType.unkonwn;
  265. }
  266. }
  267. else
  268. {
  269. personEnum = PersonType.unkonwn;
  270. }
  271. model.AlarmTypeDesc = dayEnum.GetDescription();
  272. model.PersonType = personEnum.GetDescription();
  273. var signImg = Path.Combine(Directory.GetCurrentDirectory(), "Files", App.Configuration["AppInfo:AlarmImg"], model.AlarmId + ".jpg");
  274. var steam = await model.SnapshotUrl.GetAsByteArrayAsync();
  275. model.SnapshotUrl = $"/Files/{App.Configuration["AppInfo:AlarmImg"]}/{model.AlarmId}.jpg";
  276. using (MemoryStream ms = new MemoryStream(steam))
  277. {
  278. using (Bitmap bmp = new Bitmap(ms))
  279. {
  280. using (Graphics g = Graphics.FromImage(bmp))
  281. {
  282. using (Pen pen = new Pen(Color.Red, 3))
  283. {
  284. foreach (var item in body["rects"])
  285. {
  286. Rectangle rect = new Rectangle((int)item["left"], (int)item["top"], (int)item["width"], (int)item["height"]);
  287. g.DrawRectangle(pen, rect);
  288. }
  289. }
  290. }
  291. bmp.Save(signImg, ImageFormat.Jpeg);
  292. }
  293. }
  294. Scoped.Create((_, scope) =>
  295. {
  296. var services = scope.ServiceProvider;
  297. var _repository = services.GetService<IWarnInfoService>();
  298. _repository.Add(model);
  299. });
  300. }
  301. }
  302. else if (json["type"].ToString() == "cmd")
  303. {
  304. if ((bool)json["success"])
  305. {
  306. if (json["message"].ToString().Contains("connect success"))
  307. {
  308. LogHelper.WriteToLog("预警连接成功");
  309. }
  310. else if (json["message"].ToString().Contains("subscribe success"))
  311. {
  312. LogHelper.WriteToLog("预警订阅成功");
  313. }
  314. }
  315. }
  316. }
  317. catch (Exception e)
  318. {
  319. LogHelper.WriteToLog($"收到: {Encoding.UTF8.GetString(buffer, 0, result.Count)}");
  320. LogHelper.WriteToLog("预警webSocket处理异常");
  321. LogHelper.WriteToLog(e, "预警webSocket处理异常");
  322. }
  323. }
  324. else if (result.MessageType == WebSocketMessageType.Close)
  325. {
  326. LogHelper.WriteToLog("WebSocket 连接已被服务器关闭");
  327. break;
  328. }
  329. }
  330. LogHelper.WriteToLog("预警webSocket关闭");
  331. }
  332. /// <summary>
  333. /// 订阅点名事件
  334. /// </summary>
  335. /// <returns></returns>
  336. public async Task SubscriberRoomCall()
  337. {
  338. var setting = App.GetOptionsMonitor<AppInfoOptions>();
  339. var timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds();
  340. var url = GetWebSocketUrl(AuthConstants.SXROOM_CALL, AuthConstants.SXROOM_CAL_Group);
  341. var subscribeJson = JsonConvert.SerializeObject(new
  342. {
  343. token = GetToken(),
  344. type = "subscribe",
  345. timestamp,
  346. payload = new
  347. {
  348. topic = AuthConstants.SXROOM_CALL, consumerGroup = AuthConstants.SXROOM_CAL_Group, tags = setting.TenantCode
  349. }
  350. });
  351. ClientWebSocket _webSocket = new ClientWebSocket();
  352. webScokets.Add(_webSocket);
  353. await _webSocket.ConnectAsync(new Uri(url), CancellationToken.None);
  354. //LogHelper.WriteToLog($"点名WebSocket 地址:{url}");
  355. await _webSocket.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(subscribeJson)), WebSocketMessageType.Text, true, CancellationToken.None);
  356. byte[] buffer = new byte[1024*8];
  357. while (_webSocket.State == WebSocketState.Open)
  358. {
  359. WebSocketReceiveResult result = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
  360. if (result.MessageType == WebSocketMessageType.Text)
  361. {
  362. try
  363. {
  364. string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
  365. //LogHelper.WriteToLog($"收到: {message}");
  366. var json = JsonConvert.DeserializeObject<JObject>(message);
  367. if (json["type"].ToString() == "msg")
  368. {
  369. var body = json["body"];
  370. if (body != null)
  371. {
  372. //TODO 发送短信
  373. //TxySmsUtil.SendSms(new[] { "" }, new[] { "" });
  374. //TODO 由于未知道数据格式暂不写处理
  375. if (!Enum.TryParse(body["alarmType"].ToString(), out AlarmType dayEnum))
  376. {
  377. dayEnum = AlarmType.class_room_call;
  378. }
  379. var model = new ClassRoomCallDto
  380. {
  381. TenantCode = body["tenantCode"]?.ToString(),
  382. PoiId = body["poiId"]?.ToString(),
  383. TaskId = body["taskId"]?.ToString(),
  384. AlarmType = body["alarmType"].ToString(),
  385. AlarmTypeDesc = dayEnum.GetDescription(),
  386. EventId = body["eventId"]?.ToString(),
  387. CameraId = body["cameraId"]?.ToString(),
  388. Tick = TimestampToDateTime(body["tick"]?.ToString()),
  389. PersonSetId = body["personSetId"]?.ToString(),
  390. PersonId = body["personId"]?.ToString(),
  391. Similarity = body["similarity"] != null ? (float)body["similarity"] : 0,
  392. FaceScore = body["faceScore"] != null ? (float)body["faceScore"] : 0,
  393. SnapshotUrl = body["snapshotUrl"]?.ToString(),
  394. SnapshotData = body["snapshotData"]?.ToString(),
  395. Rects = body["rects"]?.ToString(),
  396. Extend = body["extend"]?.ToString(),
  397. CreateTime = DateTime.Now,
  398. TrackId = body["TrackId"]?.ToString()
  399. };
  400. var signImg = Path.Combine(Directory.GetCurrentDirectory(), "Files", App.Configuration["AppInfo:RoomCallImg"], model.EventId + ".jpg");
  401. var steam = await model.SnapshotUrl.GetAsByteArrayAsync();
  402. model.SnapshotUrl = $"/Files/{App.Configuration["AppInfo:RoomCallImg"]}/{model.EventId}.jpg";
  403. using (MemoryStream ms = new MemoryStream(steam))
  404. {
  405. using (Bitmap bmp = new Bitmap(ms))
  406. {
  407. using (Graphics g = Graphics.FromImage(bmp))
  408. {
  409. using (Pen pen = new Pen(Color.Red, 3))
  410. {
  411. foreach (var item in body["rects"])
  412. {
  413. Rectangle rect = new Rectangle((int)item["left"], (int)item["top"], (int)item["width"], (int)item["height"]);
  414. g.DrawRectangle(pen, rect);
  415. }
  416. }
  417. }
  418. bmp.Save(signImg, ImageFormat.Jpeg);
  419. }
  420. }
  421. Scoped.Create((_, scope) =>
  422. {
  423. var services = scope.ServiceProvider;
  424. var _repository = services.GetService<IClassRoomCallService>();
  425. _repository.Add(model);
  426. });
  427. }
  428. }
  429. else if (json["type"].ToString() == "cmd")
  430. {
  431. if ((bool)json["success"])
  432. {
  433. if (json["message"].ToString().Contains("connect success"))
  434. {
  435. LogHelper.WriteToLog("点名连接成功");
  436. }
  437. else if (json["message"].ToString().Contains("subscribe success"))
  438. {
  439. LogHelper.WriteToLog("点名订阅成功");
  440. }
  441. }
  442. }
  443. }
  444. catch (Exception e)
  445. {
  446. LogHelper.WriteToLog($"收到: {Encoding.UTF8.GetString(buffer, 0, result.Count)}");
  447. LogHelper.WriteToLog("点名webSocket处理异常");
  448. LogHelper.WriteToLog(e, "点名webSocket处理异常");
  449. }
  450. }
  451. else if (result.MessageType == WebSocketMessageType.Close)
  452. {
  453. LogHelper.WriteToLog("点名WebSocket 连接已被服务器关闭");
  454. break;
  455. }
  456. }
  457. LogHelper.WriteToLog("点名webSocket已关闭");
  458. }
  459. /// <summary>
  460. /// 订阅无感考勤
  461. /// </summary>
  462. /// <returns></returns>
  463. public async Task SubscriberAttendance()
  464. {
  465. var setting = App.GetOptionsMonitor<AppInfoOptions>();
  466. var timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds();
  467. var url = GetWebSocketUrl(AuthConstants.SXECOLOGY_ATTENDANCE, AuthConstants.SXECOLOGY_ATTENDANCE_Group);
  468. var subscribeJson = JsonConvert.SerializeObject(new
  469. {
  470. token = GetToken(),
  471. type = "subscribe",
  472. timestamp,
  473. payload = new
  474. {
  475. topic = AuthConstants.SXECOLOGY_ATTENDANCE,
  476. consumerGroup = AuthConstants.SXECOLOGY_ATTENDANCE_Group,
  477. tags = setting.TenantCode
  478. }
  479. });
  480. ClientWebSocket _webSocket = new ClientWebSocket();
  481. webScokets.Add(_webSocket);
  482. await _webSocket.ConnectAsync(new Uri(url), CancellationToken.None);
  483. //LogHelper.WriteToLog($"考勤WebSocket 已连接:{url}");
  484. await _webSocket.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(subscribeJson)), WebSocketMessageType.Text, true, CancellationToken.None);
  485. byte[] buffer = new byte[1024 * 8];
  486. while (_webSocket.State == WebSocketState.Open)
  487. {
  488. WebSocketReceiveResult result = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
  489. if (result.MessageType == WebSocketMessageType.Text)
  490. {
  491. try
  492. {
  493. string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
  494. //LogHelper.WriteToLog($"收到: {message}");
  495. var json = JsonConvert.DeserializeObject<JObject>(message);
  496. if (json["type"].ToString() == "msg")
  497. {
  498. var body = json["body"];
  499. if (body != null)
  500. {
  501. //TODO 发送短信
  502. //TxySmsUtil.SendSms(new[] { "" }, new[] { "" });
  503. //TODO 由于未知道数据格式暂不写处理
  504. var model = new AttendanceDto()
  505. {
  506. TenantCode = body["tenantCode"]?.ToString(),
  507. PoiId = body["poiId"]?.ToString(),
  508. EventId = body["eventId"]?.ToString(),
  509. CameraId = body["cameraId"]?.ToString(),
  510. Tick = TimestampToDateTime(body["tick"]?.ToString()),
  511. PersonSetId = body["personSetId"]?.ToString(),
  512. PersonId = body["personId"]?.ToString(),
  513. Similarity = body["similarity"] != null ? (float)body["similarity"] : 0,
  514. FaceScore = body["faceScore"] != null ? (float)body["faceScore"] : 0,
  515. SnapshotUrl = body["snapshotUrl"]?.ToString(),
  516. SnapshotData = body["snapshotData"]?.ToString(),
  517. Rects = body["rects"]?.ToString(),
  518. Extend = body["extend"]?.ToString(),
  519. CreateTime = DateTime.Now,
  520. TrackId = body["trackId"]?.ToString(),
  521. IsAuto = true
  522. };
  523. var signImg = Path.Combine(Directory.GetCurrentDirectory(), "Files", App.Configuration["AppInfo:AttendanceImg"], model.EventId + ".jpg");
  524. var steam = await model.SnapshotUrl.GetAsByteArrayAsync();
  525. model.SnapshotUrl = $"/Files/{App.Configuration["AppInfo:AttendanceImg"]}/{model.EventId}.jpg";
  526. using (MemoryStream ms = new MemoryStream(steam))
  527. {
  528. using (Bitmap bmp = new Bitmap(ms))
  529. {
  530. using (Graphics g = Graphics.FromImage(bmp))
  531. {
  532. using (Pen pen = new Pen(Color.Red, 3))
  533. {
  534. foreach (var item in body["rects"])
  535. {
  536. Rectangle rect = new Rectangle((int)item["left"], (int)item["top"], (int)item["width"], (int)item["height"]);
  537. g.DrawRectangle(pen, rect);
  538. }
  539. }
  540. }
  541. bmp.Save(signImg, ImageFormat.Jpeg);
  542. }
  543. }
  544. Scoped.Create((_, scope) =>
  545. {
  546. var services = scope.ServiceProvider;
  547. var repository = services.GetService<IAttendanceService>();
  548. repository.Add(model);
  549. });
  550. }
  551. }else if (json["type"].ToString()=="cmd")
  552. {
  553. if ((bool)json["success"])
  554. {
  555. if (json["message"].ToString().Contains("connect success"))
  556. {
  557. LogHelper.WriteToLog("考勤连接成功");
  558. }else if (json["message"].ToString().Contains("subscribe success"))
  559. {
  560. LogHelper.WriteToLog("考勤订阅成功");
  561. }
  562. }
  563. }
  564. }
  565. catch (Exception e)
  566. {
  567. LogHelper.WriteToLog($"收到: {Encoding.UTF8.GetString(buffer, 0, result.Count)}");
  568. LogHelper.WriteToLog("考勤webSocket处理异常");
  569. LogHelper.WriteToLog(e, "考勤webSocket处理异常");
  570. }
  571. }
  572. else if (result.MessageType == WebSocketMessageType.Close)
  573. {
  574. LogHelper.WriteToLog("考勤WebSocket 连接已被服务器关闭");
  575. break;
  576. }
  577. }
  578. LogHelper.WriteToLog("考勤webSocket已关闭");
  579. }
  580. private async Task GetWebSocketData(string url, string json)
  581. {
  582. ClientWebSocket _webSocket = new ClientWebSocket();
  583. while (!_cancellationTokenSource.IsCancellationRequested)
  584. {
  585. try
  586. {
  587. await _webSocket.ConnectAsync(new Uri(url), CancellationToken.None);
  588. LogHelper.WriteToLog("WebSocket 已连接");
  589. _isConnected = true;
  590. //订阅预警消息
  591. await _webSocket.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(json)), WebSocketMessageType.Text, true, CancellationToken.None);
  592. //_pingTimer = new Timer(async (state) =>
  593. //{
  594. // if (_webSocket.State == WebSocketState.Open)
  595. // {
  596. // try
  597. // {
  598. // LogHelper.WriteToLog("发送 ping...");
  599. // byte[] emptyPingMessage = Array.Empty<byte>();
  600. // await _webSocket.SendAsync(new ArraySegment<byte>(emptyPingMessage), WebSocketMessageType.Binary, true, CancellationToken.None);
  601. // //byte[] pingMessage = Encoding.UTF8.GetBytes("pong");
  602. // //await _webSocket.SendAsync(new ArraySegment<byte>(pingMessage), WebSocketMessageType.Text, true, CancellationToken.None);
  603. // }
  604. // catch (Exception ex)
  605. // {
  606. // LogHelper.WriteToLog($"发送ping失败: {ex.Message}");
  607. // }
  608. // }
  609. //}, null, TimeSpan.Zero, TimeSpan.FromSeconds(30));
  610. await ReceiveLoop(_webSocket);
  611. _isConnected = false;
  612. LogHelper.WriteToLog("WebSocket 连接已关闭,正在重连。。。");
  613. }
  614. catch (Exception ex)
  615. {
  616. LogHelper.WriteToLog($"WebSocket连接失败: {ex.Message}");
  617. }
  618. await Task.Delay(GetReconnectInterval());
  619. }
  620. }
  621. private async Task ReceiveLoop(ClientWebSocket _webSocket)
  622. {
  623. byte[] buffer = new byte[1024];
  624. while (_webSocket.State == WebSocketState.Open)
  625. {
  626. WebSocketReceiveResult result = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
  627. if (result.MessageType == WebSocketMessageType.Text)
  628. {
  629. string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
  630. LogHelper.WriteToLog($"收到: {message}");
  631. var json= JsonConvert.DeserializeObject<JObject>(message);
  632. if (json["type"].ToString()=="msg")
  633. {
  634. var body = json["body"];
  635. if (body!=null)
  636. {
  637. }
  638. }
  639. }
  640. else if (result.MessageType == WebSocketMessageType.Close)
  641. {
  642. LogHelper.WriteToLog("WebSocket 连接已被服务器关闭");
  643. break;
  644. }
  645. }
  646. }
  647. private TimeSpan GetReconnectInterval()
  648. {
  649. // You can implement your own logic for calculating reconnect interval, e.g., exponential backoff
  650. return TimeSpan.FromSeconds(10); // Example: Attempt to reconnect every 10 seconds
  651. }
  652. public async Task DisconnectAsync()
  653. {
  654. foreach (var clientWebSocket in webScokets.Where(clientWebSocket => clientWebSocket.State == WebSocketState.Open))
  655. {
  656. await clientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
  657. }
  658. }
  659. private string GetWebSocketUrl(string topic, string consumerGroup)
  660. {
  661. var serverAddr = "";
  662. var setting = App.GetOptionsMonitor<AppInfoOptions>();
  663. var list = $"{setting.SXAPIURL}/emitter/connection/get"
  664. .SetBody(new
  665. {
  666. token = GetToken(),
  667. topic ,
  668. consumerGroup,
  669. })
  670. .SetContentType("application/json")
  671. .PostAsAsync<string>().Result;
  672. var model = JsonConvert.DeserializeObject<JObject>(list);
  673. if (model["data"]["serverAddr"]!=null)
  674. {
  675. serverAddr = model["data"]["serverAddr"].ToString();
  676. }
  677. return serverAddr;
  678. }
  679. //public async Task<bool> GetData()
  680. //{
  681. // //var setting = App.GetOptionsMonitor<AppInfoOptions>();
  682. // //var timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds();
  683. // ////订阅预警消息
  684. // //var warnUrl = GetWebSocketUrl(AuthConstants.SXALARM, AuthConstants.SXALARM_Grpup);
  685. // //GetWebSocketData(warnUrl,
  686. // // JsonConvert.SerializeObject(new
  687. // // {
  688. // // token = GetToken(), type = "subscribe", timestamp,
  689. // // payload = new { topic = AuthConstants.SXALARM, consumerGroup= AuthConstants.SXALARM_Grpup, tags= setting.TenantCode }
  690. // // }));
  691. // //订阅预警更新消息
  692. // await SubscribeAlarm();
  693. // //订阅点名事件
  694. // //await SubscriberRoomCall();
  695. // return true;
  696. //}
  697. /// <summary>
  698. /// 时间戳转本时区日期时间
  699. /// </summary>
  700. /// <param name="timeStamp"></param>
  701. /// <returns></returns>
  702. public static DateTime TimestampToDateTime(string timeStamp)
  703. {
  704. DateTimeOffset utcDateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(long.Parse(timeStamp));
  705. return utcDateTimeOffset.LocalDateTime;
  706. }
  707. }