mirror of
https://github.com/yawaflua/WebSockets.git
synced 2026-02-04 14:04:11 +02:00
Adds more confs for handlers and try to fix error with swagger when using attribute
This commit is contained in:
15
Examples/Controllers/TestDefaultController.cs
Normal file
15
Examples/Controllers/TestDefaultController.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace Examples.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("/api/v1/test")]
|
||||||
|
public class TestDefaultController : ControllerBase
|
||||||
|
{
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> TestController([FromBody] string TextTest)
|
||||||
|
{
|
||||||
|
return Ok("Test");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
using yawaflua.WebSockets;
|
using yawaflua.WebSockets;
|
||||||
using yawaflua.WebSockets.Core;
|
using yawaflua.WebSockets.Core;
|
||||||
using yawaflua.WebSockets.Models.Interfaces;
|
|
||||||
|
|
||||||
namespace Examples;
|
namespace Examples;
|
||||||
|
|
||||||
@@ -22,18 +21,20 @@ class Program
|
|||||||
|
|
||||||
internal class Startup
|
internal class Startup
|
||||||
{
|
{
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public static void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.SettingUpWebSockets();
|
services.SettingUpWebSockets();
|
||||||
services.AddRouting();
|
services.AddRouting();
|
||||||
|
services.AddControllers();
|
||||||
|
services.AddEndpointsApiExplorer();
|
||||||
services.AddHttpLogging();
|
services.AddHttpLogging();
|
||||||
services.AddSingleton<TestWebSocketServer>();
|
services.AddSingleton<TestWebSocketServer>();
|
||||||
services.AddSingleton<ChatController>();
|
services.AddSingleton<ChatController>();
|
||||||
services.AddSingleton(new WebSocketConfig()
|
services.AddSingleton(new WebSocketConfig()
|
||||||
{
|
{
|
||||||
OnOpenHandler = async (socket, context) =>
|
OnOpenHandler = async (socket, _) =>
|
||||||
{
|
{
|
||||||
if (socket.WebSocketManager!.GetAllClients().Count(k =>
|
if (socket.WebSocketManager.GetAllClients().Count(k =>
|
||||||
Equals(k.ConnectionInfo!.RemoteIpAddress!.MapToIPv4(),
|
Equals(k.ConnectionInfo!.RemoteIpAddress!.MapToIPv4(),
|
||||||
socket.Client.ConnectionInfo!.RemoteIpAddress!.MapToIPv4())) >= 3)
|
socket.Client.ConnectionInfo!.RemoteIpAddress!.MapToIPv4())) >= 3)
|
||||||
{
|
{
|
||||||
@@ -42,15 +43,16 @@ internal class Startup
|
|||||||
Console.WriteLine($"{socket.Client.Id} has been connected to {socket.Client.Path}");
|
Console.WriteLine($"{socket.Client.Id} has been connected to {socket.Client.Path}");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
services.AddScoped<IConfiguration>(k => new ConfigurationBuilder()
|
services.AddScoped<IConfiguration>(_ => new ConfigurationBuilder()
|
||||||
.AddJsonFile("appsettings.json", true)
|
.AddJsonFile("appsettings.json", true)
|
||||||
.Build());
|
.Build());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app)
|
public static void Configure(IApplicationBuilder app)
|
||||||
{
|
{
|
||||||
app.ConnectWebSockets();
|
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
|
||||||
|
app.UseWebSocketWithSwagger();
|
||||||
app.UseHttpLogging();
|
app.UseHttpLogging();
|
||||||
app.UseWelcomePage();
|
app.UseWelcomePage();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Routing;
|
||||||
|
|
||||||
namespace yawaflua.WebSockets.Attributes;
|
namespace yawaflua.WebSockets.Attributes;
|
||||||
|
|
||||||
@@ -18,12 +20,16 @@ namespace yawaflua.WebSockets.Attributes;
|
|||||||
/// When applied to methods, defines specific sub-routes (requires class-level base path).
|
/// When applied to methods, defines specific sub-routes (requires class-level base path).
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
|
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
|
||||||
public class WebSocketAttribute : RouteAttribute
|
[ApiExplorerSettings(IgnoreApi = true)]
|
||||||
|
public class WebSocketAttribute : RouteAttribute, IRouteTemplateProvider, IApiDescriptionVisibilityProvider
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Original route template specified in attribute
|
/// Original route template specified in attribute
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Template { get; }
|
public new string Template { get; }
|
||||||
|
|
||||||
|
public new int? Order { get; } = 0;
|
||||||
|
public new string? Name { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates WebSocket route definition
|
/// Creates WebSocket route definition
|
||||||
@@ -36,5 +42,8 @@ public class WebSocketAttribute : RouteAttribute
|
|||||||
public WebSocketAttribute([RouteTemplate]string path) : base(path)
|
public WebSocketAttribute([RouteTemplate]string path) : base(path)
|
||||||
{
|
{
|
||||||
Template = path;
|
Template = path;
|
||||||
|
Name = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IgnoreApi => true;
|
||||||
}
|
}
|
||||||
@@ -6,5 +6,7 @@ namespace yawaflua.WebSockets.Core;
|
|||||||
public class WebSocketConfig
|
public class WebSocketConfig
|
||||||
{
|
{
|
||||||
public Func<IWebSocket, HttpContext, Task>? OnOpenHandler { get; set; } = null;
|
public Func<IWebSocket, HttpContext, Task>? OnOpenHandler { get; set; } = null;
|
||||||
|
public Func<Exception, IWebSocket, HttpContext, Task>? OnErrorHandler { get; set; } = null;
|
||||||
|
public Func<Exception, HttpContext, Task>? OnConnectionErrorHandler { get; set; } = null;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -140,21 +140,22 @@ public class WebSocketRouter
|
|||||||
|
|
||||||
var path = context.Request.Path.Value;
|
var path = context.Request.Path.Value;
|
||||||
|
|
||||||
if (Routes.TryGetValue(path, out var handler))
|
if (path != null && Routes.TryGetValue(path, out var handler))
|
||||||
{
|
{
|
||||||
var webSocket = await context.WebSockets.AcceptWebSocketAsync();
|
var webSocket = await context.WebSockets.AcceptWebSocketAsync();
|
||||||
await Task.Run(async () =>
|
await Task.Run(async () =>
|
||||||
{
|
{
|
||||||
|
IWebSocketClient client = null!;
|
||||||
|
var webSocketManager = new WebSocketManager();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var webSocketManager = new WebSocketManager();
|
client = new WebSocketClient(context, webSocket, path);
|
||||||
var client = new WebSocketClient(context, webSocket, path);
|
|
||||||
Clients.Add(client);
|
Clients.Add(client);
|
||||||
|
|
||||||
await Task.Run(async () =>
|
await Task.Run(async () =>
|
||||||
{
|
{
|
||||||
if (_webSocketConfig?.OnOpenHandler != null)
|
if (_webSocketConfig?.OnOpenHandler != null)
|
||||||
await _webSocketConfig.OnOpenHandler(new WebSocket(webSocket, client, webSocketManager)!, context);
|
await _webSocketConfig.OnOpenHandler(new WebSocket(webSocket, client, webSocketManager), context);
|
||||||
}, cts);
|
}, cts);
|
||||||
|
|
||||||
var buffer = new byte[1024 * 4];
|
var buffer = new byte[1024 * 4];
|
||||||
@@ -179,6 +180,11 @@ public class WebSocketRouter
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(message:"Error with handling request: ",exception: ex);
|
_logger.LogError(message:"Error with handling request: ",exception: ex);
|
||||||
|
await Task.Run(async () =>
|
||||||
|
{
|
||||||
|
if (_webSocketConfig?.OnErrorHandler != null)
|
||||||
|
await _webSocketConfig.OnErrorHandler(ex, new WebSocket(webSocket, client, webSocketManager), context);
|
||||||
|
}, cts);
|
||||||
}
|
}
|
||||||
|
|
||||||
}, cts);
|
}, cts);
|
||||||
@@ -186,11 +192,14 @@ public class WebSocketRouter
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
context.Response.StatusCode = 404;
|
context.Response.StatusCode = 404;
|
||||||
|
throw new KeyNotFoundException("Path not found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, $"Error when handle request {context.Connection.Id}: ");
|
_logger.LogError(ex, $"Error when handle request {context.Connection.Id}: ");
|
||||||
|
if (_webSocketConfig!.OnConnectionErrorHandler != null)
|
||||||
|
await _webSocketConfig.OnConnectionErrorHandler(ex, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,14 +9,15 @@ internal class WebSocketClient : IWebSocketClient
|
|||||||
private HttpContext HttpContext { get; set; }
|
private HttpContext HttpContext { get; set; }
|
||||||
public Guid Id { get; } = Guid.NewGuid();
|
public Guid Id { get; } = Guid.NewGuid();
|
||||||
public string Path { get; }
|
public string Path { get; }
|
||||||
public ConnectionInfo ConnectionInfo { get => HttpContext.Connection; }
|
public ConnectionInfo ConnectionInfo => HttpContext.Connection;
|
||||||
public IDictionary<object, object> Items
|
|
||||||
|
public IDictionary<object, object>? Items
|
||||||
{
|
{
|
||||||
get => HttpContext.Items;
|
get => HttpContext.Items;
|
||||||
set => HttpContext.Items = (value);
|
set => HttpContext.Items = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpRequest HttpRequest { get => HttpContext.Request; }
|
public HttpRequest HttpRequest => HttpContext.Request;
|
||||||
public WebSocket webSocket { get; }
|
public WebSocket webSocket { get; }
|
||||||
|
|
||||||
internal WebSocketClient(HttpContext httpContext, WebSocket webSocket, string path)
|
internal WebSocketClient(HttpContext httpContext, WebSocket webSocket, string path)
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ namespace yawaflua.WebSockets;
|
|||||||
|
|
||||||
public static class ServiceBindings
|
public static class ServiceBindings
|
||||||
{
|
{
|
||||||
public static IServiceCollection SettingUpWebSockets(this IServiceCollection isc, WebSocketConfig? socketOptions = null)
|
public static IServiceCollection SettingUpWebSockets(this IServiceCollection isc,
|
||||||
|
WebSocketConfig? socketOptions = null)
|
||||||
{
|
{
|
||||||
isc.AddSingleton<WebSocketRouter>();
|
isc.AddSingleton<WebSocketRouter>();
|
||||||
if (socketOptions != null) isc.AddSingleton(socketOptions);
|
if (socketOptions != null) isc.AddSingleton(socketOptions);
|
||||||
@@ -19,10 +20,11 @@ public static class ServiceBindings
|
|||||||
return isc;
|
return isc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IApplicationBuilder ConnectWebSockets(this IApplicationBuilder iab)
|
public static IApplicationBuilder UseWebSocketWithSwagger(this IApplicationBuilder app)
|
||||||
{
|
{
|
||||||
iab.UseWebSockets();
|
app.UseWebSockets();
|
||||||
iab.UseMiddleware<WebSocketMiddleware>();
|
app.UseMiddleware<WebSocketMiddleware>();
|
||||||
return iab;
|
|
||||||
|
return app;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -19,11 +19,11 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="JetBrains.Annotations" Version="(2023.3.0,)"/>
|
<PackageReference Include="JetBrains.Annotations" Version=">= (2023.3.0,)"/>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="(2.1.7,)" />
|
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version=">= (2.1.7,)" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="(6.0.0,)" />
|
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version=">= (6.0.0,)" />
|
||||||
<PackageReference Include="System.Net.WebSockets" Version="(4.0.0,)"/>
|
<PackageReference Include="System.Net.WebSockets" Version=">= (4.0.0,)"/>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="(2.2.0,)" PrivateAssets="all">
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version=">= (2.2.2,)" PrivateAssets="all">
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<None Include="..\README.md" Pack="true" PackagePath="\"/>
|
<None Include="..\README.md" Pack="true" PackagePath="\"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user