SignalRScreenServerHub.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. using Grpc.Core;
  2. using Microsoft.AspNetCore.SignalR;
  3. using Microsoft.Azure.Cosmos.Linq;
  4. using Microsoft.Extensions.Primitives;
  5. using TEAMModelOS.SDK.DI;
  6. using TEAMModelOS.SDK.Extension;
  7. using TEAMModelOS.SDK;
  8. namespace HTEX.Complex.Services
  9. {
  10. public class SignalRScreenServerHub : Hub<IClient>
  11. {
  12. private readonly AzureRedisFactory _azureRedis;
  13. public SignalRScreenServerHub(AzureRedisFactory azureRedis)
  14. {
  15. _azureRedis = azureRedis;
  16. }
  17. /// <summary>
  18. /// 客户连接成功时触发
  19. /// </summary>
  20. /// <returns></returns>
  21. public override async Task OnConnectedAsync()
  22. {
  23. var connid = Context.ConnectionId;
  24. var httpContext = Context.GetHttpContext();
  25. if (httpContext != null)
  26. {
  27. //wss://www.winteach.cn/signalr/notify?grant_type=wechat_qrcode&scene=0a75aca57536490ba00fe62e27bb8f6c&id=U2MNiCFNPPuVcw2gUI_gRA
  28. //wss://www.winteach.cn/signalr/notify?grant_type=bookjs_api&clientid={clientid}&id=客户端自动生成的
  29. httpContext.Request.Query.TryGetValue("grant_type", out StringValues grant_type);
  30. httpContext.Request.Query.TryGetValue("clientid", out StringValues clientid);
  31. var ip = GetIP(httpContext);
  32. await Groups.AddToGroupAsync(connid, grant_type!);
  33. if (!clientid.Equals(StringValues.Empty) && !grant_type.Equals(StringValues.Empty)) {
  34. ///连接配置,并且使用钉钉 通知。
  35. ///
  36. var client = new SignalRClient
  37. {
  38. connid = connid,
  39. grant_type = grant_type,
  40. clientid= clientid
  41. };
  42. await _azureRedis.GetRedisClient(8).StringSetAsync($"SignalRClient:connects:{connid}", client.ToJsonString());
  43. switch (true)
  44. {
  45. case bool when grant_type.Equals(ScreenConstant.grant_type):
  46. ScreenClient screenClient = null;
  47. var value = await _azureRedis.GetRedisClient(8).HashGetAsync($"ScreenApi:clients", client.clientid);
  48. if (value!=default && value.HasValue)
  49. {
  50. screenClient = value.ToString().ToObject<ScreenClient>();
  51. // 这里不强制设置free ,因为如果是重连,可能正在执行命令,需要等待执行完成
  52. //screenClient.status="free";
  53. screenClient.connid=connid;
  54. }
  55. else
  56. {
  57. screenClient= new ScreenClient
  58. {
  59. status=ScreenConstant.free,
  60. connid=connid,
  61. grant_type=grant_type,
  62. clientid= clientid,
  63. desc="",
  64. domain="",
  65. ip=ip,
  66. time= DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
  67. weight= 0,
  68. duration=0,
  69. };
  70. }
  71. //连接成功,发送消息给客户端。
  72. await SendConnection(connid, new ConnectionMessageContent
  73. {
  74. clientid = clientid,
  75. status = ScreenConstant.free,
  76. grant_type = grant_type,
  77. content = $"连接成功"
  78. });
  79. //先检查状态是否是在忙碌,在时间戳范围里,如果不在时间戳范围,强制free。
  80. if (!screenClient.status!.Equals(ScreenConstant.free) &&screenClient.time + screenClient.duration < DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()) {
  81. screenClient.status = ScreenConstant.free;
  82. }
  83. if (screenClient.status!.Equals(ScreenConstant.free)) {
  84. //连接成功,马上分发任务。
  85. //从尾部弹出元素,队列先进先出
  86. var queueValue = await _azureRedis.GetRedisClient(8).ListRightPopAsync("PDFGen:Queue");
  87. if (queueValue!=default && queueValue.HasValue)
  88. {
  89. PDFGenQueue genQueue = queueValue.ToString().ToObject<PDFGenQueue>();
  90. await SendConnection(connid, new ScreenProcessMessageContent
  91. {
  92. clientid = clientid,
  93. status = ScreenConstant.busy,
  94. grant_type = grant_type,
  95. content =$"{queueValue.ToString()}",//从Redis中获取任务信息
  96. });
  97. screenClient.status = ScreenConstant.busy;
  98. screenClient.time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  99. //预计占用时长,并冗余5秒
  100. screenClient.duration= genQueue.timeout+genQueue.delay+ScreenConstant.time_excess;
  101. }
  102. }
  103. await _azureRedis.GetRedisClient(8).HashSetAsync($"ScreenApi:clients", client.clientid, screenClient.ToJsonString());
  104. break;
  105. }
  106. }
  107. else
  108. {
  109. await SendConnection(connid, new ConnectionMessageContent
  110. {
  111. clientid = string.Empty,
  112. status =ScreenConstant.error,
  113. grant_type = grant_type,
  114. content = "客户端配置错误",
  115. connid = connid,
  116. });
  117. }
  118. }
  119. }
  120. public async override Task OnDisconnectedAsync(Exception? exception)
  121. {
  122. var connid = Context.ConnectionId;
  123. var redisData = await _azureRedis.GetRedisClient(8).StringGetAsync($"SignalRClient:connects:{connid}");
  124. if (!redisData.IsNullOrEmpty)
  125. {
  126. await _azureRedis.GetRedisClient(8).KeyDeleteAsync($"SignalRClient:connects:{connid}");
  127. var client = redisData.ToString().ToObject<SignalRClient>();
  128. if (client != null)
  129. {
  130. var value = await _azureRedis.GetRedisClient(8).HashGetAsync($"ScreenApi:clients", client.clientid);
  131. if (value!=default && value.HasValue)
  132. {
  133. ScreenClient screenClient = value.ToString().ToObject<ScreenClient>() ;
  134. screenClient.status=ScreenConstant.down;
  135. screenClient.connid= string.Empty;
  136. await _azureRedis.GetRedisClient(8).HashSetAsync($"ScreenApi:clients", client.clientid, screenClient.ToJsonString());
  137. }
  138. await Groups.RemoveFromGroupAsync(connid, client.grant_type!);
  139. ///连接配置,并且使用钉钉 离线通知。
  140. }
  141. }
  142. }
  143. public async Task SendConnection(string connectionId, MessageBody msg)
  144. {
  145. await Clients.Client(connectionId).ReceiveConnection(msg);
  146. }
  147. public string GetIP(HttpContext httpContext)
  148. {
  149. var IpPort = httpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault();
  150. if (string.IsNullOrEmpty(IpPort))
  151. {
  152. IpPort = $"{httpContext.Connection.RemoteIpAddress}";
  153. }
  154. if (IpPort.Contains("::"))
  155. {
  156. IpPort = "127.0.0.1";
  157. }
  158. return IpPort;
  159. }
  160. }
  161. }