wasm: gate UniFFI + reqwest timeout + enable gossip net (15 → 3 errors)
- UniFFI is the native FFI surface; cfg_attr all of it (setup_scaffolding, Record derives, export/callback_interface/constructor) to cfg(not(wasm32)). The wasm binding layer will be wasm-bindgen instead. - rendezvous_register: reqwest Builder::timeout isn't on the wasm fetch backend — cfg it (browser bounds the request itself). - iroh-gossip on wasm needs default-features=false + features=["net"] for the net module (Gossip/GossipSender/api). wasm32 build now down to the two genuinely structural blockers: the tokio multi-thread runtime (new_multi_thread → spawn_local) and the iroh wasm endpoint (presets::N0 is native-only — pulls ring/portmapper). Native unaffected (verified). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -56,7 +56,7 @@ getrandom = "0.4.3"
|
||||
getrandom_02 = { package = "getrandom", version = "0.2", features = ["js"] }
|
||||
wasm-bindgen-futures = "0.4"
|
||||
iroh = { version = "1", optional = true, default-features = false }
|
||||
iroh-gossip = { version = "0.101", optional = true, default-features = false }
|
||||
iroh-gossip = { version = "0.101", optional = true, default-features = false, features = ["net"] }
|
||||
iroh-blobs = { version = "0.103", optional = true, default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -99,11 +99,15 @@ async fn rendezvous_register(server: &str, room: &str, my_id: &str) -> Vec<Endpo
|
||||
}
|
||||
let url = format!("{}/rendezvous/register", server.trim_end_matches('/'));
|
||||
let body = serde_json::json!({ "room": room, "id": my_id });
|
||||
// Bounded — a stuck rendezvous must never wedge the transport.
|
||||
// Bounded — a stuck rendezvous must never wedge the transport. On wasm the
|
||||
// fetch backend has no Builder::timeout (the browser bounds it instead).
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let client = reqwest::Client::builder()
|
||||
.timeout(std::time::Duration::from_secs(8))
|
||||
.build()
|
||||
.unwrap_or_default();
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let client = reqwest::Client::new();
|
||||
let mut req = client.post(&url).json(&body);
|
||||
// Optional bearer token, matching the rendezvous's TETHER_RENDEZVOUS_TOKEN.
|
||||
if let Ok(token) = std::env::var("TETHER_RENDEZVOUS_TOKEN") {
|
||||
|
||||
@@ -40,11 +40,15 @@ mod rtc;
|
||||
|
||||
use crypto::Crypto;
|
||||
|
||||
// UniFFI is the native FFI surface (Swift/Kotlin). On wasm the bindings come
|
||||
// from wasm-bindgen instead, so gate all of it out for wasm32.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
uniffi::setup_scaffolding!();
|
||||
|
||||
/// 1:1 with the Go server `Message`, minus the RTC `signal` blob.
|
||||
/// `type` is renamed to `kind` (reserved word in the target languages).
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, uniffi::Record)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), derive(uniffi::Record))]
|
||||
pub struct Message {
|
||||
#[serde(rename = "type", default)]
|
||||
pub kind: String,
|
||||
@@ -67,7 +71,7 @@ pub struct Message {
|
||||
/// Implemented on the foreign side (Swift/Kotlin) or natively (desktop agent).
|
||||
/// Callbacks fire on the engine's runtime thread — marshal to the UI thread
|
||||
/// on the consumer side.
|
||||
#[uniffi::export(callback_interface)]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), uniffi::export(callback_interface))]
|
||||
pub trait MessageHandler: Send + Sync {
|
||||
fn on_message(&self, msg: Message);
|
||||
fn on_status(&self, connected: bool);
|
||||
@@ -78,7 +82,8 @@ pub trait MessageHandler: Send + Sync {
|
||||
/// A tether device discovered on the local network (mDNS). Surfaced to the UI
|
||||
/// for an AirDrop-style "nearby devices" list. `room` lets the UI offer to pair
|
||||
/// (join that device's room).
|
||||
#[derive(Clone, Debug, uniffi::Record)]
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), derive(uniffi::Record))]
|
||||
pub struct Peer {
|
||||
pub id: String, // stable device id (`from`)
|
||||
pub name: String, // friendly name, e.g. "Patrick's MacBook"
|
||||
@@ -94,7 +99,8 @@ type Discovered = Arc<Mutex<HashMap<String, (Peer, Instant)>>>;
|
||||
/// A delivery acknowledgement: device `from` (named `name`) received a clipboard
|
||||
/// whose text matches `text`. Lets the sender show "delivered to <name>" instead
|
||||
/// of asking. Auto-sent by the engine on every inbound clipboard.
|
||||
#[derive(Clone, Debug, uniffi::Record)]
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), derive(uniffi::Record))]
|
||||
pub struct Receipt {
|
||||
pub from: String, // device that received it
|
||||
pub name: String, // its friendly name
|
||||
@@ -136,7 +142,7 @@ fn directly_covered(direct: &DirectSet, present: &PresentSet) -> bool {
|
||||
/// Defined once here and exported so every client (Swift/Kotlin/agent) derives
|
||||
/// the SAME room — that's what puts all of one account's devices together across
|
||||
/// LAN, relay, and RTC. Empty account → empty (caller falls back to a device id).
|
||||
#[uniffi::export]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), uniffi::export)]
|
||||
pub fn room_for_account(account: String) -> String {
|
||||
use sha2::{Digest, Sha256};
|
||||
if account.is_empty() {
|
||||
@@ -194,7 +200,8 @@ pub(crate) struct IncomingFile {
|
||||
}
|
||||
|
||||
/// Progress of an in-flight file transfer, for the UI.
|
||||
#[derive(Clone, Debug, uniffi::Record)]
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), derive(uniffi::Record))]
|
||||
pub struct Transfer {
|
||||
pub name: String,
|
||||
pub received: u64, // bytes transferred so far
|
||||
@@ -320,7 +327,7 @@ trait Transport: Send + Sync {
|
||||
fn send_file(&self, _rt: &Handle, _id: String, _name: String, _mime: String, _data: Vec<u8>) {}
|
||||
}
|
||||
|
||||
#[derive(uniffi::Object)]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), derive(uniffi::Object))]
|
||||
pub struct Engine {
|
||||
cfg: Config,
|
||||
rt: Arc<tokio::runtime::Runtime>,
|
||||
@@ -349,7 +356,7 @@ pub struct Engine {
|
||||
iroh_id: Arc<Mutex<Option<String>>>,
|
||||
}
|
||||
|
||||
#[uniffi::export]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), uniffi::export)]
|
||||
impl Engine {
|
||||
/// `server` is the bus base URL, e.g. "http://192.168.11.233:8765".
|
||||
/// `from` is this device's stable id (echo suppression); `source` a label.
|
||||
@@ -357,7 +364,7 @@ impl Engine {
|
||||
/// `account` is a shared identity (Apple/Google `sub`); devices with the
|
||||
/// same non-empty account auto-pair on the LAN regardless of room. Pass ""
|
||||
/// when signed out.
|
||||
#[uniffi::constructor]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), uniffi::constructor)]
|
||||
pub fn new(
|
||||
server: String,
|
||||
room: String,
|
||||
|
||||
Reference in New Issue
Block a user