git.lucas.co / cce-browser
web browser (Servo)
git clone https://git.lucas.co/cce-browser.git

commitdf90093c1c5fbfe799216c3fc89aae2336db57ae
parent6126faf49a
authorLucas Galante <lsgalante12@gmail.com>
date2026-10-07 22:34
refactor(open): forward through cce_core::ipc instead of a copy

cce-browser-open copied the instance client — the socket path and the
one-line forward with its ack wait — to stay clear of cce-ui's native
link flags. The client is in cce-core now, which links no native
libraries, so the bin calls cce_core::ipc::instance::forward. Same
dynamic libraries (libc, libgcc_s); checked against a stand-in instance:
the same `open <absolute path>` and `new-tab` lines, exit 0, no exec.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

 Cargo.toml      |  3 +++
 src/bin/open.rs | 43 +++++++++++--------------------------------
 2 files changed, 14 insertions(+), 32 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 76877a2..5f117dc 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -20,6 +20,9 @@ servo = ["dep:servo", "dep:dpi", "dep:euclid", "dep:rustls", "dep:http"]
 
 [dependencies]
 cce-ui = { git = "https://github.com/lsgalante/cce-ui.git", rev = "4dcb970d84f0a6aeeef5311ac1d4cacb0c63a803" }
+# For `cce-browser-open`: the instance client, from the GUI-free half of the
+# toolkit, so the launcher links no Wayland, Vulkan or WebKit.
+cce-core = { git = "https://github.com/lsgalante/cce-core.git", rev = "39e989d6ebc7850a1e5aa96bf228fe8714e538e0" }
 calloop = "0.13.0"
 wayland-client = { version = "0.31", features = ["system"] }
 servo = { version = "0.4", optional = true }
diff --git a/src/bin/open.rs b/src/bin/open.rs
index 8498210..6b7e552 100644
--- a/src/bin/open.rs
+++ b/src/bin/open.rs
@@ -6,34 +6,18 @@
 //! path. This bin exists to link nothing, forward in a few ms, and only
 //! `exec` the real browser when no instance answers.
 //!
-//! It therefore deliberately duplicates the client half of the socket
-//! protocol instead of importing it: `src/instance.rs` (same crate, on
-//! `cce_ui::ipc::instance`) is the server side and the fallback client,
-//! `cce_ui::ipc::socket_path` is the path convention. All three must agree on `/tmp/cce-browser-<display>.sock`
-//! and the `open <arg>` / `new-tab` lines. The protocol is small on purpose;
-//! change it in both files or not at all.
+//! It takes the client half of the socket protocol from `cce_core::ipc`
+//! (the GUI-free half of the toolkit, which has no native libraries): the
+//! path convention and the one-line forward with its ack wait. `src/instance.rs`
+//! (same crate, on `cce_ui::ipc::instance`, the same module) is the server side.
+//! Both must agree on the `open <arg>` / `new-tab` lines. Until 2026-10-07 this
+//! file copied both halves, to stay clear of cce-ui's native link flags.
 
-use std::io::{BufRead, BufReader, Write};
-use std::os::unix::net::UnixStream;
 use std::os::unix::process::CommandExt;
 
-fn socket_path() -> String {
-    // Mirrors cce_ui::ipc::socket_path("cce-browser") — not imported, so this
-    // bin stays free of cce-ui's native link flags.
-    match std::env::var("WAYLAND_DISPLAY") {
-        Ok(d) if !d.is_empty() => format!("/tmp/cce-browser-{d}.sock"),
-        _ => "/tmp/cce-browser.sock".to_string(),
-    }
-}
-
-/// One forwarding attempt; false on any failure. Mirrors the client half of
-/// `cce_ui::ipc::instance::forward_or_claim`, ack wait included — exiting on
-/// write alone races the instance actually reading the line — and so is its
-/// bound on that wait: a stuck instance must not hang every click forever.
+/// One forwarding attempt; false on any failure. A stuck instance does not
+/// hang the click: `forward` bounds its wait for the ack.
 fn try_forward(arg: Option<&str>) -> bool {
-    let Ok(mut stream) = UnixStream::connect(socket_path()) else {
-        return false;
-    };
     let command = match arg {
         Some(a) => {
             // A relative file path is resolved against *this* process's cwd —
@@ -46,16 +30,11 @@ fn try_forward(arg: Option<&str>) -> bool {
             } else {
                 None
             };
-            format!("open {}\n", abs.as_deref().unwrap_or(a))
+            format!("open {}", abs.as_deref().unwrap_or(a))
         }
-        None => "new-tab\n".to_string(),
+        None => "new-tab".to_string(),
     };
-    if stream.write_all(command.as_bytes()).is_err() {
-        return false;
-    }
-    let _ = stream.set_read_timeout(Some(std::time::Duration::from_secs(5)));
-    let mut reply = String::new();
-    BufReader::new(stream).read_line(&mut reply).is_ok()
+    cce_core::ipc::instance::forward("cce-browser", &command).is_some()
 }
 
 fn main() {