split session management into separate module
This commit is contained in:
48
src/main.rs
48
src/main.rs
@@ -2,13 +2,13 @@ use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use cookie::{Cookie, SameSite};
|
||||
use futures::TryFutureExt;
|
||||
use log::{debug, error, info, trace};
|
||||
use sessions::{Session, SessionStatus, Storable};
|
||||
use sessions::Session;
|
||||
use warp::{Filter, Rejection, Reply};
|
||||
use warp::http::{StatusCode, Uri};
|
||||
|
||||
const SESSION_HEADER: &str = "Spectrum-Session";
|
||||
mod session;
|
||||
use crate::session::{NoSession, SESSION_HEADER, SESSION_NAME, SessionPolicy, with_session};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
@@ -78,44 +78,6 @@ where From: 'static,
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum SessionPolicy {
|
||||
Existing,
|
||||
AllowNew
|
||||
}
|
||||
|
||||
const SESSION_NAME: &str = "name";
|
||||
|
||||
fn with_session(store: Arc<impl Storable>,
|
||||
policy: SessionPolicy) -> impl Filter<Extract = (Session,),
|
||||
Error = Rejection> + Clone {
|
||||
warp::cookie::cookie(SESSION_HEADER)
|
||||
.and_then(move |session_id: String| {
|
||||
trace!("Looking up session: {}", session_id);
|
||||
let store = store.clone(); // pending async reqs allowed to outlive returned Filter
|
||||
async move {
|
||||
let session = store.get(&session_id).await?;
|
||||
session.set_id(session_id)?;
|
||||
Ok(session)
|
||||
}
|
||||
}.map_err(|err: std::io::Error| warp::reject::custom(ServerError(Box::new(err)))))
|
||||
.or_else(clarify_error::<_, warp::reject::MissingCookie, NoSession>) // Has cookies, but not session cookie
|
||||
.or_else(clarify_error::<_, warp::reject::InvalidHeader, NoSession>) // No cookies at all
|
||||
.and_then(move |session: Session| async move {
|
||||
match (session.status(), policy) {
|
||||
(Ok(SessionStatus::Existed), _ )
|
||||
// Session exists, but name might not be set yet
|
||||
if session.get::<String>(SESSION_NAME)
|
||||
.map_or(false, |name| name.filter(|name| !name.is_empty()).is_some()) => Ok(session),
|
||||
(Ok(SessionStatus::Existed), _ ) => Err(warp::reject::custom(BadName)),
|
||||
(Ok(SessionStatus::Created), SessionPolicy::AllowNew) => Ok(session),
|
||||
(Ok(SessionStatus::Created), _) => Err(warp::reject::custom(NoSession)),
|
||||
(Err(e), _) => Err(warp::reject::custom(ServerError(Box::new(e)))),
|
||||
_ => Err(warp::reject::custom(NoSession))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct BadName;
|
||||
impl warp::reject::Reject for BadName {}
|
||||
@@ -135,10 +97,6 @@ async fn handle_reject(err: Rejection) -> Result<Box<dyn Reply>, Rejection> {
|
||||
struct ServerError(Box<dyn std::error::Error + Send + Sync>);
|
||||
impl warp::reject::Reject for ServerError {}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct NoSession;
|
||||
impl warp::reject::Reject for NoSession {}
|
||||
|
||||
async fn handle_no_session(err: Rejection) -> Result<impl Reply, Rejection> {
|
||||
match err.find() {
|
||||
Some(NoSession) => {
|
||||
|
||||
51
src/session.rs
Normal file
51
src/session.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use futures::TryFutureExt;
|
||||
use log::trace;
|
||||
use sessions::{Session, SessionStatus, Storable};
|
||||
use warp::{Filter, Rejection};
|
||||
|
||||
use crate::{BadName, clarify_error, ServerError};
|
||||
|
||||
pub const SESSION_HEADER: &str = "Spectrum-Session";
|
||||
pub const SESSION_NAME: &str = "name";
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum SessionPolicy {
|
||||
Existing,
|
||||
AllowNew
|
||||
}
|
||||
|
||||
pub fn with_session(store: Arc<impl Storable>,
|
||||
policy: SessionPolicy) -> impl Filter<Extract = (Session,),
|
||||
Error = Rejection> + Clone {
|
||||
warp::cookie::cookie(SESSION_HEADER)
|
||||
.and_then(move |session_id: String| {
|
||||
trace!("Looking up session: {}", session_id);
|
||||
let store = store.clone(); // pending async reqs allowed to outlive returned Filter
|
||||
async move {
|
||||
let session = store.get(&session_id).await?;
|
||||
session.set_id(session_id)?;
|
||||
Ok(session)
|
||||
}
|
||||
}.map_err(|err: std::io::Error| warp::reject::custom(ServerError(Box::new(err)))))
|
||||
.or_else(clarify_error::<_, warp::reject::MissingCookie, NoSession>) // Has cookies, but not session cookie
|
||||
.or_else(clarify_error::<_, warp::reject::InvalidHeader, NoSession>) // No cookies at all
|
||||
.and_then(move |session: Session| async move {
|
||||
match (session.status(), policy) {
|
||||
(Ok(SessionStatus::Existed), _ )
|
||||
// Session exists, but name might not be set yet
|
||||
if session.get::<String>(SESSION_NAME)
|
||||
.map_or(false, |name| name.filter(|name| !name.is_empty()).is_some()) => Ok(session),
|
||||
(Ok(SessionStatus::Existed), _ ) => Err(warp::reject::custom(BadName)),
|
||||
(Ok(SessionStatus::Created), SessionPolicy::AllowNew) => Ok(session),
|
||||
(Ok(SessionStatus::Created), _) => Err(warp::reject::custom(NoSession)),
|
||||
(Err(e), _) => Err(warp::reject::custom(ServerError(Box::new(e)))),
|
||||
_ => Err(warp::reject::custom(NoSession))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct NoSession;
|
||||
impl warp::reject::Reject for NoSession {}
|
||||
Reference in New Issue
Block a user