diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..83fc89c --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,10 @@ +[env] +MTP_TYPE_MAPS = { value = "example-type-maps.yaml", relative = true } + +# web-sys's WebTransport* bindings are behind unstable APIs, gated by this cfg. +# Scoped to the wasm32 target so it applies to the wasm crate however cargo is +# invoked (e.g. `cargo build -p mtp-wasm --target wasm32-unknown-unknown` from +# the workspace root). Cargo only reads .cargo/config.toml from the invocation +# dir and its ancestors, so the wasm crate's own config isn't seen from here. +[target.wasm32-unknown-unknown] +rustflags = ["--cfg=web_sys_unstable_apis"] diff --git a/docs/NATIVE-CLIENT.md b/docs/NATIVE-CLIENT.md index ce493d5..48d6a76 100644 --- a/docs/NATIVE-CLIENT.md +++ b/docs/NATIVE-CLIENT.md @@ -24,11 +24,12 @@ let config = ClientConfig::new("https://host.example.com:4433") .with_client_id(0); ``` -| Field | Type | Description | -|--------------|--------------------|-----------------------------------------------------| -| `url` | `String` | `https://host:port` address of the MTP host | -| `tls` | `ClientTlsConfig` | `SystemRoots` or `PinnedPem(pem_bytes)` | -| `client_id` | `u64` | Client identifier (ignored during `auth_register`) | +| Field | Type | Description | +|---------------|--------------------|-----------------------------------------------------| +| `url` | `String` | `https://host:port` address of the MTP host | +| `tls` | `ClientTlsConfig` | `SystemRoots` or `PinnedPem(pem_bytes)` | +| `client_id` | `u64` | Client identifier (ignored during `auth_register`) | +| `auth_timeout` | `Duration` (crypto) | Authentication handshake timeout (default 30s) | ### TLS Certificate Handling diff --git a/docs/NATIVE-HOST.md b/docs/NATIVE-HOST.md index dd7454d..caf92f9 100644 --- a/docs/NATIVE-HOST.md +++ b/docs/NATIVE-HOST.md @@ -29,13 +29,15 @@ let config = HostConfig::new( ) .with_authentication( /* Keyring */, - |client_id: u64| -> Option { - CLIENT_DB.lock().unwrap().get(&client_id).cloned() + |client_id: u64| { + let db = CLIENT_DB.clone(); + Box::pin(async move { db.lock().unwrap().get(&client_id).cloned() }) }, - |bundle: PublicKeyBundle| -> u64 { + |bundle: PublicKeyBundle| { + let mut db = CLIENT_DB.lock().unwrap(); let id = next_id(); - CLIENT_DB.lock().unwrap().insert(id, bundle); - id + db.insert(id, bundle); + Box::pin(async move { id }) }, ); ``` @@ -48,8 +50,8 @@ let config = HostConfig::new( | `tls_key` | `Vec` | PEM-encoded TLS private key | | `require_authentication` | `bool` (crypto) | Enable login/register handshake | | `host_keyring` | `Keyring` (crypto) | Host's signing and KEM keys | -| `get_existing_user` | `Fn(u64) -> Option + Send + Sync` (crypto) | Lookup callback for login | -| `complete_register` | `Fn(PublicKeyBundle) -> u64 + Send + Sync` (crypto) | Registration callback, returns new client ID | +| `get_existing_user` | `Fn(u64) -> Pin> + Send>> + Send + Sync` (crypto) | Async lookup callback for login | +| `complete_register` | `Fn(PublicKeyBundle) -> Pin + Send>> + Send + Sync` (crypto) | Async registration callback, returns new client ID | ### TLS @@ -262,8 +264,9 @@ verification. Must return `Some(PublicKeyBundle)` if the client ID is known, or `None` to reject. ```rust -let get_existing_user = |id: u64| -> Option { - db.lock().unwrap().get(&id).cloned() +let get_existing_user = |id: u64| { + let db = db.clone(); + Box::pin(async move { db.lock().unwrap().get(&id).cloned() }) }; ``` @@ -274,18 +277,19 @@ assign a client ID. The returned `u64` becomes the client's permanent identifier. ```rust -let complete_register = |bundle: PublicKeyBundle| -> u64 { - let mut db = db.lock().unwrap(); - let id = next_id; - next_id += 1; - db.insert(id, bundle); - id +let complete_register = |bundle: PublicKeyBundle| { + let db = db.clone(); + let id = next_id.fetch_add(1, Ordering::SeqCst); + Box::pin(async move { + db.lock().unwrap().insert(id, bundle); + id + }) }; ``` -Both callbacks are called from within `accept()` and must be `Send + Sync`. They are -invoked synchronously, so avoid long-running operations (or use `spawn_blocking` -if needed, though the callbacks are `Fn`, not `AsyncFn`). +Both callbacks are called from within `accept()` and must be `Send + Sync`. They +are `async` (returning `Pin>`) and are `.await`ed by the +host, so they can perform I/O or other async work as needed. ## Host Key Generation