Skip to content

Commit 5d315ac

Browse files
Resolve identities root inside setup() for Android/iOS (#7)
* Resolve identities root inside setup() so Android can initialize On desktop, identities root comes from $DMP_DESKTOP_HOME / $DMP_CONFIG_HOME / $HOME, resolved before the Tauri builder runs. Mobile sandboxes don't expose $HOME, so that path bombed with 'cannot resolve identities root' before any UI could come up — the process exit-2'd inside the JNI bridge and crash-looped. Defer root resolution to the setup() callback. On Android/iOS, ask Tauri for app_local_data_dir() (per-app private storage, guaranteed writable). Desktop behavior is unchanged: same env-driven resolution, same error surface if HOME is unset. Verified locally: APK now gets past the early HOME crash. A separate tao/Tauri runtime panic in onActivityCreate is the next blocker — filed separately. * gitignore: drop src-tauri/gen/ regenerated by mobile init Tauri rebuilds gen/android (and gen/ios when wired) on every `cargo tauri android init`, so we don't track it. Eliminates the '1 uncommitted change' warning when local mobile builds run on the side. Promote to a tracked dir if/when we customize the AndroidManifest / icons / signing config. * clippy: collapse nested if/let blocks into 2024 if-let chains Rust 1.95 + edition 2024 promoted `clippy::collapsible_if` and the `if let chains` syntax. CI runs clippy with `-D warnings`, so the four pre-existing nested patterns now fail the build: src/commands/identity.rs:485 src/commands/nodes.rs:403 src/commands/nodes.rs:482 src/commands/nodes.rs:869 Mechanical rewrite — same control flow, same behavior, just expressed as `if let X && cond { ... }` instead of `if let X { if cond { ... } }`. Required edition 2024 (already set on this branch via main).
1 parent 2fa5a4b commit 5d315ac

4 files changed

Lines changed: 48 additions & 36 deletions

File tree

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ node_modules
55
/package
66
dist/
77

8+
# Tauri mobile scaffolding — regenerated by `tauri android/ios init`
9+
# on every build. Commit explicitly only once we need to customize the
10+
# AndroidManifest / icons / signing config.
11+
src-tauri/gen/
12+
813
# Environment / local overrides
914
.env
1015
.env.*

src-tauri/src/commands/identity.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -482,10 +482,10 @@ pub async fn update_publish_config(
482482
// can't swap them at runtime, so drop it and let the UI re-prompt
483483
// for the passphrase before the next unlock.
484484
let mut guard = state.active.write().await;
485-
if let Some(active) = guard.as_ref() {
486-
if active.username == username {
487-
*guard = None;
488-
}
485+
if let Some(active) = guard.as_ref()
486+
&& active.username == username
487+
{
488+
*guard = None;
489489
}
490490
drop(guard);
491491

src-tauri/src/commands/nodes.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -400,10 +400,10 @@ async fn directory_feed_cache_slot() -> &'static DirectoryFeedCache {
400400
/// enrichment on top of the curated list.
401401
async fn fetch_directory_feed() -> Vec<DirectoryNode> {
402402
let slot = directory_feed_cache_slot().await;
403-
if let Some((stored_at, ref cached)) = *slot.lock() {
404-
if stored_at.elapsed() < DIRECTORY_FEED_TTL {
405-
return cached.clone();
406-
}
403+
if let Some((stored_at, ref cached)) = *slot.lock()
404+
&& stored_at.elapsed() < DIRECTORY_FEED_TTL
405+
{
406+
return cached.clone();
407407
}
408408

409409
let Ok(client) = reqwest::ClientBuilder::new()
@@ -479,10 +479,10 @@ pub async fn list_known_nodes() -> CommandResult<Vec<KnownNodeStatus>> {
479479
let mut slots: Vec<Option<DiscoveredNode>> =
480480
(0..WELL_KNOWN_NODES.len()).map(|_| None).collect();
481481
while let Some(joined) = set.join_next().await {
482-
if let Ok((idx, live)) = joined {
483-
if let Some(slot) = slots.get_mut(idx) {
484-
*slot = live;
485-
}
482+
if let Ok((idx, live)) = joined
483+
&& let Some(slot) = slots.get_mut(idx)
484+
{
485+
*slot = live;
486486
}
487487
}
488488

@@ -866,10 +866,10 @@ fn strip_endpoint_to_host(endpoint: &str) -> String {
866866
let host_only = no_scheme.split('/').next().unwrap_or(no_scheme);
867867
// Handle bracketed IPv6 literals: `[::1]:8443` → `::1`,
868868
// `[::1]` → `::1`. Python's CLI does the same.
869-
if let Some(rest) = host_only.strip_prefix('[') {
870-
if let Some(end) = rest.find(']') {
871-
return rest[..end].to_string();
872-
}
869+
if let Some(rest) = host_only.strip_prefix('[')
870+
&& let Some(end) = rest.find(']')
871+
{
872+
return rest[..end].to_string();
873873
}
874874
if let Some((host, _port)) = host_only.rsplit_once(':') {
875875
// Bare-IPv6 (more than one `:`, no brackets) isn't a valid

src-tauri/src/lib.rs

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,32 +24,39 @@ fn version() -> String {
2424

2525
/// Build the Tauri runtime.
2626
///
27-
/// Identities-root resolution order mirrors the CLI:
28-
/// `$DMP_DESKTOP_HOME` > `$DMP_CONFIG_HOME/identities` >
29-
/// `$HOME/.dmp/identities`.
27+
/// Identities-root resolution differs by platform:
28+
/// - Desktop: `$DMP_DESKTOP_HOME` > `$DMP_CONFIG_HOME/identities` >
29+
/// `$HOME/.dmp/identities` (mirrors the CLI).
30+
/// - Mobile (Android / iOS): the per-app local-data directory the OS
31+
/// hands us via `app.path().app_local_data_dir()`. Mobile sandboxes
32+
/// don't expose `$HOME` so the env-driven resolution can't run, and
33+
/// identities have to live inside the app's private storage.
34+
///
35+
/// The mobile branch needs the `App` handle, so root resolution is
36+
/// deferred into the `setup()` callback rather than computed before the
37+
/// builder runs.
3038
#[cfg_attr(mobile, tauri::mobile_entry_point)]
3139
pub fn run() {
3240
init_tracing();
3341

34-
let root = match AppState::default_root() {
35-
Ok(p) => p,
36-
Err(e) => {
37-
eprintln!("dnsmesh-desktop: cannot resolve identities root: {e:#}");
38-
std::process::exit(2);
39-
}
40-
};
41-
if let Err(e) = std::fs::create_dir_all(&root) {
42-
eprintln!(
43-
"dnsmesh-desktop: cannot create identities root {}: {e}",
44-
root.display()
45-
);
46-
std::process::exit(2);
47-
}
48-
let app_state = AppState::new(root);
49-
5042
tauri::Builder::default()
5143
.plugin(tauri_plugin_opener::init())
52-
.manage(app_state)
44+
.setup(|app| {
45+
use tauri::Manager;
46+
let root = if cfg!(any(target_os = "android", target_os = "ios")) {
47+
app.path()
48+
.app_local_data_dir()
49+
.map_err(|e| format!("app_local_data_dir unavailable: {e}"))?
50+
.join("identities")
51+
} else {
52+
AppState::default_root()
53+
.map_err(|e| format!("cannot resolve identities root: {e:#}"))?
54+
};
55+
std::fs::create_dir_all(&root)
56+
.map_err(|e| format!("cannot create identities root {}: {e}", root.display()))?;
57+
app.manage(AppState::new(root));
58+
Ok(())
59+
})
5360
.invoke_handler(tauri::generate_handler![
5461
version,
5562
// identity

0 commit comments

Comments
 (0)