Class BidiNetworkActivitySource

java.lang.Object
com.shaft.gui.browser.internal.BidiNetworkActivitySource
All Implemented Interfaces:
AutoCloseable

public class BidiNetworkActivitySource extends Object implements AutoCloseable
Advisory, best-effort BiDi network-activity signal that JavaScriptWaitManager folds into its existing JS-derived quiet-window engine (issue #3749, Increment B).

Wraps Network (Selenium's org.openqa.selenium.bidi.module.Network) to observe network.beforeRequestSent, network.responseCompleted, and network.fetchError events, which today's JS-only marker cannot see at all: worker/ sendBeacon-adjacent traffic issued before SHAFT's monkey-patch runs, requests on CSP/frozen-prototype pages where the monkey-patch fails to install, etc.

Everything here is advisory, never a hard gate. inFlightCount() can only extend JavaScriptWaitManager's quiet window the same way a JS marker change does; it is never compared against zero as a pass/fail condition. This is deliberate: BiDi, unlike the JS layer, genuinely observes SSE (EventSource) and WebSocket-upgrade requests, which by design stay "in flight" for the entire page lifetime. Treating inFlightCount() > 0 as a hard requirement would regress today's tolerance of long-lived connections (the JS layer's activeRequests simply can't see them) into a wait that never completes.

Lifecycle contract. One instance is created lazily per WebDriver session (see forDriver(WebDriver)) the first time it is needed, cached for the life of that session, and torn down via closeAndRemove(WebDriver) during driver teardown. Instances are only ever constructed when SHAFT.Properties.platform.enableBiDi() is true and the underlying new Network(driver) call succeeds; new Network(driver) throws for any session that does not support/enable the BiDi protocol (see attach(WebDriver)), and construction is never retried for a given driver instance once it has failed -- the failure is logged once (discretely) and the driver falls back to the JS-only signal for the rest of its session.

Thread-safety. BiDi event callbacks fire on Selenium's websocket reader thread while activityMarker()/inFlightCount() are read from the test thread inside JavaScriptWaitManager's poll loop. All mutable state is therefore ConcurrentHashMap/Atomic*-backed.

Close discipline. close() only removes the listeners this instance registered via Network.close(); it never issues a Network.disable-style command and never touches DevTools/CDP. Per the review-corrected ownership contract for issue #3749, the DevTools/BiDi session itself is shared and unowned by design -- passive listening never conflicts with another component's NetworkInterceptor Fetch filter, so the only safe lifecycle rule is "never disable, only detach your own listeners" (see BrowserNetworkInterceptor for the analogous CDP-side contract). Note: Selenium 4.46's Network.close() clears the shared BiDi connection's listeners for the beforeRequestSent/responseStarted/ responseCompleted/authRequired event types outright (not scoped to the calling instance) and does not clear fetchError listeners at all; harmless here because this class is the sole registrant of BiDi network.* listeners in SHAFT today, and because close() is only called from driver teardown, where the whole BiDi connection is about to go away with the driver regardless.

  • Method Details

    • closeAndRemove

      public static void closeAndRemove(org.openqa.selenium.WebDriver driver)
      Closes and removes the cached BidiNetworkActivitySource for driver, if one exists. Wired into driver teardown (see DriverFactoryHelper.closeDriver) so a source is never leaked past its driver's session; safe to call even when no source was ever created for driver (no-op).
      Parameters:
      driver - the WebDriver session being torn down
    • close

      public void close()
      Detaches this source's listeners from the driver's BiDi connection via Network.close() and marks the source unhealthy. Best-effort: exceptions during close (for example a session that already tore down) are swallowed, matching the driver-teardown close idioms elsewhere in SHAFT (see BrowserNetworkInterceptor#closeActiveInterceptor).
      Specified by:
      close in interface AutoCloseable