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,
}
#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
#[non_exhaustive]
pub enum ERLError {
#[error("Unexpected ERL error")]
Unexpected,
#[error("Unknown ERL error: {0:?}")]
Unknown(FastlyStatus),
#[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)
}
}