brakes 0.1.1

A distributed rate limiting library
Documentation
pub mod fixed_window;
pub mod leaky_bucket;
pub mod sliding_window;
pub mod token_bucket;

use crate::backend::BackendError;
use fixed_window::FixedWindowInstance;
use leaky_bucket::LeakyBucketInstance;
use serde::{Deserialize, Serialize};
use sliding_window::SlidingWindowInstance;
use std::{
    error::Error,
    fmt::{self, Debug, Display},
};
use token_bucket::TokenBucketInstance;

pub trait LimiterType: Clone {
    fn is_ratelimited(&self, value: Option<Vec<u8>>) -> Result<LimiterInstance, RateLimiterError>;
    fn window_instance(&self, value: Vec<u8>) -> Result<LimiterInstance, RateLimiterError> {
        LimiterInstance::from_bytes(value)
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub enum LimiterInstance {
    FixedWindowInstance(FixedWindowInstance),
    SlidingWindowInstance(SlidingWindowInstance),
    TokenBucketInstance(TokenBucketInstance),
    LeakyBucketInstance(LeakyBucketInstance),
}

impl LimiterInstance {
    pub fn as_fixed_window_instance(self) -> Result<FixedWindowInstance, RateLimiterError> {
        match self {
            Self::FixedWindowInstance(i) => Ok(i),
            _ => Err(RateLimiterError::WrongLimiterInstanceType),
        }
    }

    pub fn as_sliding_window_instance(self) -> Result<SlidingWindowInstance, RateLimiterError> {
        match self {
            Self::SlidingWindowInstance(i) => Ok(i),
            _ => Err(RateLimiterError::WrongLimiterInstanceType),
        }
    }

    pub fn as_token_bucket_instance(self) -> Result<TokenBucketInstance, RateLimiterError> {
        match self {
            Self::TokenBucketInstance(i) => Ok(i),
            _ => Err(RateLimiterError::WrongLimiterInstanceType),
        }
    }

    pub fn as_leaky_bucket_instance(self) -> Result<LeakyBucketInstance, RateLimiterError> {
        match self {
            Self::LeakyBucketInstance(i) => Ok(i),
            _ => Err(RateLimiterError::WrongLimiterInstanceType),
        }
    }
}

impl SerializableInstance for LimiterInstance {}

pub(crate) trait SerializableInstance:
    Debug + Serialize + for<'de> Deserialize<'de>
{
    fn from_bytes(bytes: Vec<u8>) -> Result<Self, RateLimiterError> {
        bincode::deserialize(&bytes).map_err(RateLimiterError::MalformedValue)
    }
    fn to_bytes(self) -> Result<Vec<u8>, RateLimiterError> {
        bincode::serialize(&self).map_err(RateLimiterError::MalformedValue)
    }
}

#[derive(Debug)]
pub enum RateLimiterError {
    MalformedValue(bincode::Error),
    WrongLimiterInstanceType,
    RateExceeded,
    BackendError(BackendError),
    BackendConflict,
}

impl Display for RateLimiterError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            RateLimiterError::MalformedValue(e) => std::fmt::Display::fmt(&e, f),
            RateLimiterError::WrongLimiterInstanceType => {
                write!(f, "wrong instance type provided")
            }
            RateLimiterError::RateExceeded => write!(f, "rate exceeded"),
            RateLimiterError::BackendError(e) => std::fmt::Display::fmt(&e, f),
            RateLimiterError::BackendConflict => write!(f, "backend value conflict"),
        }
    }
}

impl Error for RateLimiterError {}