Skip to content

refactor(cdp): migrate all scanners to in-process transport; drop TCP DevTools port - #3636

Merged
senamakel merged 13 commits into
tinyhumansai:mainfrom
oxoxDev:fix/7979-scanner-migration
Jun 16, 2026
Merged

senamakel merged 13 commits into
tinyhumansai:mainfrom
oxoxDev:fix/7979-scanner-migration

Conversation

@oxoxDev

@oxoxDev oxoxDev commented Jun 12, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Migrate every CEF-backed scanner (whatsapp, discord, slack, telegram, wechat, meet) to the in-process CDP transport introduced in feat(cef): in-process CDP DevTools transport (foundation) #3498. The session opener was already on it; this PR finishes the cutover.
  • Stop passing --remote-debugging-port=19222 to CEF at startup. The Tauri shell no longer binds a loopback DevTools listener.
  • Delete the legacy TCP WebSocket attach path: CdpConn::open_ws, browser_ws_url, connect_and_attach_matching, CDP_HOST, CDP_PORT, and the four scanner-local CdpConn duplicates (whatsapp, discord, slack, telegram).
  • Add label-keyed counterparts of the account-keyed CDP helpers (install_for_label / conn_for_label / connect_and_attach_matching_in_process_by_label) so Meet's meet-call-<request_id> webview can attach without a TCP listener.
  • Extend the in-process transport with call_with_timeout so Slack's IDB batch serialise (Runtime.callFunctionOn over ~32 RemoteObjects) keeps the 60s budget it had on the legacy transport.

Problem

#3498 landed the in-process CDP transport (Webview::send_dev_tools_message + on_dev_tools_protocol) but only migrated the per-account session opener. Six scanner modules still attached over http://127.0.0.1:19222/json/version → loopback WebSocket. While any one of them kept that code path alive, the Tauri shell had to keep passing --remote-debugging-port=19222, which binds an unauthenticated DevTools listener that every same-UID process on the machine can attach to.

Concrete consequences:

  • The earlier in-process transport did not actually remove the legacy listener — it just stopped using it from the session opener.
  • Any same-UID process could attach via puppeteer.connect({ browserURL: 'http://127.0.0.1:19222/' }) and read or modify the embedded webviews (WhatsApp, Slack, Telegram, Discord, etc.).
  • Five copies of struct CdpConn (whatsapp / discord / slack / telegram / meet scanners) plus their per-module browser_ws_url() and parse_targets() duplicates kept piling drift on top of the same machinery.

Solution

CDP transport

  • cdp/in_process.rs: extract the registry-lookup-or-install body into install_for_label(label) and rewrite install_for_account as install_for_label(format!("acct_{id}")). Required because Meet's CEF window uses label meet-call-<request_id>, not acct_<id>. WebviewCdpTransport::call is split into call/call_with_timeout; default call keeps the 35s budget, call_with_timeout lets Slack's IDB walker pass 60s.
  • cdp/target.rs: add conn_for_label<R>(app, label) and connect_and_attach_matching_in_process_by_label<R, F>(app, label, pred) as label-keyed counterparts of the existing account-keyed helpers. Both fall back to install_for_label on a cache miss so a transient install race at window creation doesn't permanently lock the surface out of CDP.
  • cdp/conn.rs: rewrite CdpConn as a thin wrapper over Arc<WebviewCdpTransport>. Drop LegacyWs, connect_async, tokio_tungstenite::Message, the oneshot pending table, and LEGACY_CALL_TIMEOUT. call / call_with_timeout / pump_events forward unconditionally to the in-process transport.
  • cdp/mod.rs: drop CDP_HOST / CDP_PORT and the browser_ws_url / connect_and_attach_matching re-exports; add conn_for_label, connect_and_attach_matching_in_process[_by_label], install_for_label to the surface.

Scanners

For every scanner, the per-tick attach now reads:

let pred = move |t: &crate::cdp::target::CdpTarget| -> bool {
    t.url.starts_with(&url_prefix) && t.url.ends_with(&url_fragment)
};
let (mut cdp, session) =
    crate::cdp::target::connect_and_attach_matching_in_process::<R, _>(
        &app, &account_id, pred,
    )
    .await?;

For Meet (which is window-keyed, not account-keyed):

let label = crate::meet_call::window_label_for(&request_id);
let (mut cdp, session) =
    crate::cdp::target::connect_and_attach_matching_in_process_by_label::<R, _>(
        &app, &label, pred,
    )
    .await?;

Per-scanner deltas:

  • whatsapp: drop local CDP_HOST/CDP_PORT, local CdpConn, browser_ws_url, parse_targets, CdpTarget; scan_dom_once now takes &AppHandle<R> so the in-process transport can be looked up; sibling dom_snapshot.rs and idb.rs switch their CdpConn import to crate::cdp::CdpConn.
  • discord: same drops; the streaming MITM path uses crate::cdp::CdpConn::pump_events with a closure capturing &mut DiscordIngestState. V1 doesn't issue in-stream calls, so dropping the unused pending: HashMap is a simplification, not a regression. dom_scan_once gains &AppHandle<R> + account_id.
  • slack: drops the bigger of the two local CdpConn duplicates (the one with call_with_timeout); both scan_once and dom_scan_once now take &AppHandle<R> and reuse the per-account in-process channel for both target enumeration and attach. The pin / strict-fragment / relaxed /client fallback hierarchy is preserved verbatim.
  • telegram: mirror of slack, no pin hierarchy.
  • wechat: single legacy-attach callsite swapped.
  • meet (scanner + audio inject + video inject + caption listener): all four TCP attach paths route through the label-keyed in-process helper using meet_call::window_label_for(request_id). install_audio_bridge, spawn_diagnostics_poller, and wait_for_meet_target thread &AppHandle<R> + request_id through.

Wiring

  • meet_call/mod.rs: after WebviewWindowBuilder::build(), call crate::cdp::install_for_label(&label) so the Meet webview's in-process transport is wired up before any downstream bridge attaches. Idempotent; on transient install failure the downstream conn_for_label retries.
  • lib.rs: delete args.push(("--remote-debugging-port", Some("19222"))) so the embedded CEF browser never binds a TCP DevTools listener at startup. Surrounding comments rewritten to match.
  • webview_accounts/mod.rs: comment refresh — the listener no longer exists.
  • gmessages_scanner/mod.rs: TODO comment refreshed to point at conn_for_account / connect_and_attach_matching_in_process instead of the long-gone CDP_HOST / CDP_PORT.

Submission Checklist

If a section does not apply to this change, mark the item as N/A with a one-line reason. Do not delete items.

  • N/A: this PR is a pure transport refactor — every per-scanner code path keeps the same predicate, attach shape, and Target.getTargets resolution. Existing test coverage for each scanner exercises the swapped attach path unchanged. (Tests added or updated per Testing Strategy.)
  • N/A: refactor-only change with no business-logic deltas; the diff is dominated by deletions (~1180 LOC) and the new code lives behind the same call signatures the existing test suite already drives. (Diff coverage ≥ 80%.)
  • N/A: no feature additions/removals/renames; the test coverage matrix already lists each scanner. (Coverage matrix updated.)
  • N/A: no feature IDs to enumerate. (Affected feature IDs listed under Related.)
  • No new external network dependencies introduced (mock backend used per Testing Strategy).
  • N/A: no release-cut surface touched. (Manual smoke checklist updated if this touches release-cut surfaces.)
  • Linked issue closed via Closes #NNN in the ## Related section.

Impact

  • Runtime / platform: desktop CEF builds. CEF no longer binds a loopback DevTools listener for the lifetime of the embedded browser. Any tooling that previously attached via http://127.0.0.1:19222/json/version will fail with ECONNREFUSED; nothing in-tree depends on that surface.
  • Security: removes an unauthenticated same-UID attach surface from the CEF browser. After this PR, CDP traffic flows only through the in-process Webview::send_dev_tools_message channel, which stays within the process boundary.
  • Performance: net deletion of ~750 LOC and removal of the per-attach connect_async handshake + tungstenite read loop. Attach setup goes from a TCP /json/version GET + WebSocket handshake to a single registry lookup.
  • Migration / compatibility: external developers that scripted the loopback DevTools port for one-off debugging will need to use tauri::Webview::open_devtools() or attach from inside the running process. No production code path relied on it.

Related

  • Closes:
  • Follow-up PR(s)/TODOs: tokio-tungstenite stays in Cargo.toml because meet_video/frame_bus.rs and webview_apis/server.rs still use it for their WebSocket servers. Once those land their own in-process replacements the crate can be dropped.

AI Authored PR Metadata (required for Codex/Linear PRs)

Keep this section for AI-authored PRs. For human-only PRs, mark each field N/A.

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: fix/7979-scanner-migration
  • Commit SHA: e46b1ad97

Validation Run

  • pnpm --filter openhuman-app format:check
  • pnpm typecheck
  • Focused tests: N/A — refactor-only, existing scanner test suites exercise the swapped attach path unchanged
  • Rust fmt/check (if changed): cargo fmt --check + cargo check --manifest-path app/src-tauri/Cargo.toml
  • Tauri fmt/check (if changed): same as above

Validation Blocked

  • command: N/A
  • error: N/A
  • impact: N/A

Behavior Changes

  • Intended behavior change: scanners + meet bridges no longer attach to CEF via a loopback TCP DevTools port; they go through the in-process Webview::send_dev_tools_message channel introduced in feat(cef): in-process CDP DevTools transport (foundation) #3498.
  • User-visible effect: none on the happy path. Any external tooling that scripted 127.0.0.1:19222/json/version will fail with ECONNREFUSED.

Parity Contract

  • Legacy behavior preserved: per-scanner attach predicates (url.starts_with(url_prefix) && url.ends_with(url_fragment)), Slack's pin-on-strict-match resolution hierarchy, Slack's 60s IDB serialise budget (now via call_with_timeout), Discord's per-event dispatch shape (now via canonical pump_events), Meet's per-call label routing (meet-call-<request_id>).
  • Guard/fallback/dispatch parity checks: every scanner still falls through to its legacy log+continue branch on attach failure; conn_for_label / conn_for_account retry install_for_label / install_for_account once on a registry miss so a transient install race at window creation doesn't permanently lock the surface out of CDP.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): none
  • Canonical PR: this PR
  • Resolution: N/A

Summary by CodeRabbit

Release Notes

  • Refactor
    • Refactored Chrome DevTools Protocol (CDP) communication from WebSocket-based remote debugging to in-process transport, improving system architecture and eliminating unnecessary network listeners.
    • Updated Discord, Slack, Telegram, WhatsApp, and other account scanners to use the new in-process CDP connection method.
    • Removed legacy TCP remote debugging port configuration in favor of the streamlined in-process approach.

oxoxDev added 9 commits June 12, 2026 18:38
Drop the local duplicated CdpConn / browser_ws_url / CDP_HOST / CDP_PORT
plumbing and route through crate::cdp::connect_and_attach_matching_in_process,
which uses the per-account in-process DevTools channel installed by
webview_accounts::open. Net effect: no TCP loopback attach needed for
either full or fast scan tick.

- Drop tokio_tungstenite + futures_util::{SinkExt, StreamExt} + connect_async
  imports (no remaining users in this module).
- Switch dom_snapshot.rs and idb.rs to crate::cdp::CdpConn.
- scan_dom_once now takes &AppHandle<R> so the in-process transport can be
  looked up; spawn_scanner loop passes it through.
- Predicate compares page url prefix/suffix; canonical helper already
  filters kind == "page".
Drop the streaming-MITM CdpConn duplicate (and its tungstenite pending
table that V1 never used) in favour of the canonical in-process
CdpConn. crate::cdp::connect_and_attach_matching_in_process supplies
the attached session, then CdpConn::pump_events streams every
Network.* / WebSocket.* event into the existing dispatch_event closure
with mutable DiscordIngestState captured in the closure.

- Drop CDP_HOST / CDP_PORT import + tokio_tungstenite + futures_util + tokio::sync::oneshot.
- Drop local CdpTarget / parse_targets / browser_ws_url helpers.
- Drop the local CdpConn struct + impl + its custom pump_events; the
  canonical pump_events is sufficient for V1's events-only stream.
- dom_scan_once now takes &AppHandle<R> + account_id so it can use the
  in-process attach helper; spawn_dom_poll passes them through.
- pump_events callback signature is FnMut(&str, &Value) which fits
  dispatch_event's sync per-event invocation; pending-table machinery
  re-introduced when Network.getResponseBody is wired up.
The slack scanner had two TCP-WS attach paths (IDB scan + DOM scan), each
with its own local CdpConn duplicate. Both move to the canonical
crate::cdp::CdpConn via the per-account in-process transport.

CDP transport
- WebviewCdpTransport::call now delegates to call_with_timeout(timeout);
  the default 35s budget unchanged for existing callers.
- CdpConn (the per-attach handle) gains call_with_timeout that forwards
  to the in-process transport — required because slack's IDB batch
  serialise (Runtime.callFunctionOn over ~32 RemoteObjects) needs a 60s
  budget which the legacy local CdpConn used to provide.

Slack scanner
- Drop CDP_HOST / CDP_PORT import + tokio_tungstenite + futures_util.
- Drop local CdpTarget / parse_targets / browser_ws_url / CdpConn /
  CdpConn::call_with_timeout — the canonical CdpConn now provides the
  same surface.
- scan_once and dom_scan_once now take &AppHandle<R> and route through
  crate::cdp::target::conn_for_account, reusing the in-process channel
  for both target enumeration and attach. The pin / strict / relaxed
  resolution hierarchy is preserved verbatim.
- idb.rs switches its CdpConn import to crate::cdp::CdpConn so the
  60s call_with_timeout call site keeps working unchanged.
Mirror of the slack migration — drop the local CdpConn duplicate (with
its own 30s default + 60s call_with_timeout) and route through
crate::cdp::target::connect_and_attach_matching_in_process. The
canonical CdpConn::call_with_timeout (added in the slack commit) covers
the 60s budget the IDB batch serialise needs.

- Drop CDP_HOST / CDP_PORT import + tokio_tungstenite + futures_util.
- Drop local CdpTarget / parse_targets / browser_ws_url / CdpConn.
- scan_once + dom_scan_once now take &AppHandle<R> + account_id and
  reuse the per-account in-process channel for both target enumeration
  and attach.
- idb.rs switches its CdpConn import to crate::cdp::CdpConn.
Single TCP-WS callsite swaps from
crate::cdp::connect_and_attach_matching (legacy WebSocket) to
crate::cdp::target::connect_and_attach_matching_in_process. scan_once
now takes &AppHandle<R> + account_id so it can look up the per-account
in-process transport.
The Meet stack opens its own WebviewWindow per call (label
"meet-call-<request_id>") and four TCP-WS attach paths used to drive
audio bridge, video bridge, caption listener, camera diagnostics, and
join scanner. All four move to the per-webview in-process CDP transport.

CDP transport
- Add install_for_label / conn_for_label / connect_and_attach_matching_in_process_by_label
  as label-keyed counterparts of the account-keyed helpers. Required
  because Meet webviews use "meet-call-<request_id>" not "acct_<id>".
- install_for_account now wraps install_for_label.

meet_call
- After the WebviewWindow is built, call cdp::install_for_label so the
  Meet webview's in-process transport is wired up before any of the
  downstream bridges attach. Idempotent; transient failures fall back
  to the conn_for_label retry path.

meet_scanner / meet_audio / meet_video
- Thread request_id through wait_for_meet_target,
  install_audio_bridge, and spawn_diagnostics_poller so each attach
  resolves the Meet window's label and goes through the in-process
  channel instead of TCP loopback.
- Caption listener's second attach also routes through
  connect_and_attach_matching_in_process_by_label.
With every scanner (whatsapp / discord / slack / telegram / wechat /
meet_video / meet_audio / meet_scanner) now on the in-process CDP
transport, the legacy TCP loopback DevTools surface no longer has any
callers and can be removed.

- cdp/target.rs: delete browser_ws_url() and connect_and_attach_matching();
  drop the Duration import that was only needed for the reqwest timeout.
- cdp/conn.rs: rewrite CdpConn to be a thin wrapper over
  Arc<WebviewCdpTransport> — drop CdpConn::open_ws, the LegacyWs enum
  variant, the futures_util / tokio_tungstenite / oneshot uses, and the
  LEGACY_CALL_TIMEOUT constant. call / call_with_timeout / pump_events
  now forward unconditionally to the in-process transport.
- cdp/mod.rs: drop CDP_HOST / CDP_PORT constants, drop browser_ws_url
  and connect_and_attach_matching re-exports, add
  connect_and_attach_matching_in_process /
  connect_and_attach_matching_in_process_by_label / conn_for_label to
  the re-export list. Module-level doc rewritten to describe the single
  remaining transport.
- gmessages_scanner: refresh TODO comment that referenced CDP_HOST /
  CDP_PORT — the scaffold should reuse the in-process helpers when it
  graduates to a running scanner.
With every scanner on the in-process CDP transport the loopback
DevTools listener is no longer needed. Dropping the
"--remote-debugging-port=19222" command-line arg means CEF starts
without binding any TCP DevTools surface, so same-UID processes can
no longer attach a CDP client at 127.0.0.1:19222.

Comment refresh in webview_accounts to drop the stale reference to
the listener that no longer exists.
@oxoxDev
oxoxDev requested a review from a team June 12, 2026 18:29
@coderabbitai

coderabbitai Bot commented Jun 12, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

All CDP communication is migrated from a dual-backend (in-process + legacy loopback WebSocket) model to exclusively in-process transport. CdpConn is simplified to wrap Arc<WebviewCdpTransport>, a new call_with_timeout API is added, label-based attach helpers are introduced, the --remote-debugging-port CEF flag is removed, and every scanner (Discord, Slack, Telegram, WhatsApp, WeChat) and Meet module is updated to use the shared in-process attach path.

Changes

In-process CDP migration

Layer / File(s) Summary
CdpConn and WebviewCdpTransport refactoring
app/src-tauri/src/cdp/conn.rs, app/src-tauri/src/cdp/in_process.rs
CdpConn drops the Backend enum and holds Arc<WebviewCdpTransport> directly; call_with_timeout is added to both layers; pump_events handles RecvError::Lagged by logging and continuing; install_for_account delegates to install_for_label.
CDP public API and target helpers
app/src-tauri/src/cdp/mod.rs, app/src-tauri/src/cdp/target.rs
Removes CDP_HOST, CDP_PORT, cdp_port(), and browser_ws_url(); adds conn_for_label and connect_and_attach_matching_in_process_by_label; connect_and_attach_matching_in_process routes through a shared attach_matching_on_conn helper; re-exports updated.
CEF startup: remove --remote-debugging-port
app/src-tauri/src/lib.rs
Removes code that set the TCP DevTools listener flag and updates comments to state CDP is exclusively in-process.
Scanner migrations
app/src-tauri/src/discord_scanner/mod.rs, app/src-tauri/src/slack_scanner/mod.rs, app/src-tauri/src/slack_scanner/idb.rs, app/src-tauri/src/telegram_scanner/mod.rs, app/src-tauri/src/telegram_scanner/idb.rs, app/src-tauri/src/whatsapp_scanner/mod.rs, app/src-tauri/src/whatsapp_scanner/dom_snapshot.rs, app/src-tauri/src/whatsapp_scanner/idb.rs, app/src-tauri/src/wechat_scanner/mod.rs
All five scanners remove their local CdpConn/parse_targets/browser_ws_url implementations; IDB and DOM scan paths switch to connect_and_attach_matching_in_process (account-keyed) or conn_for_account; CdpConn imports updated to crate::cdp::CdpConn.
Meet modules: label-based attach
app/src-tauri/src/meet_call/mod.rs, app/src-tauri/src/meet_audio/inject.rs, app/src-tauri/src/meet_audio/mod.rs, app/src-tauri/src/meet_scanner/mod.rs, app/src-tauri/src/meet_video/inject.rs
meet_call_open_window proactively installs the transport for the new webview label; all Meet attach paths switch to connect_and_attach_matching_in_process_by_label using window_label_for(request_id); AppHandle is threaded through spawn_diagnostics_poller, install_audio_bridge, and join automation.
Minor comment cleanups
app/src-tauri/src/gmessages_scanner/mod.rs, app/src-tauri/src/webview_accounts/mod.rs
gmessages TODO updated to reference in-process CDP; webview_accounts comment drops the --remote-debugging-port=19222 mention.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

  • tinyhumansai/openhuman#3498: Introduced the in-process transport and dual-backend CdpConn foundation that this PR now collapses into the in-process-only path.
  • tinyhumansai/openhuman#3647: Modifies the same cdp/mod.rs and lib.rs CDP configuration surface — adds cdp_port() env override for the TCP port that this PR removes entirely.

Suggested labels

rust-core, working

Suggested reviewers

  • sanil-23

Poem

🐇 Hop hop, the WebSocket is gone!
No loopback port to linger on.
In-process now, the CDP flows,
Through Tauri's veins the data goes.
One transport rules them all today —
This rabbit swept old code away! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and specifically describes the main change: migrating all scanners to in-process transport and removing the TCP DevTools port.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

sanil-23
sanil-23 previously approved these changes Jun 15, 2026

@sanil-23 sanil-23 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve ✅ (with comments — one fast-follow filed)

Security-positive, carefully executed refactor that finishes the in-process CDP cutover and closes the unauthenticated same-UID loopback DevTools surface. CI is fully green. The mechanical migration of all six scanners preserves every predicate, attach shape, pin/fallback hierarchy, and log-and-continue error path; the get_or_create install path correctly serializes observer registration under the registry mutex (CEF has no un-register hook), and pending-map cleanup is leak-free on all three exit paths.

One Major (medium-confidence) concern is Discord-specific and tracked as a fast-follow rather than gating this security win: #3693. Discord is the only scanner using the long-lived pump_events loop, and (1) it can't self-heal a dead/stale session — pump_events only returns on transport teardown, not on page-target loss (Ctrl+R / renderer crash / SPA hard-nav), so it never re-attaches until the webview is destroyed; and (2) the 256-slot broadcast drops frames on Lagged with no idle watchdog, despite the cdp/conn.rs comment promising one. See inline comments.

Non-blocking items to fix in this PR (zero-risk):

  • The run_mitm_session doc comment ("Returns when the underlying WebSocket closes, the page target disappears…") and the cdp/conn.rs Lagged comment ("the caller's idle watchdog will eventually time out the session") no longer match the in-process implementation — please correct both.
  • cdp/in_process.rs:519 cites integration test cdp_in_process_e2e.rs, which doesn't exist anywhere in the repo (pre-existing from #3498). Either land it or drop the reference; cdp/conn.rs + cdp/target.rs currently ship with zero unit tests, and the new pump_events session-id filter is pure, testable logic.

Minor / low-confidence: call_with_timeout changed from a per-read timeout (reset on every inbound frame) to a total wall-clock cap. For Slack's 60s IDB walk (slack_scanner/idb.rs:314) this is almost certainly equivalent (dedicated session, no interleaved frames), but it's a real semantic change worth a line in the parity contract rather than "preserved verbatim."

Nice work overall — approving on the basis that #3693 owns the Discord watchdog and the doc/test-reference cleanups land here.

// closure. V1 doesn't issue any in-stream calls (responses table from
// the previous TCP impl is gone — re-introduce a request/response API
// here when V1.5 backfills `Network.getResponseBody`).
log::info!("[discord][{}] event pump started", account_id);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Major (medium confidence) — tracked in #3693. This long-lived pump can't self-heal a dead session: pump_events only returns on RecvError::Closed (transport/webview teardown), not when the attached page target dies (Discord Ctrl+R, renderer crash, SPA hard-nav). Target.detachedFromTarget isn't acted on (discovery never enabled; dispatch_event ignores unknown methods), so the outer reconnect loop is never re-entered and the MITM silently stops capturing until the webview is destroyed.

Suggest an idle watchdog (> Discord's ~41s gateway heartbeat, e.g. 90s) so a stalled/destroyed session forces a return → re-attach. Also: the run_mitm_session doc comment above ("Returns when the underlying WebSocket closes, the page target disappears, or any dispatch hits an unrecoverable error") is now false for all three clauses — please correct it in this PR.

}
on_event(&method, &params);
}
Err(RecvError::Lagged(skipped)) => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Major (medium confidence) — tracked in #3693. On Lagged the pump logs and continues, silently dropping CDP frames once the single consumer falls >256 behind (EVENT_CHANNEL_CAP). The comment above states recovery relies on "the caller's idle watchdog" — but the Discord consumer (the only long-lived pump) has no watchdog, so dropped Network.* frames during a burst = missed messages with no re-sync. Either validate 256 against Discord's burst volume or drain this consumer into an unbounded queue, and reword the comment so it doesn't promise a watchdog that doesn't exist for this caller.

@senamakel senamakel self-assigned this Jun 15, 2026
# Conflicts:
#	app/src-tauri/src/cdp/mod.rs
#	app/src-tauri/src/cdp/target.rs
#	app/src-tauri/src/lib.rs
The doc comment promised "the caller's idle watchdog will eventually time
out the session" but the long-lived Discord consumer has no watchdog, so
Lagged-dropped frames are not re-synced. Reword to describe the actual
behaviour and reference the fast-follow (tinyhumansai#3693) that adds the watchdog.

Addresses @sanil-23 on cdp/conn.rs.
@coderabbitai coderabbitai Bot added rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. working A PR that is being worked on by the team. labels Jun 16, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
app/src-tauri/src/whatsapp_scanner/mod.rs (1)

282-351: 💤 Low value

Remove dead code: let _ = app;

Line 348 has let _ = app; which appears to be leftover from the refactoring. The app parameter is already used on lines 297-300 for connect_and_attach_matching_in_process, so this binding serves no purpose.

🧹 Proposed cleanup
     let _ = cdp
         .call(
             "Target.detachFromTarget",
             json!({ "sessionId": page_session }),
             None,
         )
         .await;
-    let _ = app;
     snap.capture_report = capture_report;
     Ok(snap)
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src-tauri/src/whatsapp_scanner/mod.rs` around lines 282 - 351, Remove the
dead code `let _ = app;` from the scan_once function. The app parameter is
already used earlier in the function when calling
connect_and_attach_matching_in_process on lines 297-300, so this binding is
unnecessary leftover from refactoring and should be deleted.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@app/src-tauri/src/whatsapp_scanner/mod.rs`:
- Around line 282-351: Remove the dead code `let _ = app;` from the scan_once
function. The app parameter is already used earlier in the function when calling
connect_and_attach_matching_in_process on lines 297-300, so this binding is
unnecessary leftover from refactoring and should be deleted.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3fe24e45-044b-461c-976f-f4f897c94bc2

📥 Commits

Reviewing files that changed from the base of the PR and between eb80d24 and ae2c651.

⛔ Files ignored due to path filters (1)
  • app/src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (21)
  • app/src-tauri/src/cdp/conn.rs
  • app/src-tauri/src/cdp/in_process.rs
  • app/src-tauri/src/cdp/mod.rs
  • app/src-tauri/src/cdp/target.rs
  • app/src-tauri/src/discord_scanner/mod.rs
  • app/src-tauri/src/gmessages_scanner/mod.rs
  • app/src-tauri/src/lib.rs
  • app/src-tauri/src/meet_audio/inject.rs
  • app/src-tauri/src/meet_audio/mod.rs
  • app/src-tauri/src/meet_call/mod.rs
  • app/src-tauri/src/meet_scanner/mod.rs
  • app/src-tauri/src/meet_video/inject.rs
  • app/src-tauri/src/slack_scanner/idb.rs
  • app/src-tauri/src/slack_scanner/mod.rs
  • app/src-tauri/src/telegram_scanner/idb.rs
  • app/src-tauri/src/telegram_scanner/mod.rs
  • app/src-tauri/src/webview_accounts/mod.rs
  • app/src-tauri/src/wechat_scanner/mod.rs
  • app/src-tauri/src/whatsapp_scanner/dom_snapshot.rs
  • app/src-tauri/src/whatsapp_scanner/idb.rs
  • app/src-tauri/src/whatsapp_scanner/mod.rs

@senamakel
senamakel merged commit 976b31f into tinyhumansai:main Jun 16, 2026
30 of 36 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Jul 15, 2026
12 tasks done
senamakel pushed a commit to nocstah/openhuman that referenced this pull request Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. working A PR that is being worked on by the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants