move code from tap to session's from_request, add tap_mut and make tap read-only

refactor
Ondřej Hruška 4 years ago
parent 4a2287ee46
commit af30c552ac
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 91
      src/lib.rs

@ -55,22 +55,13 @@ impl<D> SessionStore<D>
#[derive(PartialEq, Hash, Clone, Debug)]
struct SessionID(String);
impl<'a, 'r> FromRequest<'a, 'r> for &'a SessionID {
type Error = ();
impl SessionID {
fn as_str(&self) -> &str {
self.0.as_str()
}
fn from_request(request: &'a Request<'r>) -> Outcome<Self, (Status, Self::Error), ()> {
Outcome::Success(request.local_cache(|| {
if let Some(cookie) = request.cookies().get(SESSION_COOKIE) {
SessionID(cookie.value().to_string()) // FIXME avoid cloning (cow?)
} else {
SessionID(
rand::thread_rng()
.sample_iter(&rand::distributions::Alphanumeric)
.take(16)
.collect(),
)
}
}))
fn to_string(&self) -> String {
self.0.clone()
}
}
@ -93,9 +84,11 @@ impl<'a, 'r, D> FromRequest<'a, 'r> for Session<'a, D>
type Error = ();
fn from_request(request: &'a Request<'r>) -> Outcome<Self, (Status, Self::Error), ()> {
let store : State<SessionStore<D>> = request.guard().unwrap();
Outcome::Success(Session {
id: request.local_cache(|| {
if let Some(cookie) = request.cookies().get(SESSION_COOKIE) {
// Resolve session ID
let id = if let Some(cookie) = request.cookies().get(SESSION_COOKIE) {
SessionID(cookie.value().to_string())
} else {
SessionID(
@ -104,9 +97,34 @@ impl<'a, 'r, D> FromRequest<'a, 'r> for Session<'a, D>
.take(SESSION_ID_LEN)
.collect(),
)
}
};
let new_expiration = Instant::now().add(store.lifespan);
let mut wg = store.inner.write();
match wg.get_mut(id.as_str()) {
Some(ses) => {
// Check expiration
if ses.expires <= Instant::now() {
ses.data = D::default();
}
// Update expiry timestamp
ses.expires = new_expiration;
},
None => {
// New session
wg.insert(
id.to_string(),
SessionInstance {
data: D::default(),
expires: new_expiration,
}
);
}
};
id
}),
store: request.guard().unwrap(),
store,
})
}
}
@ -130,42 +148,21 @@ impl<'a, D> Session<'a, D>
/// Set the session object to its default state
pub fn reset(&self) {
self.tap(|m| {
self.tap_mut(|m| {
*m = D::default();
})
}
/// Renew the session without changing any data
pub fn renew(&self) {
self.tap(|_| ())
pub fn tap<T>(&self, func: impl FnOnce(&D) -> T) -> T {
let rg = self.store.inner.read();
let instance = rg.get(self.id.as_str()).unwrap();
func(&instance.data)
}
/// Run a closure with a mutable reference to the session object.
/// The closure's return value is send to the caller.
pub fn tap<T>(&self, func: impl FnOnce(&mut D) -> T) -> T {
pub fn tap_mut<T>(&self, func: impl FnOnce(&mut D) -> T) -> T {
let mut wg = self.store.inner.write();
if let Some(instance) = wg.get_mut(&self.id.0) {
// wipe session data if expired
if instance.expires <= Instant::now() {
instance.data = D::default();
}
// update expiry timestamp
instance.expires = Instant::now().add(self.store.lifespan);
func(&mut instance.data)
} else {
// no object in the store yet, start fresh
let mut data = D::default();
let result = func(&mut data);
wg.insert(
self.id.0.clone(),
SessionInstance {
data,
expires: Instant::now().add(self.store.lifespan),
},
);
result
}
let instance = wg.get_mut(self.id.as_str()).unwrap();
func(&mut instance.data)
}
}

Loading…
Cancel
Save