use chrono::{Duration, Utc};
use tracing::{debug, info};
use crate::server::database::{BindingAction, Database, PerformedBy};
use super::JobError;
pub async fn run_stale_device_cleanup(db: &Database, stale_days: u32) -> Result<u32, JobError> {
let now = Utc::now().naive_utc();
let threshold = now - Duration::days(stale_days as i64);
debug!(
"Checking for stale devices (last seen before {}) at {}",
threshold, now
);
let stale_licenses = db.get_stale_device_licenses(threshold).await?;
let mut count = 0;
for license in stale_licenses {
debug!(
"Releasing license {} from stale device {} (last seen {:?})",
license.license_id,
license.hardware_id.as_deref().unwrap_or("unknown"),
license.last_seen_at
);
let hardware_id = license.hardware_id.clone();
let device_name = license.device_name.clone();
let device_info = license.device_info.clone();
if db.release_license(&license.license_id).await.is_ok() {
let _ = db
.record_binding_history(
&license.license_id,
BindingAction::SystemRelease,
hardware_id.as_deref(),
device_name.as_deref(),
device_info.as_deref(),
PerformedBy::System,
Some(&format!(
"Automatic release: device not seen for {} days",
stale_days
)),
)
.await;
count += 1;
info!(
"License {} released from stale device {}",
license.license_id,
hardware_id.unwrap_or_default()
);
}
}
Ok(count)
}
#[cfg(test)]
mod tests {
}