brakes 0.1.1

A distributed rate limiting library
Documentation
pub mod local;

#[cfg(feature = "memcache")]
#[cfg_attr(docsrs, doc(cfg(feature = "memcache")))]
pub mod memcache;
#[cfg(feature = "redis")]
#[cfg_attr(docsrs, doc(cfg(feature = "redis")))]
pub mod redis;

#[cfg(feature = "memcache")]
use ::memcache::MemcacheError;
#[cfg(feature = "redis")]
use ::redis::RedisError;
use std::{
    error::Error,
    fmt::{self, Debug, Display},
};

pub trait Backend: Clone {
    fn get(&self, key: &str) -> Result<(Vec<u8>, Option<u64>), BackendError>;
    fn set(&self, key: &str, value: &[u8], version: Option<u64>) -> Result<(), BackendError>;
    fn delete(&self, key: &str) -> Result<(), BackendError>;

    fn get_with_retries(
        &self,
        key: &str,
        tries: u32,
    ) -> Result<(Vec<u8>, Option<u64>), BackendError> {
        let mut err = None;
        for _ in 0..tries {
            match self.get(key) {
                Ok(v) => return Ok(v),
                Err(BackendError::KeyMissing) => return Err(BackendError::KeyMissing),
                Err(e) => {
                    err = Some(e);
                    continue;
                }
            }
        }
        Err(err.unwrap())
    }

    fn set_with_retries(
        &self,
        key: &str,
        value: Vec<u8>,
        version: Option<u64>,
        tries: u32,
    ) -> Result<(), BackendError> {
        let mut err = None;
        for _ in 0..tries {
            match self.set(key, &value, version) {
                Ok(_) => return Ok(()),
                Err(BackendError::ValueChanged) => return Err(BackendError::ValueChanged),
                Err(e) => {
                    err = Some(e);
                    continue;
                }
            }
        }
        Err(err.unwrap())
    }

    fn delete_with_retries(&self, key: &str, tries: u32) -> Result<(), BackendError> {
        let mut err = None;
        for _ in 0..tries {
            match self.delete(key) {
                Ok(_) => return Ok(()),
                Err(e) => {
                    err = Some(e);
                    continue;
                }
            }
        }
        Err(err.unwrap())
    }
}

#[derive(Debug)]
pub enum BackendError {
    #[cfg(feature = "redis")]
    R2D2Error(r2d2::Error),
    #[cfg(feature = "redis")]
    RedisError(RedisError),
    #[cfg(feature = "memcache")]
    MemCacheError(MemcacheError),
    LocalMemLockError,
    KeyMissing,
    ValueChanged,
}

impl Display for BackendError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            #[cfg(feature = "redis")]
            BackendError::R2D2Error(e) => std::fmt::Display::fmt(&e, f),
            #[cfg(feature = "redis")]
            BackendError::RedisError(e) => std::fmt::Display::fmt(&e, f),
            #[cfg(feature = "memcache")]
            BackendError::MemCacheError(e) => std::fmt::Display::fmt(&e, f),
            BackendError::LocalMemLockError => write!(f, "mutex poison error"),
            BackendError::ValueChanged => write!(f, "value changed"),
            BackendError::KeyMissing => write!(f, "key missing"),
        }
    }
}

impl Error for BackendError {}