Something went wrong. Try again.
Identities for entities did.bot
agent llm did
Something went wrong. Try again.
6.9 kB · 178 lines
Rust
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179//! What a machine that has never been configured looks like.
use std::collections::BTreeMap;use std::path::PathBuf;
use crate::config::{Config, Profile, Service, ServiceKind};
/// The profile a directory nobody has bound resolves to.pub const DEFAULT_PROFILE: &str = "default";
/// Directory this project keeps its own files in, under each XDG base.const PROJECT_DIR: &str = "didbot";
/// Name of the configuration file itself.const CONFIG_FILE: &str = "stack.toml";
/// The personal data server the default profile names, and so the directory/// its store lands in.const PDS_SERVICE: &str = "pds";
/// The interface a service listens on unless it says otherwise.////// Loopback, and an address rather than a name: `localhost` resolves to `::1`/// under systemd-resolved and to `127.0.0.1` elsewhere, and a default that/// means different things on different machines is not a default.pub(crate) fn host() -> String { "127.0.0.1".to_owned()}
/// An XDG base directory: the variable if it names one, else the fallback/// under `$HOME`, else this directory.////// The current directory last because these paths are read on machines that/// have neither variable — a container, a cron job — and returning a relative/// path there beats returning one rooted at `/`.fn xdg_base(variable: &str, fallback: &str) -> PathBuf { std::env::var_os(variable) .map(PathBuf::from) .filter(|path| !path.as_os_str().is_empty()) .or_else(|| { std::env::var_os("HOME") .map(PathBuf::from) .filter(|path| !path.as_os_str().is_empty()) .map(|home| home.join(fallback)) }) .unwrap_or_else(|| PathBuf::from("."))}
/// `$XDG_CONFIG_HOME/didbot/stack.toml`.////// Configuration rather than state: it is hand-editable, it is worth keeping,/// and losing it changes what this machine does rather than merely costing it/// some accounts. That is the opposite of [`default_data_dir`], which lives/// under the state directory for the opposite reasons.pub fn default_config_path() -> PathBuf { xdg_base("XDG_CONFIG_HOME", ".config") .join(PROJECT_DIR) .join(CONFIG_FILE)}
/// `$XDG_STATE_HOME/didbot/<service>`, where that server keeps its store.////// State rather than configuration: nothing here is hand-editable, and losing/// it costs this machine its local accounts and nothing else. That is what/// the state directory is for, and it is why this is the default — a restart/// that keeps the accounts a session is holding is worth more than a clean/// slate, which `DIDBOT_PDS_DATA=` still asks for by name.////// Per user rather than per checkout, because the agents on this machine/// address one server on one port; a second checkout serving the same port/// is refused by `pds.lock` before it can write. Keyed by service name so/// that a machine running two of them keeps two stores: one log has one/// writer, and the second opener is refused rather than interleaved.pub fn default_data_dir(service: &str) -> PathBuf { xdg_base("XDG_STATE_HOME", ".local/state") .join(PROJECT_DIR) .join(service)}
/// One of everything, on the ports and the state directory `scripts/dev-*.sh`/// use.////// These are duplicated from those scripts on purpose, and the duplication is/// checked: the tests below read the scripts and compare. A default that/// drifted from what the scripts actually bind would send every hook on an/// unconfigured machine to a port with nothing on it, and one that drifted/// from where they keep state would have `didbot-setup show` describe a store/// nothing is writing.pub(crate) fn builtin() -> Config { let mut services = BTreeMap::new(); services.insert( PDS_SERVICE.to_owned(), Service { kind: ServiceKind::Pds, port: 3000, host: host(), zone: Some("agents.localhost".to_owned()), names: Some("mineral+creature".to_owned()), pds: None, index: None, query: None, data: Some(default_data_dir(PDS_SERVICE)), }, ); let mut profiles = BTreeMap::new(); profiles.insert( DEFAULT_PROFILE.to_owned(), Profile { pds: PDS_SERVICE.to_owned(), // The record host, the index, the query service and the // canvas are vibescrobble.com's processes now. `ServiceKind` // still names them, so a developer running both can declare them // in their own profile; what is built in is what this repository // can start. index: None, query: None, web: None, }, );
Config { services, profiles, bind: BTreeMap::new(), debug: false, }}
#[cfg(test)]mod tests { use super::*;
/// The one duplication in this crate, checked rather than trusted. #[test] fn the_builtin_ports_match_the_development_scripts() { let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) .parent() .and_then(|crates| crates.parent()) .expect("the workspace root is two levels up") .join("scripts"); let config = builtin();
let (script, variable, service) = ("dev-pds.sh", "DIDBOT_PDS_PORT", "pds"); let source = std::fs::read_to_string(root.join(script)) .unwrap_or_else(|err| panic!("read {script}: {err}")); let expected = config.services[service].port; let needle = format!("${{{variable}:-{expected}}}"); assert!( source.contains(&needle), "{script} does not default {variable} to {expected}; \ the builtin configuration and the script disagree" ); }
/// The other duplication, checked the same way. /// /// `-` rather than `:-` is the whole escape hatch: an unset variable takes /// the default, and one explicitly emptied asks for a store in memory. #[test] fn the_builtin_data_directory_matches_the_development_script() { let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) .parent() .and_then(|crates| crates.parent()) .expect("the workspace root is two levels up") .join("scripts"); let source = std::fs::read_to_string(root.join("dev-pds.sh")) .unwrap_or_else(|err| panic!("read dev-pds.sh: {err}")); let service = &builtin().profiles[DEFAULT_PROFILE].pds; let needle = format!( "${{DIDBOT_PDS_DATA-${{XDG_STATE_HOME:-$HOME/.local/state}}/{PROJECT_DIR}/{service}}}" ); assert!( source.contains(&needle), "dev-pds.sh does not default DIDBOT_PDS_DATA to {needle}; \ the builtin configuration and the script disagree" ); }}