fastly 0.12.0

Fastly Compute API
Documentation
use std::time::Duration;

use fastly_shared::FastlyStatus;

use crate::abi::{self};

use super::{CounterDuration, Penaltybox, RateCounter, RateWindow};

pub struct ERLHandle {
    penaltybox: Penaltybox,
    ratecounter: RateCounter,
}

pub struct RateCounterHandle {
    name: String,
}

pub struct PenaltyboxHandle {
    name: String,
}

/// Errors that can arise during ERL operations.
///
/// This type is marked as non-exhaustive because more variants will be added over time.
#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
#[non_exhaustive]
pub enum ERLError {
    /// Unexpected ERL error.
    // #[error("Unexpected ERL error")]
    // Unexpected,
    #[error("Unexpected ERL error")]
    Unexpected,
    /// Unknown ERL error.
    // #[error("Unknown ERL error")]
    // Unknown,
    #[error("Unknown ERL error: {0:?}")]
    Unknown(FastlyStatus),
    /// InvalidArgument ERL error.
    // #[error("InvalidArgument ERL error")]
    // InvalidArgument,
    #[error("InvalidArgument ERL")]
    InvalidArgument,
}

impl From<FastlyStatus> for ERLError {
    fn from(st: FastlyStatus) -> Self {
        match st {
            FastlyStatus::ERROR => ERLError::Unexpected,
            FastlyStatus::INVAL => ERLError::InvalidArgument,
            _ => ERLError::Unknown(st),
        }
    }
}

impl ERLHandle {
    pub fn open(ratecounter: RateCounter, penaltybox: Penaltybox) -> Self {
        ERLHandle {
            ratecounter,
            penaltybox,
        }
    }

    pub fn check_rate(
        &self,
        entry: &str,
        delta: u32,
        window: RateWindow,
        limit: u32,
        ttl: Duration,
    ) -> Result<bool, ERLError> {
        let mut blocked = 0;

        let win: u32 = match window {
            RateWindow::OneSec => 1,
            RateWindow::TenSecs => 10,
            RateWindow::SixtySecs => 60,
        };

        let status = unsafe {
            abi::fastly_erl::check_rate(
                self.ratecounter.handle.name.as_ptr(),
                self.ratecounter.handle.name.len(),
                entry.as_ptr(),
                entry.len(),
                delta,
                win,
                limit,
                self.penaltybox.handle.name.as_ptr(),
                self.penaltybox.handle.name.len(),
                ttl.as_secs() as u32,
                &mut blocked,
            )
        };

        let blocked_bool = match status.result() {
            Ok(_) => blocked == 1,
            Err(e) => return Err(e.into()),
        };

        Ok(blocked_bool)
    }
}

impl RateCounterHandle {
    pub fn open(ratecounter_name: &str) -> Self {
        RateCounterHandle {
            name: ratecounter_name.to_owned(),
        }
    }

    pub fn increment(&self, entry: &str, delta: u32) -> Result<(), ERLError> {
        let status = unsafe {
            abi::fastly_erl::ratecounter_increment(
                self.name.as_ptr(),
                self.name.len(),
                entry.as_ptr(),
                entry.len(),
                delta,
            )
        };

        match status.result() {
            Ok(_) => Ok(()),
            Err(e) => Err(e.into()),
        }
    }

    pub fn lookup_rate(&self, entry: &str, window: RateWindow) -> Result<u32, ERLError> {
        let mut rate = 0;

        let win: u32 = match window {
            RateWindow::OneSec => 1,
            RateWindow::TenSecs => 10,
            RateWindow::SixtySecs => 60,
        };

        let status = unsafe {
            abi::fastly_erl::ratecounter_lookup_rate(
                self.name.as_ptr(),
                self.name.len(),
                entry.as_ptr(),
                entry.len(),
                win,
                &mut rate,
            )
        };

        match status.result() {
            Ok(_) => Ok(rate),
            Err(e) => Err(e.into()),
        }
    }

    pub fn lookup_count(&self, entry: &str, duration: CounterDuration) -> Result<u32, ERLError> {
        let mut count = 0;

        let dur: u32 = match duration {
            CounterDuration::TenSec => 10,
            CounterDuration::TwentySecs => 20,
            CounterDuration::ThirtySecs => 30,
            CounterDuration::FortySecs => 40,
            CounterDuration::FiftySecs => 50,
            CounterDuration::SixtySecs => 60,
        };

        let status = unsafe {
            abi::fastly_erl::ratecounter_lookup_count(
                self.name.as_ptr(),
                self.name.len(),
                entry.as_ptr(),
                entry.len(),
                dur,
                &mut count,
            )
        };

        match status.result() {
            Ok(_) => Ok(count),
            Err(e) => Err(e.into()),
        }
    }
}

impl PenaltyboxHandle {
    pub fn open(penaltybox_name: &str) -> Self {
        PenaltyboxHandle {
            name: penaltybox_name.to_owned(),
        }
    }

    pub fn add(&self, entry: &str, ttl: Duration) -> Result<(), ERLError> {
        let status = unsafe {
            abi::fastly_erl::penaltybox_add(
                self.name.as_ptr(),
                self.name.len(),
                entry.as_ptr(),
                entry.len(),
                ttl.as_secs() as u32,
            )
        };

        match status.result() {
            Ok(_) => Ok(()),
            Err(e) => Err(e.into()),
        }
    }

    pub fn has(&self, entry: &str) -> Result<bool, ERLError> {
        let mut has = 0;
        let status = unsafe {
            abi::fastly_erl::penaltybox_has(
                self.name.as_ptr(),
                self.name.len(),
                entry.as_ptr(),
                entry.len(),
                &mut has,
            )
        };

        let has_bool = match status.result() {
            Ok(_) => has == 1,
            Err(e) => return Err(e.into()),
        };

        Ok(has_bool)
    }
}