-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlib.rs
89 lines (74 loc) · 2.5 KB
/
lib.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use neon::prelude::*;
use dashmap::DashMap;
use chrono::Utc;
use std::sync::Arc;
// Configuration struct for rate limiting.
struct RateLimiterConfig {
max_requests: usize,
window_seconds: i64,
burst_allowance: usize,
}
// Struct to store client request info.
struct ClientInfo {
requests: usize,
last_request: i64,
}
// Shared state for the rate limiter.
struct RateLimiter {
config: Arc<RateLimiterConfig>,
clients: Arc<DashMap<String, ClientInfo>>,
}
// Implement Finalize for RateLimiter.
impl Finalize for RateLimiter {}
impl RateLimiter {
fn new(max_requests: usize, window_seconds: i64, burst_allowance: usize) -> Self {
RateLimiter {
config: Arc::new(RateLimiterConfig {
max_requests,
window_seconds,
burst_allowance,
}),
clients: Arc::new(DashMap::new()),
}
}
fn check_rate_limit(&self, ip: &str) -> bool {
let now = Utc::now().timestamp();
let mut client = self.clients.entry(ip.to_string()).or_insert(ClientInfo {
requests: 0,
last_request: now,
});
let elapsed = now - client.last_request;
if elapsed > self.config.window_seconds {
// Reset the rate limit window.
client.requests = 0;
client.last_request = now;
}
// Allow bursts up to burst_allowance.
if client.requests < self.config.max_requests + self.config.burst_allowance {
client.requests += 1;
true
} else {
false
}
}
}
// Neon module to expose the rate limiter.
fn create_rate_limiter(mut cx: FunctionContext) -> JsResult<JsBox<RateLimiter>> {
let max_requests = cx.argument::<JsNumber>(0)?.value(&mut cx) as usize;
let window_seconds = cx.argument::<JsNumber>(1)?.value(&mut cx) as i64;
let burst_allowance = cx.argument::<JsNumber>(2)?.value(&mut cx) as usize;
let rate_limiter = RateLimiter::new(max_requests, window_seconds, burst_allowance);
Ok(cx.boxed(rate_limiter))
}
fn check_ip(mut cx: FunctionContext) -> JsResult<JsBoolean> {
let rate_limiter = cx.argument::<JsBox<RateLimiter>>(0)?;
let ip = cx.argument::<JsString>(1)?.value(&mut cx);
let allowed = rate_limiter.check_rate_limit(&ip);
Ok(cx.boolean(allowed))
}
#[neon::main]
fn main(mut cx: ModuleContext) -> NeonResult<()> {
cx.export_function("createRateLimiter", create_rate_limiter)?;
cx.export_function("checkIp", check_ip)?;
Ok(())
}