2025-02-26 13:10:50 -08:00
|
|
|
use anyhow::Result;
|
|
|
|
use async_session::{async_trait, Session, SessionStore};
|
2025-02-26 13:10:48 -08:00
|
|
|
use chrono::{DateTime, TimeDelta, Utc};
|
|
|
|
use diesel::{pg::Pg, prelude::*, upsert::excluded};
|
2025-02-26 13:10:50 -08:00
|
|
|
|
2025-02-26 13:10:48 -08:00
|
|
|
use crate::schema::browser_sessions::dsl::*;
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, Identifiable, Queryable, Selectable)]
|
|
|
|
#[diesel(table_name = crate::schema::browser_sessions)]
|
|
|
|
#[diesel(check_for_backend(Pg))]
|
|
|
|
pub struct BrowserSession {
|
|
|
|
pub id: String,
|
|
|
|
pub serialized: String,
|
|
|
|
pub last_seen_at: DateTime<Utc>,
|
|
|
|
}
|
2025-02-26 13:10:50 -08:00
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct PgStore {
|
|
|
|
pool: deadpool_diesel::postgres::Pool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PgStore {
|
|
|
|
pub fn new(pool: deadpool_diesel::postgres::Pool) -> PgStore {
|
|
|
|
Self { pool }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::fmt::Debug for PgStore {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
2025-02-26 13:10:48 -08:00
|
|
|
write!(f, "PgStore")?;
|
2025-02-26 13:10:50 -08:00
|
|
|
Ok(()).into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[async_trait]
|
|
|
|
impl SessionStore for PgStore {
|
|
|
|
async fn load_session(&self, cookie_value: String) -> Result<Option<Session>> {
|
|
|
|
let session_id = Session::id_from_cookie_value(&cookie_value)?;
|
2025-02-26 13:10:48 -08:00
|
|
|
let timestamp_stale = Utc::now() - TimeDelta::days(7);
|
|
|
|
let conn = self.pool.get().await?;
|
|
|
|
let row = conn
|
2025-02-26 13:10:50 -08:00
|
|
|
.interact(move |conn| {
|
2025-02-26 13:10:48 -08:00
|
|
|
// Drop all sessions without recent activity
|
|
|
|
diesel::delete(browser_sessions.filter(last_seen_at.lt(timestamp_stale)))
|
|
|
|
.execute(conn)?;
|
|
|
|
diesel::update(browser_sessions.filter(id.eq(session_id)))
|
|
|
|
.set(last_seen_at.eq(diesel::dsl::now))
|
|
|
|
.returning(BrowserSession::as_returning())
|
|
|
|
.get_result(conn)
|
|
|
|
.optional()
|
2025-02-26 13:10:50 -08:00
|
|
|
})
|
|
|
|
.await
|
|
|
|
.unwrap()?;
|
2025-02-26 13:10:48 -08:00
|
|
|
Ok(match row {
|
|
|
|
Some(session) => Some(serde_json::from_str::<Session>(
|
|
|
|
session.serialized.as_str(),
|
|
|
|
)?),
|
|
|
|
None => None,
|
|
|
|
})
|
2025-02-26 13:10:50 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
async fn store_session(&self, session: Session) -> Result<Option<String>> {
|
2025-02-26 13:10:48 -08:00
|
|
|
let serialized_data = serde_json::to_string(&session)?;
|
2025-02-26 13:10:50 -08:00
|
|
|
let session_id = session.id().to_string();
|
2025-02-26 13:10:48 -08:00
|
|
|
let conn = self.pool.get().await?;
|
2025-02-26 13:10:50 -08:00
|
|
|
conn.interact(move |conn| {
|
2025-02-26 13:10:48 -08:00
|
|
|
diesel::insert_into(browser_sessions)
|
2025-02-26 13:10:50 -08:00
|
|
|
.values((
|
2025-02-26 13:10:48 -08:00
|
|
|
id.eq(session_id),
|
|
|
|
serialized.eq(serialized_data),
|
|
|
|
last_seen_at.eq(diesel::dsl::now),
|
2025-02-26 13:10:50 -08:00
|
|
|
))
|
2025-02-26 13:10:48 -08:00
|
|
|
.on_conflict(id)
|
2025-02-26 13:10:50 -08:00
|
|
|
.do_update()
|
2025-02-26 13:10:48 -08:00
|
|
|
.set((
|
|
|
|
serialized.eq(excluded(serialized)),
|
|
|
|
last_seen_at.eq(excluded(last_seen_at)),
|
|
|
|
))
|
2025-02-26 13:10:50 -08:00
|
|
|
.execute(conn)
|
|
|
|
})
|
|
|
|
.await
|
|
|
|
.unwrap()?;
|
|
|
|
session.reset_data_changed();
|
|
|
|
Ok(session.into_cookie_value())
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn destroy_session(&self, session: Session) -> Result<()> {
|
|
|
|
let conn = self.pool.get().await?;
|
|
|
|
conn.interact(move |conn| {
|
2025-02-26 13:10:48 -08:00
|
|
|
diesel::delete(browser_sessions.filter(id.eq(session.id().to_string()))).execute(conn)
|
2025-02-26 13:10:50 -08:00
|
|
|
})
|
|
|
|
.await
|
|
|
|
.unwrap()?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn clear_store(&self) -> Result<()> {
|
|
|
|
let conn = self.pool.get().await?;
|
2025-02-26 13:10:48 -08:00
|
|
|
conn.interact(move |conn| diesel::delete(browser_sessions).execute(conn))
|
2025-02-26 13:10:50 -08:00
|
|
|
.await
|
|
|
|
.unwrap()?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|