Ensure a persistent CDP session is attached to the given target for continuous event collection (Network + Console). If the target has changed, detaches the old session and attaches to the new one.
(&mut self, target_id: &str)
| 195 | /// event collection (Network + Console). If the target has changed, detaches |
| 196 | /// the old session and attaches to the new one. |
| 197 | pub async fn ensure_persistent_session(&mut self, target_id: &str) -> Result<()> { |
| 198 | // Already attached to this target |
| 199 | if self.persistent_target_id.as_deref() == Some(target_id) |
| 200 | && self.persistent_session.is_some() |
| 201 | { |
| 202 | return Ok(()); |
| 203 | } |
| 204 | |
| 205 | // Target is changing — discard events accumulated under the previous |
| 206 | // target so a later drain under the new page can't return stale events. |
| 207 | self.network_events.clear(); |
| 208 | self.console_events.clear(); |
| 209 | |
| 210 | // Save the previously-active tab's emulation state so it can be restored |
| 211 | // when we return to it (per-tab isolation). The active state lives in the |
| 212 | // top-level fields; stash it under the old target id — but only if the |
| 213 | // tab actually has overrides, so the map doesn't accumulate empty entries |
| 214 | // for every tab ever visited. |
| 215 | if let Some(old_target) = self.persistent_target_id.clone() { |
| 216 | let saved = TabEmulation { |
| 217 | blocklist: std::mem::take(&mut self.blocklist), |
| 218 | viewport: self.viewport.take(), |
| 219 | geolocation: self.geolocation.take(), |
| 220 | }; |
| 221 | stash_tab_emulation(&mut self.emulation_saved, old_target, saved); |
| 222 | } |
| 223 | |
| 224 | // Detach old session if target changed |
| 225 | if let Some(old_session) = self.persistent_session.take() { |
| 226 | let _ = self |
| 227 | .send("Target.detachFromTarget", json!({"sessionId": old_session})) |
| 228 | .await; |
| 229 | self.persistent_target_id = None; |
| 230 | self.events |
| 231 | .retain(|event| event["sessionId"].as_str() != Some(old_session.as_str())); |
| 232 | } |
| 233 | |
| 234 | // Attach new persistent session |
| 235 | let result = self |
| 236 | .send( |
| 237 | "Target.attachToTarget", |
| 238 | json!({"targetId": target_id, "flatten": true}), |
| 239 | ) |
| 240 | .await?; |
| 241 | |
| 242 | let session_id = result["sessionId"] |
| 243 | .as_str() |
| 244 | .ok_or_else(|| anyhow!("No sessionId in persistent attachToTarget"))? |
| 245 | .to_string(); |
| 246 | |
| 247 | // Store the session id BEFORE enabling domains so events arriving |
| 248 | // during Network.enable / Runtime.enable are routed to persistent |
| 249 | // buffers instead of the generic events buffer. |
| 250 | self.persistent_session = Some(session_id.clone()); |
| 251 | self.persistent_target_id = Some(target_id.to_string()); |
| 252 | |
| 253 | // Enable Network and Runtime domains on the persistent session. If |
| 254 | // either fails, clear the just-set session, detach it (so it isn't |
no test coverage detected