Skip to main content

kindling_server/
config.rs

1//! Daemon configuration.
2
3use std::path::PathBuf;
4use std::time::Duration;
5
6/// Default idle timeout before the daemon shuts itself down (30 minutes).
7pub const DEFAULT_IDLE_TIMEOUT: Duration = Duration::from_secs(30 * 60);
8
9/// Which transport the daemon binds and serves the v1 HTTP API on.
10///
11/// Unix domain sockets are the default (and only authenticated) transport on
12/// Unix; Windows has no UDS so it falls back to loopback TCP, publishing the
13/// bound ephemeral port in a side-channel file ([`ServerConfig::port_path`]).
14///
15/// The variant set is platform-gated so each platform's `match` stays
16/// exhaustive: `Uds` exists only on Unix, `Tcp` everywhere. The Linux build
17/// keeps both so the TCP path can be exercised in tests (and is what real
18/// Windows uses by default).
19#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
20pub enum Transport {
21    /// Unix domain socket at [`ServerConfig::socket_path`] (Unix only; the
22    /// platform default there).
23    #[cfg(unix)]
24    #[cfg_attr(unix, default)]
25    Uds,
26    /// Loopback TCP on an ephemeral `127.0.0.1` port published to
27    /// [`ServerConfig::port_path`]. The platform default on non-Unix (Windows).
28    #[cfg_attr(not(unix), default)]
29    Tcp,
30}
31
32/// Runtime configuration for [`serve`](crate::serve).
33///
34/// Construct via [`ServerConfig::new`] for the default home-relative paths, or
35/// build the struct directly (tests inject a temp `kindling_home`, a unique
36/// `socket_path`, a unique `pid_path`, and a short `idle_timeout`).
37#[derive(Debug, Clone)]
38pub struct ServerConfig {
39    /// Unix domain socket to bind (`~/.kindling/kindling.sock` by default).
40    pub socket_path: PathBuf,
41    /// Root of per-project databases (`~/.kindling` by default). Each request's
42    /// `X-Kindling-Project` header routes to `kindling_home/projects/<hash>/…`.
43    pub kindling_home: PathBuf,
44    /// PID file written on startup (`~/.kindling/kindling.pid` by default).
45    pub pid_path: PathBuf,
46    /// File the TCP port is published to when [`Self::transport`] is
47    /// [`Transport::Tcp`] (`~/.kindling/kindling.port` by default). Written
48    /// after binding the ephemeral loopback port; removed on shutdown. Unused
49    /// for the UDS transport.
50    pub port_path: PathBuf,
51    /// Shut down after this much idle time (no in-flight and no recent
52    /// requests). Defaults to [`DEFAULT_IDLE_TIMEOUT`].
53    pub idle_timeout: Duration,
54    /// Transport to bind. Defaults to [`Transport::default`] (UDS on Unix, TCP
55    /// on Windows).
56    pub transport: Transport,
57}
58
59impl ServerConfig {
60    /// Build a config rooted at `kindling_home` with conventional file names.
61    pub fn new(kindling_home: PathBuf) -> Self {
62        Self {
63            socket_path: kindling_home.join("kindling.sock"),
64            pid_path: kindling_home.join("kindling.pid"),
65            port_path: kindling_home.join("kindling.port"),
66            kindling_home,
67            idle_timeout: DEFAULT_IDLE_TIMEOUT,
68            transport: Transport::default(),
69        }
70    }
71
72    /// Build a config from the default kindling home (`~/.kindling`).
73    ///
74    /// Returns `None` when no home directory can be determined (mirrors
75    /// [`kindling_store::default_kindling_home`]).
76    pub fn from_default_home() -> Option<Self> {
77        kindling_store::default_kindling_home().map(Self::new)
78    }
79}