|
@@ -1,157 +1,175 @@
|
|
|
using Microsoft.AspNetCore.Http;
|
|
|
-using Microsoft.Extensions.Primitives;
|
|
|
-using System;
|
|
|
-using System.Collections.Generic;
|
|
|
-using System.Linq;
|
|
|
+using Microsoft.Extensions.Logging;
|
|
|
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
|
|
|
+namespace EVCB_OCPP.WSServer.Service.WsService;
|
|
|
+
|
|
|
+public class WsSession
|
|
|
{
|
|
|
- public class WsSession
|
|
|
+ public WsSession(ILogger<WsSession> logger)
|
|
|
{
|
|
|
- public WsSession()
|
|
|
- {
|
|
|
-
|
|
|
- }
|
|
|
+ this.logger = logger;
|
|
|
+ }
|
|
|
|
|
|
- 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; }
|
|
|
+ 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
|
|
|
+ private WebSocket _WebSocket;
|
|
|
+ public WebSocket ClientWebSocket
|
|
|
+ {
|
|
|
+ get => _WebSocket;
|
|
|
+ set
|
|
|
{
|
|
|
- get => _WebSocket;
|
|
|
- set
|
|
|
- {
|
|
|
- Init(value);
|
|
|
- }
|
|
|
+ Init(value);
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- public WebSocketState State => ClientWebSocket.State;
|
|
|
- public string SecWebSocketProtocol => ClientWebSocket.SubProtocol;
|
|
|
+ public WebSocketState State => ClientWebSocket.State;
|
|
|
+ public string SecWebSocketProtocol => ClientWebSocket.SubProtocol;
|
|
|
|
|
|
- public SemaphoreSlim EndConnSemaphore { get; } = new SemaphoreSlim(0);
|
|
|
+ public SemaphoreSlim EndConnSemaphore { get; } = new SemaphoreSlim(0);
|
|
|
|
|
|
- //public event OCPPClientDataEventHandler<WsSession, String> m_ReceiveData;
|
|
|
+ //public event OCPPClientDataEventHandler<WsSession, String> m_ReceiveData;
|
|
|
|
|
|
- public event EventHandler<string> SessionClosed;
|
|
|
+ public event EventHandler<string> SessionClosed;
|
|
|
|
|
|
- private CancellationTokenSource disconnectCancellationTokenSource = new CancellationTokenSource();
|
|
|
- private Task ReceiveLoopTask;
|
|
|
+ private CancellationTokenSource disconnectCancellationTokenSource = new CancellationTokenSource();
|
|
|
+ private Task ReceiveLoopTask;
|
|
|
+ private readonly ILogger<WsSession> logger;
|
|
|
|
|
|
- private void Init(WebSocket webSocket)
|
|
|
- {
|
|
|
- _WebSocket = webSocket;
|
|
|
- ReceiveLoopTask = StartReceivd(webSocket, disconnectCancellationTokenSource.Token);
|
|
|
- }
|
|
|
+ private void Init(WebSocket webSocket)
|
|
|
+ {
|
|
|
+ _WebSocket = webSocket;
|
|
|
+ ReceiveLoopTask = StartReceivd(webSocket, disconnectCancellationTokenSource.Token);
|
|
|
+ }
|
|
|
+
|
|
|
+ private async Task StartReceivd(WebSocket webSocket, CancellationToken token)
|
|
|
+ {
|
|
|
+ logger.LogInformation("{func}:{Path} Start", nameof(StartReceivd), Path);
|
|
|
|
|
|
- private async Task StartReceivd(WebSocket webSocket, CancellationToken token)
|
|
|
+ byte[] receivdBuffer = new byte[0];
|
|
|
+ int bufferExpand = 1;
|
|
|
+ int receivedBytes = 0;
|
|
|
+ while (!token.IsCancellationRequested)
|
|
|
{
|
|
|
- string received = string.Empty;
|
|
|
- while (!token.IsCancellationRequested)
|
|
|
+ var tempReceiveBuffer = new byte[1024 * 4];
|
|
|
+ WebSocketReceiveResult result = null;
|
|
|
+
|
|
|
+ try
|
|
|
{
|
|
|
- var buffer = new byte[1024 * 4];
|
|
|
- WebSocketReceiveResult result = null;
|
|
|
-
|
|
|
- try
|
|
|
- {
|
|
|
- result = await webSocket.ReceiveAsync(new ArraySegment<byte>(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;
|
|
|
- }
|
|
|
+ result = await webSocket.ReceiveAsync(new ArraySegment<byte>(tempReceiveBuffer), token);
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- internal virtual void HandleReceivedData(string data)
|
|
|
- {
|
|
|
+ catch (Exception e)
|
|
|
+ {
|
|
|
+ _ = BruteClose(e.Message);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ LastActiveTime = DateTime.UtcNow;
|
|
|
|
|
|
- }
|
|
|
+ if (result == null || result.CloseStatus.HasValue)
|
|
|
+ {
|
|
|
+ //closed gracefully
|
|
|
+ await GracefulClose(result.CloseStatus.Value);
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
- internal Task Send(string dataString)
|
|
|
- {
|
|
|
- var data = Encoding.UTF8.GetBytes(dataString);
|
|
|
- return Send(data, 0 , data.Length);
|
|
|
- }
|
|
|
+ receivdBuffer = new byte[1024 * 4 * bufferExpand];
|
|
|
+ Array.Copy(tempReceiveBuffer, 0, receivdBuffer, receivedBytes, result.Count);
|
|
|
+ receivedBytes += result.Count;
|
|
|
|
|
|
- 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)
|
|
|
+ if (!result.EndOfMessage)
|
|
|
{
|
|
|
-
|
|
|
+ bufferExpand++;
|
|
|
+ continue;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- internal Task Close()
|
|
|
- {
|
|
|
- return ServerClose();
|
|
|
+ var received = Encoding.UTF8.GetString(receivdBuffer, 0, receivedBytes);
|
|
|
+ logger.LogInformation("{func}:{Path} {value}", nameof(StartReceivd), Path, received);
|
|
|
+
|
|
|
+ HandleReceivedData(received);
|
|
|
+
|
|
|
+ bufferExpand = 1;
|
|
|
+ receivedBytes = 0;
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ internal virtual void HandleReceivedData(string data)
|
|
|
+ {
|
|
|
|
|
|
- private Task ServerClose()
|
|
|
+ }
|
|
|
+
|
|
|
+ internal Task Send(string dataString)
|
|
|
+ {
|
|
|
+ logger.LogInformation("{func}:{Path} {value}", nameof(Send), Path, dataString);
|
|
|
+
|
|
|
+ var data = Encoding.UTF8.GetBytes(dataString);
|
|
|
+ return Send(data);
|
|
|
+ }
|
|
|
+
|
|
|
+ internal Task Close()
|
|
|
+ {
|
|
|
+ return ServerClose();
|
|
|
+ }
|
|
|
+
|
|
|
+ private async Task Send(byte[] data)
|
|
|
+ {
|
|
|
+ try
|
|
|
{
|
|
|
- SessionClosed?.Invoke(this, "ServerShutdown");
|
|
|
- return InternalClose(WebSocketCloseStatus.NormalClosure, "ServerShutdown");
|
|
|
+ await ClientWebSocket.SendAsync(data, WebSocketMessageType.Text, endOfMessage: true, cancellationToken: disconnectCancellationTokenSource.Token);
|
|
|
}
|
|
|
-
|
|
|
- private Task GracefulClose(WebSocketCloseStatus closeStatus)
|
|
|
+ catch (Exception e)
|
|
|
{
|
|
|
- SessionClosed?.Invoke(this, closeStatus.ToString());
|
|
|
- return InternalClose(closeStatus , null);
|
|
|
+ logger.LogInformation("{func}:{Path} exception:{msg}", nameof(Send), Path, e.Message);
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ private Task ServerClose()
|
|
|
+ {
|
|
|
+ logger.LogInformation("{func}:{Path}", nameof(ServerClose), Path);
|
|
|
+
|
|
|
+ SessionClosed?.Invoke(this, "ServerShutdown");
|
|
|
+ return InternalClose(WebSocketCloseStatus.NormalClosure, "ServerShutdown");
|
|
|
+ }
|
|
|
+
|
|
|
+ private Task GracefulClose(WebSocketCloseStatus closeStatus)
|
|
|
+ {
|
|
|
+ logger.LogInformation("{func}:{Path} {value}", nameof(GracefulClose), Path, closeStatus);
|
|
|
+
|
|
|
+ SessionClosed?.Invoke(this, closeStatus.ToString());
|
|
|
+ return InternalClose(closeStatus , null);
|
|
|
+ }
|
|
|
+
|
|
|
+ private Task BruteClose(string description)
|
|
|
+ {
|
|
|
+ logger.LogInformation("{func}:{Path} {value}", nameof(ServerClose), Path, description);
|
|
|
|
|
|
- private Task BruteClose(string description)
|
|
|
+ SessionClosed?.Invoke(this, description);
|
|
|
+ return InternalClose(WebSocketCloseStatus.EndpointUnavailable, description);
|
|
|
+ }
|
|
|
+
|
|
|
+ private async Task InternalClose(WebSocketCloseStatus closeStatus, string description)
|
|
|
+ {
|
|
|
+ try
|
|
|
{
|
|
|
- SessionClosed?.Invoke(this, description);
|
|
|
- return InternalClose(WebSocketCloseStatus.EndpointUnavailable, description);
|
|
|
+ await _WebSocket.CloseAsync(closeStatus, description, default);
|
|
|
}
|
|
|
-
|
|
|
- private async Task InternalClose(WebSocketCloseStatus closeStatus, string description)
|
|
|
+ catch
|
|
|
+ {
|
|
|
+ }
|
|
|
+ finally
|
|
|
{
|
|
|
- try
|
|
|
- {
|
|
|
- await _WebSocket.CloseAsync(closeStatus, description, default);
|
|
|
- }
|
|
|
- catch
|
|
|
- {
|
|
|
- }
|
|
|
- finally
|
|
|
- {
|
|
|
- _WebSocket.Dispose();
|
|
|
- }
|
|
|
-
|
|
|
- disconnectCancellationTokenSource.Cancel();
|
|
|
- EndConnSemaphore.Release();
|
|
|
+ _WebSocket.Dispose();
|
|
|
}
|
|
|
+
|
|
|
+ disconnectCancellationTokenSource.Cancel();
|
|
|
+ EndConnSemaphore.Release();
|
|
|
}
|
|
|
}
|