Initial commit: Client Doc docs Server Tools
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6c110a898ae8b0b41bcf4da49c2b0425
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+364
@@ -0,0 +1,364 @@
|
||||
#if !NET_LEGACY && (UNITY_EDITOR || !UNITY_WEBGL)
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.WebSockets;
|
||||
using System.IO;
|
||||
|
||||
namespace UnityWebSocket
|
||||
{
|
||||
public class WebSocket : IWebSocket
|
||||
{
|
||||
public string Address { get; private set; }
|
||||
public string[] SubProtocols { get; private set; }
|
||||
|
||||
public WebSocketState ReadyState
|
||||
{
|
||||
get
|
||||
{
|
||||
if (socket == null)
|
||||
return WebSocketState.Closed;
|
||||
switch (socket.State)
|
||||
{
|
||||
case System.Net.WebSockets.WebSocketState.Closed:
|
||||
case System.Net.WebSockets.WebSocketState.None:
|
||||
return WebSocketState.Closed;
|
||||
case System.Net.WebSockets.WebSocketState.CloseReceived:
|
||||
case System.Net.WebSockets.WebSocketState.CloseSent:
|
||||
return WebSocketState.Closing;
|
||||
case System.Net.WebSockets.WebSocketState.Connecting:
|
||||
return WebSocketState.Connecting;
|
||||
case System.Net.WebSockets.WebSocketState.Open:
|
||||
return WebSocketState.Open;
|
||||
}
|
||||
return WebSocketState.Closed;
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<OpenEventArgs> OnOpen;
|
||||
public event EventHandler<CloseEventArgs> OnClose;
|
||||
public event EventHandler<ErrorEventArgs> OnError;
|
||||
public event EventHandler<MessageEventArgs> OnMessage;
|
||||
|
||||
private ClientWebSocket socket;
|
||||
private bool isOpening => socket != null && socket.State == System.Net.WebSockets.WebSocketState.Open;
|
||||
|
||||
#region APIs
|
||||
public WebSocket(string address)
|
||||
{
|
||||
this.Address = address;
|
||||
}
|
||||
|
||||
public WebSocket(string address, string subProtocol)
|
||||
{
|
||||
this.Address = address;
|
||||
this.SubProtocols = new string[] { subProtocol };
|
||||
}
|
||||
|
||||
public WebSocket(string address, string[] subProtocols)
|
||||
{
|
||||
this.Address = address;
|
||||
this.SubProtocols = subProtocols;
|
||||
}
|
||||
|
||||
public void ConnectAsync()
|
||||
{
|
||||
#if !UNITY_WEB_SOCKET_ENABLE_ASYNC
|
||||
WebSocketManager.Instance.Add(this);
|
||||
#endif
|
||||
if (socket != null)
|
||||
{
|
||||
HandleError(new Exception("Socket is busy."));
|
||||
return;
|
||||
}
|
||||
socket = new ClientWebSocket();
|
||||
if (this.SubProtocols != null)
|
||||
{
|
||||
foreach (var protocol in this.SubProtocols)
|
||||
{
|
||||
if (string.IsNullOrEmpty(protocol)) continue;
|
||||
Log($"Add Sub Protocol {protocol}");
|
||||
socket.Options.AddSubProtocol(protocol);
|
||||
}
|
||||
}
|
||||
Task.Run(ConnectTask);
|
||||
}
|
||||
|
||||
public void CloseAsync()
|
||||
{
|
||||
if (!isOpening) return;
|
||||
SendBufferAsync(new SendBuffer(null, WebSocketMessageType.Close));
|
||||
}
|
||||
|
||||
public void SendAsync(byte[] data)
|
||||
{
|
||||
if (!isOpening) return;
|
||||
var buffer = new SendBuffer(data, WebSocketMessageType.Binary);
|
||||
SendBufferAsync(buffer);
|
||||
}
|
||||
|
||||
public void SendAsync(string text)
|
||||
{
|
||||
if (!isOpening) return;
|
||||
var data = Encoding.UTF8.GetBytes(text);
|
||||
var buffer = new SendBuffer(data, WebSocketMessageType.Text);
|
||||
SendBufferAsync(buffer);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
private async Task ConnectTask()
|
||||
{
|
||||
Log("Connect Task Begin ...");
|
||||
|
||||
try
|
||||
{
|
||||
var uri = new Uri(Address);
|
||||
UnityEngine.Debug.Log($"WebSocket Connect {Address}");
|
||||
await socket.ConnectAsync(uri, CancellationToken.None);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
HandleError(e);
|
||||
HandleClose((ushort)CloseStatusCode.Abnormal, e.Message);
|
||||
SocketDispose();
|
||||
return;
|
||||
}
|
||||
UnityEngine.Debug.Log("WebSocket Connect Open ok!!");
|
||||
HandleOpen();
|
||||
|
||||
Log("Connect Task End !");
|
||||
|
||||
await ReceiveTask();
|
||||
}
|
||||
|
||||
class SendBuffer
|
||||
{
|
||||
public byte[] data;
|
||||
public WebSocketMessageType type;
|
||||
public SendBuffer(byte[] data, WebSocketMessageType type)
|
||||
{
|
||||
this.data = data;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
private object sendQueueLock = new object();
|
||||
private Queue<SendBuffer> sendQueue = new Queue<SendBuffer>();
|
||||
private bool isSendTaskRunning;
|
||||
|
||||
private void SendBufferAsync(SendBuffer buffer)
|
||||
{
|
||||
if (isSendTaskRunning)
|
||||
{
|
||||
lock (sendQueueLock)
|
||||
{
|
||||
if (buffer.type == WebSocketMessageType.Close)
|
||||
{
|
||||
sendQueue.Clear();
|
||||
}
|
||||
sendQueue.Enqueue(buffer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
isSendTaskRunning = true;
|
||||
sendQueue.Enqueue(buffer);
|
||||
Task.Run(SendTask);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SendTask()
|
||||
{
|
||||
Log("Send Task Begin ...");
|
||||
|
||||
try
|
||||
{
|
||||
SendBuffer buffer = null;
|
||||
while (sendQueue.Count > 0 && isOpening)
|
||||
{
|
||||
lock (sendQueueLock)
|
||||
{
|
||||
buffer = sendQueue.Dequeue();
|
||||
}
|
||||
if (buffer.type == WebSocketMessageType.Close)
|
||||
{
|
||||
Log($"Close Send Begin ...");
|
||||
await socket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "Normal Closure", CancellationToken.None);
|
||||
Log($"Close Send End !");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log($"Send, type: {buffer.type}, size: {buffer.data.Length}, queue left: {sendQueue.Count}");
|
||||
await socket.SendAsync(new ArraySegment<byte>(buffer.data), buffer.type, true, CancellationToken.None);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
HandleError(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
isSendTaskRunning = false;
|
||||
}
|
||||
|
||||
Log("Send Task End !");
|
||||
}
|
||||
|
||||
private async Task ReceiveTask()
|
||||
{
|
||||
Log("Receive Task Begin ...");
|
||||
|
||||
string closeReason = "";
|
||||
ushort closeCode = 0;
|
||||
bool isClosed = false;
|
||||
var segment = new ArraySegment<byte>(new byte[8192]);
|
||||
var ms = new MemoryStream();
|
||||
|
||||
try
|
||||
{
|
||||
while (!isClosed)
|
||||
{
|
||||
var result = await socket.ReceiveAsync(segment, CancellationToken.None);
|
||||
//UnityEngine.Debug.Log($"C# WebSocket recv {result.Count}");
|
||||
ms.Write(segment.Array, 0, result.Count);
|
||||
if (!result.EndOfMessage) continue;
|
||||
//UnityEngine.Debug.Log($"C# WebSocket recv 2");
|
||||
var data = ms.ToArray();
|
||||
ms.SetLength(0);
|
||||
switch (result.MessageType)
|
||||
{
|
||||
case WebSocketMessageType.Binary:
|
||||
HandleMessage(Opcode.Binary, data);
|
||||
break;
|
||||
case WebSocketMessageType.Text:
|
||||
HandleMessage(Opcode.Text, data);
|
||||
break;
|
||||
case WebSocketMessageType.Close:
|
||||
isClosed = true;
|
||||
closeCode = (ushort)result.CloseStatus;
|
||||
closeReason = result.CloseStatusDescription;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
HandleError(e);
|
||||
closeCode = (ushort)CloseStatusCode.Abnormal;
|
||||
closeReason = e.Message;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ms.Close();
|
||||
}
|
||||
|
||||
HandleClose(closeCode, closeReason);
|
||||
SocketDispose();
|
||||
|
||||
Log("Receive Task End !");
|
||||
}
|
||||
|
||||
private void SocketDispose()
|
||||
{
|
||||
sendQueue.Clear();
|
||||
socket.Dispose();
|
||||
socket = null;
|
||||
}
|
||||
|
||||
private void HandleOpen()
|
||||
{
|
||||
Log("OnOpen");
|
||||
#if !UNITY_WEB_SOCKET_ENABLE_ASYNC
|
||||
HandleEventSync(new OpenEventArgs());
|
||||
#else
|
||||
OnOpen?.Invoke(this, new OpenEventArgs());
|
||||
#endif
|
||||
}
|
||||
|
||||
private void HandleMessage(Opcode opcode, byte[] rawData)
|
||||
{
|
||||
Log($"OnMessage, type: {opcode}, size: {rawData.Length}");
|
||||
#if !UNITY_WEB_SOCKET_ENABLE_ASYNC
|
||||
HandleEventSync(new MessageEventArgs(opcode, rawData));
|
||||
#else
|
||||
OnMessage?.Invoke(this, new MessageEventArgs(opcode, rawData));
|
||||
#endif
|
||||
}
|
||||
|
||||
private void HandleClose(ushort code, string reason)
|
||||
{
|
||||
Log($"OnClose, code: {code}, reason: {reason}");
|
||||
#if !UNITY_WEB_SOCKET_ENABLE_ASYNC
|
||||
HandleEventSync(new CloseEventArgs(code, reason));
|
||||
#else
|
||||
OnClose?.Invoke(this, new CloseEventArgs(code, reason));
|
||||
#endif
|
||||
}
|
||||
|
||||
private void HandleError(Exception exception)
|
||||
{
|
||||
Log("OnError, error: " + exception.Message);
|
||||
#if !UNITY_WEB_SOCKET_ENABLE_ASYNC
|
||||
HandleEventSync(new ErrorEventArgs(exception.Message));
|
||||
#else
|
||||
OnError?.Invoke(this, new ErrorEventArgs(exception.Message));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !UNITY_WEB_SOCKET_ENABLE_ASYNC
|
||||
private readonly Queue<EventArgs> eventQueue = new Queue<EventArgs>();
|
||||
private readonly object eventQueueLock = new object();
|
||||
private void HandleEventSync(EventArgs eventArgs)
|
||||
{
|
||||
lock (eventQueueLock)
|
||||
{
|
||||
eventQueue.Enqueue(eventArgs);
|
||||
}
|
||||
}
|
||||
|
||||
internal void Update()
|
||||
{
|
||||
EventArgs e;
|
||||
while (eventQueue.Count > 0)
|
||||
{
|
||||
lock (eventQueueLock)
|
||||
{
|
||||
e = eventQueue.Dequeue();
|
||||
}
|
||||
|
||||
if (e is CloseEventArgs)
|
||||
{
|
||||
OnClose?.Invoke(this, e as CloseEventArgs);
|
||||
WebSocketManager.Instance.Remove(this);
|
||||
}
|
||||
else if (e is OpenEventArgs)
|
||||
{
|
||||
OnOpen?.Invoke(this, e as OpenEventArgs);
|
||||
}
|
||||
else if (e is MessageEventArgs)
|
||||
{
|
||||
OnMessage?.Invoke(this, e as MessageEventArgs);
|
||||
}
|
||||
else if (e is ErrorEventArgs)
|
||||
{
|
||||
OnError?.Invoke(this, e as ErrorEventArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[System.Diagnostics.Conditional("UNITY_WEB_SOCKET_LOG")]
|
||||
static void Log(string msg)
|
||||
{
|
||||
UnityEngine.Debug.Log($"<color=yellow>[UnityWebSocket]</color>" +
|
||||
$"<color=green>[T-{Thread.CurrentThread.ManagedThreadId:D3}]</color>" +
|
||||
$"<color=red>[{DateTime.Now.TimeOfDay}]</color>" +
|
||||
$" {msg}");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d10f88a23641b4beb8df74460fb7f705
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
#if !NET_LEGACY && (UNITY_EDITOR || !UNITY_WEBGL) && !UNITY_WEB_SOCKET_ENABLE_ASYNC
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityWebSocket
|
||||
{
|
||||
[DefaultExecutionOrder(-10000)]
|
||||
internal class WebSocketManager : MonoBehaviour
|
||||
{
|
||||
private const string rootName = "[UnityWebSocket]";
|
||||
private static WebSocketManager _instance;
|
||||
public static WebSocketManager Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_instance) CreateInstance();
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
DontDestroyOnLoad(gameObject);
|
||||
}
|
||||
|
||||
public static void CreateInstance()
|
||||
{
|
||||
GameObject go = GameObject.Find("/" + rootName);
|
||||
if (!go) go = new GameObject(rootName);
|
||||
_instance = go.GetComponent<WebSocketManager>();
|
||||
if (!_instance) _instance = go.AddComponent<WebSocketManager>();
|
||||
}
|
||||
|
||||
private readonly List<WebSocket> sockets = new List<WebSocket>();
|
||||
|
||||
public void Add(WebSocket socket)
|
||||
{
|
||||
if (!sockets.Contains(socket))
|
||||
sockets.Add(socket);
|
||||
}
|
||||
|
||||
public void Remove(WebSocket socket)
|
||||
{
|
||||
if (sockets.Contains(socket))
|
||||
sockets.Remove(socket);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (sockets.Count <= 0) return;
|
||||
for (int i = sockets.Count - 1; i >= 0; i--)
|
||||
{
|
||||
sockets[i].Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 99157fb5def394c83a9e5342036c92b0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1fb37927ec1ce4def9c5e7cff883f9f5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,147 @@
|
||||
#if !UNITY_EDITOR && UNITY_WEBGL
|
||||
using System;
|
||||
|
||||
namespace UnityWebSocket
|
||||
{
|
||||
public class WebSocket : IWebSocket
|
||||
{
|
||||
public string Address { get; private set; }
|
||||
public string[] SubProtocols { get; private set; }
|
||||
public WebSocketState ReadyState { get { return (WebSocketState)WebSocketManager.WebSocketGetState(instanceId); } }
|
||||
|
||||
public event EventHandler<OpenEventArgs> OnOpen;
|
||||
public event EventHandler<CloseEventArgs> OnClose;
|
||||
public event EventHandler<ErrorEventArgs> OnError;
|
||||
public event EventHandler<MessageEventArgs> OnMessage;
|
||||
|
||||
internal int instanceId = 0;
|
||||
|
||||
public WebSocket(string address)
|
||||
{
|
||||
this.Address = address;
|
||||
AllocateInstance();
|
||||
}
|
||||
|
||||
public WebSocket(string address, string subProtocol)
|
||||
{
|
||||
this.Address = address;
|
||||
this.SubProtocols = new string[] { subProtocol };
|
||||
AllocateInstance();
|
||||
}
|
||||
|
||||
public WebSocket(string address, string[] subProtocols)
|
||||
{
|
||||
this.Address = address;
|
||||
this.SubProtocols = subProtocols;
|
||||
AllocateInstance();
|
||||
}
|
||||
|
||||
internal void AllocateInstance()
|
||||
{
|
||||
instanceId = WebSocketManager.AllocateInstance(this.Address);
|
||||
Log($"Allocate socket with instanceId: {instanceId}");
|
||||
if (this.SubProtocols == null) return;
|
||||
foreach (var protocol in this.SubProtocols)
|
||||
{
|
||||
if (string.IsNullOrEmpty(protocol)) continue;
|
||||
Log($"Add Sub Protocol {protocol}, with instanceId: {instanceId}");
|
||||
int code = WebSocketManager.WebSocketAddSubProtocol(instanceId, protocol);
|
||||
if (code < 0)
|
||||
{
|
||||
HandleOnError(GetErrorMessageFromCode(code));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~WebSocket()
|
||||
{
|
||||
Log($"Free socket with instanceId: {instanceId}");
|
||||
WebSocketManager.WebSocketFree(instanceId);
|
||||
}
|
||||
|
||||
public void ConnectAsync()
|
||||
{
|
||||
Log($"Connect with instanceId: {instanceId}");
|
||||
WebSocketManager.Add(this);
|
||||
int code = WebSocketManager.WebSocketConnect(instanceId);
|
||||
if (code < 0) HandleOnError(GetErrorMessageFromCode(code));
|
||||
}
|
||||
|
||||
public void CloseAsync()
|
||||
{
|
||||
Log($"Close with instanceId: {instanceId}");
|
||||
int code = WebSocketManager.WebSocketClose(instanceId, (int)CloseStatusCode.Normal, "Normal Closure");
|
||||
if (code < 0) HandleOnError(GetErrorMessageFromCode(code));
|
||||
}
|
||||
|
||||
public void SendAsync(string text)
|
||||
{
|
||||
Log($"Send, type: {Opcode.Text}, size: {text.Length}");
|
||||
int code = WebSocketManager.WebSocketSendStr(instanceId, text);
|
||||
if (code < 0) HandleOnError(GetErrorMessageFromCode(code));
|
||||
}
|
||||
|
||||
public void SendAsync(byte[] data)
|
||||
{
|
||||
Log($"Send, type: {Opcode.Binary}, size: {data.Length}");
|
||||
int code = WebSocketManager.WebSocketSend(instanceId, data, data.Length);
|
||||
if (code < 0) HandleOnError(GetErrorMessageFromCode(code));
|
||||
}
|
||||
|
||||
internal void HandleOnOpen()
|
||||
{
|
||||
Log("OnOpen");
|
||||
OnOpen?.Invoke(this, new OpenEventArgs());
|
||||
}
|
||||
|
||||
internal void HandleOnMessage(byte[] rawData)
|
||||
{
|
||||
Log($"OnMessage, type: {Opcode.Binary}, size: {rawData.Length}");
|
||||
OnMessage?.Invoke(this, new MessageEventArgs(Opcode.Binary, rawData));
|
||||
}
|
||||
|
||||
internal void HandleOnMessageStr(string data)
|
||||
{
|
||||
Log($"OnMessage, type: {Opcode.Text}, size: {data.Length}");
|
||||
OnMessage?.Invoke(this, new MessageEventArgs(Opcode.Text, data));
|
||||
}
|
||||
|
||||
internal void HandleOnClose(ushort code, string reason)
|
||||
{
|
||||
Log($"OnClose, code: {code}, reason: {reason}");
|
||||
OnClose?.Invoke(this, new CloseEventArgs(code, reason));
|
||||
WebSocketManager.Remove(instanceId);
|
||||
}
|
||||
|
||||
internal void HandleOnError(string msg)
|
||||
{
|
||||
Log("OnError, error: " + msg);
|
||||
OnError?.Invoke(this, new ErrorEventArgs(msg));
|
||||
}
|
||||
|
||||
internal static string GetErrorMessageFromCode(int errorCode)
|
||||
{
|
||||
switch (errorCode)
|
||||
{
|
||||
case -1: return "WebSocket instance not found.";
|
||||
case -2: return "WebSocket is already connected or in connecting state.";
|
||||
case -3: return "WebSocket is not connected.";
|
||||
case -4: return "WebSocket is already closing.";
|
||||
case -5: return "WebSocket is already closed.";
|
||||
case -6: return "WebSocket is not in open state.";
|
||||
case -7: return "Cannot close WebSocket. An invalid code was specified or reason is too long.";
|
||||
default: return $"Unknown error code {errorCode}.";
|
||||
}
|
||||
}
|
||||
|
||||
[System.Diagnostics.Conditional("UNITY_WEB_SOCKET_LOG")]
|
||||
static void Log(string msg)
|
||||
{
|
||||
UnityEngine.Debug.Log($"[UnityWebSocket]" +
|
||||
$"[{DateTime.Now.TimeOfDay}]" +
|
||||
$" {msg}");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74a5b3c22251243d2a2f33e74741559d
|
||||
timeCreated: 1466578513
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
#if !UNITY_EDITOR && UNITY_WEBGL
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using AOT;
|
||||
|
||||
namespace UnityWebSocket
|
||||
{
|
||||
/// <summary>
|
||||
/// Class providing static access methods to work with JSLIB WebSocket
|
||||
/// </summary>
|
||||
internal static class WebSocketManager
|
||||
{
|
||||
/* Map of websocket instances */
|
||||
private static Dictionary<int, WebSocket> sockets = new Dictionary<int, WebSocket>();
|
||||
|
||||
/* Delegates */
|
||||
public delegate void OnOpenCallback(int instanceId);
|
||||
public delegate void OnMessageCallback(int instanceId, IntPtr msgPtr, int msgSize);
|
||||
public delegate void OnMessageStrCallback(int instanceId, IntPtr msgStrPtr);
|
||||
public delegate void OnErrorCallback(int instanceId, IntPtr errorPtr);
|
||||
public delegate void OnCloseCallback(int instanceId, int closeCode, IntPtr reasonPtr);
|
||||
|
||||
/* 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 WebSocketSendStr(int instanceId, string dataPtr);
|
||||
|
||||
[DllImport("__Internal")]
|
||||
public static extern int WebSocketGetState(int instanceId);
|
||||
|
||||
/* WebSocket JSLIB callback setters and other functions */
|
||||
[DllImport("__Internal")]
|
||||
public static extern int WebSocketAllocate(string url);
|
||||
|
||||
[DllImport("__Internal")]
|
||||
public static extern int WebSocketAddSubProtocol(int instanceId, string protocol);
|
||||
|
||||
[DllImport("__Internal")]
|
||||
public static extern void WebSocketFree(int instanceId);
|
||||
|
||||
[DllImport("__Internal")]
|
||||
public static extern void WebSocketSetOnOpen(OnOpenCallback callback);
|
||||
|
||||
[DllImport("__Internal")]
|
||||
public static extern void WebSocketSetOnMessage(OnMessageCallback callback);
|
||||
|
||||
[DllImport("__Internal")]
|
||||
public static extern void WebSocketSetOnMessageStr(OnMessageStrCallback callback);
|
||||
|
||||
[DllImport("__Internal")]
|
||||
public static extern void WebSocketSetOnError(OnErrorCallback callback);
|
||||
|
||||
[DllImport("__Internal")]
|
||||
public static extern void WebSocketSetOnClose(OnCloseCallback callback);
|
||||
|
||||
/* If callbacks was initialized and set */
|
||||
private static bool isInitialized = false;
|
||||
|
||||
/* Initialize WebSocket callbacks to JSLIB */
|
||||
private static void Initialize()
|
||||
{
|
||||
WebSocketSetOnOpen(DelegateOnOpenEvent);
|
||||
WebSocketSetOnMessage(DelegateOnMessageEvent);
|
||||
WebSocketSetOnMessageStr(DelegateOnMessageStrEvent);
|
||||
WebSocketSetOnError(DelegateOnErrorEvent);
|
||||
WebSocketSetOnClose(DelegateOnCloseEvent);
|
||||
|
||||
isInitialized = true;
|
||||
}
|
||||
|
||||
[MonoPInvokeCallback(typeof(OnOpenCallback))]
|
||||
public static void DelegateOnOpenEvent(int instanceId)
|
||||
{
|
||||
if (sockets.TryGetValue(instanceId, out var socket))
|
||||
{
|
||||
socket.HandleOnOpen();
|
||||
}
|
||||
}
|
||||
|
||||
[MonoPInvokeCallback(typeof(OnMessageCallback))]
|
||||
public static void DelegateOnMessageEvent(int instanceId, IntPtr msgPtr, int msgSize)
|
||||
{
|
||||
if (sockets.TryGetValue(instanceId, out var socket))
|
||||
{
|
||||
var bytes = new byte[msgSize];
|
||||
Marshal.Copy(msgPtr, bytes, 0, msgSize);
|
||||
socket.HandleOnMessage(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
[MonoPInvokeCallback(typeof(OnMessageCallback))]
|
||||
public static void DelegateOnMessageStrEvent(int instanceId, IntPtr msgStrPtr)
|
||||
{
|
||||
if (sockets.TryGetValue(instanceId, out var socket))
|
||||
{
|
||||
string msgStr = Marshal.PtrToStringAuto(msgStrPtr);
|
||||
socket.HandleOnMessageStr(msgStr);
|
||||
}
|
||||
}
|
||||
|
||||
[MonoPInvokeCallback(typeof(OnErrorCallback))]
|
||||
public static void DelegateOnErrorEvent(int instanceId, IntPtr errorPtr)
|
||||
{
|
||||
if (sockets.TryGetValue(instanceId, out var socket))
|
||||
{
|
||||
string errorMsg = Marshal.PtrToStringAuto(errorPtr);
|
||||
socket.HandleOnError(errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
[MonoPInvokeCallback(typeof(OnCloseCallback))]
|
||||
public static void DelegateOnCloseEvent(int instanceId, int closeCode, IntPtr reasonPtr)
|
||||
{
|
||||
if (sockets.TryGetValue(instanceId, out var socket))
|
||||
{
|
||||
string reason = Marshal.PtrToStringAuto(reasonPtr);
|
||||
socket.HandleOnClose((ushort)closeCode, reason);
|
||||
}
|
||||
}
|
||||
|
||||
internal static int AllocateInstance(string address)
|
||||
{
|
||||
if (!isInitialized) Initialize();
|
||||
return WebSocketAllocate(address);
|
||||
}
|
||||
|
||||
internal static void Add(WebSocket socket)
|
||||
{
|
||||
if (!sockets.ContainsKey(socket.instanceId))
|
||||
{
|
||||
sockets.Add(socket.instanceId, socket);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Remove(int instanceId)
|
||||
{
|
||||
if (sockets.ContainsKey(instanceId))
|
||||
{
|
||||
sockets.Remove(instanceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 246cdc66a1e2047148371a8e56e17d3a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user