using System; using System.Threading.Tasks; using InABox.Clients; using InABox.Core; using WebSocketSharp; using ErrorEventArgs = WebSocketSharp.ErrorEventArgs; namespace InABox.Rpc { public class RpcClientSocketTransport : RpcClientTransport, IDisposable { private WebSocket _socket; private string _url; public RpcClientSocketTransport(string url) { _url = url; } private void Socket_OnOpen(object? sender, EventArgs e) { DoOpen(); } private void Socket_OnMessage(object? sender, MessageEventArgs e) { RpcMessage? message = null; if (e.IsBinary && (e.RawData != null)) message = Serialization.ReadBinary(e.RawData, BinarySerializationSettings.Latest); else if (e.IsText && !string.IsNullOrWhiteSpace(e.Data)) message = Serialization.Deserialize(e.Data); Accept(message); } private void Socket_OnClose(object? sender, CloseEventArgs e) { DoClose(RpcTransportCloseEventType.Closed); } private void Socket_OnError(object? sender, ErrorEventArgs e) { DoException(e.Exception); } private WebSocket CreateSocket(bool secure) { var socket = new WebSocket($"{(secure ? "wss" : "ws")}://{_url}"); // Time to wait before disconnect - the default meant that the client disconnected during debugging, since the ping would fail socket.WaitTime = TimeSpan.FromSeconds(5); socket.OnOpen -= Socket_OnOpen; socket.OnError -= Socket_OnError; socket.OnClose -= Socket_OnClose; socket.OnMessage -= Socket_OnMessage; socket.Connect(); if (socket.ReadyState == WebSocketState.Open) { DoOpen(); socket.OnOpen += Socket_OnOpen; socket.OnError += Socket_OnError; socket.OnClose += Socket_OnClose; socket.OnMessage += Socket_OnMessage; return socket; } return null; } public override void Connect() { var findsocket = new Task[] { Task.Run(() => CreateSocket(true)), Task.Run(() => CreateSocket(false)) } ; var index = Task.WaitAny(findsocket); _socket = findsocket[index].Result; } public override bool IsConnected() => _socket?.ReadyState == WebSocketState.Open; public override bool IsSecure() => _socket?.IsSecure == true; public override void Disconnect() { _socket.Close(CloseStatusCode.Normal); } public override void Send(RpcMessage message) { var buffer = Serialization.WriteBinary(message, BinarySerializationSettings.Latest); _socket.Send(buffer); } protected override RpcClientTransport Clone() => new RpcClientSocketTransport(_url); public void Dispose() { if (IsConnected()) Disconnect(); } } }