feat: implement background old session cleanup task
parent
f00d842bad
commit
bc80515474
|
@ -1,3 +1,5 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use crate::{db, server};
|
||||
|
||||
pub fn serve(config: &crate::config::Config) -> u8 {
|
||||
|
@ -11,7 +13,7 @@ pub fn serve(config: &crate::config::Config) -> u8 {
|
|||
let ctx = server::Context {
|
||||
store: crate::gpodder::GpodderRepository::new(repo),
|
||||
};
|
||||
let app = server::app(ctx);
|
||||
let app = server::app(ctx.clone());
|
||||
|
||||
let rt = tokio::runtime::Builder::new_multi_thread()
|
||||
.enable_all()
|
||||
|
@ -21,7 +23,28 @@ pub fn serve(config: &crate::config::Config) -> u8 {
|
|||
let address = format!("{}:{}", config.domain, config.port);
|
||||
tracing::info!("Starting server on {address}");
|
||||
|
||||
let session_removal_duration = Duration::from_secs(config.session_cleanup_interval);
|
||||
|
||||
rt.block_on(async {
|
||||
tokio::task::spawn(async move {
|
||||
let mut interval = tokio::time::interval(session_removal_duration);
|
||||
|
||||
loop {
|
||||
interval.tick().await;
|
||||
|
||||
tracing::info!("Performing session cleanup");
|
||||
|
||||
match ctx.store.remove_old_sessions() {
|
||||
Ok(n) => {
|
||||
tracing::info!("Removed {} old sessions", n);
|
||||
}
|
||||
Err(err) => {
|
||||
tracing::error!("Error occured during session cleanup: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let listener = tokio::net::TcpListener::bind(address).await.unwrap();
|
||||
axum::serve(listener, app.into_make_service())
|
||||
.await
|
||||
|
|
|
@ -10,6 +10,8 @@ pub struct Config {
|
|||
pub domain: String,
|
||||
#[serde(default = "default_port")]
|
||||
pub port: u16,
|
||||
#[serde(default = "default_session_cleanup_interval")]
|
||||
pub session_cleanup_interval: u64,
|
||||
}
|
||||
|
||||
fn default_data_dir() -> PathBuf {
|
||||
|
@ -23,3 +25,8 @@ fn default_domain() -> String {
|
|||
fn default_port() -> u16 {
|
||||
8080
|
||||
}
|
||||
|
||||
fn default_session_cleanup_interval() -> u64 {
|
||||
// Default is once a day
|
||||
60 * 60 * 24
|
||||
}
|
||||
|
|
|
@ -197,4 +197,13 @@ impl gpodder::AuthStore for SqliteRepository {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_old_sessions(&self, min_last_seen: DateTime<chrono::Utc>) -> Result<usize, AuthErr> {
|
||||
let min_last_seen = min_last_seen.timestamp();
|
||||
|
||||
Ok(
|
||||
diesel::delete(sessions::table.filter(sessions::last_seen.lt(min_last_seen)))
|
||||
.execute(&mut self.pool.get()?)?,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
pub mod models;
|
||||
mod repository;
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
pub use models::*;
|
||||
pub use repository::GpodderRepository;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AuthErr {
|
||||
UnknownSession,
|
||||
UnknownUser,
|
||||
|
@ -12,6 +15,19 @@ pub enum AuthErr {
|
|||
Other(Box<dyn std::error::Error + Sync + Send>),
|
||||
}
|
||||
|
||||
impl Display for AuthErr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::UnknownUser => write!(f, "unknown user"),
|
||||
Self::UnknownSession => write!(f, "unknown session"),
|
||||
Self::InvalidPassword => write!(f, "invalid password"),
|
||||
Self::Other(err) => err.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for AuthErr {}
|
||||
|
||||
pub trait Store:
|
||||
AuthStore + DeviceRepository + SubscriptionRepository + EpisodeActionRepository
|
||||
{
|
||||
|
@ -55,6 +71,9 @@ pub trait AuthStore {
|
|||
|
||||
/// Update the session's timestamp
|
||||
fn refresh_session(&self, session: &Session, timestamp: DateTime<Utc>) -> Result<(), AuthErr>;
|
||||
|
||||
/// Remove any sessions whose last_seen timestamp is before the given minimum value
|
||||
fn remove_old_sessions(&self, min_last_seen: DateTime<Utc>) -> Result<usize, AuthErr>;
|
||||
}
|
||||
|
||||
pub trait DeviceRepository {
|
||||
|
|
|
@ -75,6 +75,12 @@ impl GpodderRepository {
|
|||
self.store.remove_session(session_id)
|
||||
}
|
||||
|
||||
pub fn remove_old_sessions(&self) -> Result<usize, AuthErr> {
|
||||
let min_last_seen = Utc::now() - TimeDelta::seconds(MAX_SESSION_AGE);
|
||||
|
||||
self.store.remove_old_sessions(min_last_seen)
|
||||
}
|
||||
|
||||
pub fn devices_for_user(&self, user: &models::User) -> Result<Vec<models::Device>, AuthErr> {
|
||||
self.store.devices_for_user(user)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue