fix(callback_host): revert close_helper_page that broke helper page loading

The close_helper_page function opened a second browser WebSocket
connection during Drop and sent a close command directly via the WS
bypassing the HTTP polling system. This interfered with the browser's
normal state and caused the helper page to fail to open.

The cached_host lift (previous commit) already solves the duplicate
helper page issue within a single process lifetime. The Drop-based
close logic is deferred until a proper cleanup mechanism is designed.

🤖 Generated with [Qoder][https://qoder.com]
This commit is contained in:
木炎
2026-04-14 09:41:33 +08:00
parent 0f70702914
commit 390a431a4b

View File

@@ -41,6 +41,7 @@ pub(crate) struct BrowserCallbackHost {
} }
#[derive(Debug)] #[derive(Debug)]
#[allow(dead_code)]
pub(crate) struct LiveBrowserCallbackHost { pub(crate) struct LiveBrowserCallbackHost {
host: Arc<BrowserCallbackHost>, host: Arc<BrowserCallbackHost>,
shutdown: Arc<AtomicBool>, shutdown: Arc<AtomicBool>,
@@ -324,13 +325,6 @@ impl BrowserCallbackExecutor for LiveBrowserCallbackHost {
impl Drop for LiveBrowserCallbackHost { impl Drop for LiveBrowserCallbackHost {
fn drop(&mut self) { fn drop(&mut self) {
// Best-effort: tell the browser to close the helper page tab.
close_helper_page(
&self.browser_ws_url,
self.host.helper_url(),
self.use_hidden_domain,
);
self.shutdown.store(true, Ordering::Relaxed); self.shutdown.store(true, Ordering::Relaxed);
if let Some(handle) = self.server_thread.lock().unwrap().take() { if let Some(handle) = self.server_thread.lock().unwrap().take() {
let _ = handle.join(); let _ = handle.join();
@@ -380,46 +374,6 @@ fn bootstrap_helper_page(
Ok(()) Ok(())
} }
/// Best-effort attempt to close the helper page tab via browser WebSocket.
/// Silently ignores all errors — this runs during Drop and must not panic.
fn close_helper_page(browser_ws_url: &str, helper_url: &str, use_hidden_domain: bool) {
let close_action = if use_hidden_domain {
"sgHideBrowerserClosePage"
} else {
"sgBrowserClosePage"
};
let result: Result<(), Box<dyn std::error::Error>> = (|| {
// Use a raw TcpStream with timeouts instead of tungstenite::connect
// which does not expose a connection timeout.
let addr = browser_ws_url
.trim_start_matches("ws://")
.trim_start_matches("wss://");
let stream = TcpStream::connect_timeout(
&addr.parse().map_err(|e| format!("addr parse: {e}"))?,
Duration::from_millis(100),
)?;
stream.set_read_timeout(Some(Duration::from_millis(200)))?;
stream.set_write_timeout(Some(Duration::from_millis(200)))?;
let (mut websocket, _) = tungstenite::client(
browser_ws_url,
stream,
)?;
websocket.send(Message::Text(
r#"{"type":"register","role":"web"}"#.to_string().into(),
))?;
// Drain the welcome prelude (best-effort, ignore timeout).
let _ = websocket.read();
let payload = json!([helper_url, close_action, helper_url]).to_string();
websocket.send(Message::Text(payload.into()))?;
Ok(())
})();
if let Err(err) = result {
eprintln!("close_helper_page best-effort failed (harmless): {err}");
}
}
fn recv_bootstrap_prelude( fn recv_bootstrap_prelude(
websocket: &mut tungstenite::WebSocket<tungstenite::stream::MaybeTlsStream<TcpStream>>, websocket: &mut tungstenite::WebSocket<tungstenite::stream::MaybeTlsStream<TcpStream>>,
) -> Result<(), PipeError> { ) -> Result<(), PipeError> {