fix lightpanda (#1050)

* fix lightpanda

* fmt
This commit is contained in:
Chris Tate
2026-03-27 09:33:08 -07:00
committed by GitHub
parent a95bc0f75a
commit db215a1467
6 changed files with 110 additions and 44 deletions
+18 -2
View File
@@ -1,4 +1,5 @@
use std::collections::HashMap;
use std::io::Write;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
@@ -90,10 +91,25 @@ impl CdpClient {
Ok(text) => text,
Err(_) => continue,
},
Ok(Message::Close(_)) => break,
Ok(Message::Close(frame)) => {
if std::env::var("AGENT_BROWSER_DEBUG").is_ok() {
let reason = frame
.as_ref()
.map(|f| format!("code={}, reason={}", f.code, f.reason))
.unwrap_or_else(|| "no frame".to_string());
let _ =
writeln!(std::io::stderr(), "[cdp] WebSocket Close: {}", reason);
}
break;
}
Ok(Message::Pong(_)) => continue,
Ok(_) => continue,
Err(_) => break,
Err(e) => {
if std::env::var("AGENT_BROWSER_DEBUG").is_ok() {
let _ = writeln!(std::io::stderr(), "[cdp] WebSocket Error: {}", e);
}
break;
}
};
// Broadcast raw message for inspect proxy subscribers before typed parse,
+21
View File
@@ -22,6 +22,27 @@ pub async fn run_daemon(session: &str) {
let _ = fs::create_dir_all(&socket_dir);
}
// When debug mode is on, redirect stderr to a log file so daemon
// output can be inspected (the daemon normally has stderr piped to its
// parent which drops the read end after startup).
#[cfg(unix)]
if env::var("AGENT_BROWSER_DEBUG").is_ok() {
let log_path = socket_dir.join(format!("{}.log", session));
if let Ok(file) = fs::File::create(&log_path) {
use std::os::unix::io::IntoRawFd;
let fd = file.into_raw_fd();
unsafe {
libc::dup2(fd, 2);
libc::close(fd);
}
let _ = writeln!(
std::io::stderr(),
"[daemon] Debug logging started for session: {}",
session
);
}
}
let pid_path = socket_dir.join(format!("{}.pid", session));
let _ = fs::write(&pid_path, process::id().to_string());
+14 -5
View File
@@ -776,6 +776,10 @@ async fn cdp_event_loop(
let vw = *viewport_width.lock().await;
let vh = *viewport_height.lock().await;
let eng = last_engine.read().await.clone();
let supports_screencast = eng == "chrome";
if supports_screencast {
let _ = client_arc
.send_command(
"Page.startScreencast",
@@ -789,19 +793,19 @@ async fn cdp_event_loop(
session_id.as_deref(),
)
.await;
}
{
let mut sc = screencasting.lock().await;
*sc = true;
*sc = supports_screencast;
}
// Broadcast screencasting:true status with current viewport
let eng = last_engine.read().await.clone();
// Broadcast connection status with current viewport
let rec = *recording.lock().await;
let status = json!({
"type": "status",
"connected": true,
"screencasting": true,
"screencasting": supports_screencast,
"viewportWidth": vw,
"viewportHeight": vh,
"engine": eng,
@@ -814,10 +818,12 @@ async fn cdp_event_loop(
tokio::select! {
changed = shutdown_rx.changed() => {
if changed.is_err() || *shutdown_rx.borrow() {
if supports_screencast {
let session_id = cdp_session_id.read().await.clone();
let _ = client_arc
.send_command_no_params("Page.stopScreencast", session_id.as_deref())
.await;
}
let mut sc = screencasting.lock().await;
*sc = false;
return;
@@ -943,9 +949,11 @@ async fn cdp_event_loop(
let count = *client_count.lock().await;
let new_session_id = cdp_session_id.read().await.clone();
if count == 0 {
if supports_screencast {
let _ = client_arc
.send_command_no_params("Page.stopScreencast", session_id.as_deref())
.await;
}
let mut sc = screencasting.lock().await;
*sc = false;
break;
@@ -962,10 +970,11 @@ async fn cdp_event_loop(
let new_vh = *viewport_height.lock().await;
let viewport_changed = new_vw != vw || new_vh != vh;
if client_changed || session_changed || viewport_changed {
// Stop screencast, restart loop to pick up new settings
if supports_screencast {
let _ = client_arc
.send_command_no_params("Page.stopScreencast", session_id.as_deref())
.await;
}
let mut sc = screencasting.lock().await;
*sc = false;
client_notify.notify_one();
@@ -194,14 +194,20 @@ export function Viewport() {
addressRef.current?.blur();
const target = normalizeUrl(addressValue);
const previousUrl = url;
setAddressValue(target);
setNavigating(true);
try {
await runCmd("navigate", target);
const result = await runCmd("navigate", target);
if (!result.success) {
setAddressValue(previousUrl || "about:blank");
}
} catch {
setAddressValue(previousUrl || "about:blank");
} finally {
setNavigating(false);
}
}, [addressValue, navigating, runCmd]);
}, [addressValue, navigating, runCmd, url]);
const drawFrame = useCallback((base64: string) => {
const canvas = canvasRef.current;
+13
View File
@@ -8,12 +8,21 @@ export interface ExecResult {
}
export async function execCommand(args: string[]): Promise<ExecResult> {
try {
const resp = await fetch(`http://localhost:${DASHBOARD_PORT}/api/exec`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ args }),
});
return resp.json();
} catch {
return {
success: false,
exit_code: null,
stdout: "",
stderr: "Network error: dashboard server unreachable",
};
}
}
export function sessionArgs(session: string, ...args: string[]): string[] {
@@ -21,10 +30,14 @@ export function sessionArgs(session: string, ...args: string[]): string[] {
}
export async function killSession(session: string): Promise<{ success: boolean; killed_pid?: number }> {
try {
const resp = await fetch(`http://localhost:${DASHBOARD_PORT}/api/kill`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ session }),
});
return resp.json();
} catch {
return { success: false };
}
}
File diff suppressed because one or more lines are too long