use std::{
fmt::{Debug, Display},
hash::Hash,
net::IpAddr,
};
use http::Request;
use super::error::RateLimitError;
pub trait KeyExtractor: Clone + Send + Sync {
type Key: Clone + Hash + Eq + Debug + Display;
fn extract<T>(&self, request: &Request<T>) -> Result<Self::Key, RateLimitError>;
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct IpKeyExtractor;
impl IpKeyExtractor {
pub const fn new() -> Self {
Self
}
}
impl KeyExtractor for IpKeyExtractor {
type Key = IpAddr;
fn extract<T>(&self, request: &Request<T>) -> Result<Self::Key, RateLimitError> {
http_extract::extract_socket_ip(request).ok_or_else(|| {
RateLimitError::Key(
String::from("socket_ip_unavailable"),
String::from("request extensions do not contain a socket ip address"),
)
})
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct ClientIpKeyExtractor;
impl ClientIpKeyExtractor {
pub const fn new() -> Self {
Self
}
}
impl KeyExtractor for ClientIpKeyExtractor {
type Key = IpAddr;
fn extract<T>(&self, request: &Request<T>) -> Result<Self::Key, RateLimitError> {
http_extract::extract_proxy_client_ip(request)
.map_err(|error| RateLimitError::Key(String::from("invalid_client_ip"), error.to_string()))?
.ok_or_else(|| {
RateLimitError::Key(
String::from("client_ip_unavailable"),
String::from("request does not contain a client or socket IP address"),
)
})
}
}