Skip to main content

objectiveai_sdk/filesystem/
client.rs

1use std::path::PathBuf;
2use std::sync::{Arc, Mutex};
3
4#[derive(Debug, Clone)]
5pub struct Client {
6    base_dir: PathBuf,
7    pub commit_author_name: String,
8    pub commit_author_email: String,
9    /// Lazily-initialised SQLite connection shared across clones of this
10    /// `Client`. Populated on first call to `db()` (see
11    /// `filesystem::config::db`). Wrapped in `Arc<Mutex<Option<…>>>` so
12    /// every clone sees the same connection once one exists, and so
13    /// init failures don't poison the slot — a failed attempt leaves
14    /// the inner `Option::None` intact and later calls can retry.
15    db_conn: Arc<Mutex<Option<Arc<Mutex<rusqlite::Connection>>>>>,
16}
17
18impl Client {
19    pub fn new(
20        base_dir: Option<impl Into<PathBuf>>,
21        commit_author_name: Option<impl Into<String>>,
22        commit_author_email: Option<impl Into<String>>,
23    ) -> Self {
24        let base_dir = match base_dir {
25            Some(dir) => dir.into(),
26            None => {
27                #[cfg(feature = "env")]
28                if let Ok(dir) = std::env::var("CONFIG_BASE_DIR") {
29                    return Self {
30                        base_dir: PathBuf::from(dir),
31                        commit_author_name: resolve_author_name(commit_author_name),
32                        commit_author_email: resolve_author_email(commit_author_email),
33                        db_conn: Arc::new(Mutex::new(None)),
34                    };
35                }
36                dirs::home_dir()
37                    .unwrap_or_else(|| PathBuf::from("."))
38                    .join(".objectiveai")
39            }
40        };
41        Self {
42            base_dir,
43            commit_author_name: resolve_author_name(commit_author_name),
44            commit_author_email: resolve_author_email(commit_author_email),
45            db_conn: Arc::new(Mutex::new(None)),
46        }
47    }
48
49    pub fn base_dir(&self) -> &PathBuf {
50        &self.base_dir
51    }
52
53    pub fn config_path(&self) -> PathBuf {
54        self.base_dir.join("config.json")
55    }
56
57    pub fn db_path(&self) -> PathBuf {
58        self.base_dir.join("config.sqlite")
59    }
60
61    pub fn logs_dir(&self) -> PathBuf {
62        self.base_dir.join("logs")
63    }
64
65    /// Internal accessor to the lazy-init slot. Used by
66    /// `filesystem::config::db` to open the connection on first use.
67    pub(crate) fn db_conn_slot(&self) -> &Mutex<Option<Arc<Mutex<rusqlite::Connection>>>> {
68        &self.db_conn
69    }
70}
71
72fn resolve_author_name(explicit: Option<impl Into<String>>) -> String {
73    if let Some(name) = explicit {
74        return name.into();
75    }
76    #[cfg(feature = "env")]
77    if let Ok(name) = std::env::var("COMMIT_AUTHOR_NAME") {
78        return name;
79    }
80    "ObjectiveAI".to_string()
81}
82
83fn resolve_author_email(explicit: Option<impl Into<String>>) -> String {
84    if let Some(email) = explicit {
85        return email.into();
86    }
87    #[cfg(feature = "env")]
88    if let Ok(email) = std::env::var("COMMIT_AUTHOR_EMAIL") {
89        return email;
90    }
91    "admin@objectiveai.dev".to_string()
92}