app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit a7444957acc41618170f38d28bd087c926d086ba
parent 7b9df71480e46e043f95fe19a176b27f64df6de1
Author: triesap <tyson@radroots.org>
Date:   Sun, 19 Apr 2026 20:56:01 +0000

runtime: derive app metadata inside rust

Diffstat:
Mcrates/launchers/desktop/src/app.rs | 2+-
Mcrates/shared/core/src/lib.rs | 8++++----
Mcrates/shared/core/src/runtime.rs | 230+++++++++++++++++++++++++------------------------------------------------------
3 files changed, 78 insertions(+), 162 deletions(-)

diff --git a/crates/launchers/desktop/src/app.rs b/crates/launchers/desktop/src/app.rs @@ -26,7 +26,7 @@ pub enum AppLaunchError { pub fn launch() -> Result<(), AppLaunchError> { let build = build_identity(); let runtime_config = AppRuntimeConfig::from_env()?; - let snapshot = AppRuntimeSnapshot::from_config(build, &runtime_config); + let snapshot = AppRuntimeSnapshot::capture_for_mode(build, runtime_config.runtime_mode); bootstrap_logging(&snapshot, runtime_config.local_log_root.as_path())?; install_panic_hook(); diff --git a/crates/shared/core/src/lib.rs b/crates/shared/core/src/lib.rs @@ -19,9 +19,9 @@ pub use paths::{ }; pub use runtime::{ APP_HOST_PLATFORM, APP_ID, APP_NAME, APP_PLATFORM_RUNTIME, APP_PROJECTION_SOURCE, - APP_RUNTIME_MODE_ENV, APP_RUN_ID_ENV, APP_DEFAULT_NOSTR_RELAY_URL_ENV, - APP_LOCAL_LOG_ROOT_ENV, APP_RUNTIME_ORIGIN, AppBuildIdentity, AppCoreRuntimeMetadata, - AppHostRuntimeMetadata, AppRuntimeCapture, AppRuntimeConfig, AppRuntimeConfigError, - AppRuntimeMode, AppRuntimeSnapshot, runtime_mode_label, + APP_RUNTIME_MODE_ENV, APP_DEFAULT_NOSTR_RELAY_URL_ENV, APP_LOCAL_LOG_ROOT_ENV, + APP_RUNTIME_ORIGIN, AppBuildIdentity, AppCoreRuntimeMetadata, AppHostRuntimeMetadata, + AppRuntimeCapture, AppRuntimeConfig, AppRuntimeConfigError, AppRuntimeMode, + AppRuntimeSnapshot, runtime_mode_label, }; pub use startup::{AppStartupEvent, AppStartupEventMetadata, launch_startup_event}; diff --git a/crates/shared/core/src/runtime.rs b/crates/shared/core/src/runtime.rs @@ -6,6 +6,8 @@ use std::{ use serde::Serialize; use thiserror::Error; +use crate::{AppRuntimePathsError, AppRuntimeRoots}; + pub const APP_ID: &str = "org.radroots.app"; pub const APP_NAME: &str = "Radroots"; pub const APP_PLATFORM_RUNTIME: &str = "app-macos-native"; @@ -13,7 +15,6 @@ pub const APP_PROJECTION_SOURCE: &str = "gpui-native"; pub const APP_RUNTIME_ORIGIN: &str = "gpui://localhost"; pub const APP_HOST_PLATFORM: &str = "desktop"; pub const APP_RUNTIME_MODE_ENV: &str = "RADROOTS_APP_RUNTIME_MODE"; -pub const APP_RUN_ID_ENV: &str = "RADROOTS_APP_RUN_ID"; pub const APP_DEFAULT_NOSTR_RELAY_URL_ENV: &str = "RADROOTS_APP_DEFAULT_NOSTR_RELAY_URL"; pub const APP_LOCAL_LOG_ROOT_ENV: &str = "RADROOTS_APP_LOCAL_LOG_ROOT"; @@ -27,16 +28,7 @@ pub enum AppRuntimeMode { #[derive(Clone, Debug, Eq, PartialEq)] pub struct AppRuntimeConfig { pub runtime_mode: AppRuntimeMode, - pub run_id: String, pub default_nostr_relay_url: String, - pub bundle_identifier: String, - pub bundle_name: String, - pub marketing_version: String, - pub build_number: String, - pub platform_name: String, - pub operating_system_version: String, - pub host_locale: String, - pub runtime_origin: String, pub local_log_root: PathBuf, } @@ -90,6 +82,8 @@ pub struct AppRuntimeSnapshot { #[derive(Debug, Error)] pub enum AppRuntimeConfigError { + #[error(transparent)] + RuntimePaths(#[from] AppRuntimePathsError), #[error("missing required runtime env: {0}")] MissingEnv(&'static str), #[error("unsupported runtime mode: {0}")] @@ -100,10 +94,14 @@ pub enum AppRuntimeConfigError { impl AppRuntimeConfig { pub fn from_env() -> Result<Self, AppRuntimeConfigError> { - Self::from_env_with(|name| std::env::var(name).ok()) + let default_log_root = AppRuntimeRoots::current_desktop()?.logs; + Self::from_env_with(|name| std::env::var(name).ok(), default_log_root) } - fn from_env_with<F>(mut read_env: F) -> Result<Self, AppRuntimeConfigError> + fn from_env_with<F>( + mut read_env: F, + default_log_root: PathBuf, + ) -> Result<Self, AppRuntimeConfigError> where F: FnMut(&str) -> Option<String>, { @@ -111,26 +109,16 @@ impl AppRuntimeConfig { &mut read_env, APP_RUNTIME_MODE_ENV, )?)?; - let run_id = require_env_value(&mut read_env, APP_RUN_ID_ENV)?; let default_nostr_relay_url = require_env_value(&mut read_env, APP_DEFAULT_NOSTR_RELAY_URL_ENV)?; - let local_log_root = - require_path_value(APP_LOCAL_LOG_ROOT_ENV, require_env_value(&mut read_env, APP_LOCAL_LOG_ROOT_ENV)?)?; + let local_log_root = read_env(APP_LOCAL_LOG_ROOT_ENV) + .map(|value| require_path_value(APP_LOCAL_LOG_ROOT_ENV, value)) + .transpose()? + .unwrap_or(default_log_root); Ok(Self { runtime_mode, - run_id, default_nostr_relay_url, - bundle_identifier: APP_ID.to_owned(), - bundle_name: APP_NAME.to_owned(), - marketing_version: env!("CARGO_PKG_VERSION").to_owned(), - build_number: option_env!("RADROOTS_GIT_COMMIT") - .unwrap_or(option_env!("PROFILE").unwrap_or("debug")) - .to_owned(), - platform_name: APP_HOST_PLATFORM.to_owned(), - operating_system_version: std::env::consts::OS.to_owned(), - host_locale: detect_host_locale(), - runtime_origin: APP_RUNTIME_ORIGIN.to_owned(), local_log_root, }) } @@ -149,33 +137,11 @@ impl AppRuntimeCapture { impl AppRuntimeSnapshot { pub fn capture(build: AppBuildIdentity) -> Self { let mode = parse_build_runtime_mode(&build.build_profile); - Self::from_capture(build, mode, AppRuntimeCapture::current(&mode)) + Self::capture_for_mode(build, mode) } - pub fn from_config(build: AppBuildIdentity, config: &AppRuntimeConfig) -> Self { - Self { - title: APP_NAME.to_owned(), - runtime_mode: config.runtime_mode, - run_id: config.run_id.clone(), - core: AppCoreRuntimeMetadata { - package_name: env!("CARGO_PKG_NAME").to_owned(), - package_version: env!("CARGO_PKG_VERSION").to_owned(), - package_authors: env!("CARGO_PKG_AUTHORS").to_owned(), - rust_edition: "2024".to_owned(), - rust_toolchain: env!("CARGO_PKG_RUST_VERSION").to_owned(), - }, - build, - host: AppHostRuntimeMetadata { - app_identifier: config.bundle_identifier.clone(), - app_name: config.bundle_name.clone(), - app_version: config.marketing_version.clone(), - app_build: config.build_number.clone(), - platform_name: config.platform_name.clone(), - operating_system: config.operating_system_version.clone(), - host_locale: config.host_locale.clone(), - runtime_origin: config.runtime_origin.clone(), - }, - } + pub fn capture_for_mode(build: AppBuildIdentity, runtime_mode: AppRuntimeMode) -> Self { + Self::from_capture(build, runtime_mode, AppRuntimeCapture::current(&runtime_mode)) } pub fn from_capture( @@ -311,9 +277,9 @@ mod tests { use super::{ APP_DEFAULT_NOSTR_RELAY_URL_ENV, APP_HOST_PLATFORM, APP_ID, APP_LOCAL_LOG_ROOT_ENV, - APP_NAME, APP_PROJECTION_SOURCE, APP_RUN_ID_ENV, APP_RUNTIME_MODE_ENV, - APP_RUNTIME_ORIGIN, AppBuildIdentity, AppRuntimeCapture, AppRuntimeConfig, - AppRuntimeConfigError, AppRuntimeMode, AppRuntimeSnapshot, runtime_mode_label, + APP_NAME, APP_PROJECTION_SOURCE, APP_RUNTIME_MODE_ENV, APP_RUNTIME_ORIGIN, + AppBuildIdentity, AppRuntimeCapture, AppRuntimeConfig, AppRuntimeConfigError, + AppRuntimeMode, AppRuntimeSnapshot, runtime_mode_label, }; fn test_build_identity() -> AppBuildIdentity { @@ -331,14 +297,9 @@ mod tests { BTreeMap::from([ (APP_RUNTIME_MODE_ENV, "localhost-dev".to_owned()), ( - APP_RUN_ID_ENV, - "run-localhost-dev-20260417T000000Z-deadbeefcafefeed".to_owned(), - ), - ( APP_DEFAULT_NOSTR_RELAY_URL_ENV, "ws://127.0.0.1:8080".to_owned(), ), - (APP_LOCAL_LOG_ROOT_ENV, "/tmp/radroots/logs".to_owned()), ]) } @@ -376,15 +337,16 @@ mod tests { #[test] fn runtime_config_requires_explicit_runtime_mode_env() { let env = BTreeMap::from([ - (APP_RUN_ID_ENV, "run-localhost-dev-20260417T000000Z-deadbeefcafefeed".to_owned()), ( APP_DEFAULT_NOSTR_RELAY_URL_ENV, "ws://127.0.0.1:8080".to_owned(), ), - (APP_LOCAL_LOG_ROOT_ENV, "/tmp/radroots/logs".to_owned()), ]); - let error = AppRuntimeConfig::from_env_with(|name| env.get(name).cloned()) - .expect_err("missing runtime mode env should fail"); + let error = AppRuntimeConfig::from_env_with( + |name| env.get(name).cloned(), + PathBuf::from("/tmp/default-logs"), + ) + .expect_err("missing runtime mode env should fail"); assert!(matches!( error, @@ -394,44 +356,35 @@ mod tests { #[test] fn runtime_config_surfaces_explicit_local_log_root() { - let env = test_runtime_env(); - let config = AppRuntimeConfig::from_env_with(|name| env.get(name).cloned()) + let env = BTreeMap::from([ + (APP_RUNTIME_MODE_ENV, "localhost-dev".to_owned()), + ( + APP_DEFAULT_NOSTR_RELAY_URL_ENV, + "ws://127.0.0.1:8080".to_owned(), + ), + (APP_LOCAL_LOG_ROOT_ENV, "/tmp/radroots/logs".to_owned()), + ]); + let config = AppRuntimeConfig::from_env_with( + |name| env.get(name).cloned(), + PathBuf::from("/tmp/default-logs"), + ) .expect("valid env config"); assert_eq!(config.runtime_mode, AppRuntimeMode::LocalhostDev); - assert_eq!( - config.run_id, - "run-localhost-dev-20260417T000000Z-deadbeefcafefeed" - ); assert_eq!(config.default_nostr_relay_url, "ws://127.0.0.1:8080"); - assert_eq!(config.bundle_identifier, APP_ID); - assert_eq!(config.bundle_name, APP_NAME); - assert_eq!(config.platform_name, APP_HOST_PLATFORM); - assert_eq!(config.runtime_origin, APP_RUNTIME_ORIGIN); - assert_eq!(config.operating_system_version, std::env::consts::OS); - assert!(!config.host_locale.trim().is_empty()); assert_eq!(config.local_log_root, PathBuf::from("/tmp/radroots/logs")); } #[test] - fn runtime_snapshot_uses_explicit_runtime_config_host_identity() { + fn runtime_config_defaults_local_log_root_from_runtime_paths() { let env = test_runtime_env(); - let snapshot = AppRuntimeSnapshot::from_config( - test_build_identity(), - &AppRuntimeConfig::from_env_with(|name| env.get(name).cloned()) - .expect("valid env config"), - ); + let config = AppRuntimeConfig::from_env_with( + |name| env.get(name).cloned(), + PathBuf::from("/tmp/default-logs"), + ) + .expect("default log root should apply"); - assert_eq!( - snapshot.run_id, - "run-localhost-dev-20260417T000000Z-deadbeefcafefeed" - ); - assert_eq!(snapshot.host.app_identifier, APP_ID); - assert_eq!(snapshot.host.app_name, APP_NAME); - assert_eq!(snapshot.host.platform_name, APP_HOST_PLATFORM); - assert_eq!(snapshot.host.operating_system, std::env::consts::OS); - assert_eq!(snapshot.host.runtime_origin, APP_RUNTIME_ORIGIN); - assert_eq!(runtime_mode_label(&snapshot.runtime_mode), "localhost-dev"); + assert_eq!(config.local_log_root, PathBuf::from("/tmp/default-logs")); } #[test] @@ -455,78 +408,44 @@ mod tests { } #[test] - fn runtime_snapshot_capture_matches_canonical_runtime_config_metadata() { - let build = test_build_identity(); - let env = BTreeMap::from([ - (APP_RUNTIME_MODE_ENV, "development".to_owned()), - (APP_RUN_ID_ENV, "run-development-123-pid456".to_owned()), - ( - APP_DEFAULT_NOSTR_RELAY_URL_ENV, - "ws://127.0.0.1:8080".to_owned(), - ), - (APP_LOCAL_LOG_ROOT_ENV, "/tmp/radroots/logs".to_owned()), - ]); - let snapshot_from_capture = AppRuntimeSnapshot::from_capture( - build.clone(), - AppRuntimeMode::Development, - AppRuntimeCapture { - host_locale: "en_US.UTF-8".to_owned(), - operating_system: "macos".to_owned(), - run_id: "run-development-123-pid456".to_owned(), - }, - ); - let snapshot_from_config = AppRuntimeSnapshot::from_config( - build.clone(), - &AppRuntimeConfig::from_env_with(|name| env.get(name).cloned()) - .expect("canonical env config should parse"), + fn runtime_snapshot_capture_for_mode_uses_rust_owned_host_identity() { + let snapshot = AppRuntimeSnapshot::capture_for_mode( + test_build_identity(), + AppRuntimeMode::LocalhostDev, ); - assert_eq!(snapshot_from_config.title, snapshot_from_capture.title); - assert_eq!(snapshot_from_config.runtime_mode, snapshot_from_capture.runtime_mode); - assert_eq!(snapshot_from_config.run_id, snapshot_from_capture.run_id); - assert_eq!(snapshot_from_config.core, snapshot_from_capture.core); - assert_eq!( - snapshot_from_config.host.app_identifier, - snapshot_from_capture.host.app_identifier - ); - assert_eq!( - snapshot_from_config.host.app_name, - snapshot_from_capture.host.app_name - ); - assert_eq!( - snapshot_from_config.host.app_version, - snapshot_from_capture.host.app_version - ); - assert_eq!( - snapshot_from_config.host.platform_name, - snapshot_from_capture.host.platform_name - ); - assert_eq!( - snapshot_from_config.host.operating_system, - snapshot_from_capture.host.operating_system - ); - assert_eq!( - snapshot_from_config.host.runtime_origin, - snapshot_from_capture.host.runtime_origin - ); + assert_eq!(snapshot.title, APP_NAME); + assert!(snapshot.run_id.starts_with("run-localhost-dev-")); + assert!(snapshot.run_id.contains("-pid")); + assert_eq!(snapshot.host.app_identifier, APP_ID); + assert_eq!(snapshot.host.app_name, APP_NAME); + assert_eq!(snapshot.host.app_version, env!("CARGO_PKG_VERSION")); + assert_eq!(snapshot.host.platform_name, APP_HOST_PLATFORM); + assert_eq!(snapshot.host.operating_system, std::env::consts::OS); + assert_eq!(snapshot.host.runtime_origin, APP_RUNTIME_ORIGIN); + assert!(!snapshot.host.host_locale.trim().is_empty()); } #[test] fn runtime_config_rejects_empty_required_fields() { let env = BTreeMap::from([ (APP_RUNTIME_MODE_ENV, "localhost-dev".to_owned()), - (APP_RUN_ID_ENV, "".to_owned()), ( APP_DEFAULT_NOSTR_RELAY_URL_ENV, - "ws://127.0.0.1:8080".to_owned(), + "".to_owned(), ), - (APP_LOCAL_LOG_ROOT_ENV, "/tmp/radroots/logs".to_owned()), ]); - let error = AppRuntimeConfig::from_env_with(|name| env.get(name).cloned()) - .expect_err("missing run id should fail"); + let error = AppRuntimeConfig::from_env_with( + |name| env.get(name).cloned(), + PathBuf::from("/tmp/default-logs"), + ) + .expect_err("missing relay env should fail"); assert!( - matches!(error, AppRuntimeConfigError::MissingField(APP_RUN_ID_ENV)), + matches!( + error, + AppRuntimeConfigError::MissingField(APP_DEFAULT_NOSTR_RELAY_URL_ENV) + ), "unexpected error: {error}" ); } @@ -535,20 +454,17 @@ mod tests { fn runtime_config_rejects_missing_default_nostr_relay_url() { let env = BTreeMap::from([ (APP_RUNTIME_MODE_ENV, "localhost-dev".to_owned()), - ( - APP_RUN_ID_ENV, - "run-localhost-dev-20260417T000000Z-deadbeefcafefeed".to_owned(), - ), - (APP_DEFAULT_NOSTR_RELAY_URL_ENV, "".to_owned()), - (APP_LOCAL_LOG_ROOT_ENV, "/tmp/radroots/logs".to_owned()), ]); - let error = AppRuntimeConfig::from_env_with(|name| env.get(name).cloned()) + let error = AppRuntimeConfig::from_env_with( + |name| env.get(name).cloned(), + PathBuf::from("/tmp/default-logs"), + ) .expect_err("missing default relay url should fail"); assert!( matches!( error, - AppRuntimeConfigError::MissingField(APP_DEFAULT_NOSTR_RELAY_URL_ENV) + AppRuntimeConfigError::MissingEnv(APP_DEFAULT_NOSTR_RELAY_URL_ENV) ), "unexpected error: {error}" );