WebGLBrowser.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. #if (UNITY_WEBGL && !UNITY_EDITOR) && !BESTHTTP_DISABLE_WEBSOCKET
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Runtime.InteropServices;
  5. using BestHTTP.PlatformSupport.Memory;
  6. namespace BestHTTP.WebSocket
  7. {
  8. delegate void OnWebGLWebSocketOpenDelegate(uint id);
  9. delegate void OnWebGLWebSocketTextDelegate(uint id, string text);
  10. delegate void OnWebGLWebSocketBinaryDelegate(uint id, IntPtr pBuffer, int length);
  11. delegate void OnWebGLWebSocketErrorDelegate(uint id, string error);
  12. delegate void OnWebGLWebSocketCloseDelegate(uint id, int code, string reason);
  13. internal sealed class WebGLBrowser : WebSocketBaseImplementation
  14. {
  15. public override WebSocketStates State => ImplementationId != 0 ? WS_GetState(ImplementationId) : WebSocketStates.Unknown;
  16. public override bool IsOpen => ImplementationId != 0 && WS_GetState(ImplementationId) == WebSocketStates.Open;
  17. public override int BufferedAmount => WS_GetBufferedAmount(ImplementationId);
  18. internal static Dictionary<uint, WebSocket> WebSockets = new Dictionary<uint, WebSocket>();
  19. private uint ImplementationId;
  20. public WebGLBrowser(WebSocket parent, Uri uri, string origin, string protocol) : base(parent, uri, origin, protocol)
  21. {
  22. }
  23. public override void StartOpen()
  24. {
  25. try
  26. {
  27. ImplementationId = WS_Create(this.Uri.OriginalString, this.Protocol, OnOpenCallback, OnTextCallback, OnBinaryCallback, OnErrorCallback, OnCloseCallback);
  28. WebSockets.Add(ImplementationId, this.Parent);
  29. }
  30. catch(Exception ex)
  31. {
  32. HTTPManager.Logger.Exception("WebSocket", "Open", ex, this.Parent.Context);
  33. }
  34. }
  35. public override void StartClose(UInt16 code, string message)
  36. {
  37. WS_Close(this.ImplementationId, code, message);
  38. }
  39. public override void Send(string message)
  40. {
  41. var count = System.Text.Encoding.UTF8.GetByteCount(message);
  42. var buffer = BufferPool.Get(count, true);
  43. System.Text.Encoding.UTF8.GetBytes(message, 0, message.Length, buffer, 0);
  44. WS_Send_String(this.ImplementationId, buffer, 0, count);
  45. BufferPool.Release(buffer);
  46. }
  47. public override void Send(byte[] buffer)
  48. {
  49. WS_Send_Binary(this.ImplementationId, buffer, 0, buffer.Length);
  50. }
  51. public override void Send(byte[] buffer, ulong offset, ulong count)
  52. {
  53. WS_Send_Binary(this.ImplementationId, buffer, (int)offset, (int)count);
  54. }
  55. [DllImport("__Internal")]
  56. static extern uint WS_Create(string url, string protocol, OnWebGLWebSocketOpenDelegate onOpen, OnWebGLWebSocketTextDelegate onText, OnWebGLWebSocketBinaryDelegate onBinary, OnWebGLWebSocketErrorDelegate onError, OnWebGLWebSocketCloseDelegate onClose);
  57. [DllImport("__Internal")]
  58. static extern WebSocketStates WS_GetState(uint id);
  59. [DllImport("__Internal")]
  60. static extern int WS_GetBufferedAmount(uint id);
  61. [DllImport("__Internal")]
  62. static extern int WS_Send_String(uint id, byte[] strData, int pos, int length);
  63. [DllImport("__Internal")]
  64. static extern int WS_Send_Binary(uint id, byte[] buffer, int pos, int length);
  65. [DllImport("__Internal")]
  66. static extern void WS_Close(uint id, ushort code, string reason);
  67. [DllImport("__Internal")]
  68. static extern void WS_Release(uint id);
  69. [AOT.MonoPInvokeCallback(typeof(OnWebGLWebSocketOpenDelegate))]
  70. static void OnOpenCallback(uint id)
  71. {
  72. WebSocket ws;
  73. if (WebSockets.TryGetValue(id, out ws))
  74. {
  75. if (ws.OnOpen != null)
  76. {
  77. try
  78. {
  79. ws.OnOpen(ws);
  80. }
  81. catch(Exception ex)
  82. {
  83. HTTPManager.Logger.Exception("WebSocket", "OnOpen", ex, ws.Context);
  84. }
  85. }
  86. }
  87. else
  88. HTTPManager.Logger.Warning("WebSocket", "OnOpenCallback - No WebSocket found for id: " + id.ToString(), ws.Context);
  89. }
  90. [AOT.MonoPInvokeCallback(typeof(OnWebGLWebSocketTextDelegate))]
  91. static void OnTextCallback(uint id, string text)
  92. {
  93. WebSocket ws;
  94. if (WebSockets.TryGetValue(id, out ws))
  95. {
  96. if (ws.OnMessage != null)
  97. {
  98. try
  99. {
  100. ws.OnMessage(ws, text);
  101. }
  102. catch (Exception ex)
  103. {
  104. HTTPManager.Logger.Exception("WebSocket", "OnMessage", ex, ws.Context);
  105. }
  106. }
  107. }
  108. else
  109. HTTPManager.Logger.Warning("WebSocket", "OnTextCallback - No WebSocket found for id: " + id.ToString());
  110. }
  111. [AOT.MonoPInvokeCallback(typeof(OnWebGLWebSocketBinaryDelegate))]
  112. static void OnBinaryCallback(uint id, IntPtr pBuffer, int length)
  113. {
  114. WebSocket ws;
  115. if (WebSockets.TryGetValue(id, out ws))
  116. {
  117. if (ws.OnBinary != null)
  118. {
  119. try
  120. {
  121. byte[] buffer = new byte[length];
  122. // Copy data from the 'unmanaged' memory to managed memory. Buffer will be reclaimed by the GC.
  123. Marshal.Copy(pBuffer, buffer, 0, length);
  124. ws.OnBinary(ws, buffer);
  125. }
  126. catch (Exception ex)
  127. {
  128. HTTPManager.Logger.Exception("WebSocket", "OnBinary", ex, ws.Context);
  129. }
  130. }
  131. }
  132. else
  133. HTTPManager.Logger.Warning("WebSocket", "OnBinaryCallback - No WebSocket found for id: " + id.ToString());
  134. }
  135. [AOT.MonoPInvokeCallback(typeof(OnWebGLWebSocketErrorDelegate))]
  136. static void OnErrorCallback(uint id, string error)
  137. {
  138. WebSocket ws;
  139. if (WebSockets.TryGetValue(id, out ws))
  140. {
  141. WebSockets.Remove(id);
  142. if (ws.OnError != null)
  143. {
  144. try
  145. {
  146. ws.OnError(ws, error);
  147. }
  148. catch (Exception ex)
  149. {
  150. HTTPManager.Logger.Exception("WebSocket", "OnError", ex, ws.Context);
  151. }
  152. }
  153. }
  154. else
  155. HTTPManager.Logger.Warning("WebSocket", "OnErrorCallback - No WebSocket found for id: " + id.ToString());
  156. try
  157. {
  158. WS_Release(id);
  159. }
  160. catch(Exception ex)
  161. {
  162. HTTPManager.Logger.Exception("WebSocket", "WS_Release", ex);
  163. }
  164. }
  165. [AOT.MonoPInvokeCallback(typeof(OnWebGLWebSocketCloseDelegate))]
  166. static void OnCloseCallback(uint id, int code, string reason)
  167. {
  168. // To match non-webgl behavior, we have to treat this client-side generated message as an error
  169. if (code == (int)WebSocketStausCodes.ClosedAbnormally)
  170. {
  171. OnErrorCallback(id, "Abnormal disconnection.");
  172. return;
  173. }
  174. WebSocket ws;
  175. if (WebSockets.TryGetValue(id, out ws))
  176. {
  177. WebSockets.Remove(id);
  178. if (ws.OnClosed != null)
  179. {
  180. try
  181. {
  182. ws.OnClosed(ws, (ushort)code, reason);
  183. }
  184. catch (Exception ex)
  185. {
  186. HTTPManager.Logger.Exception("WebSocket", "OnClosed", ex, ws.Context);
  187. }
  188. }
  189. }
  190. else
  191. HTTPManager.Logger.Warning("WebSocket", "OnCloseCallback - No WebSocket found for id: " + id.ToString());
  192. try
  193. {
  194. WS_Release(id);
  195. }
  196. catch(Exception ex)
  197. {
  198. HTTPManager.Logger.Exception("WebSocket", "WS_Release", ex);
  199. }
  200. }
  201. }
  202. }
  203. #endif