Skip to content

Mobile iroh peer discovery parity: feed native browse results into an in-process AddressLookup #310

Description

@momics

Summary

Bring mobile (iOS/Android) iroh peer discovery to parity with desktop by feeding natively-discovered peers into an in-process iroh AddressLookup registered on the endpoint, so a mobile node can auto-dial a discovered iroh peer by node-id alone — exactly as desktop does today.

Scope reset (see ADR-016). This epic previously proposed a standards-compliant, general DNS-SD layer (browse/advertise arbitrary non-iroh services, custom TXT schema, dns-sd/avahi-browse interop). ADR-016 rejects that direction: iroh-http stays lean and iroh-only. advertise/browse remain scoped to iroh peers and continue to map onto the official iroh-mdns-address-lookup crate's advertise() / subscribe(). General DNS-SD, if ever wanted, belongs in a separate package outside iroh-http. Desktop is unchanged; the only remaining work is the mobile bridge below. The rejected general-DNS-SD spike is preserved on branch momics-spike-mdns-sd-addresslookup as the record of why.

Evidence / Motivation

  • Desktop already auto-dials by node-id. crates/iroh-http-discovery/src/lib.rs:115-122 builds an MdnsAddressLookup and registers it via ep.address_lookup().add(mdns), so iroh's dialer transparently resolves discovered peers by node-id. iroh core's discovery contract is exactly this AddressLookup (publish / resolve-by-node-id) — a targeted resolver that feeds the dialer (verified against iroh 1.0.1 src/address_lookup.rs:333).
  • Mobile stops at "report to JS". packages/iroh-http-tauri/src/mobile_mdns.rs bridges to NWBrowser/NWListener (iOS) and NsdManager (Android) and surfaces MobileDiscoveryEvent { node_id, addrs } (:97-104) up to the browse API. But nothing feeds those results back into an in-process AddressLookup on the endpoint. Result: on mobile, a discovered peer is only visible as a UI list entry — a subsequent fetch(nodeId) has no address to dial unless the app plumbs addrs through by hand. Desktop needs none of that.
  • Interop groundwork already shipped. The pk-TXT vs instance-name mismatch (mobile couldn't see desktop-advertised nodes) was fixed in Mobile mDNS browse cannot discover desktop-advertised iroh nodes (pk-TXT vs instance-name mismatch) #318 / fix(tauri): mobile mDNS browse falls back to instance name for node-id (#318) #320: mobile browse now falls back to the DNS-SD instance name for the node-id when no pk TXT is present.

Impact

  • Users: on iOS/Android, discovering an iroh peer over the LAN is enough to then fetch(nodeId) it — no manual address plumbing — matching desktop behaviour.
  • Existing callers: additive. The serviceName-scoped browse/advertise API and the MobileDiscoveryEvent surface are unchanged; this wires an internal auto-dial path.
  • Architecture: consistent "discovery feeds the dialer" model across all platforms; mobile joins desktop on iroh's native AddressLookup seam.

Implementation plan

  1. Mobile AddressLookup bridge (Rust, tauri crate). Implement an impl iroh::AddressLookup whose resolve(node_id) yields an Item/EndpointAddr built from the addrs the native layer discovered for that node-id (the data already carried on MobileDiscoveryEvent). Drive it from the existing browse_poll event stream (maintain a node-id → addrs map, updated on discovered, evicted on expired).
  2. Register it on the endpoint via ep.address_lookup().add(...) on mobile targets, the same call desktop makes — so iroh's dialer resolves discovered peers transparently.
  3. Expiry mapping. Honour MobileDiscoveryEvent { kind: "expired" } so stale addrs are dropped from the lookup (desktop gets this from the mdns crate's DiscoveryEvent::Expired).
  4. Keep the browse-to-JS surface intact — the bridge is additive; the discovery event stream to JS continues unchanged.

Honour the core→adapter ripple only if a shared type changes; the expectation is this is contained to the tauri crate (mobile_mdns.rs + endpoint wiring) since desktop already has the pattern.

Acceptance criteria

  1. On iOS and Android, after browse discovers an iroh peer, fetch(nodeId) (or a dial by node-id) connects without the caller supplying addresses — parity with desktop.
  2. Discovered peers are registered on the endpoint's AddressLookup; expired events remove them.
  3. The existing serviceName-scoped browse/advertise API and MobileDiscoveryEvent surface are unchanged (additive only).
  4. Behaviour is verified on-device for both platforms (owed since fix(tauri): add path-change subscription parity (#314) #317/fix(tauri): mobile mDNS browse falls back to instance name for node-id (#318) #320 mobile changes were reasoned + manual-repro only, not on-device), with a documented manual repro: desktop advertise → mobile browse → mobile fetch(nodeId) succeeds.
  5. No general DNS-SD surface is added; advertise/browse stay iroh-node-scoped per ADR-016.

Priority

P2 — important; mobile discovery is functionally incomplete without it.

Area

connectivity

Metadata

Metadata

Assignees

No one assigned

    Labels

    connectivityPeer discovery and connectionenhancementNew feature or requestepicTracking issue for a multi-slice initiative

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions