Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade to async-session v4 #50

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ repository = "https://github.com/maxcountryman/axum-sessions"
documentation = "https://docs.rs/axum-sessions"

[dependencies]
async-session = "3.0.0"
async-session = { git = "https://github.com/http-rs/async-session", rev = "35cb0998f91b81b133c3314414adae4019a62741", default-features = false }
base64 = "0.21.0"
futures = "0.3.21"
hmac = { version = "0.12.1", features = ["std"] }
http-body = "0.4.5"
sha2 = "0.10.6"
tower = "0.4.12"
tracing = "0.1"

Expand All @@ -34,6 +37,7 @@ features = ["sync"]
http = "0.2.8"
hyper = "0.14.19"
serde = "1.0.147"
serde_json = "1.0.106"

[dev-dependencies.rand]
version = "0.8.5"
Expand All @@ -43,3 +47,7 @@ features = ["min_const_gen"]
version = "1.20.1"
default-features = false
features = ["macros", "rt-multi-thread"]

[dev-dependencies.async-session-memory-store]
git = "https://github.com/http-rs/async-session"
rev = "35cb0998f91b81b133c3314414adae4019a62741"
4 changes: 4 additions & 0 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@
members = ["*"]
exclude = ["target"]
resolver = "2"

[workspace.dependencies.async-session-memory-store]
git = "https://github.com/http-rs/async-session"
rev = "35cb0998f91b81b133c3314414adae4019a62741"
7 changes: 4 additions & 3 deletions examples/async-sqlx-session/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ axum = "0.6.0"
axum-sessions = { path = "../../" }

[dependencies.async-sqlx-session]
version = "0.4.0"
# version = "0.4.0"
git = "https://github.com/sbihel/async-sqlx-session"
rev = "9ed73b641cb5e5c0c08b9d29dd723b3c8e57993d"
default-features = false
features = ["sqlite"]

Expand All @@ -18,8 +20,7 @@ version = "0.8.5"
features = ["min_const_gen"]

[dependencies.sqlx]
version = "0.5.13"
default-features = false
version = "0.7.1"
features = ["runtime-tokio-rustls", "sqlite"]

[dependencies.tokio]
Expand Down
9 changes: 3 additions & 6 deletions examples/async-sqlx-session/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@

use async_sqlx_session::SqliteSessionStore;
use axum::{routing::get, Router};
use axum_sessions::{
extractors::{ReadableSession, WritableSession},
SessionLayer,
};
use axum_sessions::{extractors::Session, SessionLayer};
use rand::Rng;

#[tokio::main]
Expand All @@ -24,14 +21,14 @@ async fn main() {
let secret = rand::thread_rng().gen::<[u8; 128]>();
let session_layer = SessionLayer::new(store, &secret);

async fn increment_count_handler(mut session: WritableSession) {
async fn increment_count_handler(mut session: Session) {
let previous: usize = session.get("counter").unwrap_or_default();
session
.insert("counter", previous + 1)
.expect("Could not store counter.");
}

async fn handler(session: ReadableSession) -> String {
async fn handler(session: Session) -> String {
format!(
"Counter: {}",
session.get::<usize>("counter").unwrap_or_default()
Expand Down
1 change: 1 addition & 0 deletions examples/counter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ publish = false
[dependencies]
axum = "0.6.0"
axum-sessions = { path = "../../" }
async-session-memory-store = { workspace = true }

[dependencies.rand]
version = "0.8.5"
Expand Down
13 changes: 5 additions & 8 deletions examples/counter/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@
//! cd examples && cargo run -p example-counter
//! ```

use async_session_memory_store::MemoryStore;
use axum::{response::IntoResponse, routing::get, Router};
use axum_sessions::{
async_session::MemoryStore,
extractors::{ReadableSession, WritableSession},
SessionLayer,
};
use axum_sessions::{extractors::Session, SessionLayer};
use rand::Rng;

#[tokio::main]
Expand All @@ -18,7 +15,7 @@ async fn main() {
let secret = rand::thread_rng().gen::<[u8; 128]>();
let session_layer = SessionLayer::new(store, &secret).with_secure(false);

async fn display_handler(session: ReadableSession) -> impl IntoResponse {
async fn display_handler(session: Session) -> impl IntoResponse {
let mut count = 0;
count = session.get("count").unwrap_or(count);
format!(
Expand All @@ -27,14 +24,14 @@ async fn main() {
)
}

async fn increment_handler(mut session: WritableSession) -> impl IntoResponse {
async fn increment_handler(mut session: Session) -> impl IntoResponse {
let mut count = 1;
count = session.get("count").map(|n: i32| n + 1).unwrap_or(count);
session.insert("count", count).unwrap();
format!("Count is: {}", count)
}

async fn reset_handler(mut session: WritableSession) -> impl IntoResponse {
async fn reset_handler(mut session: Session) -> impl IntoResponse {
session.destroy();
"Count reset"
}
Expand Down
1 change: 1 addition & 0 deletions examples/regenerate/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ publish = false
[dependencies]
axum = "0.6.0"
axum-sessions = { path = "../../" }
async-session-memory-store = { workspace = true }

[dependencies.rand]
version = "0.8.5"
Expand Down
13 changes: 5 additions & 8 deletions examples/regenerate/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@
//! cd examples && cargo run -p example-regenerate
//! ```

use async_session_memory_store::MemoryStore;
use axum::{routing::get, Router};
use axum_sessions::{
async_session::MemoryStore,
extractors::{ReadableSession, WritableSession},
SessionLayer,
};
use axum_sessions::{extractors::Session, SessionLayer};
use rand::Rng;

#[tokio::main]
Expand All @@ -18,19 +15,19 @@ async fn main() {
let secret = rand::thread_rng().gen::<[u8; 128]>();
let session_layer = SessionLayer::new(store, &secret);

async fn regenerate_handler(mut session: WritableSession) {
async fn regenerate_handler(mut session: Session) {
// NB: This DOES NOT update the store, meaning that both sessions will still be
// found.
session.regenerate();
}

async fn insert_handler(mut session: WritableSession) {
async fn insert_handler(mut session: Session) {
session
.insert("foo", 42)
.expect("Could not store the answer.");
}

async fn handler(session: ReadableSession) -> String {
async fn handler(session: Session) -> String {
session
.get::<usize>("foo")
.map(|answer| format!("{}", answer))
Expand Down
1 change: 1 addition & 0 deletions examples/signin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ publish = false
[dependencies]
axum = "0.6.0"
axum-sessions = { path = "../../" }
async-session-memory-store = { workspace = true }

[dependencies.rand]
version = "0.8.5"
Expand Down
13 changes: 5 additions & 8 deletions examples/signin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@
//! cd examples && cargo run -p example-signin
//! ```

use async_session_memory_store::MemoryStore;
use axum::{routing::get, Router};
use axum_sessions::{
async_session::MemoryStore,
extractors::{ReadableSession, WritableSession},
SessionLayer,
};
use axum_sessions::{extractors::Session, SessionLayer};
use rand::Rng;

#[tokio::main]
Expand All @@ -18,17 +15,17 @@ async fn main() {
let secret = rand::thread_rng().gen::<[u8; 128]>();
let session_layer = SessionLayer::new(store, &secret);

async fn signin_handler(mut session: WritableSession) {
async fn signin_handler(mut session: Session) {
session
.insert("signed_in", true)
.expect("Could not sign in.");
}

async fn signout_handler(mut session: WritableSession) {
async fn signout_handler(mut session: Session) {
session.destroy();
}

async fn protected_handler(session: ReadableSession) -> &'static str {
async fn protected_handler(session: Session) -> &'static str {
if session.get::<bool>("signed_in").unwrap_or(false) {
"Shh, it's secret!"
} else {
Expand Down
68 changes: 18 additions & 50 deletions src/extractors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,78 +3,46 @@
use std::ops::{Deref, DerefMut};

use axum::{async_trait, extract::FromRequestParts, http::request::Parts, Extension};
use tokio::sync::{OwnedRwLockReadGuard, OwnedRwLockWriteGuard};
use tokio::sync::OwnedMutexGuard;

use crate::SessionHandle;

/// An extractor which provides a readable session. Sessions may have many
/// readers.
#[derive(Debug)]
pub struct ReadableSession {
session: OwnedRwLockReadGuard<async_session::Session>,
pub struct Session {
session_guard: OwnedMutexGuard<async_session::Session>,
}

impl Deref for ReadableSession {
type Target = OwnedRwLockReadGuard<async_session::Session>;
impl Deref for Session {
type Target = OwnedMutexGuard<async_session::Session>;

fn deref(&self) -> &Self::Target {
&self.session
&self.session_guard
}
}

#[async_trait]
impl<S> FromRequestParts<S> for ReadableSession
where
S: Send + Sync,
{
type Rejection = std::convert::Infallible;

async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
let Extension(session_handle): Extension<SessionHandle> =
Extension::from_request_parts(parts, state)
.await
.expect("Session extension missing. Is the session layer installed?");
let session = session_handle.read_owned().await;

Ok(Self { session })
}
}

/// An extractor which provides a writable session. Sessions may have only one
/// writer.
#[derive(Debug)]
pub struct WritableSession {
session: OwnedRwLockWriteGuard<async_session::Session>,
}

impl Deref for WritableSession {
type Target = OwnedRwLockWriteGuard<async_session::Session>;

fn deref(&self) -> &Self::Target {
&self.session
}
}

impl DerefMut for WritableSession {
impl DerefMut for Session {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.session
&mut self.session_guard
}
}

#[async_trait]
impl<S> FromRequestParts<S> for WritableSession
impl<S> FromRequestParts<S> for Session
where
S: Send + Sync,
S: Send + Sync + Clone,
{
type Rejection = std::convert::Infallible;

async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
let Extension(session_handle): Extension<SessionHandle> =
Extension::from_request_parts(parts, state)
.await
.expect("Session extension missing. Is the session layer installed?");
let session = session_handle.write_owned().await;
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
use axum::RequestPartsExt;
let Extension(session) = parts
.extract::<Extension<SessionHandle>>()
.await
.expect("Session extension missing. Is the session layer installed?");

Ok(Self { session })
let session_guard = session.lock_owned().await;
Ok(Self { session_guard })
}
}
17 changes: 8 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,25 @@
//! when they're not found or are otherwise invalid. When a valid, known cookie
//! is received in a request, the session is hydrated from this cookie. The
//! middleware provides sessions via [`SessionHandle`]. Handlers use the
//! [`ReadableSession`](crate::extractors::ReadableSession) and
//! [`WritableSession`](crate::extractors::WritableSession) extractors to read
//! from and write to sessions respectively.
//! [`Session`](crate::extractors::Session) extractor to read from and write to
//! sessions respectively.
//!
//! # Example
//!
//! Using the middleware with axum is straightforward:
//!
//! ```rust,no_run
//! use async_session_memory_store::MemoryStore;
//! use axum::{routing::get, Router};
//! use axum_sessions::{
//! async_session::MemoryStore, extractors::WritableSession, PersistencePolicy, SessionLayer,
//! };
//! use axum_sessions::{extractors::Session, PersistencePolicy, SessionLayer};
//!
//! #[tokio::main]
//! async fn main() {
//! let store = MemoryStore::new();
//! let secret = b"..."; // MUST be at least 64 bytes!
//! let session_layer = SessionLayer::new(store, secret);
//!
//! async fn handler(mut session: WritableSession) {
//! async fn handler(mut session: Session) {
//! session
//! .insert("foo", 42)
//! .expect("Could not store the answer.");
Expand All @@ -47,16 +45,17 @@
//! ```rust
//! use std::convert::Infallible;
//!
//! use async_session_memory_store::MemoryStore;
//! use axum::http::header::SET_COOKIE;
//! use axum_sessions::{async_session::MemoryStore, SessionHandle, SessionLayer};
//! use axum_sessions::{SessionHandle, SessionLayer};
//! use http::{Request, Response};
//! use hyper::Body;
//! use rand::Rng;
//! use tower::{Service, ServiceBuilder, ServiceExt};
//!
//! async fn handle(request: Request<Body>) -> Result<Response<Body>, Infallible> {
//! let session_handle = request.extensions().get::<SessionHandle>().unwrap();
//! let session = session_handle.read().await;
//! let session = session_handle.lock().await;
//! // Use the session as you'd like.
//!
//! Ok(Response::new(Body::empty()))
Expand Down
Loading