1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-24 16:02:59 +01:00

refactor session impl

This commit is contained in:
Nikolay Kim 2018-05-01 09:40:23 -07:00
parent d9a4fadaae
commit 9b6343d54b

View File

@ -63,6 +63,7 @@
//! let _ = sys.run(); //! let _ = sys.run();
//! } //! }
//! ``` //! ```
use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::rc::Rc; use std::rc::Rc;
@ -72,7 +73,8 @@ use cookie::{Cookie, CookieJar, Key};
use futures::future::{err as FutErr, ok as FutOk, FutureResult}; use futures::future::{err as FutErr, ok as FutOk, FutureResult};
use futures::Future; use futures::Future;
use http::header::{self, HeaderValue}; use http::header::{self, HeaderValue};
use serde::{Deserialize, Serialize}; use serde::de::DeserializeOwned;
use serde::Serialize;
use serde_json; use serde_json;
use serde_json::error::Error as JsonError; use serde_json::error::Error as JsonError;
use time::Duration; use time::Duration;
@ -101,17 +103,15 @@ use middleware::{Middleware, Response, Started};
/// # fn main() {} /// # fn main() {}
/// ``` /// ```
pub trait RequestSession { pub trait RequestSession {
fn session(&mut self) -> Session; fn session(&self) -> Session;
} }
impl<S> RequestSession for HttpRequest<S> { impl<S> RequestSession for HttpRequest<S> {
fn session(&mut self) -> Session { fn session(&self) -> Session {
if let Some(s_impl) = self.extensions_mut().get_mut::<Arc<SessionImplBox>>() { if let Some(s_impl) = self.extensions().get::<Arc<SessionImplCell>>() {
if let Some(s) = Arc::get_mut(s_impl) { return Session(SessionInner::Session(Arc::clone(&s_impl)));
return Session(s.0.as_mut());
} }
} Session(SessionInner::None)
Session(unsafe { &mut DUMMY })
} }
} }
@ -137,41 +137,65 @@ impl<S> RequestSession for HttpRequest<S> {
/// } /// }
/// # fn main() {} /// # fn main() {}
/// ``` /// ```
pub struct Session<'a>(&'a mut SessionImpl); pub struct Session(SessionInner);
impl<'a> Session<'a> { enum SessionInner {
Session(Arc<SessionImplCell>),
None,
}
impl Session {
/// Get a `value` from the session. /// Get a `value` from the session.
pub fn get<T: Deserialize<'a>>(&'a self, key: &str) -> Result<Option<T>> { pub fn get<T: DeserializeOwned>(&self, key: &str) -> Result<Option<T>> {
if let Some(s) = self.0.get(key) { match self.0 {
SessionInner::Session(ref sess) => {
if let Some(s) = sess.as_ref().0.borrow().get(key) {
Ok(Some(serde_json::from_str(s)?)) Ok(Some(serde_json::from_str(s)?))
} else { } else {
Ok(None) Ok(None)
} }
} }
SessionInner::None => Ok(None),
}
}
/// Set a `value` from the session. /// Set a `value` from the session.
pub fn set<T: Serialize>(&mut self, key: &str, value: T) -> Result<()> { pub fn set<T: Serialize>(&self, key: &str, value: T) -> Result<()> {
self.0.set(key, serde_json::to_string(&value)?); match self.0 {
SessionInner::Session(ref sess) => {
sess.as_ref()
.0
.borrow_mut()
.set(key, serde_json::to_string(&value)?);
Ok(()) Ok(())
} }
SessionInner::None => Ok(()),
}
}
/// Remove value from the session. /// Remove value from the session.
pub fn remove(&'a mut self, key: &str) { pub fn remove(&self, key: &str) {
self.0.remove(key) match self.0 {
SessionInner::Session(ref sess) => sess.as_ref().0.borrow_mut().remove(key),
SessionInner::None => (),
}
} }
/// Clear the session. /// Clear the session.
pub fn clear(&'a mut self) { pub fn clear(&self) {
self.0.clear() match self.0 {
SessionInner::Session(ref sess) => sess.as_ref().0.borrow_mut().clear(),
SessionInner::None => (),
}
} }
} }
struct SessionImplBox(Box<SessionImpl>); struct SessionImplCell(RefCell<Box<SessionImpl>>);
#[doc(hidden)] #[doc(hidden)]
unsafe impl Send for SessionImplBox {} unsafe impl Send for SessionImplCell {}
#[doc(hidden)] #[doc(hidden)]
unsafe impl Sync for SessionImplBox {} unsafe impl Sync for SessionImplCell {}
/// Session storage middleware /// Session storage middleware
/// ///
@ -206,8 +230,9 @@ impl<S: 'static, T: SessionBackend<S>> Middleware<S> for SessionStorage<T, S> {
.from_request(&mut req) .from_request(&mut req)
.then(move |res| match res { .then(move |res| match res {
Ok(sess) => { Ok(sess) => {
req.extensions_mut() req.extensions_mut().insert(Arc::new(SessionImplCell(
.insert(Arc::new(SessionImplBox(Box::new(sess)))); RefCell::new(Box::new(sess)),
)));
FutOk(None) FutOk(None)
} }
Err(err) => FutErr(err), Err(err) => FutErr(err),
@ -218,8 +243,8 @@ impl<S: 'static, T: SessionBackend<S>> Middleware<S> for SessionStorage<T, S> {
fn response( fn response(
&self, req: &mut HttpRequest<S>, resp: HttpResponse, &self, req: &mut HttpRequest<S>, resp: HttpResponse,
) -> Result<Response> { ) -> Result<Response> {
if let Some(s_box) = req.extensions_mut().remove::<Arc<SessionImplBox>>() { if let Some(s_box) = req.extensions_mut().remove::<Arc<SessionImplCell>>() {
s_box.0.write(resp) s_box.0.borrow_mut().write(resp)
} else { } else {
Ok(Response::Done(resp)) Ok(Response::Done(resp))
} }
@ -251,23 +276,6 @@ pub trait SessionBackend<S>: Sized + 'static {
fn from_request(&self, request: &mut HttpRequest<S>) -> Self::ReadFuture; fn from_request(&self, request: &mut HttpRequest<S>) -> Self::ReadFuture;
} }
/// Dummy session impl, does not do anything
struct DummySessionImpl;
static mut DUMMY: DummySessionImpl = DummySessionImpl;
impl SessionImpl for DummySessionImpl {
fn get(&self, _: &str) -> Option<&str> {
None
}
fn set(&mut self, _: &str, _: String) {}
fn remove(&mut self, _: &str) {}
fn clear(&mut self) {}
fn write(&self, resp: HttpResponse) -> Result<Response> {
Ok(Response::Done(resp))
}
}
/// Session that uses signed cookies as session storage /// Session that uses signed cookies as session storage
pub struct CookieSession { pub struct CookieSession {
changed: bool, changed: bool,