Got session expiration working.
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled

This commit is contained in:
2026-05-02 14:04:42 -04:00
parent 7afa49a7ba
commit 947c87c215

View File

@@ -11,6 +11,7 @@ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
sync::mpsc::Receiver, sync::mpsc::Receiver,
thread::spawn, thread::spawn,
time::Duration,
}; };
use uuid::Uuid; use uuid::Uuid;
@@ -492,18 +493,25 @@ struct SessionEntry {
} }
impl SessionEntry { impl SessionEntry {
const EXPIRE_IN: Duration = Duration::from_hours(1);
fn new(id: Field) -> Self {
Self {
id: id,
expire_time: Utc::now() + SessionEntry::EXPIRE_IN,
}
}
fn id(&self) -> &Field { fn id(&self) -> &Field {
&self.id &self.id
} }
fn is_expired(&self) -> bool { fn extend(&mut self) {
Utc::now() > self.expire_time self.expire_time = Utc::now() + SessionEntry::EXPIRE_IN;
}
} }
impl SessionEntry { fn is_expired(&self) -> bool {
fn new(id: Field) -> Self { Utc::now() > self.expire_time
Self { id: id, expire_time: Utc::now(), }
} }
} }
@@ -516,8 +524,12 @@ mod session_entries {
#[test] #[test]
fn does_entry_return_id() { fn does_entry_return_id() {
let id: Field = Uuid::new_v4().into(); let id: Field = Uuid::new_v4().into();
let start = Utc::now() + SessionEntry::EXPIRE_IN;
let entry = SessionEntry::new(id.clone()); let entry = SessionEntry::new(id.clone());
let end = Utc::now() + SessionEntry::EXPIRE_IN;
assert_eq!(entry.id(), &id); assert_eq!(entry.id(), &id);
assert!(start < entry.expire_time, "{:?} should have been after {:?}", entry.expire_time, start);
assert!(end > entry.expire_time, "{:?} should have been after {:?}", entry.expire_time, end);
} }
#[test] #[test]
@@ -529,6 +541,17 @@ mod session_entries {
entry.expire_time = data - Duration::from_secs(1); entry.expire_time = data - Duration::from_secs(1);
assert!(entry.is_expired(), "entry should be expired"); assert!(entry.is_expired(), "entry should be expired");
} }
#[test]
fn can_expiration_be_reset() {
let mut entry = SessionEntry::new(Uuid::nil().into());
entry.expire_time = Utc::now();
let start = Utc::now() + SessionEntry::EXPIRE_IN;
entry.extend();
let end = Utc::now() + SessionEntry::EXPIRE_IN;
assert!(start < entry.expire_time, "{:?} should have been after {:?}", entry.expire_time, start);
assert!(end > entry.expire_time, "{:?} should have been after {:?}", entry.expire_time, end);
}
} }
struct Session { struct Session {
@@ -551,8 +574,11 @@ impl Session {
}, },
_ => Field::None, _ => Field::None,
}; };
match self.entries.get(&converted) { match self.entries.get_mut(&converted) {
Some(data) => data.clone(), Some(data) => {
data.extend();
data.clone()
}
None => { None => {
let mut new_id: Field = Uuid::new_v4().into(); let mut new_id: Field = Uuid::new_v4().into();
while self.entries.contains_key(&new_id) { while self.entries.contains_key(&new_id) {
@@ -564,6 +590,18 @@ impl Session {
} }
} }
} }
fn expire(&mut self) {
let mut remove: Vec<Field> = Vec::new();
for (id, session) in self.entries.iter() {
if session.is_expired() {
remove.push(id.clone());
}
}
for id in remove.iter() {
self.entries.remove(id);
}
}
} }
#[cfg(test)] #[cfg(test)]
@@ -590,8 +628,13 @@ mod sessions {
fn are_valid_uuids_returned() { fn are_valid_uuids_returned() {
let mut sess = Session::new(); let mut sess = Session::new();
let data = sess.get(&Field::None); let data = sess.get(&Field::None);
let start = Utc::now() + SessionEntry::EXPIRE_IN;
let result = sess.get(data.id()); let result = sess.get(data.id());
let end = Utc::now() + SessionEntry::EXPIRE_IN;
assert_eq!(result.id(), data.id()); assert_eq!(result.id(), data.id());
let entry = sess.entries.get(data.id()).unwrap();
assert!(start < entry.expire_time, "{:?} should have been after {:?}", entry.expire_time, start);
assert!(end > entry.expire_time, "{:?} should have been after {:?}", entry.expire_time, end);
} }
#[test] #[test]
@@ -646,6 +689,17 @@ mod sessions {
_ => panic!("session id should always return a uuid field"), _ => panic!("session id should always return a uuid field"),
} }
} }
#[test]
fn are_expired_sessions_removed() {
let mut sess = Session::new();
let lose = sess.get(&Field::None);
sess.entries.get_mut(&lose.id).unwrap().expire_time = Utc::now() - SessionEntry::EXPIRE_IN;
let keep = sess.get(&Field::None);
sess.expire();
assert_eq!(sess.entries.len(), 1, "should only contain one entry, had {:?}", sess.entries);
assert!(sess.entries.contains_key(&keep.id), "had {:?}, expected {:?}", sess.entries.keys(), &keep.id)
}
} }
pub struct DocRegistry { pub struct DocRegistry {