Skip to main content

systemprompt_config/paths/
writable.rs

1//! The directories a node writes at runtime, declared in one place.
2//!
3//! On a read-only root filesystem every path the server writes must be a
4//! mounted volume. [`AppPaths::writable_roots`] is that contract: the boot
5//! probe creates and write-tests each root, so a missing mount fails the
6//! boot by name instead of failing the first request that writes. A
7//! `gateway` node renders no `web/dist` and fetches no services bundle, so
8//! it needs neither.
9//!
10//! Copyright (c) systemprompt.io — Business Source License 1.1.
11//! See <https://systemprompt.io> for licensing details.
12
13use std::path::{Path, PathBuf};
14
15use systemprompt_manifest::profile::NodeRole;
16
17use super::AppPaths;
18
19/// A directory the server writes, with the name operators see in errors.
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct WritableRoot {
22    pub name: &'static str,
23    pub path: PathBuf,
24}
25
26impl WritableRoot {
27    fn new(name: &'static str, path: impl Into<PathBuf>) -> Self {
28        Self {
29            name,
30            path: path.into(),
31        }
32    }
33}
34
35impl AppPaths {
36    pub fn writable_roots(&self, role: NodeRole, services_cache: &Path) -> Vec<WritableRoot> {
37        let storage = self.storage();
38        let mut roots = vec![
39            WritableRoot::new("system.logs", self.system().logs()),
40            WritableRoot::new("storage.files", storage.files()),
41            WritableRoot::new("storage.exports", storage.exports()),
42            WritableRoot::new("storage.data", storage.data()),
43            WritableRoot::new("storage.scratch", storage.scratch()),
44        ];
45        if role.runs_workers() {
46            roots.push(WritableRoot::new("web.dist", self.web().dist()));
47            roots.push(WritableRoot::new("services.cache_dir", services_cache));
48        }
49        roots
50    }
51}