39static void make_key(
const char *ip_address,
rate_event_type_t event_type,
char *key,
size_t key_size) {
40 snprintf(key, key_size,
"%s:%d", ip_address, event_type);
49 event->timestamps[
event->count++] = timestamp;
52 event->timestamps[
event->head] = timestamp;
53 event->head = (
event->head + 1) % event->
capacity;
63 for (
size_t i = 0; i <
event->count; i++) {
79 for (
size_t read_idx = 0; read_idx <
event->count; read_idx++) {
80 if (event->
timestamps[read_idx] >= cutoff_ms) {
81 event->timestamps[write_idx++] =
event->timestamps[read_idx];
85 event->count = write_idx;
102 make_key(ip_address, event_type, key,
sizeof(key));
108 HASH_FIND_STR(backend->events, key, event);
114 event_count = count_events_in_window(event, window_start_ms);
120 *allowed = (event_count < limit->max_events);
123 log_warn(
"Rate limit exceeded for %s (event: %s, count: %u/%u)", ip_address,
138 make_key(ip_address, event_type, key,
sizeof(key));
144 HASH_FIND_STR(backend->
events, key, event);
154 memset(event, 0,
sizeof(*event));
158 event->capacity = 100;
166 HASH_ADD_STR(backend->
events, key, event);
170 add_timestamp(event, now_ms);
182 if (max_age_secs == 0) {
192 size_t total_removed = 0;
195 HASH_ITER(hh, backend->
events, event, tmp) {
196 size_t before_count =
event->
count;
199 cleanup_old_events(event, cutoff_ms);
201 total_removed += (before_count -
event->count);
204 if (event->
count == 0) {
205 HASH_DEL(backend->
events, event);
213 if (total_removed > 0) {
214 log_debug(
"Cleaned up %zu old rate events", total_removed);
220static void memory_destroy(
void *backend_data) {
228 HASH_ITER(hh, backend->
events, event, tmp) {
229 HASH_DEL(backend->
events, event);
241 log_error(
"Failed to allocate memory backend");
245 memset(backend, 0,
sizeof(*backend));
253 log_debug(
"Memory rate limiter backend initialized");
258 .
check = memory_check,
259 .record = memory_record,
260 .cleanup = memory_cleanup,
261 .destroy = memory_destroy,
🔌 Cross-platform abstraction layer umbrella header for ascii-chat
#define SAFE_STRNCPY(dst, src, size)
#define SAFE_MALLOC(size, cast)
unsigned long long uint64_t
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
asciichat_error_t
Error and exit codes - unified status values (0-255)
#define log_warn(...)
Log a WARN message.
#define log_error(...)
Log an ERROR message.
#define log_debug(...)
Log a DEBUG message.
📝 Logging API with multiple log levels and terminal output control
void * memory_backend_create(void)
Create memory backend instance.
const rate_limiter_backend_ops_t memory_backend_ops
Memory backend operations vtable.
struct rate_event_s rate_event_t
Rate event record in memory.
🧠 In-memory rate limiting backend interface
uint64_t rate_limiter_get_time_ms(void)
Helper: Get current time in milliseconds.
const char * rate_limiter_event_type_string(rate_event_type_t event_type)
Helper: Get event type string for logging.
const rate_limit_config_t DEFAULT_RATE_LIMITS[RATE_EVENT_MAX]
Default rate limits for each event type.
rate_event_type_t
Rate limit event types.
mutex_t lock
Mutex for thread safety.
rate_event_t * events
Hash table of rate events.
Rate event record in memory.
char key[256]
Hash key: "ip_address:event_type".
size_t count
Number of events in buffer.
UT_hash_handle hh
uthash handle
size_t capacity
Buffer capacity.
size_t head
Head index (oldest event)
uint64_t * timestamps
Array of timestamps (circular buffer)
Rate limit configuration.
uint32_t window_secs
Time window in seconds.
Backend operations vtable.
asciichat_error_t(* check)(void *backend_data, const char *ip_address, rate_event_type_t event_type, const rate_limit_config_t *config, bool *allowed)
#️⃣ Wrapper for uthash.h that ensures common.h is included first