#[must_use]
pub fn build_rate_limit_key(strategy: &str, identifier: &str, prefix: Option<&str>) -> String {
match prefix {
Some(p) => format!("fraiseql:rl:{strategy}:{p}:{identifier}"),
None => format!("fraiseql:rl:{strategy}:{identifier}"),
}
}
pub(super) const fn is_private_or_loopback(ip: std::net::IpAddr) -> bool {
match ip {
std::net::IpAddr::V4(v4) => v4.is_loopback() || v4.is_private() || v4.is_link_local(),
std::net::IpAddr::V6(v6) => v6.is_loopback(),
}
}
pub(super) fn path_matches_rule(path: &str, prefix: &str) -> bool {
if path == prefix {
return true;
}
let Some(rest) = path.strip_prefix(prefix) else {
return false;
};
rest.starts_with('/') || rest.starts_with('?')
}
#[derive(Debug, Clone)]
pub(super) struct PathRateLimit {
pub(super) path_prefix: String,
pub(super) tokens_per_sec: f64,
pub(super) burst: f64,
}