2024-07-04 11:02:45 +05:00
using Microsoft.AspNetCore.Http ;
2022-11-01 17:14:19 +05:00
using Microsoft.Extensions.Configuration ;
using System.Collections.Concurrent ;
using System.Collections.Generic ;
using System.Linq ;
using System.Threading.Tasks ;
2024-08-19 10:01:07 +05:00
namespace AsbCloudWebApi.Middlewares ;
/// <summary>
/// This is not real middleware it`s part of PermissionsMiddlware.
/// DO NOT register it in setup.cs as middleware.
/// </summary>
class UserConnectionsLimitMiddlware
2022-11-01 17:14:19 +05:00
{
2024-08-19 10:01:07 +05:00
private readonly int parallelRequestsToController ;
private readonly RequestDelegate next ;
private readonly byte [ ] responseBody ;
private readonly ConcurrentDictionary < int , ConcurrentDictionary < string , int > > stat = new ( ) ;
private readonly IEnumerable < string > ? controllerNames ;
2023-05-19 16:51:41 +05:00
2024-08-19 10:01:07 +05:00
public UserConnectionsLimitMiddlware ( RequestDelegate next , IConfiguration configuration )
2022-11-01 17:14:19 +05:00
{
2024-08-19 10:01:07 +05:00
const int parallelRequestsToControllerDefault = 8 ;
this . next = next ;
var parallelRequestsToController = configuration . GetSection ( "userLimits" ) ? . GetValue < int > ( "parallelRequestsToController" ) ? ? parallelRequestsToControllerDefault ;
this . parallelRequestsToController = parallelRequestsToController > 0
? parallelRequestsToController
: parallelRequestsToControllerDefault ;
2022-11-01 17:14:19 +05:00
2024-08-19 10:01:07 +05:00
controllerNames = configuration . GetSection ( "userLimits" ) ? . GetValue < IEnumerable < string > > ( "controllerNames" ) ;
2022-11-01 17:14:19 +05:00
2024-08-19 10:01:07 +05:00
var bodyText = $"<html><head><title>Too Many Requests</title></head><body><h1>Too Many Requests</h1><p>I only allow {this.parallelRequestsToController} parallel requests per user. Try again soon.</p></body></html>" ;
responseBody = System . Text . Encoding . UTF8 . GetBytes ( bodyText ) ;
}
2022-11-01 17:14:19 +05:00
2024-08-19 10:01:07 +05:00
public async Task InvokeAsync ( HttpContext context , int idUser , string controllerName )
{
if ( controllerNames ? . Any ( n = > controllerName . StartsWith ( n ) ) = = false )
{
await next ( context ) ;
return ;
2022-11-01 17:14:19 +05:00
}
2024-08-19 10:01:07 +05:00
var userStat = stat . GetOrAdd ( idUser , idUser = > new ( ) ) ;
var count = userStat . AddOrUpdate ( controllerName , 0 , ( k , v ) = > v ) ;
if ( count + 1 < parallelRequestsToController )
2022-11-01 17:14:19 +05:00
{
2024-08-19 10:01:07 +05:00
try
2022-11-01 17:14:19 +05:00
{
2024-08-19 10:01:07 +05:00
userStat [ controllerName ] + + ;
2022-11-01 17:14:19 +05:00
await next ( context ) ;
2022-11-10 13:59:48 +05:00
}
2024-08-19 10:01:07 +05:00
finally
2022-11-01 17:14:19 +05:00
{
2024-08-19 10:01:07 +05:00
userStat [ controllerName ] - - ;
2022-11-01 17:14:19 +05:00
}
}
2024-08-19 10:01:07 +05:00
else
{
context . Response . Clear ( ) ;
context . Response . StatusCode = ( int ) System . Net . HttpStatusCode . TooManyRequests ;
context . Response . Headers . RetryAfter = "1000" ;
context . Response . Headers . ContentType = "text/html" ;
await context . Response . BodyWriter . WriteAsync ( responseBody ) ;
}
2022-11-01 17:14:19 +05:00
}
}