From b979b9bc221f8af183c0233c535e03626fe787cb Mon Sep 17 00:00:00 2001 From: Dmitri Shimanski Date: Sun, 30 Mar 2025 00:43:20 +0300 Subject: [PATCH] Adds example of using preConnectionHandler, create OnConnectionHandler(preConnectionHandler), use WebSocketOptions for provides data --- Examples/Program.cs | 18 +++++++++++++++++- README.md | 1 + yawaflua.WebSockets/Core/WebSocket.cs | 8 +++++++- yawaflua.WebSockets/Core/WebSocketRouter.cs | 14 +++++++++----- .../Models/Interfaces/IWebSocket.cs | 2 ++ yawaflua.WebSockets/ServiceBindings.cs | 6 ++++-- 6 files changed, 40 insertions(+), 9 deletions(-) diff --git a/Examples/Program.cs b/Examples/Program.cs index e0a1396..8f31159 100644 --- a/Examples/Program.cs +++ b/Examples/Program.cs @@ -1,4 +1,7 @@ -using yawaflua.WebSockets; +using System.Net.WebSockets; +using yawaflua.WebSockets; +using yawaflua.WebSockets.Core; +using yawaflua.WebSockets.Models.Interfaces; namespace Examples; @@ -26,6 +29,19 @@ internal class Startup services.AddHttpLogging(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(new WebSocketConfig() + { + OnOpenHandler = async (socket, context) => + { + if (socket.WebSocketManager!.GetAllClients().Count(k => + Equals(k.ConnectionInfo!.RemoteIpAddress!.MapToIPv4(), + socket.Client.ConnectionInfo!.RemoteIpAddress!.MapToIPv4())) >= 3) + { + await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Too many users"); + } + Console.WriteLine($"{socket.Client.Id} has been connected to {socket.Client.Path}"); + } + }); services.AddScoped(k => new ConfigurationBuilder() .AddJsonFile("appsettings.json", true) .Build()); diff --git a/README.md b/README.md index b82141f..820c893 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,7 @@ public class ChatController : WebSocketController } ``` +## Run any code on connection to ## Lifecycle Management 1. **Connection** - Automatically handled by middleware diff --git a/yawaflua.WebSockets/Core/WebSocket.cs b/yawaflua.WebSockets/Core/WebSocket.cs index f4503dd..99c52b1 100644 --- a/yawaflua.WebSockets/Core/WebSocket.cs +++ b/yawaflua.WebSockets/Core/WebSocket.cs @@ -11,18 +11,24 @@ internal class WebSocket : IWebSocket private readonly string? _message; public WebSocketState State => _webSocket.State; + public IWebSocketManager WebSocketManager { get; } public WebSocketCloseStatus? CloseStatus => _webSocket.CloseStatus; public string? SubProtocol => _webSocket.SubProtocol; public string? CloseStatusDescription => _webSocket.CloseStatusDescription; public string? Message => _message; public WebSocketMessageType? MessageType => _webSocketReceiveResult?.MessageType; public IWebSocketClient Client { get; } - internal WebSocket(System.Net.WebSockets.WebSocket webSocket, WebSocketReceiveResult? webSocketReceiveResult, string? message, IWebSocketClient client) + internal WebSocket(System.Net.WebSockets.WebSocket webSocket, + IWebSocketClient client, + IWebSocketManager webSocketManager, + string? message = null, + WebSocketReceiveResult? webSocketReceiveResult = null) { _webSocket = webSocket; _webSocketReceiveResult = webSocketReceiveResult; _message = message; Client = client; + WebSocketManager = webSocketManager; } public async Task SendAsync(string m, WebSocketMessageType messageType = WebSocketMessageType.Text, CancellationToken cts = default) diff --git a/yawaflua.WebSockets/Core/WebSocketRouter.cs b/yawaflua.WebSockets/Core/WebSocketRouter.cs index bac0d51..9142569 100644 --- a/yawaflua.WebSockets/Core/WebSocketRouter.cs +++ b/yawaflua.WebSockets/Core/WebSocketRouter.cs @@ -65,7 +65,7 @@ public class WebSocketRouter var parameters = func.GetParameters(); if (parameters.Length != 2 || - parameters[0].ParameterType != typeof(WebSocket) || + parameters[0].ParameterType != typeof(IWebSocket) || parameters[1].ParameterType != typeof(HttpContext) || func.ReturnType != typeof(Task)) { @@ -147,13 +147,14 @@ public class WebSocketRouter { try { + var webSocketManager = new WebSocketManager(); var client = new WebSocketClient(context, webSocket, path); Clients.Add(client); await Task.Run(async () => { if (_webSocketConfig?.OnOpenHandler != null) - await _webSocketConfig.OnOpenHandler((webSocket as IWebSocket)!, context); + await _webSocketConfig.OnOpenHandler(new WebSocket(webSocket, client, webSocketManager)!, context); }, cts); var buffer = new byte[1024 * 4]; @@ -164,13 +165,16 @@ public class WebSocketRouter await handler( new WebSocket( webSocket, - result, + client, + webSocketManager, Encoding.UTF8.GetString(buffer, 0, result.Count), - client), - context); + result), context); else Clients.Remove(client); } + + if (Clients.Any(k => k.Id == client.Id)) + Clients.Remove(client); } catch (Exception ex) { diff --git a/yawaflua.WebSockets/Models/Interfaces/IWebSocket.cs b/yawaflua.WebSockets/Models/Interfaces/IWebSocket.cs index 038daa2..8f975f4 100644 --- a/yawaflua.WebSockets/Models/Interfaces/IWebSocket.cs +++ b/yawaflua.WebSockets/Models/Interfaces/IWebSocket.cs @@ -1,10 +1,12 @@ using System.Net.WebSockets; +using yawaflua.WebSockets.Core; namespace yawaflua.WebSockets.Models.Interfaces; public interface IWebSocket : IDisposable { WebSocketState State { get; } + IWebSocketManager WebSocketManager { get; } WebSocketCloseStatus? CloseStatus { get; } string? SubProtocol { get; } string? CloseStatusDescription { get; } diff --git a/yawaflua.WebSockets/ServiceBindings.cs b/yawaflua.WebSockets/ServiceBindings.cs index 4b97c3e..3d495c2 100644 --- a/yawaflua.WebSockets/ServiceBindings.cs +++ b/yawaflua.WebSockets/ServiceBindings.cs @@ -8,12 +8,14 @@ namespace yawaflua.WebSockets; public static class ServiceBindings { - public static IServiceCollection SettingUpWebSockets(this IServiceCollection isc, Action? socketOptions = null) + public static IServiceCollection SettingUpWebSockets(this IServiceCollection isc, WebSocketConfig? socketOptions = null) { isc.AddSingleton(); + if (socketOptions != null) isc.AddSingleton(socketOptions); + if (isc.All(k => k.ServiceType != typeof(WebSocketConfig))) + isc.AddSingleton(new WebSocketConfig()); isc.AddScoped(); isc.AddSingleton(); - isc.Configure("WebSocketOptions", socketOptions); return isc; }