Skip to main content

synd_support/
dirs.rs

1use std::{
2    path::{Path, PathBuf},
3    sync::OnceLock,
4};
5
6use directories::ProjectDirs;
7
8const APP_NAME: &str = "syndicationd";
9const CONFIG_FILE_NAME: &str = "config.toml";
10const SQLITE_DB_FILE_NAME: &str = "synd.db";
11const LOG_FILE_NAME: &str = "synd.log";
12
13/// Platform-specific application directories for syndicationd.
14#[derive(Debug)]
15pub struct SyndicationdDirs {
16    project_dirs: ProjectDirs,
17}
18
19impl SyndicationdDirs {
20    pub fn current() -> &'static Self {
21        static DIRS: OnceLock<SyndicationdDirs> = OnceLock::new();
22
23        DIRS.get_or_init(|| Self::new().expect("failed to resolve syndicationd directories"))
24    }
25
26    pub fn new() -> Option<Self> {
27        ProjectDirs::from("", "", APP_NAME).map(|project_dirs| Self { project_dirs })
28    }
29
30    pub fn cache_dir(&self) -> &Path {
31        self.project_dirs.cache_dir()
32    }
33
34    pub fn config_file(&self) -> PathBuf {
35        self.project_dirs.config_dir().join(CONFIG_FILE_NAME)
36    }
37
38    pub fn sqlite_db(&self) -> PathBuf {
39        self.project_dirs.data_dir().join(SQLITE_DB_FILE_NAME)
40    }
41
42    pub fn log_file(&self) -> PathBuf {
43        self.project_dirs.data_dir().join(LOG_FILE_NAME)
44    }
45
46    pub fn runtime_dir(&self) -> Option<&Path> {
47        self.project_dirs.runtime_dir()
48    }
49
50    pub fn runtime_dir_or_temp(&self) -> PathBuf {
51        self.runtime_dir()
52            .map_or_else(|| std::env::temp_dir().join(APP_NAME), Path::to_path_buf)
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use crate::dirs::SyndicationdDirs;
59
60    #[test]
61    fn resolves_current_platform_directories() {
62        let dirs = SyndicationdDirs::new().unwrap();
63
64        assert!(dirs.cache_dir().is_absolute());
65        assert!(dirs.config_file().ends_with("config.toml"));
66        assert!(dirs.sqlite_db().ends_with("synd.db"));
67        assert!(dirs.log_file().ends_with("synd.log"));
68        assert!(dirs.runtime_dir_or_temp().is_absolute());
69    }
70}