use std::{future::Future, pin::Pin};
use fraiseql_error::Result;
const WARMING_WEEKS: u32 = 6;
const WARMING_INITIAL_DAILY: u32 = 10;
const WARMING_TARGET_DAILY: u32 = 200;
#[must_use]
pub fn warming_daily_limit(days_since_start: i64) -> Option<u32> {
let week = u32::try_from(days_since_start.max(0) / 7).unwrap_or(u32::MAX);
if week >= WARMING_WEEKS {
return None;
}
let span = WARMING_TARGET_DAILY - WARMING_INITIAL_DAILY;
Some(WARMING_INITIAL_DAILY + span * week / (WARMING_WEEKS - 1))
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct WarmingState {
pub days_since_start: i64,
pub sends_today: u32,
}
impl WarmingState {
#[must_use]
pub fn within_cap(&self) -> bool {
warming_daily_limit(self.days_since_start).is_none_or(|limit| self.sends_today < limit)
}
}
pub trait SendCounter: Send + Sync {
fn state<'a>(
&'a self,
address: &'a str,
) -> Pin<Box<dyn Future<Output = Result<Option<WarmingState>>> + Send + 'a>>;
fn record_send<'a>(
&'a self,
address: &'a str,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'a>>;
}
#[cfg(test)]
mod tests;