Lightning P2P has two runtimes:
- Browser runtime: marketing site, SEO pages, and receive handoff. It does not transfer files.
- Native runtime: Tauri desktop/mobile shell plus Rust transfer engine. Real transfers run here.
Receive handoff links use /receive#t=<ticket>. The ticket stays in the URL fragment so it is not sent to the website server in normal HTTP requests.
| Area | Owner | Notes |
|---|---|---|
| Transfer engine | Rust | iroh endpoint, iroh-blobs import/fetch/export, BLAKE3 verification |
| Discovery | Rust | iroh local-network discovery, nearby-share ALPN protocol, registry state |
| Persistence | Rust | sled history/peer cache, settings JSON, profile-scoped iroh identity |
| UI state | TypeScript | view state, optimistic UX, event subscriptions |
| IPC | Tauri | typed wrappers in src/lib/tauri.ts; no frontend direct networking |
| Website SEO/AEO | TypeScript/scripts | src/content/web-pages.json plus scripts/build-web-metadata.mjs |
| Platform shell | Tauri/Android/iOS | thin platform adapters only |
src-tauri/src/
commands/ Tauri command handlers and payload mapping
crypto/ profile-scoped iroh identity key loading
node/ iroh endpoint, runtime status, nearby discovery/protocol
storage/ sled database, transfer history, peers, settings
transfer/ sender, receiver, export, destination, progress, metrics
telemetry/ tracing setup and diagnostics
error.rs application error type
lib.rs Tauri setup, managed state, command registration
The current crate remains intentionally single-crate. The next architecture step is not a workspace split; it is extracting smaller Rust modules behind the same crate interface so the core remains easy to test and Android can reuse it.
- React calls a typed Tauri wrapper in
src/lib/tauri.ts. - A Tauri command validates arguments and delegates to Rust transfer code.
- Sender imports files into iroh-blobs and creates a
BlobTicket. - Receiver parses the ticket, fetches through iroh-blobs, verifies content, and exports to the configured download directory.
- Rust emits transfer events; React renders progress.
- Rust persists history/peer records.
The frontend does not choose receive destinations anymore. It asks Rust to receive, and Rust uses the persisted settings snapshot.
- The iroh endpoint enables local-network discovery where the platform supports it.
- A background loop subscribes to iroh discovery events and keeps a candidate map.
- Candidates are queried over
lightning-p2p/nearby-share/1. - The nearby protocol returns active-share metadata only when local discovery is enabled.
- The registry normalizes, dedupes, and sorts records before emitting UI updates.
- If all peer queries fail during a refresh, the previous snapshot is retained to avoid flicker.
Important caveat: the current settings toggle controls nearby share listings and active-share responses. It does not yet rebuild the iroh endpoint to disable all local-network connectivity metadata.
The iroh endpoint identity is persistent and profile-scoped:
- OS keychain is preferred.
- Keychain account names are scoped by data-directory fingerprint.
- The old global keychain entry is only migrated for the default profile.
- If keychain storage is unavailable, a profile-local
iroh-secret-key.hexfallback is used.
This prevents LIGHTNING_P2P_PROFILE=alice and LIGHTNING_P2P_PROFILE=bob from sharing a NodeId.
The Rust crate builds as lib, staticlib, and cdylib, and lib.rs exposes the Tauri mobile entry point. The stable Android sideload path starts at v0.4.6 and depends on these boundaries staying clean:
- file picker and share-sheet
content://imports are resolved by Android glue before Rust imports content - receive/export behavior stays in Rust, with Android
MediaStorepublishing at the platform boundary - QR scanner permission flow remains a thin Tauri/platform adapter
- local-network discovery and multicast behavior stay diagnostic and user-controlled
- Windows-to-Android and Android-to-Windows transfers still use iroh QUIC and iroh-blobs
- signed APK/AAB install trust is documented through release notes, checksums, and signer fingerprints
See android-alpha.md.
- Split
node/nearby.rsinto registry, candidates, and loop modules. - Split
storage/settings.rsinto model, path resolution, and file persistence modules. - Add a node supervisor so relay/local-discovery settings can restart the endpoint safely.
- Add event-sink traits so Rust core code is less coupled to Tauri
Window/AppHandle. - Add IPC contract tests for command names and serialized event payloads.