use std::time::{Duration, SystemTime, UNIX_EPOCH};
use better_default::Default;
use serde::{Deserialize, Serialize};
use crate::{errors::RvError, rv_error_string};
#[derive(Debug, Clone, Eq, Default, PartialEq, Serialize, Deserialize)]
pub struct Lease {
#[serde(rename = "lease")]
pub ttl: Duration,
#[serde(skip)]
pub max_ttl: Duration,
#[default(true)]
pub renewable: bool,
#[serde(skip)]
pub increment: Duration,
#[serde(skip)]
#[default(Some(SystemTime::now()))]
pub issue_time: Option<SystemTime>,
}
impl Lease {
pub fn new() -> Self {
Self {
..Default::default()
}
}
pub fn ttl(&self) -> Duration {
self.ttl
}
pub fn renewable(&self) -> bool {
self.renewable
}
pub fn enabled(&self) -> bool {
self.ttl.as_secs() > 0
}
pub fn expiration_time(&self) -> SystemTime {
if self.enabled() {
SystemTime::now() + self.ttl
} else {
SystemTime::UNIX_EPOCH
}
}
}
pub fn calculate_ttl(
max_lease_ttl: Duration,
default_lease_ttl: Duration,
increment: Duration,
period: Duration,
backend_ttl: Duration,
backend_max_ttl: Duration,
explicit_max_ttl: Duration,
start_time: SystemTime,
) -> Result<Duration, RvError> {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_secs()) .unwrap_or(0);
let start_time = start_time
.duration_since(UNIX_EPOCH)
.map(|d| d.as_secs()) .unwrap_or(now);
let mut max_ttl = max_lease_ttl;
if backend_max_ttl > Duration::ZERO && backend_max_ttl < max_ttl {
max_ttl = backend_max_ttl;
}
if explicit_max_ttl > Duration::ZERO && explicit_max_ttl < max_ttl {
max_ttl = explicit_max_ttl;
}
if max_ttl <= Duration::ZERO {
return Err(rv_error_string!("max TTL must be greater than zero"));
}
let mut ttl;
let mut max_valid_time = Duration::ZERO;
if period > Duration::ZERO {
if period > max_ttl {
ttl = max_ttl;
} else {
ttl = period;
}
if explicit_max_ttl > Duration::ZERO {
max_valid_time = Duration::from_secs(start_time) + explicit_max_ttl;
}
} else {
if increment > Duration::ZERO {
ttl = increment;
} else if backend_ttl > Duration::ZERO {
ttl = backend_ttl;
} else {
ttl = default_lease_ttl;
}
max_valid_time = Duration::from_secs(start_time) + max_ttl;
}
if !max_valid_time.is_zero() {
let max_valid_ttl = max_valid_time - Duration::from_secs(now);
if max_valid_ttl <= Duration::ZERO {
return Err(rv_error_string!("past the max TTL, cannot renew"));
}
if max_valid_ttl < ttl {
ttl = max_valid_ttl;
}
}
Ok(ttl)
}