#if UNITY_WEBGL // && !UNITY_EDITOR using System; namespace XGame.Framework.Network.Web { public class WebSocket : IRemoteSession, IDisposable { internal WebSocketState ReadyState => (WebSocketState)WebSocketService.WebSocketGetState(instanceId); private volatile SessionStatus _status = SessionStatus.FREE; public SessionStatus Status => _status; public SessionAddress Address { get; private set; } internal int instanceId = 0; private ISessionContext _context; internal WebSocket(ISessionContext context) { _context = context; } //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 = WebSocketService.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 = WebSocketService.WebSocketAddSubProtocol(instanceId, protocol); // if (code < 0) // { // HandleOnError(GetErrorMessageFromCode(code)); // break; // } // } //} //~WebSocket() //{ // Log($"Free socket with instanceId: {instanceId}"); // WebSocketService.WebSocketFree(instanceId); //} //public void ConnectAsync() //{ // Log($"Connect with instanceId: {instanceId}"); // WebSocketService.Add(this); // int code = WebSocketService.WebSocketConnect(instanceId); // if (code < 0) HandleOnError(GetErrorMessageFromCode(code)); //} //public void CloseAsync() //{ // Log($"Close with instanceId: {instanceId}"); // int code = WebSocketService.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 = WebSocketService.WebSocketSendStr(instanceId, text); // if (code < 0) HandleOnError(GetErrorMessageFromCode(code)); //} //public void SendAsync(byte[] data) //{ // Log($"Send, type: {Opcode.Binary}, size: {data.Length}"); // int code = WebSocketService.WebSocketSend(instanceId, data, data.Length); // if (code < 0) HandleOnError(GetErrorMessageFromCode(code)); //} internal void HandleOnOpen() { Log.Debug($"[WebSocket] OnOpen."); _status = SessionStatus.CONNECTED; _context.Synchronizer.Enqueue(ESessionCode.Connected, null); } internal void HandleOnMessage(byte[] rawData, int offset, int length) { Log.Debug($"[WebSocket] OnMessage."); _context.Synchronizer.Enqueue(rawData, offset, length); } internal void HandleOnMessageStr(string data) { Log.Error($"[WebSocket] OnMessageStr. data:{data}"); } internal void HandleOnClose(ushort code, string reason) { Log.Debug($"[WebSocket] OnClose, code: {code}, reason: {reason}"); if (code != (int)CloseStatusCode.Normal) OnDisconnectError(new WebSocketException(reason, code)); OnDisconnect(); } internal void HandleOnError(string msg) { Log.Debug("[WebSocket] OnError, error: " + msg); OnReceiveError(new WebSocketException(msg, 0)); } internal static Exception GetErrorMessageFromCode(int errorCode) { string message; switch (errorCode) { case -1: message = "WebSocket instance not found."; break; case -2: message = "WebSocket is already connected or in connecting state."; break; case -3: message = "WebSocket is not connected."; break; case -4: message = "WebSocket is already closing."; break; case -5: message = "WebSocket is already closed."; break; case -6: message = "WebSocket is not in open state."; break; case -7: message = "Cannot close WebSocket, An invalid code was specified or reason is too long."; break; case -8: message = "Not support buffer slice. "; break; default: message = $"Unknown error code {errorCode}."; break; } return new WebSocketException(message, errorCode); } //[System.Diagnostics.Conditional("UNITY_WEB_SOCKET_LOG")] //static void Log(string msg) //{ // var time = DateTime.Now.ToString("HH:mm:ss.fff"); // UnityEngine.Debug.Log($"[{time}][UnityWebSocket] {msg}"); //} public void Connect(AddressInfo info) { if (Status != SessionStatus.FREE) { Log.Warn($"[WebSocket] SessionStatus:{Status} 已连接或者正在连接,又尝试连接"); return; } OnStartConnect(); if (Address == null || Address.Domain != info.Address || Address.PORT == info.Port || Address.ProtocolType == info.ProtocolType) { Address = new SessionAddress(info); } var uri = GetUri(Address); if (string.IsNullOrEmpty(uri)) { OnConnectFail(new Exception($"[WebSocket] ProtocolType {Address.ProtocolType} is not find")); return; } instanceId = WebSocketService.AllocateInstance(uri); WebSocketService.Add(this); int code = WebSocketService.WebSocketConnect(instanceId); if (code < 0) OnConnectFail(GetErrorMessageFromCode(code)); } public bool IsConnected(bool bPrecice) { return Status == SessionStatus.CONNECTED && ReadyState == WebSocketState.Open; } public void Disconnect() { if (Status == SessionStatus.FREE) return; _status = SessionStatus.FREE; int code = WebSocketService.WebSocketClose(instanceId, (int)CloseStatusCode.Normal, "Normal Closure"); if (code < 0) OnDisconnectError(GetErrorMessageFromCode(code)); //else // OnDisconnect(); } public bool Send(byte[] bytes, int offset, int length) { // offset 固定为零 int code = WebSocketService.WebSocketSend(instanceId, bytes, length); if (code < 0) OnSendError(GetErrorMessageFromCode(code)); SessionBufferPool.Recycle(bytes); return code >= 0; } void IDisposable.Dispose() { Disconnect(); _context = null; WebSocketService.WebSocketFree(instanceId); } string GetUri(SessionAddress info) { string url; switch (info.ProtocolType) { case ProtocolType.WS: if (string.IsNullOrEmpty(info.URI)) url = $"ws://{info.Domain}:{info.PORT}"; else url = info.URI; break; case ProtocolType.WSS: if (string.IsNullOrEmpty(info.URI)) url = $"wss://{info.Domain}:{info.PORT}"; else url = info.URI; break; default: return url = string.Empty; } return url; } #region Event private void OnConnectFail(Exception e) { _status = SessionStatus.CONNECT_FAIL; _context.Synchronizer.Enqueue(ESessionCode.ConnectFail, e); } //private void OnConnectTimeout() //{ // _status = SessionStatus.CONNECT_TIMEOUT; // _context.Synchronizer.Enqueue(ESessionCode.ConnectTimeout, null); //} //private void OnConnected() //{ // _status = SessionStatus.CONNECTED; // _context.Synchronizer.Enqueue(ESessionCode.Connected, null); //} private void OnStartConnect() { _context.Synchronizer.Enqueue(ESessionCode.StartConnect, null); } private void OnDisconnect() { _context.Synchronizer.Enqueue(ESessionCode.Disconnect, null); } private void OnDisconnectError(Exception e) { _context.Synchronizer.Enqueue(ESessionCode.DisconnectError, e); } private void OnSendError(Exception e) { _status = SessionStatus.SEND_ERROR; _context.Synchronizer.Enqueue(ESessionCode.SendException, e); } private void OnReceiveError(Exception e) { _status = SessionStatus.RECV_ERROR; _context.Synchronizer.Enqueue(ESessionCode.RecvError, e); } //private void OnRemoteClose() //{ // _status = SessionStatus.CLOSED; // _context.Synchronizer.Enqueue(ESessionCode.SessionClose, null); //} #endregion } } #endif