Skip to main content

taskers_core/
session_store.rs

1use std::{
2    fs,
3    path::{Path, PathBuf},
4};
5
6use anyhow::{Result, bail};
7use taskers_domain::{AppModel, PersistedSession, SESSION_SCHEMA_VERSION};
8use taskers_paths::default_session_path as shared_default_session_path;
9
10pub fn default_session_path() -> PathBuf {
11    shared_default_session_path()
12}
13
14pub fn load_or_bootstrap(path: &Path, demo: bool) -> Result<AppModel> {
15    if path.exists() {
16        match load_session(path) {
17            Ok(model) => Ok(model),
18            Err(error) => {
19                backup_incompatible_session(path)?;
20                eprintln!("failed to load session from {}: {}", path.display(), error);
21                if demo {
22                    Ok(AppModel::demo())
23                } else {
24                    Ok(AppModel::new("Workspace 1"))
25                }
26            }
27        }
28    } else if demo {
29        Ok(AppModel::demo())
30    } else {
31        Ok(AppModel::new("Workspace 1"))
32    }
33}
34
35pub fn load_session(path: &Path) -> Result<AppModel> {
36    let data = fs::read_to_string(path)?;
37    let session: PersistedSession = serde_json::from_str(&data)?;
38
39    if session.schema_version != SESSION_SCHEMA_VERSION {
40        bail!(
41            "unsupported session schema version {}, expected {}",
42            session.schema_version,
43            SESSION_SCHEMA_VERSION
44        );
45    }
46
47    Ok(session.model)
48}
49
50pub fn save_session(path: &Path, model: &AppModel) -> Result<()> {
51    if let Some(parent) = path.parent() {
52        fs::create_dir_all(parent)?;
53    }
54
55    let session = model.snapshot();
56    let data = serde_json::to_string_pretty(&session)?;
57    fs::write(path, data)?;
58
59    Ok(())
60}
61
62fn backup_incompatible_session(path: &Path) -> Result<()> {
63    let backup_path = path.with_extension("json.bak");
64    if backup_path.exists() {
65        fs::remove_file(&backup_path)?;
66    }
67    fs::rename(path, backup_path)?;
68    Ok(())
69}
70
71#[cfg(test)]
72mod tests {
73    use tempfile::tempdir;
74
75    use super::{load_session, save_session};
76    use taskers_domain::AppModel;
77
78    #[test]
79    fn roundtrips_session_files() {
80        let tempdir = tempdir().expect("tempdir");
81        let session_path = tempdir.path().join("session.json");
82        let model = AppModel::demo();
83
84        save_session(&session_path, &model).expect("session saved");
85        let loaded = load_session(&session_path).expect("session loaded");
86
87        assert_eq!(loaded, model);
88    }
89}