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