@@ -1,4 +1,5 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::io::Write;
|
||||||
use std::sync::atomic::{AtomicU64, Ordering};
|
use std::sync::atomic::{AtomicU64, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@@ -90,10 +91,25 @@ impl CdpClient {
|
|||||||
Ok(text) => text,
|
Ok(text) => text,
|
||||||
Err(_) => continue,
|
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(Message::Pong(_)) => continue,
|
||||||
Ok(_) => 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,
|
// Broadcast raw message for inspect proxy subscribers before typed parse,
|
||||||
|
|||||||
@@ -22,6 +22,27 @@ pub async fn run_daemon(session: &str) {
|
|||||||
let _ = fs::create_dir_all(&socket_dir);
|
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 pid_path = socket_dir.join(format!("{}.pid", session));
|
||||||
let _ = fs::write(&pid_path, process::id().to_string());
|
let _ = fs::write(&pid_path, process::id().to_string());
|
||||||
|
|
||||||
|
|||||||
+37
-28
@@ -776,32 +776,36 @@ async fn cdp_event_loop(
|
|||||||
let vw = *viewport_width.lock().await;
|
let vw = *viewport_width.lock().await;
|
||||||
let vh = *viewport_height.lock().await;
|
let vh = *viewport_height.lock().await;
|
||||||
|
|
||||||
let _ = client_arc
|
let eng = last_engine.read().await.clone();
|
||||||
.send_command(
|
let supports_screencast = eng == "chrome";
|
||||||
"Page.startScreencast",
|
|
||||||
Some(json!({
|
if supports_screencast {
|
||||||
"format": "jpeg",
|
let _ = client_arc
|
||||||
"quality": 80,
|
.send_command(
|
||||||
"maxWidth": vw,
|
"Page.startScreencast",
|
||||||
"maxHeight": vh,
|
Some(json!({
|
||||||
"everyNthFrame": 1,
|
"format": "jpeg",
|
||||||
})),
|
"quality": 80,
|
||||||
session_id.as_deref(),
|
"maxWidth": vw,
|
||||||
)
|
"maxHeight": vh,
|
||||||
.await;
|
"everyNthFrame": 1,
|
||||||
|
})),
|
||||||
|
session_id.as_deref(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut sc = screencasting.lock().await;
|
let mut sc = screencasting.lock().await;
|
||||||
*sc = true;
|
*sc = supports_screencast;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Broadcast screencasting:true status with current viewport
|
// Broadcast connection status with current viewport
|
||||||
let eng = last_engine.read().await.clone();
|
|
||||||
let rec = *recording.lock().await;
|
let rec = *recording.lock().await;
|
||||||
let status = json!({
|
let status = json!({
|
||||||
"type": "status",
|
"type": "status",
|
||||||
"connected": true,
|
"connected": true,
|
||||||
"screencasting": true,
|
"screencasting": supports_screencast,
|
||||||
"viewportWidth": vw,
|
"viewportWidth": vw,
|
||||||
"viewportHeight": vh,
|
"viewportHeight": vh,
|
||||||
"engine": eng,
|
"engine": eng,
|
||||||
@@ -814,10 +818,12 @@ async fn cdp_event_loop(
|
|||||||
tokio::select! {
|
tokio::select! {
|
||||||
changed = shutdown_rx.changed() => {
|
changed = shutdown_rx.changed() => {
|
||||||
if changed.is_err() || *shutdown_rx.borrow() {
|
if changed.is_err() || *shutdown_rx.borrow() {
|
||||||
let session_id = cdp_session_id.read().await.clone();
|
if supports_screencast {
|
||||||
let _ = client_arc
|
let session_id = cdp_session_id.read().await.clone();
|
||||||
.send_command_no_params("Page.stopScreencast", session_id.as_deref())
|
let _ = client_arc
|
||||||
.await;
|
.send_command_no_params("Page.stopScreencast", session_id.as_deref())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
let mut sc = screencasting.lock().await;
|
let mut sc = screencasting.lock().await;
|
||||||
*sc = false;
|
*sc = false;
|
||||||
return;
|
return;
|
||||||
@@ -943,9 +949,11 @@ async fn cdp_event_loop(
|
|||||||
let count = *client_count.lock().await;
|
let count = *client_count.lock().await;
|
||||||
let new_session_id = cdp_session_id.read().await.clone();
|
let new_session_id = cdp_session_id.read().await.clone();
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
let _ = client_arc
|
if supports_screencast {
|
||||||
.send_command_no_params("Page.stopScreencast", session_id.as_deref())
|
let _ = client_arc
|
||||||
.await;
|
.send_command_no_params("Page.stopScreencast", session_id.as_deref())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
let mut sc = screencasting.lock().await;
|
let mut sc = screencasting.lock().await;
|
||||||
*sc = false;
|
*sc = false;
|
||||||
break;
|
break;
|
||||||
@@ -962,10 +970,11 @@ async fn cdp_event_loop(
|
|||||||
let new_vh = *viewport_height.lock().await;
|
let new_vh = *viewport_height.lock().await;
|
||||||
let viewport_changed = new_vw != vw || new_vh != vh;
|
let viewport_changed = new_vw != vw || new_vh != vh;
|
||||||
if client_changed || session_changed || viewport_changed {
|
if client_changed || session_changed || viewport_changed {
|
||||||
// Stop screencast, restart loop to pick up new settings
|
if supports_screencast {
|
||||||
let _ = client_arc
|
let _ = client_arc
|
||||||
.send_command_no_params("Page.stopScreencast", session_id.as_deref())
|
.send_command_no_params("Page.stopScreencast", session_id.as_deref())
|
||||||
.await;
|
.await;
|
||||||
|
}
|
||||||
let mut sc = screencasting.lock().await;
|
let mut sc = screencasting.lock().await;
|
||||||
*sc = false;
|
*sc = false;
|
||||||
client_notify.notify_one();
|
client_notify.notify_one();
|
||||||
|
|||||||
@@ -194,14 +194,20 @@ export function Viewport() {
|
|||||||
addressRef.current?.blur();
|
addressRef.current?.blur();
|
||||||
|
|
||||||
const target = normalizeUrl(addressValue);
|
const target = normalizeUrl(addressValue);
|
||||||
|
const previousUrl = url;
|
||||||
setAddressValue(target);
|
setAddressValue(target);
|
||||||
setNavigating(true);
|
setNavigating(true);
|
||||||
try {
|
try {
|
||||||
await runCmd("navigate", target);
|
const result = await runCmd("navigate", target);
|
||||||
|
if (!result.success) {
|
||||||
|
setAddressValue(previousUrl || "about:blank");
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
setAddressValue(previousUrl || "about:blank");
|
||||||
} finally {
|
} finally {
|
||||||
setNavigating(false);
|
setNavigating(false);
|
||||||
}
|
}
|
||||||
}, [addressValue, navigating, runCmd]);
|
}, [addressValue, navigating, runCmd, url]);
|
||||||
|
|
||||||
const drawFrame = useCallback((base64: string) => {
|
const drawFrame = useCallback((base64: string) => {
|
||||||
const canvas = canvasRef.current;
|
const canvas = canvasRef.current;
|
||||||
|
|||||||
@@ -8,12 +8,21 @@ export interface ExecResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function execCommand(args: string[]): Promise<ExecResult> {
|
export async function execCommand(args: string[]): Promise<ExecResult> {
|
||||||
const resp = await fetch(`http://localhost:${DASHBOARD_PORT}/api/exec`, {
|
try {
|
||||||
method: "POST",
|
const resp = await fetch(`http://localhost:${DASHBOARD_PORT}/api/exec`, {
|
||||||
headers: { "Content-Type": "application/json" },
|
method: "POST",
|
||||||
body: JSON.stringify({ args }),
|
headers: { "Content-Type": "application/json" },
|
||||||
});
|
body: JSON.stringify({ args }),
|
||||||
return resp.json();
|
});
|
||||||
|
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[] {
|
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 }> {
|
export async function killSession(session: string): Promise<{ success: boolean; killed_pid?: number }> {
|
||||||
const resp = await fetch(`http://localhost:${DASHBOARD_PORT}/api/kill`, {
|
try {
|
||||||
method: "POST",
|
const resp = await fetch(`http://localhost:${DASHBOARD_PORT}/api/kill`, {
|
||||||
headers: { "Content-Type": "application/json" },
|
method: "POST",
|
||||||
body: JSON.stringify({ session }),
|
headers: { "Content-Type": "application/json" },
|
||||||
});
|
body: JSON.stringify({ session }),
|
||||||
return resp.json();
|
});
|
||||||
|
return resp.json();
|
||||||
|
} catch {
|
||||||
|
return { success: false };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user