rainier-session 1.0.1

Sessions for Rainier: the bag, the store port, and the middleware that persists it.
Documentation
rainier-session-1.0.1 has been yanked.

rainier-session

Sessions: the [Session] bag a handler reads and writes, the [SessionStore] port it is persisted through, and the [StartSession] middleware that ties them to a cookie.

use rainier_session::{MemorySessionStore, SessionRequestExt, StartSession, SessionStore};
use rainier_http::{Request, Response};
use rainier_middleware::{Middleware, Pipeline};
use std::sync::Arc;

# #[tokio::main] async fn main() {
let store = Arc::new(MemorySessionStore::default());
let start: Arc<dyn Middleware> =
    Arc::new(StartSession::new(Arc::clone(&store) as Arc<dyn SessionStore>));

let response = Pipeline::new()
    .through_arc(start)
    .then(|request: Request| async move {
        let session = request.session().expect("StartSession ran");
        session.put("user_id", 42u64).unwrap();
        Response::text("ok")
    })
    .run(Request::builder().build())
    .await;

assert!(response.header("set-cookie").is_some());
# }

The session is on the request, not on a facade

Laravel's Session::get('user_id') works because its container rebinds a request-scoped session per request. Rainier's facades resolve from a process-global application, so there is nothing honest for Session::instance().get(…) to return — with two requests in flight, which one would it be?

So the split is explicit:

request.session() this request's bag
[SessionManager] (the Session facade) the store and its settings

The facade is for what genuinely is application-wide: reading or destroying a session by id, and collecting expired ones.

Flash data

flash stores a value for exactly one further request — the redirect-then-show-a-message pattern, with nothing to remember to clean up:

# use rainier_session::{Session, SessionData};
let session = Session::new();
session.flash("status", "Saved.").unwrap();

// …the request ends, and the next one can read it.
let next = Session::restore("id", session.age_and_take());
assert_eq!(next.string("status").as_deref(), Some("Saved."));

// …and the one after that cannot.
let later = Session::restore("id", next.age_and_take());
assert!(!later.has("status"));

Drivers

Driver Survives a restart Shared Revocable Note
[MemorySessionStore] no no yes development
[DatabaseSessionStore] yes yes yes never evicts
[CacheSessionStore] depends yes yes expires itself; can evict
[CookieSessionStore] yes yes no no server state at all

A memory store behind a load balancer makes a user's session appear to vanish and reappear as they are routed around, which looks like a bug in your login code and is not.

The cookie driver is the odd one: the whole session travels encrypted in the cookie, so there is nothing to store and nothing to expire — and nothing to revoke either. A session you cannot see is a session you cannot end.