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}