commit 243886c1de9d624db38ea04b51f72c6e47bfffe2
parent 9c804bf0200c8fa3680720ec2881ba3e1e1a4bea
Author: triesap <tyson@radroots.org>
Date: Sun, 24 May 2026 08:39:53 +0000
core: centralize shared local events paths
Diffstat:
3 files changed, 104 insertions(+), 43 deletions(-)
diff --git a/crates/launchers/desktop/src/runtime.rs b/crates/launchers/desktop/src/runtime.rs
@@ -9,7 +9,8 @@ use chrono::{Duration, Utc};
use radroots_app_core::{
AppBuildIdentity, AppDesktopRuntimePaths, AppRuntimeCapture, AppRuntimeMode,
AppRuntimePathsError, AppRuntimeSnapshot, AppSharedAccountsPaths, PackDayExportWriteError,
- prepare_pack_day_export_bundle_at_data_root, write_prepared_pack_day_export_bundle,
+ prepare_pack_day_export_bundle_at_data_root,
+ shared_local_events_database_path_from_shared_accounts, write_prepared_pack_day_export_bundle,
};
use radroots_app_models::{
ActiveSurface, AppActivityContext, AppActivityKind, AppIdentityProjection, AppStartupGate,
@@ -83,8 +84,6 @@ use crate::remote_signer::{
};
const APP_DATABASE_FILE_NAME: &str = "app.sqlite3";
-const SHARED_LOCAL_EVENTS_DIR: &str = "local_events";
-const SHARED_LOCAL_EVENTS_DB_FILE_NAME: &str = "local_events.sqlite";
const SYNC_TRANSPORT_UNAVAILABLE_MESSAGE: &str = "remote sync transport is not configured";
#[derive(Debug, Default)]
@@ -955,7 +954,7 @@ impl DesktopAppRuntimeState {
}
let database_path = paths.app.data.join(APP_DATABASE_FILE_NAME);
let sqlite_store = AppSqliteStore::open(DatabaseTarget::Path(database_path.clone()))?;
- let shared_local_events_database_path = shared_local_events_database_path(&paths)?;
+ let shared_local_events_database_path = paths.shared_local_events_database_path()?;
let _ = sqlite_store
.import_shared_local_events_from_path(shared_local_events_database_path.as_path())?;
let database_schema_version = sqlite_store.schema_version()?;
@@ -3917,35 +3916,6 @@ enum DesktopAppRuntimeBootstrapError {
Sqlite(#[from] AppSqliteError),
#[error(transparent)]
State(#[from] AppStateStoreError),
- #[error("desktop app data root must be nested under the Radroots data root")]
- SharedLocalEventsPath,
-}
-
-fn shared_local_events_database_path(
- paths: &AppDesktopRuntimePaths,
-) -> Result<PathBuf, DesktopAppRuntimeBootstrapError> {
- let data_root = paths
- .app
- .data
- .parent()
- .and_then(|apps_root| apps_root.parent())
- .ok_or(DesktopAppRuntimeBootstrapError::SharedLocalEventsPath)?;
- Ok(data_root
- .join("shared")
- .join(SHARED_LOCAL_EVENTS_DIR)
- .join(SHARED_LOCAL_EVENTS_DB_FILE_NAME))
-}
-
-fn shared_local_events_database_path_from_shared_accounts(
- paths: &AppSharedAccountsPaths,
-) -> Option<PathBuf> {
- Some(
- paths
- .data_root
- .parent()?
- .join(SHARED_LOCAL_EVENTS_DIR)
- .join(SHARED_LOCAL_EVENTS_DB_FILE_NAME),
- )
}
fn current_runtime_time_ms() -> Result<i64, AppSqliteError> {
@@ -6066,8 +6036,9 @@ mod tests {
.generate_local_account(Some("Buyer".to_owned()))
.expect("account should generate")
);
- let database_path =
- super::shared_local_events_database_path(&paths).expect("shared local events path");
+ let database_path = paths
+ .shared_local_events_database_path()
+ .expect("shared local events path");
if let Some(parent) = database_path.parent() {
fs::create_dir_all(parent).expect("shared local events parent directory");
}
@@ -11180,8 +11151,9 @@ mod tests {
}
fn append_cli_local_listing_records(paths: &AppDesktopRuntimePaths, account_id: &str) {
- let database_path =
- super::shared_local_events_database_path(paths).expect("shared local events path");
+ let database_path = paths
+ .shared_local_events_database_path()
+ .expect("shared local events path");
if let Some(parent) = database_path.parent() {
fs::create_dir_all(parent).expect("shared local events directory should create");
}
@@ -11278,8 +11250,9 @@ mod tests {
title: &str,
created_at_ms: i64,
) {
- let database_path =
- super::shared_local_events_database_path(paths).expect("shared local events path");
+ let database_path = paths
+ .shared_local_events_database_path()
+ .expect("shared local events path");
if let Some(parent) = database_path.parent() {
fs::create_dir_all(parent).expect("shared local events directory should create");
}
@@ -11467,8 +11440,9 @@ mod tests {
}
fn shared_local_event_records(paths: &AppDesktopRuntimePaths) -> Vec<LocalEventRecord> {
- let database_path =
- super::shared_local_events_database_path(paths).expect("shared local events path");
+ let database_path = paths
+ .shared_local_events_database_path()
+ .expect("shared local events path");
let executor =
SqliteExecutor::open(database_path.as_path()).expect("open shared local events db");
let store = LocalEventsStore::new(executor);
diff --git a/crates/shared/core/src/lib.rs b/crates/shared/core/src/lib.rs
@@ -23,7 +23,9 @@ pub use paths::{
AppSharedAccountsPaths, AppSharedIdentityPaths, SHARED_ACCOUNTS_NAMESPACE,
SHARED_ACCOUNTS_NAMESPACE_KIND, SHARED_ACCOUNTS_NAMESPACE_VALUE,
SHARED_ACCOUNTS_STORE_FILE_NAME, SHARED_IDENTITIES_NAMESPACE, SHARED_IDENTITIES_NAMESPACE_KIND,
- SHARED_IDENTITIES_NAMESPACE_VALUE, SHARED_IDENTITY_FILE_NAME,
+ SHARED_IDENTITIES_NAMESPACE_VALUE, SHARED_IDENTITY_FILE_NAME, SHARED_LOCAL_EVENTS_DB_FILE_NAME,
+ SHARED_LOCAL_EVENTS_NAMESPACE, SHARED_LOCAL_EVENTS_NAMESPACE_KIND,
+ SHARED_LOCAL_EVENTS_NAMESPACE_VALUE, shared_local_events_database_path_from_shared_accounts,
};
pub use runtime::{
APP_DEFAULT_NOSTR_RELAY_URL_ENV, APP_HOST_PLATFORM, APP_ID, APP_LOCAL_LOG_ROOT_ENV, APP_NAME,
diff --git a/crates/shared/core/src/paths.rs b/crates/shared/core/src/paths.rs
@@ -17,6 +17,10 @@ pub const SHARED_IDENTITIES_NAMESPACE_KIND: &str = "shared";
pub const SHARED_IDENTITIES_NAMESPACE_VALUE: &str = "identities";
pub const SHARED_IDENTITIES_NAMESPACE: &str = "shared/identities";
pub const SHARED_IDENTITY_FILE_NAME: &str = "default.json";
+pub const SHARED_LOCAL_EVENTS_NAMESPACE_KIND: &str = "shared";
+pub const SHARED_LOCAL_EVENTS_NAMESPACE_VALUE: &str = "local_events";
+pub const SHARED_LOCAL_EVENTS_NAMESPACE: &str = "shared/local_events";
+pub const SHARED_LOCAL_EVENTS_DB_FILE_NAME: &str = "local_events.sqlite";
pub const APP_PATHS_PROFILE_ENV: &str = "RADROOTS_APP_PATHS_PROFILE";
pub const APP_PATHS_REPO_LOCAL_ROOT_ENV: &str = "RADROOTS_APP_PATHS_REPO_LOCAL_ROOT";
@@ -74,7 +78,7 @@ impl AppRuntimeHostEnvironment {
appdata_dir: read_env("APPDATA").map(PathBuf::from),
localappdata_dir: read_env("LOCALAPPDATA").map(PathBuf::from),
paths_profile: read_env(APP_PATHS_PROFILE_ENV)
- .and_then(|value| value.into_string().ok()),
+ .map(|value| value.to_string_lossy().into_owned()),
repo_local_root: read_env(APP_PATHS_REPO_LOCAL_ROOT_ENV).map(PathBuf::from),
}
}
@@ -109,6 +113,12 @@ pub struct AppDesktopRuntimePaths {
pub shared_identity: AppSharedIdentityPaths,
}
+impl AppSharedAccountsPaths {
+ pub fn shared_local_events_database_path(&self) -> Option<PathBuf> {
+ shared_local_events_database_path_from_shared_accounts(self)
+ }
+}
+
impl AppRuntimeRoots {
pub fn current_desktop() -> Result<Self, AppRuntimePathsError> {
AppDesktopRuntimePaths::current_desktop().map(|paths| paths.app)
@@ -182,6 +192,36 @@ impl AppDesktopRuntimePaths {
},
})
}
+
+ pub fn shared_local_events_database_path(&self) -> Result<PathBuf, AppRuntimePathsError> {
+ let data_root = self
+ .app
+ .data
+ .parent()
+ .and_then(|apps_root| apps_root.parent())
+ .ok_or(AppRuntimePathsError::SharedLocalEventsPath)?;
+
+ Ok(shared_local_events_database_path_from_data_root(data_root))
+ }
+}
+
+pub fn shared_local_events_database_path_from_shared_accounts(
+ paths: &AppSharedAccountsPaths,
+) -> Option<PathBuf> {
+ Some(
+ paths
+ .data_root
+ .parent()?
+ .join(SHARED_LOCAL_EVENTS_NAMESPACE_VALUE)
+ .join(SHARED_LOCAL_EVENTS_DB_FILE_NAME),
+ )
+}
+
+fn shared_local_events_database_path_from_data_root(data_root: &Path) -> PathBuf {
+ data_root
+ .join(SHARED_LOCAL_EVENTS_NAMESPACE_KIND)
+ .join(SHARED_LOCAL_EVENTS_NAMESPACE_VALUE)
+ .join(SHARED_LOCAL_EVENTS_DB_FILE_NAME)
}
fn resolve_desktop_base_roots(
@@ -268,6 +308,7 @@ pub enum AppRuntimePathsError {
EmptyRepoLocalRoot,
UnsupportedPathProfile { value: String },
UnsupportedPlatform { platform: AppRuntimePlatform },
+ SharedLocalEventsPath,
}
impl fmt::Display for AppRuntimePathsError {
@@ -299,6 +340,8 @@ impl fmt::Display for AppRuntimePathsError {
"desktop runtime roots are unsupported on {}",
platform.label()
),
+ Self::SharedLocalEventsPath => formatter
+ .write_str("desktop app data root must be nested under the Radroots data root"),
}
}
}
@@ -314,6 +357,7 @@ mod tests {
AppDesktopRuntimePaths, AppRuntimeHostEnvironment, AppRuntimePathsError,
AppRuntimePlatform, AppRuntimeRoots, SHARED_ACCOUNTS_NAMESPACE,
SHARED_ACCOUNTS_STORE_FILE_NAME, SHARED_IDENTITIES_NAMESPACE, SHARED_IDENTITY_FILE_NAME,
+ SHARED_LOCAL_EVENTS_DB_FILE_NAME, SHARED_LOCAL_EVENTS_NAMESPACE,
};
#[test]
@@ -355,6 +399,14 @@ mod tests {
.join(SHARED_IDENTITIES_NAMESPACE)
.join(SHARED_IDENTITY_FILE_NAME)
);
+ assert_eq!(
+ paths
+ .shared_local_events_database_path()
+ .expect("shared local events path"),
+ PathBuf::from("/Users/treesap/.radroots/data")
+ .join(SHARED_LOCAL_EVENTS_NAMESPACE)
+ .join(SHARED_LOCAL_EVENTS_DB_FILE_NAME)
+ );
}
#[test]
@@ -435,6 +487,15 @@ mod tests {
PathBuf::from("/repo/infra/local/runtime/radroots/secrets/shared/identities")
.join(SHARED_IDENTITY_FILE_NAME)
);
+ assert_eq!(
+ paths
+ .shared_accounts
+ .shared_local_events_database_path()
+ .expect("shared local events path"),
+ PathBuf::from("/repo/infra/local/runtime/radroots/data")
+ .join(SHARED_LOCAL_EVENTS_NAMESPACE)
+ .join(SHARED_LOCAL_EVENTS_DB_FILE_NAME)
+ );
}
#[test]
@@ -491,6 +552,30 @@ mod tests {
);
}
+ #[cfg(unix)]
+ #[test]
+ fn malformed_env_profile_fails_closed() {
+ use std::os::unix::ffi::OsStringExt;
+
+ let env = BTreeMap::from([(
+ APP_PATHS_PROFILE_ENV,
+ OsString::from_vec(vec![0xff, b'd', b'e', b'v']),
+ )]);
+ let err = AppRuntimeRoots::for_desktop(
+ AppRuntimePlatform::Macos,
+ AppRuntimeHostEnvironment::from_env_reader(|name| env.get(name).cloned()),
+ )
+ .expect_err("malformed configured profile should fail closed");
+
+ match err {
+ AppRuntimePathsError::UnsupportedPathProfile { value } => {
+ assert!(value.contains('\u{fffd}'));
+ assert!(value.ends_with("dev"));
+ }
+ unexpected => panic!("unexpected malformed profile error: {unexpected:?}"),
+ }
+ }
+
#[test]
fn desktop_runtime_roots_require_home_dir_on_unix() {
let err = AppRuntimeRoots::for_desktop(