diff --git a/NativeWebSocket/Assets/WebSocket/WebSocket.cs b/NativeWebSocket/Assets/WebSocket/WebSocket.cs index 956fa21..107856c 100644 --- a/NativeWebSocket/Assets/WebSocket/WebSocket.cs +++ b/NativeWebSocket/Assets/WebSocket/WebSocket.cs @@ -1,41 +1,77 @@ using System; +using System.Collections; +using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Net.WebSockets; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; using AOT; -using System.Runtime.InteropServices; using UnityEngine; -using System.Collections; public class MainThreadUtil : MonoBehaviour { public static MainThreadUtil Instance { get; private set; } public static SynchronizationContext synchronizationContext { get; private set; } + private static readonly ConcurrentQueue coroutineQueue = new ConcurrentQueue(); + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] public static void Setup() { - Instance = new GameObject("MainThreadUtil") - .AddComponent(); + if (Instance != null) + return; + + var go = new GameObject("MainThreadUtil"); + Instance = go.AddComponent(); synchronizationContext = SynchronizationContext.Current; } public static void Run(IEnumerator waitForUpdate) { - synchronizationContext.Post(_ => Instance.StartCoroutine( - waitForUpdate), null); + if (waitForUpdate == null) + return; + + if (Instance == null) + Setup(); + + coroutineQueue.Enqueue(waitForUpdate); } - void Awake() + private void Awake() { + if (Instance != null && Instance != this) + { + Destroy(gameObject); + return; + } + + Instance = this; + if (synchronizationContext == null) + synchronizationContext = SynchronizationContext.Current; + gameObject.hideFlags = HideFlags.HideAndDontSave; DontDestroyOnLoad(gameObject); } + + private void Update() + { + while (coroutineQueue.TryDequeue(out var work)) + { + try + { + StartCoroutine(work); + } + catch (Exception ex) + { + Debug.LogException(ex); + } + } + } } public class WaitForUpdate : CustomYieldInstruction @@ -54,7 +90,7 @@ public MainThreadAwaiter GetAwaiter() public class MainThreadAwaiter : INotifyCompletion { - Action continuation; + private Action continuation; public bool IsCompleted { get; set; } @@ -127,16 +163,10 @@ public static class WebSocketHelpers { public static WebSocketCloseCode ParseCloseCodeEnum(int closeCode) { - if (WebSocketCloseCode.IsDefined(typeof(WebSocketCloseCode), closeCode)) - { return (WebSocketCloseCode)closeCode; - } - else - { - return WebSocketCloseCode.Undefined; - } + return WebSocketCloseCode.Undefined; } public static WebSocketException GetErrorMessageFromCode(int errorCode, Exception inner) @@ -201,166 +231,177 @@ public ConfiguredTaskAwaitable.ConfiguredTaskAwaiter GetAwaiter() #if UNITY_WEBGL && !UNITY_EDITOR - /// - /// WebSocket class bound to JSLIB. - /// - public class WebSocket : IWebSocket { - - /* WebSocket JSLIB functions */ - [DllImport ("__Internal")] - public static extern int WebSocketConnect (int instanceId); - - [DllImport ("__Internal")] - public static extern int WebSocketClose (int instanceId, int code, string reason); - - [DllImport ("__Internal")] - public static extern int WebSocketSend (int instanceId, byte[] dataPtr, int dataLength); - - [DllImport ("__Internal")] - public static extern int WebSocketSendText (int instanceId, string message); - - [DllImport ("__Internal")] - public static extern int WebSocketGetState (int instanceId); + /// + /// WebSocket class bound to JSLIB. + /// + public class WebSocket : IWebSocket + { + /* WebSocket JSLIB functions */ + [DllImport("__Internal")] + public static extern int WebSocketConnect(int instanceId); - protected int instanceId; + [DllImport("__Internal")] + public static extern int WebSocketClose(int instanceId, int code, string reason); - public event WebSocketOpenEventHandler OnOpen; - public event WebSocketMessageEventHandler OnMessage; - public event WebSocketErrorEventHandler OnError; - public event WebSocketCloseEventHandler OnClose; + [DllImport("__Internal")] + public static extern int WebSocketSend(int instanceId, byte[] dataPtr, int dataLength); - public WebSocket (string url, Dictionary headers = null) { - if (!WebSocketFactory.isInitialized) { - WebSocketFactory.Initialize (); - } + [DllImport("__Internal")] + public static extern int WebSocketSendText(int instanceId, string message); - int instanceId = WebSocketFactory.WebSocketAllocate (url); - WebSocketFactory.instances.Add (instanceId, this); + [DllImport("__Internal")] + public static extern int WebSocketGetState(int instanceId); - this.instanceId = instanceId; - } + protected int instanceId; - public WebSocket (string url, string subprotocol, Dictionary headers = null) { - if (!WebSocketFactory.isInitialized) { - WebSocketFactory.Initialize (); - } + public event WebSocketOpenEventHandler OnOpen; + public event WebSocketMessageEventHandler OnMessage; + public event WebSocketErrorEventHandler OnError; + public event WebSocketCloseEventHandler OnClose; - int instanceId = WebSocketFactory.WebSocketAllocate (url); - WebSocketFactory.instances.Add (instanceId, this); + public WebSocket(string url, Dictionary headers = null) + { + if (!WebSocketFactory.isInitialized) + { + WebSocketFactory.Initialize(); + } - WebSocketFactory.WebSocketAddSubProtocol(instanceId, subprotocol); + int id = WebSocketFactory.WebSocketAllocate(url); + WebSocketFactory.instances.Add(id, this); - this.instanceId = instanceId; - } + this.instanceId = id; + } - public WebSocket (string url, List subprotocols, Dictionary headers = null) { - if (!WebSocketFactory.isInitialized) { - WebSocketFactory.Initialize (); - } + public WebSocket(string url, string subprotocol, Dictionary headers = null) + { + if (!WebSocketFactory.isInitialized) + { + WebSocketFactory.Initialize(); + } - int instanceId = WebSocketFactory.WebSocketAllocate (url); - WebSocketFactory.instances.Add (instanceId, this); + int id = WebSocketFactory.WebSocketAllocate(url); + WebSocketFactory.instances.Add(id, this); - foreach (string subprotocol in subprotocols) { - WebSocketFactory.WebSocketAddSubProtocol(instanceId, subprotocol); - } + WebSocketFactory.WebSocketAddSubProtocol(id, subprotocol); - this.instanceId = instanceId; - } + this.instanceId = id; + } - ~WebSocket () { - WebSocketFactory.HandleInstanceDestroy (this.instanceId); - } + public WebSocket(string url, List subprotocols, Dictionary headers = null) + { + if (!WebSocketFactory.isInitialized) + { + WebSocketFactory.Initialize(); + } - public int GetInstanceId () { - return this.instanceId; - } + int id = WebSocketFactory.WebSocketAllocate(url); + WebSocketFactory.instances.Add(id, this); - public Task Connect () { - int ret = WebSocketConnect (this.instanceId); + foreach (string subprotocol in subprotocols) + { + WebSocketFactory.WebSocketAddSubProtocol(id, subprotocol); + } - if (ret < 0) - throw WebSocketHelpers.GetErrorMessageFromCode (ret, null); + this.instanceId = id; + } - return Task.CompletedTask; - } + ~WebSocket() + { + WebSocketFactory.HandleInstanceDestroy(this.instanceId); + } - public void CancelConnection () { - if (State == WebSocketState.Open) - Close (WebSocketCloseCode.Abnormal); - } + public int GetInstanceId() + { + return this.instanceId; + } - public Task Close (WebSocketCloseCode code = WebSocketCloseCode.Normal, string reason = null) { - int ret = WebSocketClose (this.instanceId, (int) code, reason); + public Task Connect() + { + int ret = WebSocketConnect(this.instanceId); - if (ret < 0) - throw WebSocketHelpers.GetErrorMessageFromCode (ret, null); + if (ret < 0) + throw WebSocketHelpers.GetErrorMessageFromCode(ret, null); - return Task.CompletedTask; - } + return Task.CompletedTask; + } - public Task Send (byte[] data) { - int ret = WebSocketSend (this.instanceId, data, data.Length); + public void CancelConnection() + { + if (State == WebSocketState.Open) + Close(WebSocketCloseCode.Abnormal); + } - if (ret < 0) - throw WebSocketHelpers.GetErrorMessageFromCode (ret, null); + public Task Close(WebSocketCloseCode code = WebSocketCloseCode.Normal, string reason = null) + { + int ret = WebSocketClose(this.instanceId, (int)code, reason); - return Task.CompletedTask; - } + if (ret < 0) + throw WebSocketHelpers.GetErrorMessageFromCode(ret, null); - public Task SendText (string message) { - int ret = WebSocketSendText (this.instanceId, message); + return Task.CompletedTask; + } - if (ret < 0) - throw WebSocketHelpers.GetErrorMessageFromCode (ret, null); + public Task Send(byte[] data) + { + int ret = WebSocketSend(this.instanceId, data, data.Length); - return Task.CompletedTask; - } + if (ret < 0) + throw WebSocketHelpers.GetErrorMessageFromCode(ret, null); - public WebSocketState State { - get { - int state = WebSocketGetState (this.instanceId); + return Task.CompletedTask; + } - if (state < 0) - throw WebSocketHelpers.GetErrorMessageFromCode (state, null); + public Task SendText(string message) + { + int ret = WebSocketSendText(this.instanceId, message); - switch (state) { - case 0: - return WebSocketState.Connecting; + if (ret < 0) + throw WebSocketHelpers.GetErrorMessageFromCode(ret, null); - case 1: - return WebSocketState.Open; + return Task.CompletedTask; + } - case 2: - return WebSocketState.Closing; + public WebSocketState State + { + get + { + int state = WebSocketGetState(this.instanceId); - case 3: - return WebSocketState.Closed; + if (state < 0) + throw WebSocketHelpers.GetErrorMessageFromCode(state, null); - default: - return WebSocketState.Closed; + switch (state) + { + case 0: return WebSocketState.Connecting; + case 1: return WebSocketState.Open; + case 2: return WebSocketState.Closing; + case 3: return WebSocketState.Closed; + default: return WebSocketState.Closed; + } + } } - } - } - public void DelegateOnOpenEvent () { - this.OnOpen?.Invoke (); - } + public void DelegateOnOpenEvent() + { + this.OnOpen?.Invoke(); + } - public void DelegateOnMessageEvent (byte[] data) { - this.OnMessage?.Invoke (data); - } + public void DelegateOnMessageEvent(byte[] data) + { + this.OnMessage?.Invoke(data); + } - public void DelegateOnErrorEvent (string errorMsg) { - this.OnError?.Invoke (errorMsg); - } + public void DelegateOnErrorEvent(string errorMsg) + { + this.OnError?.Invoke(errorMsg); + } - public void DelegateOnCloseEvent (int closeCode) { - this.OnClose?.Invoke (WebSocketHelpers.ParseCloseCodeEnum (closeCode)); + public void DelegateOnCloseEvent(int closeCode) + { + this.OnClose?.Invoke(WebSocketHelpers.ParseCloseCodeEnum(closeCode)); + } } - } - #else public class WebSocket : IWebSocket @@ -370,34 +411,37 @@ public class WebSocket : IWebSocket public event WebSocketErrorEventHandler OnError; public event WebSocketCloseEventHandler OnClose; - private Uri uri; - private Dictionary headers; - private List subprotocols; + private readonly Uri uri; + private readonly Dictionary headers; + private readonly List subprotocols; + private ClientWebSocket m_Socket = new ClientWebSocket(); private CancellationTokenSource m_TokenSource; private CancellationToken m_CancellationToken; - private readonly object OutgoingMessageLock = new object(); private readonly object IncomingMessageLock = new object(); + private readonly List m_MessageList = new List(); - private bool isSending = false; - private List> sendBytesQueue = new List>(); - private List> sendTextQueue = new List>(); + private Task m_ReceiveTask; + private int m_CleanupOnce = 0; + + private sealed class PendingSend + { + public WebSocketMessageType MessageType; + public ArraySegment Buffer; + public TaskCompletionSource Tcs; + } + + private readonly ConcurrentQueue m_SendQueue = new ConcurrentQueue(); + private readonly SemaphoreSlim m_SendPumpGate = new SemaphoreSlim(1, 1); + private int m_SendPumpRunning = 0; public WebSocket(string url, Dictionary headers = null) { uri = new Uri(url); - if (headers == null) - { - this.headers = new Dictionary(); - } - else - { - this.headers = headers; - } - + this.headers = headers ?? new Dictionary(); subprotocols = new List(); string protocol = uri.Scheme; @@ -409,16 +453,8 @@ public WebSocket(string url, string subprotocol, Dictionary head { uri = new Uri(url); - if (headers == null) - { - this.headers = new Dictionary(); - } - else - { - this.headers = headers; - } - - subprotocols = new List {subprotocol}; + this.headers = headers ?? new Dictionary(); + subprotocols = new List { subprotocol }; string protocol = uri.Scheme; if (!protocol.Equals("ws") && !protocol.Equals("wss")) @@ -429,34 +465,86 @@ public WebSocket(string url, List subprotocols, Dictionary(); + this.subprotocols = subprotocols ?? new List(); + + string protocol = uri.Scheme; + if (!protocol.Equals("ws") && !protocol.Equals("wss")) + throw new ArgumentException("Unsupported protocol: " + protocol); + } + + public void CancelConnection() + { + try { - this.headers = new Dictionary(); + m_TokenSource?.Cancel(); } - else + catch { - this.headers = headers; } + } + + private void CleanupNoThrow() + { + if (Interlocked.Exchange(ref m_CleanupOnce, 1) != 0) + return; - this.subprotocols = subprotocols; + try + { + m_TokenSource?.Cancel(); + } + catch + { + } - string protocol = uri.Scheme; - if (!protocol.Equals("ws") && !protocol.Equals("wss")) - throw new ArgumentException("Unsupported protocol: " + protocol); + try + { + m_Socket?.Dispose(); + } + catch + { + } + + try + { + m_Socket = new ClientWebSocket(); + } + catch + { + } } - public void CancelConnection() + private void FailAllPendingSends(Exception ex) { - m_TokenSource?.Cancel(); + while (m_SendQueue.TryDequeue(out var ps)) + { + try + { + ps.Tcs.TrySetException(ex); + } + catch + { + } + } } public async Task Connect() { try { + m_CleanupOnce = 0; + m_TokenSource = new CancellationTokenSource(); m_CancellationToken = m_TokenSource.Token; + try + { + m_Socket?.Dispose(); + } + catch + { + } + m_Socket = new ClientWebSocket(); foreach (var header in headers) @@ -464,27 +552,37 @@ public async Task Connect() m_Socket.Options.SetRequestHeader(header.Key, header.Value); } - foreach (string subprotocol in subprotocols) { + foreach (string subprotocol in subprotocols) + { m_Socket.Options.AddSubProtocol(subprotocol); } await m_Socket.ConnectAsync(uri, m_CancellationToken); OnOpen?.Invoke(); - await Receive(); + m_ReceiveTask = Receive(); + await m_ReceiveTask; } catch (Exception ex) { - OnError?.Invoke(ex.Message); - OnClose?.Invoke(WebSocketCloseCode.Abnormal); - } - finally - { - if (m_Socket != null) + try + { + OnError?.Invoke(ex.ToString()); + } + catch + { + } + + try + { + OnClose?.Invoke(WebSocketCloseCode.Abnormal); + } + catch { - m_TokenSource.Cancel(); - m_Socket.Dispose(); } + + CleanupNoThrow(); + throw; } } @@ -515,118 +613,116 @@ public WebSocketState State public Task Send(byte[] bytes) { - // return m_Socket.SendAsync(buffer, WebSocketMessageType.Binary, true, CancellationToken.None); - return SendMessage(sendBytesQueue, WebSocketMessageType.Binary, new ArraySegment(bytes)); + if (bytes == null || bytes.Length == 0) + return Task.CompletedTask; + + return EnqueueSend(WebSocketMessageType.Binary, new ArraySegment(bytes)); } public Task SendText(string message) { - var encoded = Encoding.UTF8.GetBytes(message); + if (string.IsNullOrEmpty(message)) + return Task.CompletedTask; - // m_Socket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None); - return SendMessage(sendTextQueue, WebSocketMessageType.Text, new ArraySegment(encoded, 0, encoded.Length)); + var encoded = Encoding.UTF8.GetBytes(message); + return EnqueueSend(WebSocketMessageType.Text, new ArraySegment(encoded, 0, encoded.Length)); } - private async Task SendMessage(List> queue, WebSocketMessageType messageType, ArraySegment buffer) + private Task EnqueueSend(WebSocketMessageType messageType, ArraySegment buffer) { - // Return control to the calling method immediately. - // await Task.Yield (); + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - // Make sure we have data. - if (buffer.Count == 0) + m_SendQueue.Enqueue(new PendingSend { - return; - } + MessageType = messageType, + Buffer = buffer, + Tcs = tcs + }); - // The state of the connection is contained in the context Items dictionary. - bool sending; + EnsureSendPump(); + return tcs.Task; + } - lock (OutgoingMessageLock) - { - sending = isSending; + private void EnsureSendPump() + { + if (Interlocked.CompareExchange(ref m_SendPumpRunning, 1, 0) != 0) + return; - // If not, we are now. - if (!isSending) - { - isSending = true; - } - } + _ = PumpSendQueueAsync(); + } - if (!sending) + private async Task PumpSendQueueAsync() + { + try { - // Lock with a timeout, just in case. - if (!Monitor.TryEnter(m_Socket, 1000)) - { - // If we couldn't obtain exclusive access to the socket in one second, something is wrong. - await m_Socket.CloseAsync(WebSocketCloseStatus.InternalServerError, string.Empty, m_CancellationToken); - return; - } + await m_SendPumpGate.WaitAsync(m_CancellationToken); try { - // Send the message synchronously. - var t = m_Socket.SendAsync(buffer, messageType, true, m_CancellationToken); - t.Wait(m_CancellationToken); + while (true) + { + if (!m_SendQueue.TryDequeue(out var ps)) + break; + + try + { + if (m_Socket.State != System.Net.WebSockets.WebSocketState.Open) + throw new WebSocketInvalidStateException("WebSocket is not in open state."); + + await m_Socket.SendAsync(ps.Buffer, ps.MessageType, true, m_CancellationToken); + ps.Tcs.TrySetResult(true); + } + catch (Exception ex) + { + ps.Tcs.TrySetException(ex); + + if (m_Socket.State != System.Net.WebSockets.WebSocketState.Open) + { + FailAllPendingSends(ex); + break; + } + } + } } finally { - Monitor.Exit(m_Socket); - - // Note that we've finished sending. - lock (OutgoingMessageLock) - { - isSending = false; - } + m_SendPumpGate.Release(); } - - // Handle any queued messages. - await HandleQueue(queue, messageType); } - else + catch (OperationCanceledException oce) { - // Add the message to the queue. - lock (OutgoingMessageLock) - { - queue.Add(buffer); - } + FailAllPendingSends(oce); } - } - - private async Task HandleQueue(List> queue, WebSocketMessageType messageType) - { - var buffer = new ArraySegment(); - lock (OutgoingMessageLock) + catch (Exception ex) { - // Check for an item in the queue. - if (queue.Count > 0) + FailAllPendingSends(ex); + + try + { + OnError?.Invoke(ex.ToString()); + } + catch { - // Pull it off the top. - buffer = queue[0]; - queue.RemoveAt(0); } } - - // Send that message. - if (buffer.Count > 0) + finally { - await SendMessage(queue, messageType, buffer); + Interlocked.Exchange(ref m_SendPumpRunning, 0); + + if (!m_SendQueue.IsEmpty) + EnsureSendPump(); } } - private List m_MessageList = new List(); - - // simple dispatcher for queued messages. public void DispatchMessageQueue() { - if (m_MessageList.Count == 0) - { - return; - } - List messageListCopy; lock (IncomingMessageLock) { + if (m_MessageList.Count == 0) + return; + messageListCopy = new List(m_MessageList); m_MessageList.Clear(); } @@ -644,6 +740,7 @@ public async Task Receive() await new WaitForBackgroundThread(); ArraySegment buffer = new ArraySegment(new byte[8192]); + try { while (m_Socket.State == System.Net.WebSockets.WebSocketState.Open) @@ -661,24 +758,12 @@ public async Task Receive() ms.Seek(0, SeekOrigin.Begin); - if (result.MessageType == WebSocketMessageType.Text) - { - lock (IncomingMessageLock) - { - m_MessageList.Add(ms.ToArray()); - } - - //using (var reader = new StreamReader(ms, Encoding.UTF8)) - //{ - // string message = reader.ReadToEnd(); - // OnMessage?.Invoke(this, new MessageEventArgs(message)); - //} - } - else if (result.MessageType == WebSocketMessageType.Binary) + if (result.MessageType == WebSocketMessageType.Text || + result.MessageType == WebSocketMessageType.Binary) { lock (IncomingMessageLock) { - m_MessageList.Add(ms.ToArray()); + m_MessageList.Add(ms.ToArray()); } } else if (result.MessageType == WebSocketMessageType.Close) @@ -690,14 +775,44 @@ public async Task Receive() } } } - catch (Exception) + catch (Exception ex) { - m_TokenSource.Cancel(); + try + { + OnError?.Invoke(ex.ToString()); + } + catch + { + } + + try + { + m_TokenSource?.Cancel(); + } + catch + { + } } finally { - await new WaitForUpdate(); - OnClose?.Invoke(closeCode); + try + { + await new WaitForUpdate(); + } + catch + { + } + + try + { + OnClose?.Invoke(closeCode); + } + catch + { + } + + CleanupNoThrow(); + FailAllPendingSends(new WebSocketInvalidStateException("WebSocket closed.")); } } @@ -708,7 +823,13 @@ public async Task Close() await m_Socket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, m_CancellationToken); } } + + public Task WaitForClose() + { + return m_ReceiveTask ?? Task.CompletedTask; + } } + #endif /// @@ -720,117 +841,112 @@ public async Task Close() /// public static class WebSocketFactory { - #if UNITY_WEBGL && !UNITY_EDITOR - /* Map of websocket instances */ - public static Dictionary instances = new Dictionary (); - - /* Delegates */ - public delegate void OnOpenCallback (int instanceId); - public delegate void OnMessageCallback (int instanceId, System.IntPtr msgPtr, int msgSize); - public delegate void OnErrorCallback (int instanceId, System.IntPtr errorPtr); - public delegate void OnCloseCallback (int instanceId, int closeCode); - - /* WebSocket JSLIB callback setters and other functions */ - [DllImport ("__Internal")] - public static extern int WebSocketAllocate (string url); + /* Map of websocket instances */ + public static Dictionary instances = new Dictionary(); - [DllImport ("__Internal")] - public static extern int WebSocketAddSubProtocol (int instanceId, string subprotocol); + /* Delegates */ + public delegate void OnOpenCallback(int instanceId); + public delegate void OnMessageCallback(int instanceId, System.IntPtr msgPtr, int msgSize); + public delegate void OnErrorCallback(int instanceId, System.IntPtr errorPtr); + public delegate void OnCloseCallback(int instanceId, int closeCode); - [DllImport ("__Internal")] - public static extern void WebSocketFree (int instanceId); + /* WebSocket JSLIB callback setters and other functions */ + [DllImport("__Internal")] + public static extern int WebSocketAllocate(string url); - [DllImport ("__Internal")] - public static extern void WebSocketSetOnOpen (OnOpenCallback callback); + [DllImport("__Internal")] + public static extern int WebSocketAddSubProtocol(int instanceId, string subprotocol); - [DllImport ("__Internal")] - public static extern void WebSocketSetOnMessage (OnMessageCallback callback); + [DllImport("__Internal")] + public static extern void WebSocketFree(int instanceId); - [DllImport ("__Internal")] - public static extern void WebSocketSetOnError (OnErrorCallback callback); + [DllImport("__Internal")] + public static extern void WebSocketSetOnOpen(OnOpenCallback callback); - [DllImport ("__Internal")] - public static extern void WebSocketSetOnClose (OnCloseCallback callback); + [DllImport("__Internal")] + public static extern void WebSocketSetOnMessage(OnMessageCallback callback); - /* If callbacks was initialized and set */ - public static bool isInitialized = false; + [DllImport("__Internal")] + public static extern void WebSocketSetOnError(OnErrorCallback callback); - /* - * Initialize WebSocket callbacks to JSLIB - */ - public static void Initialize () { + [DllImport("__Internal")] + public static extern void WebSocketSetOnClose(OnCloseCallback callback); - WebSocketSetOnOpen (DelegateOnOpenEvent); - WebSocketSetOnMessage (DelegateOnMessageEvent); - WebSocketSetOnError (DelegateOnErrorEvent); - WebSocketSetOnClose (DelegateOnCloseEvent); + /* If callbacks was initialized and set */ + public static bool isInitialized = false; - isInitialized = true; - - } - - /// - /// Called when instance is destroyed (by destructor) - /// Method removes instance from map and free it in JSLIB implementation - /// - /// Instance identifier. - public static void HandleInstanceDestroy (int instanceId) { - - instances.Remove (instanceId); - WebSocketFree (instanceId); - - } - - [MonoPInvokeCallback (typeof (OnOpenCallback))] - public static void DelegateOnOpenEvent (int instanceId) { - - WebSocket instanceRef; - - if (instances.TryGetValue (instanceId, out instanceRef)) { - instanceRef.DelegateOnOpenEvent (); - } - - } - - [MonoPInvokeCallback (typeof (OnMessageCallback))] - public static void DelegateOnMessageEvent (int instanceId, System.IntPtr msgPtr, int msgSize) { - - WebSocket instanceRef; - - if (instances.TryGetValue (instanceId, out instanceRef)) { - byte[] msg = new byte[msgSize]; - Marshal.Copy (msgPtr, msg, 0, msgSize); - - instanceRef.DelegateOnMessageEvent (msg); - } + /* + * Initialize WebSocket callbacks to JSLIB + */ + public static void Initialize() + { + WebSocketSetOnOpen(DelegateOnOpenEvent); + WebSocketSetOnMessage(DelegateOnMessageEvent); + WebSocketSetOnError(DelegateOnErrorEvent); + WebSocketSetOnClose(DelegateOnCloseEvent); - } + isInitialized = true; + } - [MonoPInvokeCallback (typeof (OnErrorCallback))] - public static void DelegateOnErrorEvent (int instanceId, System.IntPtr errorPtr) { + /// + /// Called when instance is destroyed (by destructor) + /// Method removes instance from map and free it in JSLIB implementation + /// + /// Instance identifier. + public static void HandleInstanceDestroy(int instanceId) + { + instances.Remove(instanceId); + WebSocketFree(instanceId); + } - WebSocket instanceRef; + [MonoPInvokeCallback(typeof(OnOpenCallback))] + public static void DelegateOnOpenEvent(int instanceId) + { + WebSocket instanceRef; - if (instances.TryGetValue (instanceId, out instanceRef)) { + if (instances.TryGetValue(instanceId, out instanceRef)) + { + instanceRef.DelegateOnOpenEvent(); + } + } - string errorMsg = Marshal.PtrToStringAuto (errorPtr); - instanceRef.DelegateOnErrorEvent (errorMsg); + [MonoPInvokeCallback(typeof(OnMessageCallback))] + public static void DelegateOnMessageEvent(int instanceId, System.IntPtr msgPtr, int msgSize) + { + WebSocket instanceRef; - } + if (instances.TryGetValue(instanceId, out instanceRef)) + { + byte[] msg = new byte[msgSize]; + Marshal.Copy(msgPtr, msg, 0, msgSize); - } + instanceRef.DelegateOnMessageEvent(msg); + } + } - [MonoPInvokeCallback (typeof (OnCloseCallback))] - public static void DelegateOnCloseEvent (int instanceId, int closeCode) { + [MonoPInvokeCallback(typeof(OnErrorCallback))] + public static void DelegateOnErrorEvent(int instanceId, System.IntPtr errorPtr) + { + WebSocket instanceRef; - WebSocket instanceRef; + if (instances.TryGetValue(instanceId, out instanceRef)) + { + string errorMsg = Marshal.PtrToStringAuto(errorPtr); + instanceRef.DelegateOnErrorEvent(errorMsg); + } + } - if (instances.TryGetValue (instanceId, out instanceRef)) { - instanceRef.DelegateOnCloseEvent (closeCode); - } + [MonoPInvokeCallback(typeof(OnCloseCallback))] + public static void DelegateOnCloseEvent(int instanceId, int closeCode) + { + WebSocket instanceRef; - } + if (instances.TryGetValue(instanceId, out instanceRef)) + { + instanceRef.DelegateOnCloseEvent(closeCode); + } + } #endif /// @@ -842,7 +958,5 @@ public static WebSocket CreateInstance(string url) { return new WebSocket(url); } - } - }