Take XDG resolution from the shared crate too
Sixth and last of the modules that were the link rather than this product. main.rs loses config_home, data_home and xdg_dir, and its test module with them -- it held one test, which moved to the crate that now holds the code. The helpers gained a `product` parameter, matching certs::ensure and netif::wg_address, which is what keeps two products' state apart while resolving it identically. Verified by running it: with only XDG_CONFIG_HOME and XDG_DATA_HOME set and no --config or --data-dir, the server puts its certificates in $XDG_CONFIG_HOME/ai-app/certs and its sessions in $XDG_DATA_HOME/ai-app/sessions, and still prints an aiapp:// enrollment URI. 35 tests here and 19 in the crate, clippy silent, rustfmt clean.
This commit is contained in:
1 parent
aa05ff9336
commit
2c925a679f
2 files changed
+8
-58
No files matched your search
+7
-57
@@ -33,40 +33,13 @@ use tokio::signal::unix::{SignalKind, signal};
|
||||
|
||||
use wg_app_link::enroll;
|
||||
use wg_app_link::netif::{self, WG_INTERFACE};
|
||||
use wg_app_link::xdg::{config_home, data_home};
|
||||
|
||||
use config::TokenEntry;
|
||||
use session::SessionManager;
|
||||
|
||||
const DEFAULT_PORT: u16 = 8443;
|
||||
|
||||
/// `$XDG_CONFIG_HOME/ai-app`, or `~/.config/ai-app`. Holds `config.ron`
|
||||
/// and `certs/`.
|
||||
fn config_home() -> PathBuf {
|
||||
xdg_dir(std::env::var_os("XDG_CONFIG_HOME"), ".config")
|
||||
}
|
||||
|
||||
/// `$XDG_DATA_HOME/ai-app`, or `~/.local/share/ai-app`. Holds the session
|
||||
/// directories: transcripts, attachments, produced images.
|
||||
fn data_home() -> PathBuf {
|
||||
xdg_dir(std::env::var_os("XDG_DATA_HOME"), ".local/share")
|
||||
}
|
||||
|
||||
/// This app's directory under `base` -- the XDG variable's value, if it
|
||||
/// was set to an absolute path as the spec requires -- or under
|
||||
/// `~/<fallback>` otherwise. Takes the value rather than reading the
|
||||
/// environment itself so the rule is testable without mutating a
|
||||
/// process-wide variable other threads may be reading.
|
||||
fn xdg_dir(base: Option<std::ffi::OsString>, fallback: &str) -> PathBuf {
|
||||
base.map(PathBuf::from)
|
||||
.filter(|path| path.is_absolute())
|
||||
.unwrap_or_else(|| {
|
||||
std::env::home_dir()
|
||||
.unwrap_or_else(|| PathBuf::from("."))
|
||||
.join(fallback)
|
||||
})
|
||||
.join("ai-app")
|
||||
}
|
||||
|
||||
/// Serves AI coding sessions (Claude Code, llama.cpp) to the phone app.
|
||||
#[derive(Parser)]
|
||||
struct Args {
|
||||
@@ -121,16 +94,16 @@ async fn main() -> Result<()> {
|
||||
|
||||
let config_path = args
|
||||
.config
|
||||
.unwrap_or_else(|| config_home().join("config.ron"));
|
||||
.unwrap_or_else(|| config_home("ai-app").join("config.ron"));
|
||||
let data_dir = args
|
||||
.data_dir
|
||||
.unwrap_or_else(|| data_home().join("sessions"));
|
||||
.unwrap_or_else(|| data_home("ai-app").join("sessions"));
|
||||
// Beside the session data rather than under it: models outlive every
|
||||
// session and are shared by all of them, so deleting a session must
|
||||
// never take a multi-gigabyte download with it.
|
||||
let models_dir = args
|
||||
.models_dir
|
||||
.unwrap_or_else(|| data_home().join("models"));
|
||||
.unwrap_or_else(|| data_home("ai-app").join("models"));
|
||||
let models = Arc::new(models::ModelStore::new(models_dir.clone()));
|
||||
let manager = Arc::new(
|
||||
SessionManager::new(config_path.clone(), data_dir, models_dir.clone())
|
||||
@@ -163,7 +136,9 @@ async fn main() -> Result<()> {
|
||||
// also what the phone app embeds at build time, so they need to be
|
||||
// obtainable on a machine whose tunnel isn't up yet. The leaf is
|
||||
// reissued on every start, so once wg0 exists the next start covers it.
|
||||
let certs_dir = args.certs.unwrap_or_else(|| config_home().join("certs"));
|
||||
let certs_dir = args
|
||||
.certs
|
||||
.unwrap_or_else(|| config_home("ai-app").join("certs"));
|
||||
let certificates = wg_app_link::certs::ensure("ai-app", &certs_dir, &netif::local_addresses())
|
||||
.with_context(|| format!("failed to prepare certificates in {}", certs_dir.display()))?;
|
||||
if certificates.ca_is_new {
|
||||
@@ -247,28 +222,3 @@ async fn main() -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn xdg_dirs_respect_the_environment_and_are_namespaced() {
|
||||
let home_fallback = xdg_dir(None, ".config");
|
||||
assert!(home_fallback.ends_with("ai-app"));
|
||||
assert!(home_fallback.parent().expect("parent").ends_with(".config"));
|
||||
|
||||
assert_eq!(
|
||||
xdg_dir(Some("/somewhere".into()), ".config"),
|
||||
PathBuf::from("/somewhere/ai-app"),
|
||||
);
|
||||
|
||||
// Relative values are ignored per the spec, rather than resolving
|
||||
// against whatever the working directory happens to be -- so a
|
||||
// relative setting lands on the same path as no setting at all.
|
||||
assert_eq!(
|
||||
xdg_dir(Some("relative/path".into()), ".config"),
|
||||
home_fallback
|
||||
);
|
||||
}
|
||||
}
|
||||
+1
-1
Submodule wg-app-link updated: 841a3a8372...73a32cb897.
Reference in new issue
Block a user