use data_storage_lib::ll::distributed::DistributedStorageError;
use thiserror::Error;
use data_storage_lib::ll::local::LocalStorageError;
mod bucket;
mod builder;
mod distribution_formula;
mod implementation;
mod key_manager;
pub use builder::{RateLimitBuilder, RateLimitBuilderInstance};
pub use implementation::RateLimitInstance;
use crate::bucket::Bucket;
pub struct RateLimitStatistics {
pub remaining: u64,
pub limit: u64,
pub reset: u64,
}
pub enum RateLimitResult {
Allowed(RateLimitStatistics),
TooManyRequests(RateLimitStatistics),
}
#[non_exhaustive]
#[derive(Debug, Error)]
pub enum RateLimitError {
#[error("Unexpected error {0}.")]
Unexpected(Box<dyn std::error::Error>),
#[error("Max Hops.")]
MaxHops,
#[error("Serialization error: {0}.")]
Serialization(#[from] bincode::Error),
}
#[allow(async_fn_in_trait)]
pub trait RateLimit {
async fn is_allowed(
&self,
group_selector: &str,
bucket_selector: &str,
increment: usize,
) -> Result<RateLimitResult, RateLimitError>;
}
impl From<LocalStorageError> for RateLimitError {
fn from(value: LocalStorageError) -> Self {
RateLimitError::Unexpected(value.into())
}
}
impl From<DistributedStorageError> for RateLimitError {
fn from(value: DistributedStorageError) -> Self {
RateLimitError::Unexpected(value.into())
}
}
impl RateLimitStatistics {
fn from(bucket: &Bucket, now: u128) -> Self {
if let Some(status) = bucket.status() {
Self {
remaining: status.remaining(),
limit: status.limit(),
reset: status.reset(now) as u64,
}
} else {
Self {
remaining: 0,
limit: 0,
reset: 0,
}
}
}
}