11 releases (6 breaking)

0.11.0 Mar 5, 2024
0.10.0 Jan 23, 2024
0.9.1 Jan 4, 2024
0.8.2 Dec 24, 2023
0.5.1 Nov 15, 2023

#1235 in Network programming

Download history 13/week @ 2023-12-22 37/week @ 2023-12-29 6/week @ 2024-01-05 11/week @ 2024-01-19 2/week @ 2024-01-26 37/week @ 2024-02-23 138/week @ 2024-03-01 41/week @ 2024-03-08 9/week @ 2024-03-15 1/week @ 2024-03-22 39/week @ 2024-03-29 28/week @ 2024-04-05

90 downloads per month

MIT license

18KB
112 lines

tower-sessions-mongodb-store

MongoDB session store for `tower-sessions`.

🤸 Usage

use std::net::SocketAddr;

use axum::{response::IntoResponse, routing::get, Router};
use serde::{Deserialize, Serialize};
use time::Duration;
use tokio::{signal, task::AbortHandle};
use tower_sessions::{Expiry, Session, SessionManagerLayer};
use tower_sessions_core::ExpiredDeletion;
use tower_sessions_mongodb_store::{mongodb::Client, MongoDBStore};

const COUNTER_KEY: &str = "counter";

#[derive(Serialize, Deserialize, Default)]
struct Counter(usize);

async fn handler(session: Session) -> impl IntoResponse {
    let counter: Counter = session.get(COUNTER_KEY).await.unwrap().unwrap_or_default();
    session.insert(COUNTER_KEY, counter.0 + 1).await.unwrap();
    format!("Current count: {}", counter.0)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let database_url = std::option_env!("DATABASE_URL").expect("Missing DATABASE_URL.");
    let client = Client::with_uri_str(database_url).await?;
    let session_store = MongoDBStore::new(client, "tower-sessions".to_string());

    let deletion_task = tokio::task::spawn(
        session_store
            .clone()
            .continuously_delete_expired(tokio::time::Duration::from_secs(60)),
    );

    let session_layer = SessionManagerLayer::new(session_store)
        .with_secure(false)
        .with_expiry(Expiry::OnInactivity(Duration::seconds(10)));

    let app = Router::new().route("/", get(handler)).layer(session_layer);

    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    let listener = tokio::net::TcpListener::bind(&addr).await?;

    // Ensure we use a shutdown signal to abort the deletion task.
    axum::serve(listener, app.into_make_service())
        .with_graceful_shutdown(shutdown_signal(deletion_task.abort_handle()))
        .await?;

    deletion_task.await??;

    Ok(())
}

async fn shutdown_signal(deletion_task_abort_handle: AbortHandle) {
    let ctrl_c = async {
        signal::ctrl_c()
            .await
            .expect("failed to install Ctrl+C handler");
    };

    #[cfg(unix)]
    let terminate = async {
        signal::unix::signal(signal::unix::SignalKind::terminate())
            .expect("failed to install signal handler")
            .recv()
            .await;
    };

    #[cfg(not(unix))]
    let terminate = std::future::pending::<()>();

    tokio::select! {
        _ = ctrl_c => { deletion_task_abort_handle.abort() },
        _ = terminate => { deletion_task_abort_handle.abort() },
    }
}

Dependencies

~27–41MB
~779K SLoC