use std::time::{SystemTime, UNIX_EPOCH};
use serde::{Deserialize, Serialize};
use super::types::NodeId;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConsolidationLease {
pub holder: NodeId,
pub acquired_at: u64,
pub expires_at: u64,
pub realm: String,
}
impl ConsolidationLease {
pub const DEFAULT_DURATION_SECS: u64 = 300;
pub fn new(realm: String, holder: NodeId, duration_secs: u64) -> Self {
let now = now_epoch_secs();
Self {
holder,
acquired_at: now,
expires_at: now.saturating_add(duration_secs),
realm,
}
}
pub fn is_expired(&self) -> bool {
now_epoch_secs() >= self.expires_at
}
pub fn is_held_by(&self, node: NodeId) -> bool {
self.holder == node && !self.is_expired()
}
pub fn renew(&mut self, duration_secs: u64) {
let now = now_epoch_secs();
self.expires_at = now.saturating_add(duration_secs);
}
pub fn remaining_secs(&self) -> u64 {
let now = now_epoch_secs();
self.expires_at.saturating_sub(now)
}
}
fn now_epoch_secs() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("system clock is before UNIX epoch")
.as_secs()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lease_creation_and_expiry() {
let lease = ConsolidationLease::new("test-realm".into(), 1, 300);
assert_eq!(lease.holder, 1);
assert_eq!(lease.realm, "test-realm");
assert!(!lease.is_expired());
assert!(lease.is_held_by(1));
assert!(!lease.is_held_by(2));
assert!(lease.remaining_secs() > 0);
}
#[test]
fn expired_lease() {
let lease = ConsolidationLease {
holder: 1,
acquired_at: 0,
expires_at: 1, realm: "test".into(),
};
assert!(lease.is_expired());
assert!(!lease.is_held_by(1));
assert_eq!(lease.remaining_secs(), 0);
}
#[test]
fn renewal() {
let mut lease = ConsolidationLease::new("r".into(), 1, 10);
lease.renew(600);
assert!(lease.remaining_secs() > 500);
}
}