You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
2.9 KiB
134 lines
2.9 KiB
//! 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,
|
|
}
|
|
}
|
|
}
|