diff --git a/src/main/java/net/viper/status/ratelimit/GlobalRateLimitFramework.java b/src/main/java/net/viper/status/ratelimit/GlobalRateLimitFramework.java deleted file mode 100644 index 672c445..0000000 --- a/src/main/java/net/viper/status/ratelimit/GlobalRateLimitFramework.java +++ /dev/null @@ -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 buckets = new ConcurrentHashMap(); - - 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 hits = new ArrayDeque(); - long blockedUntil = 0L; - } -} \ No newline at end of file