From 1adf8ee54529b4e754d4f0513cc7763b3db54199 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Thu, 30 Dec 2021 16:47:58 +0100 Subject: [PATCH] fix(core): inspector works if no "Runtime.runIfWaitingForDebugger" message is sent (#13191) This commit changes flow in inspector code to no longer require "Runtime.runIfWaitingForDebugger" message to complete a handshake. Even though clients like Chrome DevTools always send this message on startup, it is against the protocol to require this message to start an inspector session. Instead "Runtime.runIfWaitingForDebugger" is required only when running with "--inspect-brk" flag, which matches behavior of Node.js. --- cli/tests/integration/inspector_tests.rs | 471 +++++++++++++++-------- core/inspector.rs | 59 +-- 2 files changed, 328 insertions(+), 202 deletions(-) diff --git a/cli/tests/integration/inspector_tests.rs b/cli/tests/integration/inspector_tests.rs index f5365ac994..f6b95c1b49 100644 --- a/cli/tests/integration/inspector_tests.rs +++ b/cli/tests/integration/inspector_tests.rs @@ -2,12 +2,16 @@ use deno_core::futures; use deno_core::futures::prelude::*; +use deno_core::futures::stream::SplitSink; use deno_core::serde_json; use deno_core::url; use deno_runtime::deno_fetch::reqwest; use deno_runtime::deno_websocket::tokio_tungstenite; +use deno_runtime::deno_websocket::tokio_tungstenite::tungstenite; use std::io::BufRead; +use std::pin::Pin; use test_util as util; +use tokio::net::TcpStream; fn inspect_flag_with_unique_port(flag_prefix: &str) -> String { use std::sync::atomic::{AtomicU16, Ordering}; @@ -28,6 +32,71 @@ fn extract_ws_url_from_stderr( url::Url::parse(ws_url).unwrap() } +fn assert_stderr_for_inspect( + stderr_lines: &mut impl std::iter::Iterator, +) { + assert_eq!( + &stderr_lines.next().unwrap(), + "Visit chrome://inspect to connect to the debugger." + ); +} + +fn assert_stderr_for_inspect_brk( + stderr_lines: &mut impl std::iter::Iterator, +) { + assert_eq!( + &stderr_lines.next().unwrap(), + "Visit chrome://inspect to connect to the debugger." + ); + assert_eq!( + &stderr_lines.next().unwrap(), + "Deno is waiting for debugger to connect." + ); +} + +async fn assert_inspector_messages( + socket_tx: &mut SplitSink< + tokio_tungstenite::WebSocketStream< + tokio_tungstenite::MaybeTlsStream, + >, + tungstenite::Message, + >, + messages: &[&str], + socket_rx: &mut Pin>>, + responses: &[&str], + notifications: &[&str], +) { + for msg in messages { + socket_tx.send(msg.to_string().into()).await.unwrap(); + } + + let expected_messages = responses.len() + notifications.len(); + let mut responses_idx = 0; + let mut notifications_idx = 0; + + for _ in 0..expected_messages { + let msg = socket_rx.next().await.unwrap(); + + if msg.starts_with(r#"{"id":"#) { + assert!( + msg.starts_with(responses[responses_idx]), + "Doesn't start with {}, instead received {}", + responses[responses_idx], + msg + ); + responses_idx += 1; + } else { + assert!( + msg.starts_with(notifications[notifications_idx]), + "Doesn't start with {}, instead received {}", + notifications[notifications_idx], + msg + ); + notifications_idx += 1; + } + } +} + #[tokio::test] async fn inspector_connect() { let script = util::testdata_path().join("inspector1.js"); @@ -54,14 +123,6 @@ async fn inspector_connect() { child.wait().unwrap(); } -#[derive(Debug)] -enum TestStep { - StdOut(&'static str), - StdErr(&'static str), - WsRecv(&'static str), - WsSend(&'static str), -} - #[tokio::test] async fn inspector_break_on_first_line() { let script = util::testdata_path().join("inspector2.js"); @@ -85,48 +146,69 @@ async fn inspector_break_on_first_line() { assert_eq!(response.status(), 101); // Switching protocols. let (mut socket_tx, socket_rx) = socket.split(); - let mut socket_rx = - socket_rx.map(|msg| msg.unwrap().to_string()).filter(|msg| { + let mut socket_rx = socket_rx + .map(|msg| msg.unwrap().to_string()) + .filter(|msg| { let pass = !msg.starts_with(r#"{"method":"Debugger.scriptParsed","#); futures::future::ready(pass) - }); + }) + .boxed_local(); let stdout = child.stdout.as_mut().unwrap(); let mut stdout_lines = std::io::BufReader::new(stdout).lines().map(|r| r.unwrap()); - use TestStep::*; - let test_steps = vec![ - StdErr("Visit chrome://inspect to connect to the debugger."), - StdErr("Deno is waiting for debugger to connect."), - WsSend(r#"{"id":1,"method":"Runtime.enable"}"#), - WsSend(r#"{"id":2,"method":"Debugger.enable"}"#), - WsRecv( - r#"{"method":"Runtime.executionContextCreated","params":{"context":{"id":1,"#, - ), - WsRecv(r#"{"id":1,"result":{}}"#), - WsRecv(r#"{"id":2,"result":{"debuggerId":"#), - WsSend(r#"{"id":3,"method":"Runtime.runIfWaitingForDebugger"}"#), - WsRecv(r#"{"id":3,"result":{}}"#), - WsRecv(r#"{"method":"Debugger.paused","#), - WsSend( - r#"{"id":4,"method":"Runtime.evaluate","params":{"expression":"Deno.core.print(\"hello from the inspector\\n\")","contextId":1,"includeCommandLineAPI":true,"silent":false,"returnByValue":true}}"#, - ), - WsRecv(r#"{"id":4,"result":{"result":{"type":"undefined"}}}"#), - StdOut("hello from the inspector"), - WsSend(r#"{"id":5,"method":"Debugger.resume"}"#), - WsRecv(r#"{"id":5,"result":{}}"#), - StdOut("hello from the script"), - ]; + assert_stderr_for_inspect_brk(&mut stderr_lines); - for step in test_steps { - match step { - StdErr(s) => assert_eq!(&stderr_lines.next().unwrap(), s), - StdOut(s) => assert_eq!(&stdout_lines.next().unwrap(), s), - WsRecv(s) => assert!(socket_rx.next().await.unwrap().starts_with(s)), - WsSend(s) => socket_tx.send(s.into()).await.unwrap(), - } - } + assert_inspector_messages( + &mut socket_tx, + &[ + r#"{"id":1,"method":"Runtime.enable"}"#, + r#"{"id":2,"method":"Debugger.enable"}"#, + ], + &mut socket_rx, + &[ + r#"{"id":1,"result":{}}"#, + r#"{"id":2,"result":{"debuggerId":"#, + ], + &[ + r#"{"method":"Runtime.executionContextCreated","params":{"context":{"id":1,"#, + ], + ) + .await; + + assert_inspector_messages( + &mut socket_tx, + &[r#"{"id":3,"method":"Runtime.runIfWaitingForDebugger"}"#], + &mut socket_rx, + &[r#"{"id":3,"result":{}}"#], + &[r#"{"method":"Debugger.paused","#], + ) + .await; + + assert_inspector_messages( + &mut socket_tx, + &[ + r#"{"id":4,"method":"Runtime.evaluate","params":{"expression":"Deno.core.print(\"hello from the inspector\\n\")","contextId":1,"includeCommandLineAPI":true,"silent":false,"returnByValue":true}}"#, + ], + &mut socket_rx, + &[r#"{"id":4,"result":{"result":{"type":"undefined"}}}"#], + &[], + ) + .await; + + assert_eq!(&stdout_lines.next().unwrap(), "hello from the inspector"); + + assert_inspector_messages( + &mut socket_tx, + &[r#"{"id":5,"method":"Debugger.resume"}"#], + &mut socket_rx, + &[r#"{"id":5,"result":{}}"#], + &[], + ) + .await; + + assert_eq!(&stdout_lines.next().unwrap(), "hello from the script"); child.kill().unwrap(); child.wait().unwrap(); @@ -266,63 +348,84 @@ async fn inspector_does_not_hang() { assert_eq!(response.status(), 101); // Switching protocols. let (mut socket_tx, socket_rx) = socket.split(); - let mut socket_rx = - socket_rx.map(|msg| msg.unwrap().to_string()).filter(|msg| { + let mut socket_rx = socket_rx + .map(|msg| msg.unwrap().to_string()) + .filter(|msg| { let pass = !msg.starts_with(r#"{"method":"Debugger.scriptParsed","#); futures::future::ready(pass) - }); + }) + .boxed_local(); let stdout = child.stdout.as_mut().unwrap(); let mut stdout_lines = std::io::BufReader::new(stdout).lines().map(|r| r.unwrap()); - use TestStep::*; - let test_steps = vec![ - StdErr("Visit chrome://inspect to connect to the debugger."), - StdErr("Deno is waiting for debugger to connect."), - WsSend(r#"{"id":1,"method":"Runtime.enable"}"#), - WsSend(r#"{"id":2,"method":"Debugger.enable"}"#), - WsRecv( - r#"{"method":"Runtime.executionContextCreated","params":{"context":{"id":1,"#, - ), - WsRecv(r#"{"id":1,"result":{}}"#), - WsRecv(r#"{"id":2,"result":{"debuggerId":"#), - WsSend(r#"{"id":3,"method":"Runtime.runIfWaitingForDebugger"}"#), - WsRecv(r#"{"id":3,"result":{}}"#), - WsRecv(r#"{"method":"Debugger.paused","#), - WsSend(r#"{"id":4,"method":"Debugger.resume"}"#), - WsRecv(r#"{"id":4,"result":{}}"#), - WsRecv(r#"{"method":"Debugger.resumed","params":{}}"#), - ]; + assert_stderr_for_inspect_brk(&mut stderr_lines); - for step in test_steps { - match step { - StdErr(s) => assert_eq!(&stderr_lines.next().unwrap(), s), - WsRecv(s) => assert!(socket_rx.next().await.unwrap().starts_with(s)), - WsSend(s) => socket_tx.send(s.into()).await.unwrap(), - _ => unreachable!(), - } - } + assert_inspector_messages( + &mut socket_tx, + &[ + r#"{"id":1,"method":"Runtime.enable"}"#, + r#"{"id":2,"method":"Debugger.enable"}"#, + ], + &mut socket_rx, + &[ + r#"{"id":1,"result":{}}"#, + r#"{"id":2,"result":{"debuggerId":"# + ], + &[ + r#"{"method":"Runtime.executionContextCreated","params":{"context":{"id":1,"# + ], + ) + .await; + + assert_inspector_messages( + &mut socket_tx, + &[r#"{"id":3,"method":"Runtime.runIfWaitingForDebugger"}"#], + &mut socket_rx, + &[r#"{"id":3,"result":{}}"#], + &[r#"{"method":"Debugger.paused","#], + ) + .await; + + assert_inspector_messages( + &mut socket_tx, + &[r#"{"id":4,"method":"Debugger.resume"}"#], + &mut socket_rx, + &[r#"{"id":4,"result":{}}"#], + &[r#"{"method":"Debugger.resumed","params":{}}"#], + ) + .await; for i in 0..128u32 { let request_id = i + 10; // Expect the number {i} on stdout. let s = i.to_string(); assert_eq!(stdout_lines.next().unwrap(), s); - // Expect console.log - let s = r#"{"method":"Runtime.consoleAPICalled","#; - assert!(socket_rx.next().await.unwrap().starts_with(s)); - // Expect hitting the `debugger` statement. - let s = r#"{"method":"Debugger.paused","#; - assert!(socket_rx.next().await.unwrap().starts_with(s)); - // Send the 'Debugger.resume' request. - let s = format!(r#"{{"id":{},"method":"Debugger.resume"}}"#, request_id); - socket_tx.send(s.into()).await.unwrap(); - // Expect confirmation of the 'Debugger.resume' request. - let s = format!(r#"{{"id":{},"result":{{}}}}"#, request_id); - assert_eq!(socket_rx.next().await.unwrap(), s); - let s = r#"{"method":"Debugger.resumed","params":{}}"#; - assert_eq!(socket_rx.next().await.unwrap(), s); + + assert_inspector_messages( + &mut socket_tx, + &[], + &mut socket_rx, + &[], + &[ + r#"{"method":"Runtime.consoleAPICalled","#, + r#"{"method":"Debugger.paused","#, + ], + ) + .await; + + assert_inspector_messages( + &mut socket_tx, + &[&format!( + r#"{{"id":{},"method":"Debugger.resume"}}"#, + request_id + )], + &mut socket_rx, + &[&format!(r#"{{"id":{},"result":{{}}}}"#, request_id)], + &[r#"{"method":"Debugger.resumed","params":{}}"#], + ) + .await; } // Check that we can gracefully close the websocket connection. @@ -386,11 +489,13 @@ async fn inspector_runtime_evaluate_does_not_crash() { assert_eq!(response.status(), 101); // Switching protocols. let (mut socket_tx, socket_rx) = socket.split(); - let mut socket_rx = - socket_rx.map(|msg| msg.unwrap().to_string()).filter(|msg| { + let mut socket_rx = socket_rx + .map(|msg| msg.unwrap().to_string()) + .filter(|msg| { let pass = !msg.starts_with(r#"{"method":"Debugger.scriptParsed","#); futures::future::ready(pass) - }); + }) + .boxed_local(); let stdin = child.stdin.take().unwrap(); @@ -400,43 +505,60 @@ async fn inspector_runtime_evaluate_does_not_crash() { .map(|r| r.unwrap()) .filter(|s| !s.starts_with("Deno ")); - use TestStep::*; - let test_steps = vec![ - StdErr("Visit chrome://inspect to connect to the debugger."), - WsSend(r#"{"id":1,"method":"Runtime.enable"}"#), - WsSend(r#"{"id":2,"method":"Debugger.enable"}"#), - WsRecv( - r#"{"method":"Runtime.executionContextCreated","params":{"context":{"id":1,"#, - ), - WsRecv(r#"{"id":1,"result":{}}"#), - WsRecv(r#"{"id":2,"result":{"debuggerId":"#), - WsSend(r#"{"id":3,"method":"Runtime.runIfWaitingForDebugger"}"#), - WsRecv(r#"{"id":3,"result":{}}"#), - StdOut("exit using ctrl+d or close()"), - WsSend( - r#"{"id":4,"method":"Runtime.compileScript","params":{"expression":"Deno.cwd()","sourceURL":"","persistScript":false,"executionContextId":1}}"#, - ), - WsRecv(r#"{"id":4,"result":{}}"#), - WsSend( - r#"{"id":5,"method":"Runtime.evaluate","params":{"expression":"Deno.cwd()","objectGroup":"console","includeCommandLineAPI":true,"silent":false,"contextId":1,"returnByValue":true,"generatePreview":true,"userGesture":true,"awaitPromise":false,"replMode":true}}"#, - ), - WsRecv(r#"{"id":5,"result":{"result":{"type":"string","value":""#), - WsSend( - r#"{"id":6,"method":"Runtime.evaluate","params":{"expression":"console.error('done');","objectGroup":"console","includeCommandLineAPI":true,"silent":false,"contextId":1,"returnByValue":true,"generatePreview":true,"userGesture":true,"awaitPromise":false,"replMode":true}}"#, - ), - WsRecv(r#"{"method":"Runtime.consoleAPICalled"#), - WsRecv(r#"{"id":6,"result":{"result":{"type":"undefined"}}}"#), - StdErr("done"), - ]; + assert_stderr_for_inspect(&mut stderr_lines); - for step in test_steps { - match step { - StdOut(s) => assert_eq!(&stdout_lines.next().unwrap(), s), - StdErr(s) => assert_eq!(&stderr_lines.next().unwrap(), s), - WsRecv(s) => assert!(socket_rx.next().await.unwrap().starts_with(s)), - WsSend(s) => socket_tx.send(s.into()).await.unwrap(), - } - } + assert_inspector_messages( + &mut socket_tx, + &[ + r#"{"id":1,"method":"Runtime.enable"}"#, + r#"{"id":2,"method":"Debugger.enable"}"#, + ], + &mut socket_rx, + &[ + r#"{"id":1,"result":{}}"#, + r#"{"id":2,"result":{"debuggerId":"#, + ], + &[ + r#"{"method":"Runtime.executionContextCreated","params":{"context":{"id":1,"#, + ], + ) + .await; + + assert_eq!( + &stdout_lines.next().unwrap(), + "exit using ctrl+d or close()" + ); + + assert_inspector_messages( + &mut socket_tx, + &[ + r#"{"id":3,"method":"Runtime.compileScript","params":{"expression":"Deno.cwd()","sourceURL":"","persistScript":false,"executionContextId":1}}"#, + ], + &mut socket_rx, + &[r#"{"id":3,"result":{}}"#], &[] + ).await; + + assert_inspector_messages( + &mut socket_tx, + &[ + r#"{"id":4,"method":"Runtime.evaluate","params":{"expression":"Deno.cwd()","objectGroup":"console","includeCommandLineAPI":true,"silent":false,"contextId":1,"returnByValue":true,"generatePreview":true,"userGesture":true,"awaitPromise":false,"replMode":true}}"#, + ], + &mut socket_rx, + &[r#"{"id":4,"result":{"result":{"type":"string","value":""#], + &[], + ).await; + + assert_inspector_messages( + &mut socket_tx, + &[ + r#"{"id":5,"method":"Runtime.evaluate","params":{"expression":"console.error('done');","objectGroup":"console","includeCommandLineAPI":true,"silent":false,"contextId":1,"returnByValue":true,"generatePreview":true,"userGesture":true,"awaitPromise":false,"replMode":true}}"#, + ], + &mut socket_rx, + &[r#"{"id":5,"result":{"result":{"type":"undefined"}}}"#], + &[r#"{"method":"Runtime.consoleAPICalled"#], + ).await; + + assert_eq!(&stderr_lines.next().unwrap(), "done"); drop(stdin); child.wait().unwrap(); @@ -549,53 +671,76 @@ async fn inspector_break_on_first_line_in_test() { assert_eq!(response.status(), 101); // Switching protocols. let (mut socket_tx, socket_rx) = socket.split(); - let mut socket_rx = - socket_rx.map(|msg| msg.unwrap().to_string()).filter(|msg| { + let mut socket_rx = socket_rx + .map(|msg| msg.unwrap().to_string()) + .filter(|msg| { let pass = !msg.starts_with(r#"{"method":"Debugger.scriptParsed","#); futures::future::ready(pass) - }); + }) + .boxed_local(); let stdout = child.stdout.as_mut().unwrap(); let mut stdout_lines = std::io::BufReader::new(stdout).lines().map(|r| r.unwrap()); - use TestStep::*; - let test_steps = vec![ - StdErr("Visit chrome://inspect to connect to the debugger."), - StdErr("Deno is waiting for debugger to connect."), - WsSend(r#"{"id":1,"method":"Runtime.enable"}"#), - WsSend(r#"{"id":2,"method":"Debugger.enable"}"#), - WsRecv( - r#"{"method":"Runtime.executionContextCreated","params":{"context":{"id":1,"#, - ), - WsRecv(r#"{"id":1,"result":{}}"#), - WsRecv(r#"{"id":2,"result":{"debuggerId":"#), - WsSend(r#"{"id":3,"method":"Runtime.runIfWaitingForDebugger"}"#), - WsRecv(r#"{"id":3,"result":{}}"#), - WsRecv(r#"{"method":"Debugger.paused","#), - WsSend( - r#"{"id":4,"method":"Runtime.evaluate","params":{"expression":"Deno.core.print(\"hello from the inspector\\n\")","contextId":1,"includeCommandLineAPI":true,"silent":false,"returnByValue":true}}"#, - ), - WsRecv(r#"{"id":4,"result":{"result":{"type":"undefined"}}}"#), - StdOut("hello from the inspector"), - WsSend(r#"{"id":5,"method":"Debugger.resume"}"#), - WsRecv(r#"{"id":5,"result":{}}"#), - StdOut("running 1 test from"), - StdOut("test has finished running"), - ]; + assert_stderr_for_inspect_brk(&mut stderr_lines); - for step in test_steps { - match step { - StdOut(s) => assert!( - &stdout_lines.next().unwrap().contains(s), - "Doesn't contain {}", - s - ), - StdErr(s) => assert_eq!(&stderr_lines.next().unwrap(), s), - WsRecv(s) => assert!(socket_rx.next().await.unwrap().starts_with(s)), - WsSend(s) => socket_tx.send(s.into()).await.unwrap(), - } - } + assert_inspector_messages( + &mut socket_tx, + &[ + r#"{"id":1,"method":"Runtime.enable"}"#, + r#"{"id":2,"method":"Debugger.enable"}"#, + ], + &mut socket_rx, + &[ + r#"{"id":1,"result":{}}"#, + r#"{"id":2,"result":{"debuggerId":"#, + ], + &[ + r#"{"method":"Runtime.executionContextCreated","params":{"context":{"id":1,"#, + ], + ) + .await; + + assert_inspector_messages( + &mut socket_tx, + &[r#"{"id":3,"method":"Runtime.runIfWaitingForDebugger"}"#], + &mut socket_rx, + &[r#"{"id":3,"result":{}}"#], + &[r#"{"method":"Debugger.paused","#], + ) + .await; + + assert_inspector_messages( + &mut socket_tx, + &[ + r#"{"id":4,"method":"Runtime.evaluate","params":{"expression":"Deno.core.print(\"hello from the inspector\\n\")","contextId":1,"includeCommandLineAPI":true,"silent":false,"returnByValue":true}}"#, + ], + &mut socket_rx, + &[r#"{"id":4,"result":{"result":{"type":"undefined"}}}"#], + &[], + ) + .await; + + assert_eq!(&stdout_lines.next().unwrap(), "hello from the inspector"); + + assert_inspector_messages( + &mut socket_tx, + &[r#"{"id":5,"method":"Debugger.resume"}"#], + &mut socket_rx, + &[r#"{"id":5,"result":{}}"#], + &[], + ) + .await; + + assert!(&stdout_lines + .next() + .unwrap() + .starts_with("running 1 test from")); + assert!(&stdout_lines + .next() + .unwrap() + .contains("test has finished running")); child.kill().unwrap(); child.wait().unwrap(); diff --git a/core/inspector.rs b/core/inspector.rs index 5dd3b00558..0339248854 100644 --- a/core/inspector.rs +++ b/core/inspector.rs @@ -27,7 +27,6 @@ use std::cell::BorrowMutError; use std::cell::RefCell; use std::collections::HashMap; use std::ffi::c_void; -use std::mem::replace; use std::mem::take; use std::mem::MaybeUninit; use std::pin::Pin; @@ -127,7 +126,7 @@ impl v8::inspector::V8InspectorClientImpl for JsRuntimeInspector { fn run_if_waiting_for_debugger(&mut self, context_group_id: i32) { assert_eq!(context_group_id, JsRuntimeInspector::CONTEXT_GROUP_ID); - self.flags.borrow_mut().session_handshake_done = true; + self.flags.borrow_mut().waiting_for_session = false; } } @@ -226,34 +225,20 @@ impl JsRuntimeInspector { loop { loop { // Do one "handshake" with a newly connected session at a time. - if let Some(session) = &mut sessions.handshake { - let poll_result = session.poll_unpin(cx); - let handshake_done = - replace(&mut self.flags.borrow_mut().session_handshake_done, false); - match poll_result { - Poll::Pending if handshake_done => { - let session = sessions.handshake.take().unwrap(); - sessions.established.push(session); - take(&mut self.flags.borrow_mut().waiting_for_session); - } - Poll::Ready(_) => sessions.handshake = None, - Poll::Pending => break, - }; + if let Some(mut session) = sessions.handshake.take() { + if session.poll_unpin(cx).is_pending() { + sessions.established.push(session); + continue; + } } // Accept new connections. - match sessions.session_rx.poll_next_unpin(cx) { - Poll::Ready(Some(session_proxy)) => { - let session = InspectorSession::new( - sessions.v8_inspector.clone(), - session_proxy, - ); - let prev = sessions.handshake.replace(session); - assert!(prev.is_none()); - continue; - } - Poll::Ready(None) => {} - Poll::Pending => {} + let poll_result = sessions.session_rx.poll_next_unpin(cx); + if let Poll::Ready(Some(session_proxy)) = poll_result { + let session = + InspectorSession::new(sessions.v8_inspector.clone(), session_proxy); + let prev = sessions.handshake.replace(session); + assert!(prev.is_none()); } // Poll established sessions. @@ -264,9 +249,8 @@ impl JsRuntimeInspector { }; } - let should_block = sessions.handshake.is_some() - || self.flags.borrow().on_pause - || self.flags.borrow().waiting_for_session; + let should_block = + self.flags.borrow().on_pause || self.flags.borrow().waiting_for_session; let new_state = self.waker.update(|w| { match w.poll_state { @@ -311,8 +295,11 @@ impl JsRuntimeInspector { } /// This function blocks the thread until at least one inspector client has - /// established a websocket connection and successfully completed the - /// handshake. After that, it instructs V8 to pause at the next statement. + /// established a websocket connection. + /// + /// After that, it instructs V8 to pause at the next statement. + /// Frontend must send "Runtime.runIfWaitingForDebugger" message to resume + /// execution. pub fn wait_for_session_and_break_on_next_statement(&mut self) { loop { match self.sessions.get_mut().established.iter_mut().next() { @@ -326,10 +313,6 @@ impl JsRuntimeInspector { } /// Obtain a sender for proxy channels. - /// - /// After a proxy is sent inspector will wait for a "handshake". - /// Frontend must send "Runtime.runIfWaitingForDebugger" message to - /// complete the handshake. pub fn get_session_sender(&self) -> UnboundedSender { self.new_session_tx.clone() } @@ -362,8 +345,7 @@ impl JsRuntimeInspector { }; // InspectorSessions for a local session is added directly to the "established" - // sessions, so it doesn't need to go through the session sender and handshake - // phase. + // sessions, so it doesn't need to go through the session sender. let inspector_session = InspectorSession::new(self.v8_inspector.clone(), proxy); self @@ -380,7 +362,6 @@ impl JsRuntimeInspector { #[derive(Default)] struct InspectorFlags { waiting_for_session: bool, - session_handshake_done: bool, on_pause: bool, }