Space-Smash-Out/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Client/Webgl/WebSocketClientWebGl.cs

126 lines
4.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using AOT;
namespace JamesFrowen.SimpleWeb
{
public class WebSocketClientWebGl : SimpleWebClient
{
static readonly Dictionary<int, WebSocketClientWebGl> instances = new Dictionary<int, WebSocketClientWebGl>();
/// <summary>
/// key for instances sent between c# and js
/// </summary>
int index;
/// <summary>
/// Message sent by high level while still connecting, they will be send after onOpen is called
/// <para>this is a workaround for mirage where send it called right after Connect</para>
/// </summary>
Queue<byte[]> 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<byte> 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<byte[]>();
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<int>))]
static void OpenCallback(int index) => instances[index].onOpen();
[MonoPInvokeCallback(typeof(Action<int>))]
static void CloseCallBack(int index) => instances[index].onClose();
[MonoPInvokeCallback(typeof(Action<int, IntPtr, int>))]
static void MessageCallback(int index, IntPtr bufferPtr, int count) => instances[index].onMessage(bufferPtr, count);
[MonoPInvokeCallback(typeof(Action<int>))]
static void ErrorCallback(int index) => instances[index].onErr();
}
}