wip

Cole Miller created

Change summary

crates/project/src/debugger/session.rs | 146 ++++++++++++++--------------
1 file changed, 73 insertions(+), 73 deletions(-)

Detailed changes

crates/project/src/debugger/session.rs 🔗

@@ -14,7 +14,7 @@ use super::dap_command::{
     TerminateCommand, TerminateThreadsCommand, ThreadsCommand, VariablesCommand,
 };
 use super::dap_store::DapStore;
-use anyhow::{Context as _, Result, anyhow};
+use anyhow::{Context as _, Result, anyhow, bail};
 use base64::Engine;
 use collections::{HashMap, HashSet, IndexMap};
 use dap::adapters::{DebugAdapterBinary, DebugAdapterName};
@@ -2749,11 +2749,16 @@ impl Session {
         cx: &mut Context<Self>,
     ) {
         let task = cx.spawn(async move |_, cx| {
-            let (port, _child) =
+            let (port_for_dap, _child) =
                 if remote_client.read_with(cx, |client, _| client.shares_network_interface())? {
                     (request.server_port, None)
                 } else {
-                    let port = TcpListener::bind("127.0.0.1").await?.local_addr()?.port();
+                    let port = {
+                        let listener = TcpListener::bind("127.0.0.1:0")
+                            .await
+                            .context("getting port for DAP")?;
+                        listener.local_addr()?.port()
+                    };
                     let child = remote_client.update(cx, |client, _| {
                         let command = client.build_forward_port_command(
                             port,
@@ -2763,7 +2768,6 @@ impl Session {
                         let child = new_smol_command(command.program)
                             .args(command.args)
                             .envs(command.env)
-                            .kill_on_drop(true)
                             .spawn()
                             .context("spawning port forwarding process")?;
                         anyhow::Ok(child)
@@ -2771,32 +2775,51 @@ impl Session {
                     (port, Some(child))
                 };
 
-            let (_child, browser_stream) = spawn_browser(&request)?;
+            let port_for_browser = {
+                let listener = TcpListener::bind("127.0.0.1:0")
+                    .await
+                    .context("getting port for browser")?;
+                listener.local_addr()?.port()
+            };
+
+            let path = request.path.clone();
+            let _child = spawn_browser(request, port_for_browser)?;
 
             Tokio::spawn(cx, async move {
-                let path = request.path;
-                let url = format!("ws://localhost:{port}{path}");
+                let url = format!("ws://localhost:{port_for_dap}{path}");
                 log::info!("will connect to DAP running on remote at {url}");
-                let (dap_stream, _response) = tokio_tungstenite::connect_async(&url).await?;
+                let (dap_stream, _response) = tokio_tungstenite::connect_async(&url)
+                    .await
+                    .context("connecting to DAP")?;
                 let (mut dap_in, mut dap_out) = dap_stream.split();
                 log::info!("established websocket connection to DAP running on remote");
 
-                // FIXME what url to use here?
-                let (browser_stream, _response) =
-                    tokio_tungstenite::client_async("ws://localhost", browser_stream).await?;
+                let url = format!("ws://localhost:{port_for_browser}");
+                log::info!("will connect to browser running running locally at {url}");
+                tokio::time::sleep(std::time::Duration::from_millis(1000)).await;
+                let (browser_stream, _response) = tokio_tungstenite::connect_async(&url)
+                    .await
+                    .context("connecting to browser")?;
                 let (mut browser_in, mut browser_out) = browser_stream.split();
+                log::info!("established websocket connection to browser running locally");
 
                 let down_task = tokio::spawn(async move {
                     while let Some(message) = dap_out.next().await {
-                        let message = message?;
-                        browser_in.send(message).await?;
+                        let message = message.context("reading message from DAP")?;
+                        browser_in
+                            .send(message)
+                            .await
+                            .context("sending message to browser")?;
                     }
                     anyhow::Ok(())
                 });
                 let up_task = tokio::spawn(async move {
                     while let Some(message) = browser_out.next().await {
-                        let message = message?;
-                        dap_in.send(message).await?;
+                        let message = message.context("reading message from browser")?;
+                        dap_in
+                            .send(message)
+                            .await
+                            .context("sending message to DAP")?;
                     }
                     anyhow::Ok(())
                 });
@@ -2808,69 +2831,46 @@ impl Session {
             anyhow::Ok(())
         });
         self.background_tasks.push(cx.spawn(async move |_, _| {
-            task.await.ok();
+            task.await.log_err();
         }));
     }
 }
 
-struct BrowserStream {
-    browser_in: async_compat::Compat<smol::Unblock<std::io::PipeWriter>>,
-    browser_out: async_compat::Compat<smol::Unblock<std::io::PipeReader>>,
-}
-
-impl BrowserStream {
-    fn new() -> Result<(Self, std::io::PipeWriter, std::io::PipeReader)> {
-        todo!()
-    }
-}
-
-impl tokio::io::AsyncRead for BrowserStream {
-    fn poll_read(
-        mut self: Pin<&mut Self>,
-        cx: &mut std::task::Context<'_>,
-        buf: &mut tokio::io::ReadBuf<'_>,
-    ) -> std::task::Poll<std::io::Result<()>> {
-        let browser_out = unsafe { Pin::new_unchecked(&mut self.browser_out) };
-        browser_out.poll_read(cx, buf)
-    }
-}
-
-impl tokio::io::AsyncWrite for BrowserStream {
-    fn poll_write(
-        mut self: Pin<&mut Self>,
-        cx: &mut std::task::Context<'_>,
-        buf: &[u8],
-    ) -> std::task::Poll<std::result::Result<usize, std::io::Error>> {
-        let browser_in = unsafe { Pin::new_unchecked(&mut self.browser_in) };
-        browser_in.poll_write(cx, buf)
-    }
-
-    fn poll_flush(
-        mut self: Pin<&mut Self>,
-        cx: &mut std::task::Context<'_>,
-    ) -> std::task::Poll<std::result::Result<(), std::io::Error>> {
-        let browser_in = unsafe { Pin::new_unchecked(&mut self.browser_in) };
-        browser_in.poll_flush(cx)
-    }
-
-    fn poll_shutdown(
-        mut self: Pin<&mut Self>,
-        cx: &mut std::task::Context<'_>,
-    ) -> std::task::Poll<std::result::Result<(), std::io::Error>> {
-        let browser_in = unsafe { Pin::new_unchecked(&mut self.browser_in) };
-        browser_in.poll_shutdown(cx)
-    }
-}
-
-#[cfg(windows)]
 fn spawn_browser(
-    request: &LaunchBrowserInCompanionParams,
-) -> Result<(smol::process::Child, Pin<Box<BrowserStream>>)> {
-    let (stream, child_in, child_out) = BrowserStream::new()?;
-
-    // create process
-    // DuplicateHandle or w/e
-    Box::pin(stream)
+    mut request: LaunchBrowserInCompanionParams,
+    port_for_browser: u16,
+) -> Result<smol::process::Child> {
+    if let Some(ix) = request
+        .browser_args
+        .iter()
+        .position(|arg| arg == "--remote-debugging-pipe")
+    {
+        request.browser_args[ix] = format!("--remote-debugging-port={port_for_browser}");
+        request
+            .browser_args
+            .retain(|arg| !arg.starts_with("--remote-debugging-io-pipes"));
+    } else {
+        // FIXME
+        bail!("expected --remote-debugging-pipe")
+    }
+
+    dbg!(&request.browser_args);
+
+    // FIXME
+    let path = match request.r#type.as_str() {
+        "edge" => "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe",
+        "chrome" => "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
+        other => bail!("unrecognized browser debugging type: {other:?}"),
+    };
+
+    let child = new_smol_command(path)
+        .args(request.browser_args)
+        .stdin(Stdio::null())
+        .stdout(Stdio::null())
+        .stderr(Stdio::null())
+        .spawn()
+        .context("spawning browser")?;
+    Ok(child)
 }
 
 #[derive(Deserialize)]