65 lines
1.6 KiB
C#
65 lines
1.6 KiB
C#
using System.Collections.Concurrent;
|
|||
|
|
using System.Net;
|
||
|
|
using System.Security.Cryptography;
|
||
|
|
|
||
|
|
using MeWeb.Shared;
|
||
|
|
|
||
|
|
namespace MeWeb.Server;
|
||
|
|
|
||
|
|
public class SpeedService
|
||
|
|
{
|
||
|
|
const int PerHour = 12;
|
||
|
|
const int AtOnce = 4;
|
||
|
|
int active;
|
||
|
|
static readonly byte[] Noise = RandomNumberGenerator.GetBytes(1024 * 1024);
|
||
|
|
readonly ConcurrentDictionary<string, List<DateTimeOffset>> uses = new();
|
||
|
|
|
||
|
|
public bool Allow(IPAddress caller)
|
||
|
|
{
|
||
|
|
var now = DateTimeOffset.UtcNow;
|
||
|
|
var times = uses.GetOrAdd(ProbeService.NetworkOf(caller), _ => []);
|
||
|
|
lock (times)
|
||
|
|
{
|
||
|
|
times.RemoveAll(t => now - t > TimeSpan.FromHours(1));
|
||
|
|
if (times.Count >= PerHour) return false;
|
||
|
|
times.Add(now);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public bool Enter()
|
||
|
|
{
|
||
|
|
if (Interlocked.Increment(ref active) <= AtOnce) return true;
|
||
|
|
Interlocked.Decrement(ref active);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void Leave() => Interlocked.Decrement(ref active);
|
||
|
|
|
||
|
|
public static async Task Stream(HttpResponse response, int bytes, CancellationToken ct)
|
||
|
|
{
|
||
|
|
response.ContentType = "application/octet-stream";
|
||
|
|
response.ContentLength = bytes;
|
||
|
|
response.Headers.CacheControl = "no-store";
|
||
|
|
var left = bytes;
|
||
|
|
while (left > 0)
|
||
|
|
{
|
||
|
|
var chunk = Math.Min(left, Noise.Length);
|
||
|
|
await response.Body.WriteAsync(Noise.AsMemory(0, chunk), ct);
|
||
|
|
left -= chunk;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public static async Task<long> Drain(Stream body, CancellationToken ct)
|
||
|
|
{
|
||
|
|
var buffer = new byte[64 * 1024];
|
||
|
|
long total = 0;
|
||
|
|
int read;
|
||
|
|
while ((read = await body.ReadAsync(buffer, ct)) > 0)
|
||
|
|
{
|
||
|
|
total += read;
|
||
|
|
if (total > Endpoints.Speed.MaxUpBytes) return -1;
|
||
|
|
}
|
||
|
|
return total;
|
||
|
|
}
|
||
|
|
}
|