using Esiur.Core; using System; using System.Collections.Generic; using System.Net; using System.Text; using System.Net.WebSockets; using Esiur.Net.Packets; using Esiur.Resource; using Esiur.Misc; using System.Drawing; using System.Threading; using System.Threading.Tasks; using System.Net.Sockets; using Microsoft.CodeAnalysis; namespace Esiur.Net.Sockets { public class FrameworkWebSocket : ISocket { bool began; WebSocket sock; NetworkBuffer receiveNetworkBuffer = new NetworkBuffer(); NetworkBuffer sendNetworkBuffer = new NetworkBuffer(); byte[] websocketReceiveBuffer = new byte[10240]; ArraySegment websocketReceiveBufferSegment; object sendLock = new object(); bool held; public event DestroyedEvent OnDestroy; long totalSent, totalReceived; public IPEndPoint LocalEndPoint { get; } = new IPEndPoint(IPAddress.Any, 0); public IPEndPoint RemoteEndPoint { get; } = new IPEndPoint(IPAddress.Any, 0); public SocketState State => sock == null ? SocketState.Closed : sock.State switch { WebSocketState.Aborted => SocketState.Closed, WebSocketState.Closed => SocketState.Closed, WebSocketState.Connecting => SocketState.Connecting, WebSocketState.Open => SocketState.Established, WebSocketState.CloseReceived => SocketState.Closed, WebSocketState.CloseSent => SocketState.Closed, WebSocketState.None => SocketState.Initial, _ => SocketState.Initial }; public INetworkReceiver Receiver { get; set; } public FrameworkWebSocket() { websocketReceiveBufferSegment = new ArraySegment(websocketReceiveBuffer); } public FrameworkWebSocket(WebSocket webSocket) { websocketReceiveBufferSegment = new ArraySegment(websocketReceiveBuffer); sock = webSocket; } public void Send(byte[] message) { lock (sendLock) { if (held) { sendNetworkBuffer.Write(message); } else { totalSent += message.Length; sock.SendAsync(new ArraySegment(message), WebSocketMessageType.Binary, true, new System.Threading.CancellationToken()); } } } public void Send(byte[] message, int offset, int size) { lock (sendLock) { if (held) { sendNetworkBuffer.Write(message, (uint)offset, (uint)size); } else { totalSent += size; sock.SendAsync(new ArraySegment(message, offset, size), WebSocketMessageType.Binary, true, new System.Threading.CancellationToken()); } } } public void Close() { sock?.CloseAsync(WebSocketCloseStatus.NormalClosure, "", new System.Threading.CancellationToken()); } public bool Secure { get; set; } public async AsyncReply Connect(string hostname, ushort port) { var url = new Uri($"{(Secure ? "wss" : "ws")}://{hostname}:{port}"); var ws = new ClientWebSocket(); sock = ws; await ws.ConnectAsync(url, new CancellationToken()); sock.ReceiveAsync(websocketReceiveBufferSegment, CancellationToken.None) .ContinueWith(NetworkReceive); return true; } public bool Begin() { // Socket destroyed if (sock == null) return false; if (began) return false; began = true; sock.ReceiveAsync(websocketReceiveBufferSegment, CancellationToken.None) .ContinueWith(NetworkReceive); return true; } public bool Trigger(ResourceTrigger trigger) { return true; } public void Destroy() { Close(); receiveNetworkBuffer = null; Receiver = null; sock = null; OnDestroy?.Invoke(this); OnDestroy = null; } public AsyncReply AcceptAsync() { throw new NotImplementedException(); } public void Hold() { held = true; } public void Unhold() { lock (sendLock) { held = false; var message = sendNetworkBuffer.Read(); if (message == null) return; totalSent += message.Length; sock.SendAsync(new ArraySegment(message), WebSocketMessageType.Binary, true, new System.Threading.CancellationToken()); } } public async AsyncReply SendAsync(byte[] message, int offset, int length) { if (held) { sendNetworkBuffer.Write(message, (uint)offset, (uint)length); } else { totalSent += length; await sock.SendAsync(new ArraySegment(message, offset, length), WebSocketMessageType.Binary, true, new System.Threading.CancellationToken()); } return true; } public ISocket Accept() { throw new NotImplementedException(); } public AsyncReply BeginAsync() { return new AsyncReply(Begin()); } private void NetworkReceive(Task task) { if (sock.State == WebSocketState.Closed || sock.State == WebSocketState.Aborted) { Receiver?.NetworkClose(this); return; } var receivedLength = task.Result.Count; receiveNetworkBuffer.Write(websocketReceiveBuffer, 0, (uint)receivedLength); Receiver?.NetworkReceive(this, receiveNetworkBuffer); sock.ReceiveAsync(websocketReceiveBufferSegment, CancellationToken.None) .ContinueWith(NetworkReceive); } public void NetworkConnect(ISocket sender) { Receiver?.NetworkConnect(this); } } }