odds/persistence/
session.rs1use serde::{Deserialize, Serialize};
2use std::{
3 path::PathBuf,
4 time::{SystemTime, UNIX_EPOCH},
5};
6
7use crate::{paths, persistence::persistable::Persistable};
8
9#[derive(Debug, Serialize, Deserialize)]
10pub struct SessionEntry {
11 pub path: PathBuf,
12}
13
14#[derive(Debug, Serialize, Deserialize)]
15pub struct Session {
16 max_size: usize,
17 pub entries: Vec<SessionEntry>,
18 saved_at: u64,
19}
20
21const SESSION_EXPIRY_SECS: u64 = 43200; const MAX_SIZE: usize = 10;
23
24impl Default for Session {
25 fn default() -> Self {
26 Self {
27 max_size: MAX_SIZE,
28 entries: Vec::new(),
29 saved_at: time_now(),
30 }
31 }
32}
33
34impl Session {
35 pub fn push(&mut self, path: &PathBuf) {
37 let path = paths::normalize(path);
38
39 if self.current() == Some(&path) {
41 return;
42 }
43
44 self.entries.retain(|e| e.path != path);
46
47 self.entries.insert(0, SessionEntry { path });
49
50 if self.entries.len() > self.max_size {
52 self.entries.truncate(self.max_size);
53 }
54 }
55
56 pub fn current(&self) -> Option<&PathBuf> {
57 self.entries.first().map(|e| &e.path)
58 }
59
60 pub fn previous(&self) -> Option<&PathBuf> {
61 self.entries.get(1).map(|e| &e.path)
62 }
63
64 pub fn list(&self) -> &[SessionEntry] {
66 &self.entries
67 }
68
69 pub fn contains(&self, path: &PathBuf) -> bool {
70 self.entries.iter().any(|e| e.path == *path)
71 }
72
73 pub fn formatted(&self) -> Vec<String> {
75 self.entries
76 .iter()
77 .enumerate()
78 .map(|(i, e)| {
79 if i == 0 {
80 format!("{} {} <-- current", i + 1, e.path.display())
81 } else {
82 format!("{} {}", i + 1, e.path.display())
83 }
84 })
85 .collect()
86 }
87
88 pub fn load_or_new() -> Self {
90 if let Ok(session) = Self::load() {
91 if time_now().saturating_sub(session.saved_at) < SESSION_EXPIRY_SECS {
93 return session;
94 }
95 }
96
97 let mut new_session = Self::default();
98
99 if let Err(e) = new_session.save() {
100 eprintln!("Error saving session: {e}");
101 }
102
103 new_session
104 }
105}
106
107fn time_now() -> u64 {
108 SystemTime::now()
109 .duration_since(UNIX_EPOCH)
110 .unwrap_or_default()
111 .as_secs()
112}
113
114impl Persistable for Session {
115 const FILE: &'static str = "session.json";
116
117 fn before_save(&mut self) {
118 self.saved_at = time_now();
119 }
120}