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.
 
 
 

253 lines
8.6 KiB

  1. using JT1078.Gateway.Extensions;
  2. using JT1078.Gateway.Metadata;
  3. using Microsoft.Extensions.Logging;
  4. using System;
  5. using System.Collections.Concurrent;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Net;
  9. using System.Net.WebSockets;
  10. using System.Text;
  11. using System.Threading;
  12. using System.Threading.Tasks;
  13. namespace JT1078.Gateway.Sessions
  14. {
  15. public class JT1078HttpSessionManager
  16. {
  17. public ConcurrentDictionary<string, JT1078HttpContext> Sessions { get; }
  18. private ILogger Logger;
  19. public JT1078HttpSessionManager(ILoggerFactory loggerFactory)
  20. {
  21. Sessions = new ConcurrentDictionary<string, JT1078HttpContext>();
  22. Logger = loggerFactory.CreateLogger<JT1078HttpSessionManager>();
  23. }
  24. public bool TryAdd(JT1078HttpContext httpContext)
  25. {
  26. return Sessions.TryAdd(httpContext.SessionId, httpContext);
  27. }
  28. public async void TryRemove(string sessionId)
  29. {
  30. if(Sessions.TryRemove(sessionId, out JT1078HttpContext session))
  31. {
  32. try
  33. {
  34. if (session.IsWebSocket)
  35. {
  36. await session.WebSocketClose("close");
  37. }
  38. else
  39. {
  40. await session.HttpClose();
  41. }
  42. }
  43. catch (Exception)
  44. {
  45. }
  46. finally
  47. {
  48. //todo:session close notice
  49. }
  50. }
  51. }
  52. private void remove(string sessionId)
  53. {
  54. if (Sessions.TryRemove(sessionId, out JT1078HttpContext session))
  55. {
  56. //todo:session close notice
  57. }
  58. }
  59. /// <summary>
  60. /// 发送音视频数据
  61. /// </summary>
  62. /// <param name="sim"></param>
  63. /// <param name="channelNo"></param>
  64. /// <param name="data"></param>
  65. public void SendAVData(string sim,int channelNo,byte[] data)
  66. {
  67. var contexts = Sessions.Select(s => s.Value).Where(w => w.Sim == sim && w.ChannelNo == channelNo).ToList();
  68. ParallelLoopResult parallelLoopResult= Parallel.ForEach(contexts, async(context) =>
  69. {
  70. if (context.IsWebSocket)
  71. {
  72. try
  73. {
  74. await context.WebSocketSendBinaryAsync(data);
  75. }
  76. catch (Exception ex)
  77. {
  78. if (Logger.IsEnabled(LogLevel.Information))
  79. {
  80. Logger.LogInformation($"[ws close]:{context.SessionId}-{context.Sim}-{context.ChannelNo}-{context.StartTime:yyyyMMddhhmmss}");
  81. }
  82. remove(context.SessionId);
  83. }
  84. }
  85. else
  86. {
  87. if (!context.SendChunked)
  88. {
  89. context.SendChunked = true;
  90. Sessions.TryUpdate(context.SessionId, context, context);
  91. try
  92. {
  93. await context.HttpSendFirstChunked(data);
  94. }
  95. catch (Exception ex)
  96. {
  97. if (Logger.IsEnabled(LogLevel.Information))
  98. {
  99. Logger.LogInformation($"[http close]:{context.SessionId}-{context.Sim}-{context.ChannelNo}-{context.StartTime:yyyyMMddhhmmss}");
  100. }
  101. remove(context.SessionId);
  102. }
  103. }
  104. else
  105. {
  106. try
  107. {
  108. await context.HttpSendChunked(data);
  109. }
  110. catch (Exception ex)
  111. {
  112. if (Logger.IsEnabled(LogLevel.Information))
  113. {
  114. Logger.LogInformation($"[http close]:{context.SessionId}-{context.Sim}-{context.ChannelNo}-{context.StartTime:yyyyMMddhhmmss}");
  115. }
  116. remove(context.SessionId);
  117. }
  118. }
  119. }
  120. });
  121. if (parallelLoopResult.IsCompleted)
  122. {
  123. }
  124. }
  125. /// <summary>
  126. /// 发送音视频数据到websocket
  127. /// </summary>
  128. /// <param name="sim"></param>
  129. /// <param name="channelNo"></param>
  130. /// <param name="data"></param>
  131. public void SendAVData2WebSocket(string sim, int channelNo, byte[] data)
  132. {
  133. var contexts = Sessions.Select(s => s.Value).Where(w => w.Sim == sim && w.ChannelNo == channelNo && w.IsWebSocket).ToList();
  134. ParallelLoopResult parallelLoopResult = Parallel.ForEach(contexts, async (context) =>
  135. {
  136. if (context.IsWebSocket)
  137. {
  138. try
  139. {
  140. await context.WebSocketSendBinaryAsync(data);
  141. }
  142. catch (Exception ex)
  143. {
  144. if (Logger.IsEnabled(LogLevel.Information))
  145. {
  146. Logger.LogInformation($"[ws close]:{context.SessionId}-{context.Sim}-{context.ChannelNo}-{context.StartTime:yyyyMMddhhmmss}");
  147. }
  148. remove(context.SessionId);
  149. }
  150. }
  151. });
  152. if (parallelLoopResult.IsCompleted)
  153. {
  154. }
  155. }
  156. /// <summary>
  157. /// 发送音视频数据到Http Chunked中
  158. /// </summary>
  159. /// <param name="sim"></param>
  160. /// <param name="channelNo"></param>
  161. /// <param name="data"></param>
  162. public void SendAVData2HttpChunked(string sim, int channelNo, byte[] data)
  163. {
  164. var contexts = Sessions.Select(s => s.Value).Where(w => w.Sim == sim && w.ChannelNo == channelNo && !w.IsWebSocket).ToList();
  165. ParallelLoopResult parallelLoopResult = Parallel.ForEach(contexts, async (context) =>
  166. {
  167. if (!context.SendChunked)
  168. {
  169. context.SendChunked = true;
  170. Sessions.TryUpdate(context.SessionId, context, context);
  171. try
  172. {
  173. await context.HttpSendFirstChunked(data);
  174. }
  175. catch (Exception ex)
  176. {
  177. if (Logger.IsEnabled(LogLevel.Information))
  178. {
  179. Logger.LogInformation($"[http close]:{context.SessionId}-{context.Sim}-{context.ChannelNo}-{context.StartTime:yyyyMMddhhmmss}");
  180. }
  181. remove(context.SessionId);
  182. }
  183. }
  184. else
  185. {
  186. try
  187. {
  188. await context.HttpSendChunked(data);
  189. }
  190. catch (Exception ex)
  191. {
  192. if (Logger.IsEnabled(LogLevel.Information))
  193. {
  194. Logger.LogInformation($"[http close]:{context.SessionId}-{context.Sim}-{context.ChannelNo}-{context.StartTime:yyyyMMddhhmmss}");
  195. }
  196. remove(context.SessionId);
  197. }
  198. }
  199. });
  200. if (parallelLoopResult.IsCompleted)
  201. {
  202. }
  203. }
  204. public int SessionCount
  205. {
  206. get
  207. {
  208. return Sessions.Count;
  209. }
  210. }
  211. public List<JT1078HttpContext> GetAll()
  212. {
  213. return Sessions.Select(s => s.Value).ToList();
  214. }
  215. internal void TryRemoveAll()
  216. {
  217. foreach(var item in Sessions)
  218. {
  219. try
  220. {
  221. if (item.Value.IsWebSocket)
  222. {
  223. item.Value.WebSocketContext.WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "server close", CancellationToken.None);
  224. }
  225. else
  226. {
  227. item.Value.Context.Response.Close();
  228. }
  229. }
  230. catch (Exception)
  231. {
  232. }
  233. }
  234. }
  235. }
  236. }