parent
f43f5d238d
commit
916bc5ed0e
@ -0,0 +1,133 @@
|
||||
//! Handles sessions and maintaining them
|
||||
use super::*;
|
||||
use tokio::{
|
||||
time::{
|
||||
self,
|
||||
DelayQueue,
|
||||
delay_queue,
|
||||
},
|
||||
sync::{
|
||||
RwLock,
|
||||
RwLockReadGuard,
|
||||
RwLockWriteGuard,
|
||||
},
|
||||
};
|
||||
use std::collections::{
|
||||
HashMap,
|
||||
};
|
||||
use std::{
|
||||
task::{Context,Poll},
|
||||
pin::Pin,
|
||||
};
|
||||
|
||||
use server::user::UserID;
|
||||
id_type!(pub SessionID: "A unique session id");
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
|
||||
pub struct Session
|
||||
{
|
||||
id: Option<SessionID>, // `None` for uncoupled
|
||||
|
||||
users: Vec<UserID>,
|
||||
}
|
||||
|
||||
impl Session
|
||||
{
|
||||
fn couple_to_new(self) -> Self
|
||||
{
|
||||
self.couple_to(SessionID::id_new())
|
||||
}
|
||||
#[inline] fn couple_to(self, id: SessionID) -> Self
|
||||
{
|
||||
Self {
|
||||
id: Some(id),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
/// See if this session object is coupled. If it is, return the session's ID.
|
||||
#[inline] pub fn coupled(&self) -> Option<&SessionID>
|
||||
{
|
||||
self.id.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct SessionPurge<'a, F = fn(Session)>(&'a mut Sessions, F);
|
||||
|
||||
impl<'a, F> Future for SessionPurge<'a, F>
|
||||
where F: FnMut(Session) + 'a + Unpin
|
||||
{
|
||||
type Output = Result<(), time::Error>;
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.get_mut();
|
||||
while let Some(res) = futures::ready!(this.0.expire.poll_expired(cx)) {
|
||||
let ent = res?;
|
||||
let _ = this.0.ids.remove(ent.get_ref()).map(|x| x.0).map(&mut this.1);
|
||||
}
|
||||
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Sessions
|
||||
{
|
||||
ids: HashMap<SessionID, (Session, delay_queue::Key)>,
|
||||
expire: DelayQueue<SessionID>,
|
||||
|
||||
ttl_range: (u64, u64),
|
||||
|
||||
rewrite_needed: !,
|
||||
}
|
||||
|
||||
impl Sessions
|
||||
{
|
||||
pub fn purge(&mut self) -> SessionPurge<'_>
|
||||
{
|
||||
SessionPurge(self, std::mem::drop)
|
||||
}
|
||||
pub fn purge_now(&mut self)
|
||||
{
|
||||
self.purge().now_or_never();
|
||||
}
|
||||
|
||||
pub fn new_session_id(&mut self, ses: Session) -> SessionID
|
||||
{
|
||||
self.purge_now();
|
||||
|
||||
let ses = ses.couple_to_new();
|
||||
let id = ses.coupled().unwrap().clone();
|
||||
let k = self.expire.insert(id.clone(), time::Duration::from_millis(self.ttl_range.jitter()));
|
||||
self.ids.insert(id.clone(), (ses, k));
|
||||
id
|
||||
}
|
||||
pub fn new_session(&mut self, ses: Session) -> &mut Session
|
||||
{
|
||||
self.purge_now();
|
||||
|
||||
let ses = ses.couple_to_new();
|
||||
let id = ses.coupled().unwrap().clone();
|
||||
let k = self.expire.insert(id.clone(), time::Duration::from_millis(self.ttl_range.jitter()));
|
||||
|
||||
&mut self.ids.entry(id).insert((ses, k)).into_mut().0
|
||||
}
|
||||
|
||||
pub fn session(&mut self, id: &SessionID) -> Option<&mut Session>
|
||||
{
|
||||
/////////TODO: `Session` and `Sessions` need a whole rework. We can't be returning references that borrow this container, it will block all other consumers wanting to get their own session reference. Rewrite using `Arc<Session>`s instead of `Session` s.
|
||||
self.purge_now();
|
||||
self.ids.get_mut(id).map(|(ses, _)| ses)
|
||||
}
|
||||
|
||||
pub fn new(cfg: &settings::Settings) -> Sessions
|
||||
{
|
||||
Self{
|
||||
ids: HashMap::new(),
|
||||
expire: DelayQueue::new(),
|
||||
|
||||
ttl_range: cfg.auth_token_ttl_millis,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in new issue