using System; using System.Collections.Generic; using System.Linq; using AOT; namespace JamesFrowen.SimpleWeb { public class WebSocketClientWebGl : SimpleWebClient { static readonly Dictionary instances = new Dictionary(); /// /// key for instances sent between c# and js /// int index; /// /// Message sent by high level while still connecting, they will be send after onOpen is called /// this is a workaround for mirage where send it called right after Connect /// Queue ConnectingSendQueue; internal WebSocketClientWebGl(int maxMessageSize, int maxMessagesPerTick) : base(maxMessageSize, maxMessagesPerTick) { #if !UNITY_WEBGL || UNITY_EDITOR throw new NotSupportedException(); #endif } public bool CheckJsConnected() => SimpleWebJSLib.IsConnected(index); public override void Connect(Uri serverAddress) { index = SimpleWebJSLib.Connect(serverAddress.ToString(), OpenCallback, CloseCallBack, MessageCallback, ErrorCallback); instances.Add(index, this); state = ClientState.Connecting; } public override void Disconnect() { state = ClientState.Disconnecting; // disconnect should cause closeCallback and OnDisconnect to be called SimpleWebJSLib.Disconnect(index); } public override void Send(ArraySegment segment) { if (segment.Count > maxMessageSize) { Log.Error($"Cant send message with length {segment.Count} because it is over the max size of {maxMessageSize}"); return; } if (state == ClientState.Connected) { SimpleWebJSLib.Send(index, segment.Array, segment.Offset, segment.Count); } else { if (ConnectingSendQueue == null) ConnectingSendQueue = new Queue(); ConnectingSendQueue.Enqueue(segment.ToArray()); } } void onOpen() { receiveQueue.Enqueue(new Message(EventType.Connected)); state = ClientState.Connected; if (ConnectingSendQueue != null) { while (ConnectingSendQueue.Count > 0) { byte[] next = ConnectingSendQueue.Dequeue(); SimpleWebJSLib.Send(index, next, 0, next.Length); } ConnectingSendQueue = null; } } void onClose() { // this code should be last in this class receiveQueue.Enqueue(new Message(EventType.Disconnected)); state = ClientState.NotConnected; instances.Remove(index); } void onMessage(IntPtr bufferPtr, int count) { try { ArrayBuffer buffer = bufferPool.Take(count); buffer.CopyFrom(bufferPtr, count); receiveQueue.Enqueue(new Message(buffer)); } catch (Exception e) { Log.Error($"onData {e.GetType()}: {e.Message}\n{e.StackTrace}"); receiveQueue.Enqueue(new Message(e)); } } void onErr() { receiveQueue.Enqueue(new Message(new Exception("Javascript Websocket error"))); Disconnect(); } [MonoPInvokeCallback(typeof(Action))] static void OpenCallback(int index) => instances[index].onOpen(); [MonoPInvokeCallback(typeof(Action))] static void CloseCallBack(int index) => instances[index].onClose(); [MonoPInvokeCallback(typeof(Action))] static void MessageCallback(int index, IntPtr bufferPtr, int count) => instances[index].onMessage(bufferPtr, count); [MonoPInvokeCallback(typeof(Action))] static void ErrorCallback(int index) => instances[index].onErr(); } }