proses 0.1.1

Proses – Professional Secure Execution System
use home::home_dir;
use once_cell::sync::OnceCell;
use std::{fs, path::PathBuf};

/// Global runtime configuration for the Proses daemon and CLI.
///
/// All paths are rooted under `~/.proses/`.
pub struct Config {
    /// Persistent process store: `~/.proses/store.json`
    pub store_path: PathBuf,
    /// Unix domain socket used for IPC: `~/.proses/proses.sock`
    pub sock_path: PathBuf,
    /// Daemon PID file: `~/.proses/daemon.pid`
    pub pid_path: PathBuf,
    /// Directory for per-process stdout/stderr logs: `~/.proses/logs/`
    pub log_dir: PathBuf,
}

static CONFIG: OnceCell<Config> = OnceCell::new();

/// Initialise the global [`Config`] singleton and create the necessary
/// directories on disk.
///
/// Safe to call multiple times — subsequent calls are no-ops.
pub fn init() {
    // If already initialised, nothing to do.
    if CONFIG.get().is_some() {
        return;
    }

    let base_dir = home_dir()
        .expect("Cannot determine the home directory")
        .join(".proses");

    let log_dir = base_dir.join("logs");

    fs::create_dir_all(&base_dir).expect("Failed to create ~/.proses directory");
    fs::create_dir_all(&log_dir).expect("Failed to create ~/.proses/logs directory");

    let config = Config {
        store_path: base_dir.join("store.json"),
        sock_path: base_dir.join("proses.sock"),
        pid_path: base_dir.join("daemon.pid"),
        log_dir,
    };

    // A concurrent caller may have beaten us to the set; that is fine —
    // the value that wins is valid for our lifetime.
    CONFIG.set(config).ok();
}

/// Return a reference to the global [`Config`].
///
/// # Panics
/// Panics if [`init`] has not been called yet.
#[inline]
pub fn get() -> &'static Config {
    CONFIG
        .get()
        .expect("Config not initialised — call config::init() first")
}