#![forbid(unsafe_code)]
use crate::connectionsignature::ConnectionSignature;
use crate::sessionpolicy::SessionPolicy;
use crate::token::Token;
use crate::AuthError;
use std::collections::HashMap;
use std::time::{Duration, Instant};
use std::sync::{Mutex, MutexGuard};
#[derive(Debug)]
struct Session {
last_access: Instant,
}
impl Session {
fn new(_: &ConnectionSignature) -> Session {
Session {
last_access: Instant::now(),
}
}
}
#[derive(Debug)]
pub struct SessionManager {
expiration: Duration,
policy: SessionPolicy,
sessions: Mutex<HashMap<ConnectionSignature, Session>>,
}
impl SessionManager {
pub fn new(expiration: Duration, policy: SessionPolicy) -> SessionManager {
SessionManager {
expiration,
policy,
sessions: Mutex::new(HashMap::new()),
}
}
pub fn is_expired(&self, signature: &ConnectionSignature) -> Result<bool, AuthError> {
let mut hashmap = self.sessions.lock().map_err(|_| AuthError::Mutex)?;
Ok(self.is_expired_locked(signature, &mut hashmap))
}
fn is_expired_locked(
&self,
signature: &ConnectionSignature,
hashmap: &mut MutexGuard<HashMap<ConnectionSignature, Session>>,
) -> bool {
let rv = match hashmap.get(signature) {
Some(sess) => sess.last_access.elapsed() >= self.expiration,
None => true,
};
if rv {
self.stop_locked(&signature, hashmap);
}
debug!("is_expired about to return {}", rv);
rv
}
fn stop_locked(
&self,
signature: &ConnectionSignature,
hashmap: &mut MutexGuard<HashMap<ConnectionSignature, Session>>,
) -> Option<Session> {
hashmap.remove(signature)
}
pub fn stop(&self, signature: &ConnectionSignature) {
match self.sessions.lock() {
Ok(mut hashmap) => self.stop_locked(signature, &mut hashmap),
Err(poisoned) => poisoned.into_inner().remove(signature),
};
}
pub fn start(
&self,
mut signature: ConnectionSignature,
) -> Result<ConnectionSignature, AuthError> {
let mut hashmap = self.sessions.lock().map_err(|_| AuthError::Mutex)?;
let need_insert = self.is_expired_locked(&signature, &mut hashmap);
if need_insert {
signature.token = Token::new(&self.policy.salt);
hashmap.insert(signature.clone(), Session::new(&signature));
} else {
match hashmap.get_mut(&signature) {
Some(sess) => sess.last_access = Instant::now(),
None => return Err(AuthError::MissingData), }
}
Ok(signature)
}
pub fn stop_all_sessions(&self) {
match self.sessions.lock() {
Ok(mut hashmap) => hashmap.clear(),
Err(poisoned) => poisoned.into_inner().clear(),
}
}
}