use crate::core::errors::StorageResult;
use crate::core::storage_provider::QueryStore;
pub trait StorageCleanup: QueryStore {
fn cleanup_expired_sessions(
&self,
now: i64,
max_inactive_seconds: Option<i64>,
) -> StorageResult<u64> {
let sql = match max_inactive_seconds {
Some(_inactive_timeout) => {
"DELETE FROM sessions WHERE expires_at < ? OR (last_active_at IS NOT NULL AND last_active_at < ?)".to_string()
}
None => "DELETE FROM sessions WHERE expires_at < ?".to_string(),
};
let params = match max_inactive_seconds {
Some(inactive_timeout) => vec![
crate::core::storage_provider::DataValue::Integer(now),
crate::core::storage_provider::DataValue::Integer(now - inactive_timeout),
],
None => vec![crate::core::storage_provider::DataValue::Integer(now)],
};
self.execute(&sql, ¶ms)
}
fn cleanup_expired_jwt_tokens(&self, now: i64) -> StorageResult<u64> {
let sql = "DELETE FROM jwt_tokens WHERE expires_at < ?";
let params = vec![crate::core::storage_provider::DataValue::Integer(now)];
self.execute(sql, ¶ms)
}
fn cleanup_expired_verification_tokens(&self, now: i64) -> StorageResult<u64> {
let sql = "DELETE FROM verification_tokens WHERE expires_at < ?";
let params = vec![crate::core::storage_provider::DataValue::Integer(now)];
self.execute(sql, ¶ms)
}
fn cleanup_expired_oauth_states(&self, now: i64) -> StorageResult<u64> {
let sql = "DELETE FROM oauth_states WHERE expires_at < ?";
let params = vec![crate::core::storage_provider::DataValue::Integer(now)];
self.execute(sql, ¶ms)
}
fn cleanup_expired_magic_links(&self, now: i64) -> StorageResult<u64> {
let sql = "DELETE FROM magic_links WHERE expires_at < ?";
let params = vec![crate::core::storage_provider::DataValue::Integer(now)];
self.execute(sql, ¶ms)
}
fn cleanup_expired_email_otps(&self, now: i64) -> StorageResult<u64> {
let sql = "DELETE FROM email_otps WHERE expires_at < ?";
let params = vec![crate::core::storage_provider::DataValue::Integer(now)];
self.execute(sql, ¶ms)
}
fn cleanup_old_rate_limits(&self, window_seconds: i64) -> StorageResult<u64> {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs()
.cast_signed();
let cutoff = now - window_seconds;
let sql = "DELETE FROM rate_limits WHERE window_start < ?";
let params = vec![crate::core::storage_provider::DataValue::Integer(cutoff)];
self.execute(sql, ¶ms)
}
#[allow(clippy::field_reassign_with_default)]
fn run_full_cleanup(&self) -> StorageResult<CleanupStats> {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs()
.cast_signed();
let mut stats = CleanupStats::default();
stats.sessions_deleted = self.cleanup_expired_sessions(now, Some(86_400))?;
stats.jwt_tokens_deleted = self.cleanup_expired_jwt_tokens(now - 2_592_000)?;
stats.verification_tokens_deleted =
self.cleanup_expired_verification_tokens(now - 3_600)?;
stats.oauth_states_deleted = self.cleanup_expired_oauth_states(now - 600)?;
stats.magic_links_deleted = self.cleanup_expired_magic_links(now - 3_600)?;
stats.email_otps_deleted = self.cleanup_expired_email_otps(now - 600)?;
stats.rate_limits_deleted = self.cleanup_old_rate_limits(3_600)?;
Ok(stats)
}
}
#[derive(Debug, Default, Clone)]
pub struct CleanupStats {
pub sessions_deleted: u64,
pub jwt_tokens_deleted: u64,
pub verification_tokens_deleted: u64,
pub oauth_states_deleted: u64,
pub magic_links_deleted: u64,
pub email_otps_deleted: u64,
pub rate_limits_deleted: u64,
}
impl CleanupStats {
#[must_use]
pub fn total_deleted(&self) -> u64 {
self.sessions_deleted
+ self.jwt_tokens_deleted
+ self.verification_tokens_deleted
+ self.oauth_states_deleted
+ self.magic_links_deleted
+ self.email_otps_deleted
+ self.rate_limits_deleted
}
#[must_use]
pub fn summary(&self) -> String {
format!(
"Cleanup complete: {} sessions, {} JWT tokens, {} verification tokens, {} OAuth states, {} magic links, {} email OTPs, {} rate limits",
self.sessions_deleted,
self.jwt_tokens_deleted,
self.verification_tokens_deleted,
self.oauth_states_deleted,
self.magic_links_deleted,
self.email_otps_deleted,
self.rate_limits_deleted
)
}
}
impl<T: QueryStore> StorageCleanup for T {}