use std::time::Duration;
use donglora_protocol::TxDonePayload;
use crate::errors::ClientError;
#[derive(Debug, Clone)]
pub struct RetryPolicy {
pub max_attempts: u8,
pub backoff_ms_min: u32,
pub backoff_ms_max: u32,
pub backoff_multiplier: f32,
pub backoff_cap_ms: u32,
pub per_attempt_timeout: Duration,
pub skip_cad: bool,
}
impl Default for RetryPolicy {
fn default() -> Self {
Self {
max_attempts: 3,
backoff_ms_min: 20,
backoff_ms_max: 100,
backoff_multiplier: 2.0,
backoff_cap_ms: 500,
per_attempt_timeout: Duration::from_secs(5),
skip_cad: false,
}
}
}
impl RetryPolicy {
pub(crate) fn jitter_ms(&self) -> u32 {
use rand::Rng;
let spread = self.backoff_ms_max.saturating_sub(self.backoff_ms_min);
if spread == 0 {
return 0;
}
rand::rng().random_range(0..=spread)
}
}
#[derive(Debug)]
pub struct TxAttempt {
pub attempt: u8,
pub result: Result<TxDonePayload, ClientError>,
pub elapsed: Duration,
}
#[derive(Debug)]
pub struct TxOutcome {
pub final_airtime_us: u32,
pub attempts: Vec<TxAttempt>,
}
impl TxOutcome {
#[must_use]
pub fn attempts_used(&self) -> u8 {
self.attempts.len() as u8
}
#[must_use]
pub fn had_retries(&self) -> bool {
self.attempts.len() > 1
}
}