diff --git a/dbal/cpp/src/security/rate_limiter.hpp b/dbal/cpp/src/security/rate_limiter.hpp index 370e58111..fc61e7c35 100644 --- a/dbal/cpp/src/security/rate_limiter.hpp +++ b/dbal/cpp/src/security/rate_limiter.hpp @@ -1,89 +1,49 @@ #pragma once /** * @file rate_limiter.hpp - * @brief Token bucket rate limiter - * @details Header-only, thread-safe rate limiting + * @brief Token bucket rate limiter (thread-safe wrapper) */ #include #include -#include #include +#include "rate_limit_try_acquire.hpp" +#include "rate_limit_remaining.hpp" namespace dbal::security { /** * Thread-safe token bucket rate limiter + * Wraps individual rate limit functions with mutex protection */ class RateLimiter { public: - /** - * @param tokens_per_second Refill rate - * @param max_tokens Maximum bucket size (burst capacity) - */ RateLimiter(double tokens_per_second, double max_tokens) : tokens_per_second_(tokens_per_second) , max_tokens_(max_tokens) {} - /** - * Try to consume a token for the given key - * @param key Client identifier (IP, user ID, etc.) - * @return true if allowed, false if rate limited - */ bool try_acquire(const std::string& key) { std::lock_guard lock(mutex_); - - auto now = std::chrono::steady_clock::now(); - auto& bucket = buckets_[key]; - - // Initialize new buckets - if (bucket.tokens == 0 && bucket.last_update.time_since_epoch().count() == 0) { - bucket.tokens = max_tokens_; - bucket.last_update = now; - } - - // Refill tokens based on elapsed time - auto elapsed = std::chrono::duration(now - bucket.last_update).count(); - bucket.tokens = std::min(max_tokens_, bucket.tokens + elapsed * tokens_per_second_); - bucket.last_update = now; - - // Try to consume - if (bucket.tokens >= 1.0) { - bucket.tokens -= 1.0; - return true; - } - - return false; + return rate_limit_try_acquire(buckets_[key], tokens_per_second_, max_tokens_); } - /** - * Get remaining tokens for a key - */ double remaining(const std::string& key) { std::lock_guard lock(mutex_); auto it = buckets_.find(key); if (it == buckets_.end()) return max_tokens_; - return it->second.tokens; + return rate_limit_remaining(it->second, max_tokens_); } - /** - * Reset a specific key's bucket - */ void reset(const std::string& key) { std::lock_guard lock(mutex_); buckets_.erase(key); } private: - struct Bucket { - double tokens = 0; - std::chrono::steady_clock::time_point last_update{}; - }; - double tokens_per_second_; double max_tokens_; - std::unordered_map buckets_; + std::unordered_map buckets_; std::mutex mutex_; }; diff --git a/docs/database/overview.md b/docs/database/overview.md index f134f82ea..13d3f9afe 100644 --- a/docs/database/overview.md +++ b/docs/database/overview.md @@ -55,6 +55,9 @@ The database manages the following entity types: - `code`: Lua source code - `parameters`: Array of parameter definitions - `returnType`: Expected return type + - `isSandboxed`: Whether script runs in sandbox + - `allowedGlobals`: Allowed global functions/modules + - `timeoutMs`: Execution timeout in milliseconds #### Pages - **Key**: `db_pages`