Skip to main content

aion_server/config/
home.rs

1//! Resolution of the server's central user-level configuration and state root.
2
3use std::path::PathBuf;
4
5use crate::error::ServerError;
6
7/// Where a resolved Aion home came from.
8///
9/// This is load-bearing, not diagnostic. Setting `AION_HOME` is how an operator
10/// says "this server's state lives here and nowhere else", so every later
11/// default that could point state somewhere else has to be able to see that the
12/// operator already answered the question. Resolving the home without carrying
13/// this fact is what let a working-directory legacy default silently win over
14/// an explicitly relocated home.
15#[derive(Clone, Copy, Debug, Eq, PartialEq)]
16pub enum HomeSource {
17    /// `AION_HOME` was set: the operator named this server's state root.
18    Explicit,
19    /// `AION_HOME` was absent: the home was derived as `$HOME/.aion`.
20    Derived,
21}
22
23/// A resolved Aion home together with the provenance of that resolution.
24#[derive(Clone, Debug, Eq, PartialEq)]
25pub struct AionHome {
26    /// The absolute home directory. Not created: config discovery is read-only.
27    pub path: PathBuf,
28    /// Whether the operator named the home or it was derived from `$HOME`.
29    pub source: HomeSource,
30}
31
32/// Resolve the Aion user-level configuration and state directory.
33///
34/// `AION_HOME` wins when set. Otherwise the directory is `$HOME/.aion`. The
35/// returned path is absolute, but is not created: config discovery is read-only,
36/// and the store or authoring surface creates it only on first write.
37///
38/// The returned [`AionHome::source`] records which of those two happened.
39/// Callers that choose defaults *below* the home must consult it rather than
40/// re-reading `AION_HOME` themselves: the environment is not guaranteed to be
41/// the same by then, and a second reading is a second answer.
42///
43/// # Errors
44///
45/// Returns [`ServerError::Config`] when `AION_HOME` is empty, neither
46/// `AION_HOME` nor `HOME` can identify a home directory, or a relative
47/// `AION_HOME` cannot be resolved because the current directory is unavailable.
48pub fn aion_home() -> Result<AionHome, ServerError> {
49    let configured = std::env::var_os("AION_HOME");
50    let (path, source) = match configured {
51        Some(value) if value.is_empty() => {
52            return Err(ServerError::Config {
53                message: "AION_HOME must not be empty".to_owned(),
54            });
55        }
56        Some(value) => (PathBuf::from(value), HomeSource::Explicit),
57        None => {
58            let Some(home) = std::env::var_os("HOME").filter(|value| !value.is_empty()) else {
59                return Err(ServerError::Config {
60                    message: "cannot resolve Aion home: set AION_HOME or HOME".to_owned(),
61                });
62            };
63            (PathBuf::from(home).join(".aion"), HomeSource::Derived)
64        }
65    };
66    let path = if path.is_absolute() {
67        path
68    } else {
69        std::env::current_dir()
70            .map(|current| current.join(path))
71            .map_err(|source| ServerError::Config {
72                message: format!(
73                    "cannot resolve relative AION_HOME against the current directory: {source}"
74                ),
75            })?
76    };
77    Ok(AionHome { path, source })
78}