12 releases (7 breaking)
0.12.0 | Mar 20, 2024 |
---|---|
0.11.0 | Mar 5, 2024 |
0.10.0 | Jan 23, 2024 |
0.9.2 |
|
0.5.1 | Nov 15, 2023 |
#278 in Network programming
2,985 downloads per month
Used in axum-login
33KB
555 lines
tower-sessions-sqlx-store
SQLx session stores for `tower-sessions`.
🤸 Usage
MySQL example
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::{session_store::ExpiredDeletion, Expiry, Session, SessionManagerLayer};
use tower_sessions_sqlx_store::{sqlx::MySqlPool, MySqlStore};
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 pool = MySqlPool::connect(database_url).await?;
let session_store = MySqlStore::new(pool);
session_store.migrate().await?;
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() },
}
}
Postgres example
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::{session_store::ExpiredDeletion, Expiry, Session, SessionManagerLayer};
use tower_sessions_sqlx_store::{sqlx::PgPool, PostgresStore};
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 pool = PgPool::connect(database_url).await?;
let session_store = PostgresStore::new(pool);
session_store.migrate().await?;
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() },
}
}
SQLite example
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::{session_store::ExpiredDeletion, Expiry, Session, SessionManagerLayer};
use tower_sessions_sqlx_store::{sqlx::SqlitePool, SqliteStore};
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 pool = SqlitePool::connect("sqlite::memory:").await?;
let session_store = SqliteStore::new(pool);
session_store.migrate().await?;
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
~39–54MB
~1M SLoC