using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Primitives; using OCPPServer.Protocol; using SuperSocket.SocketBase; using System; using System.Collections.Generic; using System.Linq; using System.Net.WebSockets; using System.ServiceModel.Channels; using System.Text; using System.Threading.Tasks; using static OCPPServer.Protocol.ClientData; namespace EVCB_OCPP.WSServer.Service; public static class AppExtention { public static void MapWsService(this WebApplication webApplication) { var protocals = new List() { "", "ocpp1.6", "ocpp2.0" }; webApplication.UseWebSockets(new WebSocketOptions() { KeepAliveInterval = TimeSpan.FromSeconds(10) }); webApplication.Use(async (HttpContext context, RequestDelegate next) => { if (context.WebSockets.IsWebSocketRequest) { var matched = context.WebSockets.WebSocketRequestedProtocols.Intersect(protocals); if (matched is null || !matched.Any()) { await context.Response.WriteAsync("Protocol not matched"); return; } using WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync(matched.First()); var servcie = context.RequestServices.GetService>(); await servcie.AddWebSocket(webSocket, context); return; } else { await next(context); } }); } } public interface IWebsocketService { public Task AddWebSocket(WebSocket webSocket, HttpContext context); } public class WebsocketService : IWebsocketService where T: WsSession { public WebsocketService() { } public Func> ValidateHandshake; public event EventHandler NewSessionConnected; public async Task AddWebSocket(WebSocket webSocket, HttpContext context) { T data = Activator.CreateInstance(); data.ClientWebSocket = webSocket; data.Path = context?.Request?.Path; data.UriScheme = context?.Request?.Scheme; data.AuthHeader = context?.Request?.Headers?.Authorization; data.SessionID = context.TraceIdentifier; data.Endpoint = null; data.Origin = context.Request.Headers.Origin; var validated = await ValidateHandshake(data); if (!validated) { return; } NewSessionConnected?.Invoke(this, data); await data.EndConnSemaphore.WaitAsync(); return; } } 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 Endpoint Endpoint { get; internal set; } public StringValues Origin { get; internal set; } public DateTime LastActiveTime { get; set; } public WebSocket _WebSocket { get; internal set; } 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 Task ReceiveLoopTask; private void Init(WebSocket webSocket) { _WebSocket = webSocket; ReceiveLoopTask = StartReceivd(webSocket); } private async Task StartReceivd(WebSocket webSocket) { while (true) { var buffer = new byte[1024 * 4]; var result = await webSocket.ReceiveAsync(new ArraySegment(buffer), default); if (result.CloseStatus.HasValue) { Close(CloseReason.ClientClosing); break; } string received = Encoding.UTF8.GetString(buffer, 0, result.Count); //m_ReceiveData?.Invoke(this, received); this.LastActiveTime = DateTime.UtcNow; HandleReceivedData(received); } } internal virtual void HandleReceivedData(string data) { } internal void Send(string dataString) { var data = Encoding.UTF8.GetBytes(dataString); ClientWebSocket.SendAsync(data, WebSocketMessageType.Text, endOfMessage: true, cancellationToken: default); } internal void Send(byte[] data, int offset, int length) { ClientWebSocket.SendAsync(data, WebSocketMessageType.Text, endOfMessage: true, cancellationToken: default); } internal void Close(CloseReason closeReason) { SessionClosed?.Invoke(this, null); _WebSocket.Dispose(); EndConnSemaphore.Release(); } }