fix(run): synthesize DevTools URL from VM service URI - #44
fix(run): synthesize DevTools URL from VM service URI#44jainam-bhavasar wants to merge 1 commit into
Conversation
Antoinegtir
left a comment
There was a problem hiding this comment.
Thanks for digging into this — issue #43 is real, and the core idea (parse the devtools.serve response + widen the app.debugPort field lookup) is the right one. I rebased it locally on current master and it builds + the full test suite passes, so the foundation is solid.
Before I can merge, a few things need to change. The PR is quite a bit heavier than the fix needs to be, and master has since gained a helper that overlaps with this PR. Details inline — happy to merge once these are addressed. 🙏
| // the id because the daemon may reuse the same shape for | ||
| // future methods — and the worst case is a harmless extra | ||
| // debug log line. | ||
| if let Some(result) = obj.get("result") { |
There was a problem hiding this comment.
Matching the JSON-RPC response by its {host, port} shape instead of the request id is fragile — the comment above even acknowledges it. devtools.serve is sent with id:2 (and app.restart already uses id:1), so please key the response on obj.get("id") == 2 and only fall back to the shape check if the id is absent. As written, any future daemon response that happens to carry {host, port} gets mis-tagged as a DevTools server.
| event_tx_for_task | ||
| .send(AppEvent::Flutter(FlutterEvent::Log { | ||
| level: LogLevel::Debug, | ||
| message: format!("app.devTools: {devtools_uri}"), |
There was a problem hiding this comment.
Re-emitting a synthetic app.devTools: <url> Log event just so the existing string-match loop picks it up is a workaround stacked on a workaround. You already hold devtools_slot in this scope — set it directly (*devtools_slot.lock().await = Some(devtools_uri)) instead of round-tripping through a fake log line. That also removes one of the (currently four) code paths that can write that slot, which makes the races easier to reason about.
| /// can synthesise the DevTools URL without waiting for the daemon to | ||
| /// print one. | ||
| async fn devtools_uri_from_existing_server(vm_service_uri: &str) -> Option<String> { | ||
| for port in 9100..9200 { |
There was a problem hiding this comment.
Scanning 100 ports sequentially with a 50 ms timeout each means a d keypress can block for up to ~5 s before it shows "not ready" — today that path is instant. Please drop the brute-force scan: the devtools.serve daemon response already hands you the exact host+port, so the synthesis path doesn't need to guess. If you want to keep any probe at all, bound it hard (a couple of ports, sub-second total) and keep it off the keypress path.
| /// Convert a VM Service URI from its WebSocket form (`ws://…/ws`) to | ||
| /// the plain HTTP origin that DevTools expects in its `?uri=` param. | ||
| /// Strips the trailing `/ws` path segment and swaps the scheme. | ||
| fn vm_service_uri_to_http(uri: &str) -> Option<String> { |
There was a problem hiding this comment.
master now has ws_uri_to_http in crates/fl-tui/src/runner.rs (added for the IntelliJ auto-attach feature) that does exactly this ws/wss → http conversion + /ws strip. Please don't add a second copy — lift one shared helper into fl-core (or fl-flutter) and call it from both crates. Two independent implementations of the same URL surgery will drift apart.
Why
Closes #43.
flutter run --machinereliably emits the VM Service URI viaapp.debugPort, but it does not always print a human-readable DevTools URL. Today thedkeybind depends entirely on capturingapp.devTools: <url>from Flutter output. When that line never arrives, the shortcut reports "DevTools not ready" even though memory polling, network polling, and the VM Service itself are all healthy.What
vm_service_urislot onDeviceSession— stores the last VM Service URI fromAppStarted/app.debugPort.send_devtools_serve()— asks the Flutter daemon to serve DevTools; the{"result":{"host":"…","port":…}}response is parsed byparse_daemon_lineand surfaced as anapp.devToolsServer:debug log.AppStarted, probe localhost ports 9100–9199 for an already-running DevTools server. If none is found, senddevtools.serveand poll until the server appears.open_devtools_all— ifdis pressed after the startup window, one more probe + daemon request before showing the warning.app.devTools: <url>prefix and the human-readable"Flutter DevTools … is available at: <url>"sentence.app.debugPortfield priority — checkdevToolsUrlandurlbeforewsUri/uriso newer Flutter SDK fields are picked up.No new workspace dependency —
urlis already declared in the rootCargo.toml.How to test
cargo clippy --workspace --all-targets -- -D warnings cargo test --workspace --lockedLive:
Expected output after
AppStarted:Files changed
crates/fl-flutter/src/daemon.rssend_devtools_serve()methodcrates/fl-flutter/src/parse.rsdevtools.serveresponse, widerapp.debugPortfield lookupcrates/flutter-cli/Cargo.tomlurl.workspace = truecrates/flutter-cli/src/multi.rs