feat: serve remote network diagnostics from the FFI#242
Open
okdistribute wants to merge 3 commits into
Open
Conversation
The dashboard's Run Diagnostics button dials back into an endpoint, which needs a capability grant and a handler for the n0/n0des-client-host/1 ALPN. Neither was reachable through the bindings, so the button stayed disabled for every FFI endpoint (#241). ServicesOptions gains remote_diagnostics: when set, create() grants NetDiagnosticsCap::GetAny to the platform endpoint named in the API secret. The grant runs in a background task owned by the client and retries with backoff, since the feature targets endpoints with bad networks, which are exactly the ones likely to start offline. Serving the dial-back has two entry points because the internal router only exists when protocols are registered at bind: services_client_host() returns a ProtocolCreator to mount under client_host_alpn() at bind time, and the ClientHost object exposes handle_connection() for apps that drive their own accept loop. The round-trip test mirrors iroh-services' own client_host tests over irpc, hence the new dev-dependencies. Python and Kotlin get the cheap validation tests; they exercise the uniffi-generated API names in CI. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Same surface as the uniffi core: a remoteDiagnostics option on ServicesClient.create that grants the net-diagnostics capability in a retrying background task, plus ClientHost.handleConnection and clientHostAlpn() for serving the dial-back from a manual accept loop. iroh-js has no router, so there is no bind-time mount here; the handleConnection docs warn that the promise resolves only when the remote closes, so it must not be awaited inline in the accept loop. The regenerated index.js also picks up the 1.0.0-rc.1 version-check strings; the committed copy was generated before the version bump. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
IrohError is a uniffi object error, so the Rust Display text does not land in the foreign exception's native message: Kotlin's Exception .message property is null and Python's str(e) is bare. Both carry the text in the exported message() method instead. The ssh-key guard tests asserted on the native message and failed in CI; the Rust and JS variants were unaffected (napi maps the message through). Verified locally against freshly generated bindings: 20/20 python, 20/20 kotlin JVM. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #241.
The dashboard's Run Diagnostics button dials back into an endpoint over the
n0/n0des-client-host/1ALPN, authorized by a capability token the endpoint grants to the platform. Both halves were Rust-only, so the button stayed disabled for every FFI endpoint. This exposes them with one option plus one mount:Design notes
remote_diagnosticsgrantsNetDiagnosticsCap::GetAnyto the platform endpoint named in the API secret, in a background task owned by the client that retries with backoff. The feature targets endpoints with bad networks, which are exactly the ones likely to start offline; a one-shot grant would silently strand them. Requires an api-secret credential (the ssh-key path carries no platform endpoint to grant to).iroh::protocol::Routeraccepts no post-spawn registrations:services_client_host()(a built-inProtocolCreator) for bind-time mounting, andClientHost.handle_connection()for manual accept loops. iroh-js has no router, so it gets only the latter.handle_connectionresolves when the remote closes the connection; the docs in both bindings warn against awaiting it inline in the accept loop.iroh-jsmirrors it in napi with regeneratedindex.js/index.d.ts(the regen also picks up the1.0.0-rc.1version-check strings; the committed copy predated the version bump).Tests
client_hosttests; needs the newirpc/irpc-irohdev-deps). Note it is slow by construction (~20s of offline relay/net-report timeouts; no FFI knob to shorten them). Plus a cheap accept-loop wiring test and option-validation tests.Upstream observations (out of scope, filing separately if wanted)
verify_rcanin iroh-services checks issuer/audience/origin but never token expiry, so dial-back grants effectively outliveDEFAULT_CAP_EXPIRY.ClientHost::handle_connectionholds the connection until the remote closes; closing server-side after the report would free handlers sooner.ssh_key_pemcredential path cannot set a remote, soClientBuilder::build()always fails withMissingRemote; pre-existing and untouched here.🤖 Generated with Claude Code