Repository: denoland/deno
Pull request: fix(unstable): update deno_tunnel for better reconnect errors

event handling is now passed as an argument so they can be emitted before the connect call returns. also adds a "reason" to reconnect to show exactly what error caused it.

Changed files:
filename: Cargo.lock
patch: @@ -2952,9 +2952,9 @@ dependencies = [
 
 [[package]]
 name = "deno_tunnel"
-version = "0.7.0"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "386488c23cda3d6f44d4fa5593a45346032902bbd5bf058e48077b85fb550f99"
+checksum = "cbe45dacb6e0d2a646b22a12fea81ba2f7128202f9ee91602782b9208da123b9"
 dependencies = [
  "pin-project",
  "quinn",

filename: Cargo.toml
patch: @@ -131,7 +131,7 @@ napi_sym = { version = "0.142.0", path = "./ext/napi/sym" }
 node_resolver = { version = "0.50.0", path = "./libs/node_resolver" }
 test_util = { package = "test_server", path = "./tests/util/server" }
 
-deno_tunnel = "0.7.0"
+deno_tunnel = "0.8.0"
 
 # widely used libraries
 anyhow = "1.0.57"

filename: cli/main.rs
patch: @@ -928,72 +928,71 @@ async fn initialize_tunnel(
     metadata.insert("entrypoint".into(), entrypoint);
   }
 
-  let (tunnel, mut events) =
-    match deno_runtime::deno_net::tunnel::TunnelConnection::connect(
-      addr,
-      hostname.to_owned(),
-      tls_config.clone(),
-      deno_runtime::deno_net::tunnel::Authentication::App {
-        token,
-        org: org.clone(),
-        app: app.clone(),
-      },
-      metadata.clone(),
-    )
-    .await
-    {
-      Ok(res) => res,
-      Err(deno_runtime::deno_net::tunnel::Error::Unauthorized) => {
-        tools::deploy::get_token_entry()?.delete_credential()?;
+  let on_event = |event| {
+    use deno_runtime::deno_net::tunnel::Event;
+    match event {
+      Event::Routed(addr) => {
+        let endpoint = if addr.port() == 443 {
+          format!("https://{}", addr.hostname())
+        } else {
+          format!("https://{}:{}", addr.hostname(), addr.port())
+        };
 
-        let token = auth_tunnel().await?;
-        deno_runtime::deno_net::tunnel::TunnelConnection::connect(
-          addr,
-          hostname.to_owned(),
-          tls_config,
-          deno_runtime::deno_net::tunnel::Authentication::App {
-            token,
-            org,
-            app,
-          },
-          metadata.clone(),
-        )
-        .await?
+        log::info!(
+          "{}",
+          colors::green(format!("You are connected to {endpoint}!"))
+        );
       }
-      Err(e) => return Err(e.into()),
-    };
-
-  let addr = tunnel.local_addr()?;
-
-  let endpoint = if addr.port() == 443 {
-    format!("https://{}", addr.hostname())
-  } else {
-    format!("https://{}:{}", addr.hostname(), addr.port())
+      Event::Reconnect(duration, reason) => {
+        let reason = if let Some(reason) = reason {
+          format!(" ({reason})")
+        } else {
+          "".into()
+        };
+        log::info!(
+          "{}",
+          colors::green(format!(
+            "Reconnecting tunnel in {}s...{}",
+            duration.as_secs(),
+            reason
+          ))
+        );
+      }
+      _ => {}
+    }
   };
 
-  tokio::spawn(async move {
-    while let Some(event) = events.next().await {
-      use deno_runtime::deno_net::tunnel::Event;
-      match event {
-        Event::Routed => {
-          log::info!(
-            "{}",
-            colors::green(format!("You are connected to {endpoint}!"))
-          );
-        }
-        Event::Reconnect(d) => {
-          log::info!(
-            "{}",
-            colors::green(format!(
-              "Reconnecting tunnel in {}s...",
-              d.as_secs()
-            ))
-          );
-        }
-        _ => {}
-      }
+  let tunnel = match deno_runtime::deno_net::tunnel::TunnelConnection::connect(
+    addr,
+    hostname.to_owned(),
+    tls_config.clone(),
+    deno_runtime::deno_net::tunnel::Authentication::App {
+      token,
+      org: org.clone(),
+      app: app.clone(),
+    },
+    metadata.clone(),
+    on_event,
+  )
+  .await
+  {
+    Ok(res) => res,
+    Err(deno_runtime::deno_net::tunnel::Error::Unauthorized) => {
+      tools::deploy::get_token_entry()?.delete_credential()?;
+
+      let token = auth_tunnel().await?;
+      deno_runtime::deno_net::tunnel::TunnelConnection::connect(
+        addr,
+        hostname.to_owned(),
+        tls_config,
+        deno_runtime::deno_net::tunnel::Authentication::App { token, org, app },
+        metadata.clone(),
+        on_event,
+      )
+      .await?
     }
-  });
+    Err(e) => return Err(e.into()),
+  };
 
   if let Some(metadata) = tunnel.metadata() {
     for (k, v) in metadata.env {