Delete src/main/java/net/viper/status/ratelimit/GlobalRateLimitFramework.java via Git Manager GUI
This commit is contained in:
@@ -1,119 +0,0 @@
|
||||
package net.viper.status.ratelimit;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Gemeinsames Rate-Limit-Framework fuer mehrere Module.
|
||||
*/
|
||||
public final class GlobalRateLimitFramework {
|
||||
|
||||
private static final GlobalRateLimitFramework INSTANCE = new GlobalRateLimitFramework();
|
||||
|
||||
private final Map<String, Bucket> buckets = new ConcurrentHashMap<String, Bucket>();
|
||||
|
||||
private GlobalRateLimitFramework() {
|
||||
}
|
||||
|
||||
public static GlobalRateLimitFramework getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public Result check(String scope, String actorId, Rule rule) {
|
||||
return check(scope, actorId, rule, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public Result check(String scope, String actorId, Rule rule, long now) {
|
||||
if (rule == null || !rule.enabled || scope == null || scope.isEmpty() || actorId == null || actorId.isEmpty()) {
|
||||
return Result.allowed(0, 0L);
|
||||
}
|
||||
|
||||
String key = scope + ":" + actorId;
|
||||
Bucket bucket = buckets.computeIfAbsent(key, k -> new Bucket());
|
||||
|
||||
synchronized (bucket) {
|
||||
if (bucket.blockedUntil > now) {
|
||||
return Result.blocked(Math.max(0L, bucket.blockedUntil - now), bucket.hits.size());
|
||||
}
|
||||
|
||||
long minTs = now - Math.max(1L, rule.windowMs);
|
||||
while (!bucket.hits.isEmpty() && bucket.hits.peekFirst() < minTs) {
|
||||
bucket.hits.pollFirst();
|
||||
}
|
||||
|
||||
bucket.hits.addLast(now);
|
||||
|
||||
if (bucket.hits.size() > Math.max(1, rule.maxActions)) {
|
||||
long blockMs = Math.max(1L, rule.blockMs);
|
||||
bucket.blockedUntil = now + blockMs;
|
||||
return Result.blocked(blockMs, bucket.hits.size());
|
||||
}
|
||||
|
||||
return Result.allowed(bucket.hits.size(), 0L);
|
||||
}
|
||||
}
|
||||
|
||||
public void clearActor(String actorId) {
|
||||
if (actorId == null || actorId.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (String key : buckets.keySet()) {
|
||||
if (key.endsWith(":" + actorId)) {
|
||||
buckets.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Rule {
|
||||
public final boolean enabled;
|
||||
public final long windowMs;
|
||||
public final int maxActions;
|
||||
public final long blockMs;
|
||||
|
||||
public Rule(boolean enabled, long windowMs, int maxActions, long blockMs) {
|
||||
this.enabled = enabled;
|
||||
this.windowMs = Math.max(1L, windowMs);
|
||||
this.maxActions = Math.max(1, maxActions);
|
||||
this.blockMs = Math.max(1L, blockMs);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Result {
|
||||
private final boolean blocked;
|
||||
private final int currentHits;
|
||||
private final long remainingBlockMs;
|
||||
|
||||
private Result(boolean blocked, int currentHits, long remainingBlockMs) {
|
||||
this.blocked = blocked;
|
||||
this.currentHits = Math.max(0, currentHits);
|
||||
this.remainingBlockMs = Math.max(0L, remainingBlockMs);
|
||||
}
|
||||
|
||||
public static Result blocked(long remainingBlockMs, int currentHits) {
|
||||
return new Result(true, currentHits, remainingBlockMs);
|
||||
}
|
||||
|
||||
public static Result allowed(int currentHits, long remainingBlockMs) {
|
||||
return new Result(false, currentHits, remainingBlockMs);
|
||||
}
|
||||
|
||||
public boolean isBlocked() {
|
||||
return blocked;
|
||||
}
|
||||
|
||||
public int getCurrentHits() {
|
||||
return currentHits;
|
||||
}
|
||||
|
||||
public long getRemainingBlockMs() {
|
||||
return remainingBlockMs;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Bucket {
|
||||
final Deque<Long> hits = new ArrayDeque<Long>();
|
||||
long blockedUntil = 0L;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user