From f88d6327676586c2000f6dcbb8e12a1e2700bee4 Mon Sep 17 00:00:00 2001 From: John Doty Date: Fri, 29 Dec 2023 07:28:43 -0800 Subject: [PATCH] WIP: Put a pin in this. It's broken but I'm moving on for a minute --- Cargo.lock | 76 ++++--- Cargo.toml | 4 + oden-js-sys/quickjs/Makefile | 8 +- src/script/debugger.rs | 400 ++++++++++++++++++++++------------- 4 files changed, 309 insertions(+), 179 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f6aa2494..3ab0eeff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -150,7 +150,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.18", + "syn 2.0.37", ] [[package]] @@ -180,6 +180,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" + [[package]] name = "better_scoped_tls" version = "0.1.1" @@ -295,7 +301,7 @@ checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.37", ] [[package]] @@ -304,6 +310,12 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + [[package]] name = "calloop" version = "0.10.5" @@ -521,7 +533,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "577ec3850834c2578eb44afa9250f9a807f8497664e6e2aaae19cea0aac2fe3b" dependencies = [ "anyhow", - "base64", + "base64 0.13.1", "deno_media_type", "dprint-swc-ext", "serde", @@ -716,7 +728,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.37", ] [[package]] @@ -749,7 +761,7 @@ dependencies = [ "pmutil", "proc-macro2", "swc_macros_common", - "syn 2.0.18", + "syn 2.0.37", ] [[package]] @@ -1034,7 +1046,7 @@ dependencies = [ "pmutil", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.37", ] [[package]] @@ -1536,7 +1548,9 @@ name = "oden" version = "0.1.0" dependencies = [ "anyhow", + "base64 0.21.4", "bytemuck", + "bytes", "deno_ast", "env_logger", "fontdue", @@ -1546,7 +1560,9 @@ dependencies = [ "notify", "oden-js", "pollster", + "sha-1", "sourcemap 7.0.0", + "thiserror", "tracy-client", "wgpu", "winit", @@ -1712,7 +1728,7 @@ checksum = "52a40bc70c2c58040d2d8b167ba9a5ff59fc9dab7ad44771cfde3dcfde7a09c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.37", ] [[package]] @@ -1764,9 +1780,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.59" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" dependencies = [ "unicode-ident", ] @@ -1788,9 +1804,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.28" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -2006,7 +2022,7 @@ checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.37", ] [[package]] @@ -2211,7 +2227,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.18", + "syn 2.0.37", ] [[package]] @@ -2277,7 +2293,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.18", + "syn 2.0.37", ] [[package]] @@ -2326,7 +2342,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.18", + "syn 2.0.37", ] [[package]] @@ -2409,7 +2425,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.18", + "syn 2.0.37", ] [[package]] @@ -2438,7 +2454,7 @@ version = "0.178.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "675b5c755b0448268830e85e59429095d3423c0ce4a850b209c6f0eeab069f63" dependencies = [ - "base64", + "base64 0.13.1", "dashmap", "indexmap", "once_cell", @@ -2513,7 +2529,7 @@ dependencies = [ "pmutil", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.37", ] [[package]] @@ -2525,7 +2541,7 @@ dependencies = [ "pmutil", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.37", ] [[package]] @@ -2549,7 +2565,7 @@ dependencies = [ "proc-macro2", "quote", "swc_macros_common", - "syn 2.0.18", + "syn 2.0.37", ] [[package]] @@ -2565,9 +2581,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" dependencies = [ "proc-macro2", "quote", @@ -2594,22 +2610,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.37", ] [[package]] @@ -2699,7 +2715,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.37", ] [[package]] @@ -2907,7 +2923,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.37", "wasm-bindgen-shared", ] @@ -2941,7 +2957,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.37", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index aba24a55..0ebe9f63 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,9 @@ tracing = ["tracy-client/enable"] [dependencies] anyhow = "1.0" +base64 = "0.21.4" bytemuck = { version = "1.13", features = ["derive"] } +bytes = "1.5.0" deno_ast = { version = "0.29.3", features = ["transpiling", "typescript"] } env_logger = "0.10" fontdue = "0.7.3" @@ -20,7 +22,9 @@ lru = "0.11.0" notify = "6" oden-js = { path = "oden-js" } pollster = "0.3" +sha-1 = "0.10.0" sourcemap = "7.0.0" +thiserror = "1.0.49" tracy-client = { version = "0.15.2", default-features = false } wgpu = "0.17" winit = "0.28" diff --git a/oden-js-sys/quickjs/Makefile b/oden-js-sys/quickjs/Makefile index 097a7e9e..0c9202a5 100644 --- a/oden-js-sys/quickjs/Makefile +++ b/oden-js-sys/quickjs/Makefile @@ -132,7 +132,7 @@ else LDEXPORT=-rdynamic endif -PROGS=qjs$(EXE) qjsc$(EXE) run-test262 +PROGS=qjs$(EXE) qjsc$(EXE) qjsd$(EXE) run-test262 ifneq ($(CROSS_PREFIX),) QJSC_CC=gcc QJSC=./host-qjsc @@ -196,6 +196,12 @@ qjsc$(EXE): $(OBJDIR)/qjsc.o $(QJS_LIB_OBJS) qjsc-debug$(EXE): $(OBJDIR)/qjsc.debug.o $(patsubst %.o, %.debug.o, $(QJS_LIB_OBJS)) $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) +qjsd$(EXE): $(OBJDIR)/qjsd.o $(QJS_LIB_OBJS) + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +qjsd-debug$(EXE): $(OBJDIR)/qjsd.debug.o $(patsubst %.o, %.debug.o, $(QJS_LIB_OBJS)) + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + ifneq ($(CROSS_PREFIX),) $(QJSC): $(OBJDIR)/qjsc.host.o \ diff --git a/src/script/debugger.rs b/src/script/debugger.rs index 214e8b52..389b0cb8 100644 --- a/src/script/debugger.rs +++ b/src/script/debugger.rs @@ -1,33 +1,146 @@ use base64::Engine; use bytes::buf::BufMut; -use oden_js::{Context, Runtime, ValueRef}; +use oden_js::{Context, ContextRef, Runtime, ValueRef}; use sha1::{Digest, Sha1}; use std::collections::HashMap; use std::io; use std::io::{BufRead, BufReader, Read, Write}; use std::net::{TcpListener, TcpStream}; +use std::sync::{ + mpsc::{channel, Receiver, Sender}, + Arc, Mutex, +}; use std::thread; use thiserror::Error; +pub enum DebuggerMethod { + UnknownMethod, + DebuggerEnable, + DebuggerSetAsyncCallStackDepth, + DebuggerSetBlackboxPatterns, + DebuggerSetPauseOnExceptions, + ProfilerEnable, + RuntimeEvaluate, + RuntimeEnable, + RuntimeRunIfWaitingForDebugger, +} + +impl DebuggerMethod { + pub fn from_request(method: &str, _params: &ValueRef) -> Result { + let evt = match method { + "Profiler.enable" => DebuggerMethod::ProfilerEnable, + "Runtime.enable" => DebuggerMethod::RuntimeEnable, + "Runtime.evaluate" => DebuggerMethod::RuntimeEvaluate, + "Runtime.runIfWaitingForDebugger" => DebuggerMethod::RuntimeRunIfWaitingForDebugger, + "Debugger.enable" => DebuggerMethod::DebuggerEnable, + "Debugger.setAsyncCallStackDepth" => DebuggerMethod::DebuggerSetAsyncCallStackDepth, + "Debugger.setBlackboxPatterns" => DebuggerMethod::DebuggerSetBlackboxPatterns, + "Debugger.setPauseOnExceptions" => DebuggerMethod::DebuggerSetPauseOnExceptions, + _ => { + eprintln!("Unsupported method: {method}"); + DebuggerMethod::UnknownMethod + } + }; + + Ok(evt) + } +} + +struct DebuggerMessage { + pub id: String, + pub session_id: Option, + pub method: DebuggerMethod, + pub response: Websocket, +} + +impl DebuggerMessage { + pub fn from_message( + context: &ContextRef, + message: &ValueRef, + response: Websocket, + ) -> Result { + let session_id = { + let session_id = message.get_property(&context, "sessionId")?; + if session_id.is_undefined() { + None + } else { + Some(session_id.to_string(&context)?) + } + }; + let id = { + let id = message.get_property(context, "id")?; + id.to_string(&context)? + }; + let method = { + let method = message.get_property(&context, "method")?; + method.to_string(&context)? + }; + let params = message.get_property(&context, "params")?; + + let method = DebuggerMethod::from_request(&method, ¶ms)?; + Ok(DebuggerMessage { + id, + session_id, + method, + response, + }) + } +} + +pub enum DebuggerEvent { + Error { + id: String, + code: i32, + message: String, + }, +} + pub struct Debugger { _thread: thread::JoinHandle<()>, + messages: Receiver, } #[allow(dead_code)] pub fn start_debugger() -> Debugger { + let (send_message, receive_message) = channel(); let thread = thread::spawn(move || { - if let Err(e) = debugger_listener() { - eprintln!("ERROR STARTING DEBUGGER: {:?}", e); + if let Err(e) = debugger_listener(send_message) { + eprintln!("Error in debug listener: {:?}", e); } }); - Debugger { _thread: thread } + Debugger { + _thread: thread, + messages: receive_message, + } } -pub fn debugger_listener() -> Result<()> { +#[allow(dead_code)] +impl Debugger { + pub fn handle_debugger_messages(&self, _context: &Context) { + while let Ok(msg) = self.messages.try_recv() { + let event = match msg.method { + // TODO + _ => DebuggerEvent::Error { + id: msg.id.clone(), + code: -32601, + message: "Unsupported method".to_string(), + }, + }; + + // msg.response.send_json_response(context, context.new_string(msg.id)? + // let _ = msg.response.send(event); + } + } + + pub fn send_debug_event(&self) {} +} + +pub fn debugger_listener(send: Sender) -> Result<()> { let listener = TcpListener::bind("127.0.0.1:9229")?; let port = listener.local_addr()?.port(); println!("Debugger listening on http://127.0.0.1:{port}"); + for stream in listener.incoming() { let stream = match stream { Ok(s) => s, @@ -37,42 +150,57 @@ pub fn debugger_listener() -> Result<()> { } }; - DebuggerConnection::start(stream); + DebuggerConnection::start(stream, send.clone()); } Ok(()) } struct DebuggerConnection { stream: TcpStream, + send: Sender, + event_send: Sender, + events: Receiver, context: Context, } impl DebuggerConnection { - fn start(stream: TcpStream) { + fn start(stream: TcpStream, send: Sender) -> Sender { + let (event_send, event_receive) = channel(); + let result = event_send.clone(); thread::spawn(move || { let mut connection = DebuggerConnection { stream, + send, + event_send, + events: event_receive, context: Context::new(Runtime::new()), }; loop { - if let Err(e) = connection.handle_connection() { - eprintln!("Closing connection: {e}"); - break; + match connection.handle_connection() { + Ok(keep_open) => { + if !keep_open { + break; + } + } + Err(e) => { + eprintln!("Closing connection: {e}"); + break; + } } } }); + result } // ============================================================================ // Dumb HTTP stuff // ============================================================================ - fn handle_connection(&mut self) -> Result<()> { + fn handle_connection(&mut self) -> Result { let port = self.stream.local_addr()?.port(); let id = "dd5cfe85-f0b1-4241-a643-8ed81e436188"; - let mut buf_reader = BufReader::new(&mut self.stream); - let mut buffer = String::new(); + let mut buf_reader = BufReader::new(&mut self.stream); while buffer.trim().is_empty() { buf_reader.read_line(&mut buffer)?; } @@ -81,7 +209,7 @@ impl DebuggerConnection { if parts.len() != 3 { eprintln!("Invalid request line: {buffer}"); self.write_http_error(400, "Invalid request")?; - return Ok(()); + return Ok(false); } let method = parts[0]; @@ -102,7 +230,7 @@ impl DebuggerConnection { Some(idx) => idx, None => { self.write_http_error(400, "Invalid request")?; - return Ok(()); + return Ok(false); } }; let header = &header_line[0..sep_idx]; @@ -148,7 +276,7 @@ impl DebuggerConnection { Some(v) => v.clone(), None => { self.write_http_error(400, "Invalid request")?; - return Ok(()); + return Ok(false); } }; key.push_str("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); @@ -165,13 +293,14 @@ impl DebuggerConnection { self.stream.write_all(response.as_bytes())?; self.handle_websocket_connection()?; + return Ok(false); } else { self.write_http_error(404, "Not Found")?; } } else { self.write_http_error(404, "Not Found")?; } - Ok(()) + Ok(true) } fn write_http_response( @@ -201,23 +330,68 @@ impl DebuggerConnection { self.write_http_response(200, "OK", content_type, data) } - // ============================================================================ - // Dumb Websocket stuff - // ============================================================================ fn handle_websocket_connection(&mut self) -> Result<()> { - // BLARG: https://datatracker.ietf.org/doc/html/rfc6455 - + let websocket = Websocket::new(&self.stream)?; let mut payload: Vec = Vec::new(); - let mut opcode: WebsocketOp = WebsocketOp::Continue; - loop { - let frame = WebsocketFrameHeader::read(&mut self.stream)?; + let op = websocket.read_websocket_message(&mut payload)?; + if let WebsocketOp::Close = op { + return Ok(()); + } + let text = String::from_utf8_lossy(&payload); + eprintln!("Received: {text}"); + + let message = match self.context.parse_json(&text, "") { + Ok(v) => v, + Err(e) => { + eprintln!("error parsing json {e}"); + websocket.send_websocket_close(1007, "invalid json")?; + return Err("invalid json".into()); + } + }; + + let message = + DebuggerMessage::from_message(&self.context, &message, websocket.clone())?; + let _ = self.send.send(message); + } + } +} + +// ============================================================================ +// Dumb Websocket stuff +// ============================================================================ +#[derive(Clone)] +struct Websocket { + // TODO: Atomic close + send: Arc>, + receive: Arc>, +} + +impl Websocket { + pub fn new(stream: &TcpStream) -> Result { + let send = stream.try_clone()?; + let receive = stream.try_clone()?; + Ok(Websocket { + send: Arc::new(Mutex::new(send)), + receive: Arc::new(Mutex::new(receive)), + }) + } + + pub fn read_websocket_message(&self, payload: &mut Vec) -> Result { + // BLARG: https://datatracker.ietf.org/doc/html/rfc6455 + payload.clear(); + + let mut stream = self.receive.lock().unwrap(); + let mut opcode: WebsocketOp = WebsocketOp::Continue; + loop { + let frame = WebsocketFrameHeader::read(&mut stream)?; eprintln!("FRAME: {:?}", frame); let mask = match frame.mask { Some(m) => m, None => { eprintln!("Client sent unmasked frame"); - return Ok(()); // TODO: _Fail the WebSocket Connection_ + self.send_websocket_close(1002, "client sent unmasked frame")?; + return Err(DebuggerError::WebsocketError); } }; @@ -227,14 +401,15 @@ impl DebuggerConnection { // This is a control frame, handle it on its own. if frame.length > 125 { eprintln!("Control frame too big ({})", frame.length); - return Ok(()); // TODO: _Fail the WebSocket Connection_ + self.send_websocket_close(1002, "control frame too big")?; + return Err(DebuggerError::WebsocketError); } let mut buffer: [u8; 125] = [0; 125]; - self.stream.read_exact(&mut buffer[0..frame.length])?; + stream.read_exact(&mut buffer[0..frame.length])?; if frame.opcode == WebsocketOp::Close { self.send_websocket_message(frame.opcode, &buffer[..frame.length])?; - return Ok(()); + return Ok(WebsocketOp::Close); } else if frame.opcode == WebsocketOp::Ping { self.send_websocket_message(WebsocketOp::Pong, &buffer[..frame.length])?; } else if frame.opcode == WebsocketOp::Pong { @@ -245,13 +420,14 @@ impl DebuggerConnection { let last_tail = payload.len(); if last_tail + frame.length > 1 * 1024 * 1024 { eprintln!("Message too big ({})", frame.length); - return Ok(()); // TODO: _Fail the WebSocket Connection_ + self.send_websocket_close(1009, "message too big")?; + return Err(DebuggerError::WebsocketError); } payload.resize(last_tail + frame.length, 0); let slice = payload.as_mut_slice(); let mut slice = &mut slice[last_tail..]; // eprintln!("Reading {} bytes", slice.len()); - self.stream.read_exact(&mut slice)?; + stream.read_exact(&mut slice)?; for i in 0..frame.length { slice[i] = slice[i] ^ mask[i % 4]; } @@ -264,27 +440,26 @@ impl DebuggerConnection { if frame.fin { // Dispatch. // eprintln!("Dispatching: {:?} {}", opcode, payload.len()); - self.handle_websocket_message(opcode, &payload)?; - payload.clear(); - opcode = WebsocketOp::Continue; + return Ok(opcode); } } } } - fn send_websocket_message(&mut self, opcode: WebsocketOp, payload: &[u8]) -> Result<()> { + pub fn send_websocket_message(&self, opcode: WebsocketOp, payload: &[u8]) -> Result<()> { + let mut stream = self.send.lock().unwrap(); WebsocketFrameHeader { fin: true, opcode, length: payload.len(), mask: None, } - .write(&mut self.stream)?; - self.stream.write_all(payload)?; + .write(&mut stream)?; + stream.write_all(payload)?; Ok(()) } - fn send_websocket_close(&mut self, close_code: u16, reason: &str) -> Result<()> { + pub fn send_websocket_close(&self, close_code: u16, reason: &str) -> Result<()> { if reason.len() > 123 { return Err("reason doesn't fit in close packet".into()); } @@ -299,103 +474,41 @@ impl DebuggerConnection { self.send_websocket_message(WebsocketOp::Close, &body[0..body_len]) } - // ============================================================================ - // Actual debugger stuff? - // ============================================================================ - fn handle_websocket_message(&mut self, _op: WebsocketOp, data: &[u8]) -> Result<()> { - let text = String::from_utf8_lossy(data); - eprintln!("Received: {text}"); - - let message = match self.context.parse_json(&text, "") { - Ok(v) => v, - Err(e) => { - eprintln!("error parsing json {e}"); - self.send_websocket_close(1007, "invalid json")?; - return Err("invalid json".into()); - } - }; - - // Oh no. - let _ = message.get_property(&self.context, "sessionId")?; - let id = message.get_property(&self.context, "id")?; - let method = { - let method = message.get_property(&self.context, "method")?; - method.to_string(&self.context)? - }; - let _ = message.get_property(&self.context, "params")?; - - match method.as_str() { - "Profiler.enable" => { - self.send_json_response(&id, self.context.new_object()?.as_ref())?; - } - - "Runtime.enable" => { - self.send_json_event( - "Runtime.executionContextCreated", - self.context - .new_object_props([( - "context", - self.context.new_object_props([ - ("id", self.context.new_i32(7)?), - ("origin", self.context.new_string("something")?), - ("name", self.context.new_string("main")?), - ("uniqueId", self.context.new_string("aaa-aaa-aaa")?), - ])?, - )])? - .as_ref(), - )?; - self.send_json_response(&id, self.context.new_object()?.as_ref())?; - } - - "Runtime.evaluate" => { - // OHHHHHHHHHH - eprintln!("****** EVALUATE *******"); - self.send_debugger_error(&id, -32601, "method does not exist")? - } - - "Runtime.runIfWaitingForDebugger" => { - self.send_json_response(&id, self.context.new_object()?.as_ref())?; - } - - "Debugger.enable" => { - self.send_json_response(&id, self.context.new_object()?.as_ref())?; - } - - "Debugger.setAsyncCallStackDepth" => { - // TODO: Do I need to respect this? - self.send_json_response(&id, self.context.new_object()?.as_ref())?; - } - - "Debugger.setBlackboxPatterns" => { - // TODO: Do I need to respect this? - self.send_json_response(&id, self.context.new_object()?.as_ref())?; - } - - "Debugger.setPauseOnExceptions" => { - // TODO: Respect this. - self.send_json_response(&id, self.context.new_object()?.as_ref())?; - } - - _ => { - eprintln!("Unsupported method: {method}"); - self.send_debugger_error(&id, -32601, "method does not exist")? - } - } - - Ok(()) + pub fn send_json_event( + &self, + context: &ContextRef, + event: &str, + params: &ValueRef, + ) -> Result<()> { + self.send_json_message( + &context, + context + .new_object_props([ + ("method", context.new_string(event)?.as_ref()), + ("params", params), + ])? + .as_ref(), + ) } - fn send_debugger_error(&mut self, id: &ValueRef, code: i32, msg: &str) -> Result<()> { + pub fn send_json_error( + &self, + context: &ContextRef, + id: &ValueRef, + code: i32, + msg: &str, + ) -> Result<()> { self.send_json_message( - self.context + &context, + context .new_object_props([ ("id", id), ( "error", - self.context + context .new_object_props([ - ("code", self.context.new_i32(code)?), - ("message", self.context.new_string(msg)?), + ("code", context.new_i32(code)?), + ("message", context.new_string(msg)?), ])? .as_ref(), ), @@ -404,29 +517,18 @@ impl DebuggerConnection { ) } - fn send_json_event(&mut self, event: &str, params: &ValueRef) -> Result<()> { - self.send_json_message( - self.context - .new_object_props([ - ("method", self.context.new_string(event)?.as_ref()), - ("params", params), - ])? - .as_ref(), - ) + pub fn send_json_response( + &self, + context: &ContextRef, + id: &ValueRef, + result: &ValueRef, + ) -> Result<()> { + let response = context.new_object_props([("id", id), ("result", result)])?; + self.send_json_message(&context, &response) } - fn send_json_response(&mut self, id: &ValueRef, result: &ValueRef) -> Result<()> { - let response = self - .context - .new_object_props([("id", id), ("result", result)])?; - self.send_json_message(&response) - } - - fn send_json_message(&mut self, value: &ValueRef) -> Result<()> { - let txt = self - .context - .json_stringify(&value)? - .to_string(&self.context)?; + pub fn send_json_message(&self, context: &ContextRef, value: &ValueRef) -> Result<()> { + let txt = context.json_stringify(&value)?.to_string(&context)?; eprintln!("Send: {txt}"); self.send_websocket_message(WebsocketOp::Text, txt.as_bytes()) } @@ -568,6 +670,8 @@ pub enum DebuggerError { JsError(oden_js::Error), #[error("an io error has occurred: {0}")] IoError(io::Error), + #[error("the websocket encountered a protocol error")] + WebsocketError, } type Result = core::result::Result;