Skip to content

Commit 25289de

Browse files
authored
Revert "perf(desktop): serve over in-process memory channel instead of TCP loopback (#35272)" (#35670)
Reverts #35272 (`perf(desktop): serve over in-process memory channel instead of TCP loopback`).
1 parent 541c51b commit 25289de

14 files changed

Lines changed: 54 additions & 660 deletions

File tree

Cargo.lock

Lines changed: 0 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/args/flags.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -830,7 +830,7 @@ static ENV_VARS: &[EnvVar] = &[
830830
name: "DENO_SERVE_ADDRESS",
831831
description: "Override address for Deno.serve",
832832
example: Some(
833-
r#"("tcp:0.0.0.0:8080", "unix:/tmp/deno.sock", "vsock:1234:5678", or "memory:my-app")"#,
833+
r#"("tcp:0.0.0.0:8080", "unix:/tmp/deno.sock", or "vsock:1234:5678")"#,
834834
),
835835
},
836836
EnvVar {

cli/rt_desktop/Cargo.toml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,13 @@ deno_core.workspace = true
2323
deno_core.workspace = true
2424
deno_error.workspace = true
2525
deno_lib.workspace = true
26-
deno_net.workspace = true
2726
deno_runtime.workspace = true
2827
deno_snapshots.workspace = true
2928
deno_terminal.workspace = true
3029
denort = { path = "../rt" }
3130
laufey = "0.5.0"
3231
libsui.workspace = true
3332

34-
bytes.workspace = true
35-
http-body-util.workspace = true
36-
hyper.workspace = true
37-
hyper-util.workspace = true
3833
log = { workspace = true, features = ["serde"] }
3934
raw-window-handle.workspace = true
4035
rustls.workspace = true

cli/rt_desktop/lib.rs

Lines changed: 53 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,8 @@
88
//! shared library and provides the browser/window layer.
99
//!
1010
//! The user's code uses `Deno.serve()` or `export default { fetch }`
11-
//! to serve an HTTP app. The desktop runtime starts it on an in-process
12-
//! memory channel and navigates the webview to `app://`, whose requests are
13-
//! bridged into that channel by [`scheme_bridge`] — there is no TCP loopback.
14-
15-
mod scheme_bridge;
11+
//! to serve an HTTP app. The desktop runtime starts it on a local port
12+
//! and navigates the webview to it.
1613
1714
use std::borrow::Cow;
1815
use std::collections::HashMap;
@@ -33,6 +30,7 @@ use deno_core::anyhow::bail;
3330
use deno_core::error::AnyError;
3431
use deno_core::serde_json;
3532
use deno_core::v8;
33+
use deno_lib::util::net::allocate_random_port;
3634
use deno_lib::util::result::js_error_downcast_ref;
3735
use deno_lib::version::otel_runtime_config;
3836
use deno_runtime::fmt_errors::format_js_error;
@@ -1257,24 +1255,26 @@ laufey::main!(|| {
12571255

12581256
laufey::set_js_namespace("bindings");
12591257

1260-
// Serve over an in-process memory channel — there is no TCP loopback for the
1261-
// desktop app at all. No port allocation, no localhost exposure, no kernel
1262-
// networking. The webview reaches the server through the `app://` scheme
1263-
// handler registered below, which bridges each browser request into this
1264-
// named in-memory channel.
1265-
//
1266-
// Publish DENO_SERVE_ADDRESS BEFORE the tokio runtime is built. Once the
1267-
// runtime spins up its mio IO thread (and, optionally, the inspector server
1268-
// thread), `setenv` is no longer thread-safe on glibc — Rust 1.81+ marks it
1269-
// unsafe for that reason. We're still single-threaded up to here: the
1270-
// worker-fork path has already returned, and the init calls above
1271-
// (init_logging, mark_standalone, rustls install_default, set_js_namespace)
1272-
// don't spawn threads.
1258+
// Allocate the desktop serve port and publish it via DENO_SERVE_ADDRESS
1259+
// BEFORE the tokio runtime is built. Once the runtime spins up its
1260+
// mio IO thread (and, optionally, the inspector server thread),
1261+
// `setenv` is no longer thread-safe on glibc — Rust 1.81+ marks it
1262+
// unsafe for that reason. We're still single-threaded up to here:
1263+
// the worker-fork path has already returned, and the init calls
1264+
// above (init_logging, mark_standalone, rustls install_default,
1265+
// set_js_namespace) don't spawn threads.
1266+
let desktop_serve_port = match allocate_random_port() {
1267+
Ok(p) => p,
1268+
Err(e) => {
1269+
log::error!("[desktop] failed to allocate serve port: {}", e);
1270+
return;
1271+
}
1272+
};
12731273
// SAFETY: see the block comment above — single-threaded at this point.
12741274
unsafe {
12751275
std::env::set_var(
12761276
"DENO_SERVE_ADDRESS",
1277-
format!("memory:{}", scheme_bridge::DESKTOP_SERVE_NAME),
1277+
format!("tcp:127.0.0.1:{}", desktop_serve_port),
12781278
);
12791279
}
12801280

@@ -1320,7 +1320,7 @@ laufey::main!(|| {
13201320

13211321
rt.block_on(async {
13221322
log::debug!("[desktop] run_desktop starting");
1323-
match run_desktop(update_rolled_back, data).await {
1323+
match run_desktop(update_rolled_back, desktop_serve_port, data).await {
13241324
Ok(()) => log::debug!("[desktop] run_desktop completed OK"),
13251325
Err(error) => {
13261326
let is_js_error = js_error_downcast_ref(&error).is_some();
@@ -1567,6 +1567,7 @@ fn find_section_in_dylib() -> Result<&'static [u8], AnyError> {
15671567

15681568
async fn run_desktop(
15691569
update_rolled_back: bool,
1570+
desktop_serve_port: u16,
15701571
data: denort::binary::StandaloneData,
15711572
) -> Result<(), AnyError> {
15721573
// Make the error reporting URL available to the panic hook.
@@ -1634,9 +1635,9 @@ async fn run_desktop(
16341635
log::debug!("[desktop] inspector server bound on {addr}");
16351636
}
16361637

1637-
// DENO_SERVE_ADDRESS (an in-process `memory:` channel) is published by
1638-
// `laufey::main!` before the tokio runtime is built — see the comment there
1639-
// for why we can't do it from here.
1638+
// DENO_SERVE_ADDRESS is published by `laufey::main!` before the
1639+
// tokio runtime is built — see the comment there for why we can't
1640+
// do it from here. `desktop_serve_port` is the port we put into it.
16401641

16411642
// Enable HMR if DENO_DESKTOP_HMR is set to a directory path
16421643
// (set by `deno compile --desktop --hmr`).
@@ -1714,10 +1715,8 @@ async fn run_desktop(
17141715

17151716
let run_opts = RunOptions {
17161717
auto_serve: true,
1717-
// The desktop app serves over an in-process memory channel
1718-
// (DENO_SERVE_ADDRESS=memory:…), so there is no TCP serve port/host.
1719-
serve_port: None,
1720-
serve_host: None,
1718+
serve_port: Some(desktop_serve_port),
1719+
serve_host: Some("127.0.0.1".to_string()),
17211720
hmr_watch_dir: if is_framework_dev {
17221721
None
17231722
} else {
@@ -1795,6 +1794,7 @@ async fn run_desktop(
17951794
// Run the Deno runtime and Laufey event loop concurrently.
17961795
// We spawn the runtime first, wait for the server to be ready,
17971796
// then navigate the webview.
1797+
let url = format!("http://127.0.0.1:{}", desktop_serve_port);
17981798
log::debug!("[desktop] starting runtime and laufey event loop");
17991799
let run_fut =
18001800
denort::run::run_with_options(Arc::new(sys.clone()), sys, data, run_opts);
@@ -1838,29 +1838,42 @@ async fn run_desktop(
18381838
}
18391839
}
18401840

1841-
// Register the app:// scheme handler now that we're running on the Deno
1842-
// tokio runtime (the bridge spawns request tasks onto it), then wait for
1843-
// Deno.serve to bind the in-process channel before navigating.
1844-
scheme_bridge::register();
1845-
18461841
let id = initial_window_id_for_navigate.load(Ordering::Acquire);
18471842
let mut server_ready = false;
18481843
for i in 0..60 {
1849-
if deno_net::memory::is_listening(scheme_bridge::DESKTOP_SERVE_NAME) {
1850-
log::debug!(
1851-
"[desktop] Server ready after {} attempts, navigating to {}",
1852-
i + 1,
1853-
scheme_bridge::APP_URL
1844+
if let Ok(mut stream) =
1845+
tokio::net::TcpStream::connect(("127.0.0.1", desktop_serve_port)).await
1846+
{
1847+
let req = format!(
1848+
"GET / HTTP/1.1\r\nHost: 127.0.0.1:{}\r\nConnection: close\r\n\r\n",
1849+
desktop_serve_port
18541850
);
1855-
server_ready = true;
1856-
break;
1851+
if stream.write_all(req.as_bytes()).await.is_ok() {
1852+
let mut buf = vec![0u8; 256];
1853+
if let Ok(n) = stream.read(&mut buf).await {
1854+
let response = String::from_utf8_lossy(&buf[..n]);
1855+
if response.starts_with("HTTP/1.1 2")
1856+
|| response.starts_with("HTTP/1.1 3")
1857+
|| response.starts_with("HTTP/1.0 2")
1858+
|| response.starts_with("HTTP/1.0 3")
1859+
{
1860+
log::debug!(
1861+
"[desktop] Server ready after {} attempts, navigating to {}",
1862+
i + 1,
1863+
&url
1864+
);
1865+
server_ready = true;
1866+
break;
1867+
}
1868+
}
1869+
}
18571870
}
18581871
tokio::time::sleep(std::time::Duration::from_millis(250)).await;
18591872
}
18601873
if !server_ready {
18611874
log::warn!("Server not ready after 15s, navigating anyway");
18621875
}
1863-
laufey::Window::from_id(id).navigate(scheme_bridge::APP_URL);
1876+
laufey::Window::from_id(id).navigate(&url);
18641877

18651878
// The window was created hidden and is normally revealed from its
18661879
// `on_page_load` handler the moment content paints. If that load never

0 commit comments

Comments
 (0)