using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.WebSockets; using System.Text; using System.Threading.Tasks; using System.Timers; using Timer = System.Timers.Timer; namespace EVCB_OCPP.WSServer.Service.WsService { public class WsSession { public WsSession() { } public PathString? Path { get; set; } public string UriScheme { get; set; } public string AuthHeader { get; set; } public string SessionID { get; set; } public IPEndPoint Endpoint { get; internal set; } public StringValues Origin { get; internal set; } public DateTime LastActiveTime { get; set; } private WebSocket _WebSocket; public WebSocket ClientWebSocket { get => _WebSocket; set { Init(value); } } public WebSocketState State => ClientWebSocket.State; public string SecWebSocketProtocol => ClientWebSocket.SubProtocol; public SemaphoreSlim EndConnSemaphore { get; } = new SemaphoreSlim(0); //public event OCPPClientDataEventHandler m_ReceiveData; public event EventHandler SessionClosed; private CancellationTokenSource disconnectCancellationTokenSource = new CancellationTokenSource(); private Task ReceiveLoopTask; private void Init(WebSocket webSocket) { _WebSocket = webSocket; ReceiveLoopTask = StartReceivd(webSocket, disconnectCancellationTokenSource.Token); } private async Task StartReceivd(WebSocket webSocket, CancellationToken token) { string received = string.Empty; while (!token.IsCancellationRequested) { var buffer = new byte[1024 * 4]; WebSocketReceiveResult result = null; try { result = await webSocket.ReceiveAsync(new ArraySegment(buffer), token); } catch (Exception e) { _ = BruteClose(e.Message); break; } if (result == null || result.CloseStatus.HasValue) { //closed gracefully _ = GracefulClose(result.CloseStatus.Value); break; } received += Encoding.UTF8.GetString(buffer, 0, result.Count); //m_ReceiveData?.Invoke(this, received); LastActiveTime = DateTime.UtcNow; if (result.EndOfMessage) { HandleReceivedData(received); received = string.Empty; } } } internal virtual void HandleReceivedData(string data) { } internal Task Send(string dataString) { var data = Encoding.UTF8.GetBytes(dataString); return Send(data, 0 , data.Length); } internal async Task Send(byte[] data, int offset, int length) { await ClientWebSocket.SendAsync(data, WebSocketMessageType.Text, endOfMessage: true, cancellationToken: disconnectCancellationTokenSource.Token); if (ClientWebSocket.State == WebSocketState.Aborted || ClientWebSocket.State == WebSocketState.Closed) { } } internal Task Close() { return ServerClose(); } private Task ServerClose() { SessionClosed?.Invoke(this, "ServerShutdown"); return InternalClose(WebSocketCloseStatus.NormalClosure, "ServerShutdown"); } private Task GracefulClose(WebSocketCloseStatus closeStatus) { SessionClosed?.Invoke(this, closeStatus.ToString()); return InternalClose(closeStatus , null); } private Task BruteClose(string description) { SessionClosed?.Invoke(this, description); return InternalClose(WebSocketCloseStatus.EndpointUnavailable, description); } private async Task InternalClose(WebSocketCloseStatus closeStatus, string description) { try { await _WebSocket.CloseAsync(closeStatus, description, default); } catch { } finally { _WebSocket.Dispose(); } disconnectCancellationTokenSource.Cancel(); EndConnSemaphore.Release(); } } }