11use anyhow:: { anyhow, Result } ;
2- use std:: time:: Duration ;
32use tokio:: net:: UnixListener ;
43
54use crate :: cdp:: CdpClient ;
65use crate :: commands;
76use crate :: friendly;
87use crate :: protocol:: * ;
98
10- const IDLE_TIMEOUT : Duration = Duration :: from_secs ( 300 ) ; // 5 minutes
11-
12- pub async fn run_daemon ( ws_url : & str ) -> Result < ( ) > {
9+ pub async fn run_daemon (
10+ ws_url : & str ,
11+ initial_idle_timeout : Option < DaemonIdleTimeout > ,
12+ ) -> Result < ( ) > {
1313 let mut client = CdpClient :: connect ( ws_url) . await ?;
14+ let mut idle_timeout = initial_idle_timeout. unwrap_or ( DaemonIdleTimeout :: DEFAULT ) ;
1415
1516 // Clean up stale socket
1617 let sock = socket_path ( ) ;
@@ -23,10 +24,8 @@ pub async fn run_daemon(ws_url: &str) -> Result<()> {
2324
2425 // Signal readiness by socket existence (it's already bound)
2526 loop {
26- let accept = tokio:: time:: timeout ( IDLE_TIMEOUT , listener. accept ( ) ) . await ;
27-
28- match accept {
29- Ok ( Ok ( ( mut stream, _) ) ) => {
27+ match accept_with_idle_timeout ( & listener, idle_timeout) . await {
28+ Ok ( Some ( ( mut stream, _) ) ) => {
3029 let req_bytes = match read_msg ( & mut stream) . await {
3130 Ok ( b) => b,
3231 Err ( e) => {
@@ -48,19 +47,23 @@ pub async fn run_daemon(ws_url: &str) -> Result<()> {
4847 }
4948 } ;
5049
50+ if let Some ( next_idle_timeout) = request. daemon_idle_timeout {
51+ idle_timeout = next_idle_timeout;
52+ }
53+
5154 let response = handle_request ( & mut client, & request) . await ;
5255
5356 if let Ok ( resp_bytes) = serde_json:: to_vec ( & response) {
5457 let _ = write_msg ( & mut stream, & resp_bytes) . await ;
5558 }
5659 }
57- Ok ( Err ( e) ) => {
58- eprintln ! ( "daemon: accept error: {e}" ) ;
59- }
60- Err ( _) => {
60+ Ok ( None ) => {
6161 // Idle timeout — exit
6262 break ;
6363 }
64+ Err ( e) => {
65+ eprintln ! ( "daemon: accept error: {e}" ) ;
66+ }
6467 }
6568 }
6669
@@ -69,6 +72,23 @@ pub async fn run_daemon(ws_url: &str) -> Result<()> {
6972 Ok ( ( ) )
7073}
7174
75+ async fn accept_with_idle_timeout (
76+ listener : & UnixListener ,
77+ idle_timeout : DaemonIdleTimeout ,
78+ ) -> std:: result:: Result <
79+ Option < ( tokio:: net:: UnixStream , tokio:: net:: unix:: SocketAddr ) > ,
80+ std:: io:: Error ,
81+ > {
82+ if let Some ( duration) = idle_timeout. as_duration ( ) {
83+ return match tokio:: time:: timeout ( duration, listener. accept ( ) ) . await {
84+ Ok ( accept_result) => accept_result. map ( Some ) ,
85+ Err ( _) => Ok ( None ) ,
86+ } ;
87+ }
88+
89+ listener. accept ( ) . await . map ( Some )
90+ }
91+
7292async fn handle_request ( client : & mut CdpClient , req : & DaemonRequest ) -> DaemonResponse {
7393 match execute_command ( client, req) . await {
7494 Ok ( output) => DaemonResponse {
@@ -85,7 +105,10 @@ async fn handle_request(client: &mut CdpClient, req: &DaemonRequest) -> DaemonRe
85105}
86106
87107fn is_browser_level ( cmd : & str ) -> bool {
88- matches ! ( cmd, "list-pages" | "new-page" | "close-page" | "select-page" )
108+ matches ! (
109+ cmd,
110+ "list-pages" | "new-page" | "close-page" | "select-page"
111+ )
89112}
90113
91114async fn execute_command ( client : & mut CdpClient , req : & DaemonRequest ) -> Result < String > {
@@ -145,11 +168,15 @@ async fn execute_command(client: &mut CdpClient, req: &DaemonRequest) -> Result<
145168 commands:: evaluate:: evaluate ( client, & session_id, expr, req. json_output ) . await
146169 }
147170 "click" => {
148- let sel = args[ "selector" ] . as_str ( ) . ok_or ( anyhow ! ( "selector required" ) ) ?;
171+ let sel = args[ "selector" ]
172+ . as_str ( )
173+ . ok_or ( anyhow ! ( "selector required" ) ) ?;
149174 commands:: input:: click ( client, & session_id, sel) . await
150175 }
151176 "fill" => {
152- let sel = args[ "selector" ] . as_str ( ) . ok_or ( anyhow ! ( "selector required" ) ) ?;
177+ let sel = args[ "selector" ]
178+ . as_str ( )
179+ . ok_or ( anyhow ! ( "selector required" ) ) ?;
153180 let val = args[ "value" ] . as_str ( ) . ok_or ( anyhow ! ( "value required" ) ) ?;
154181 commands:: input:: fill ( client, & session_id, sel, val) . await
155182 }
@@ -162,12 +189,12 @@ async fn execute_command(client: &mut CdpClient, req: &DaemonRequest) -> Result<
162189 commands:: input:: press_key ( client, & session_id, key) . await
163190 }
164191 "hover" => {
165- let sel = args[ "selector" ] . as_str ( ) . ok_or ( anyhow ! ( "selector required" ) ) ?;
192+ let sel = args[ "selector" ]
193+ . as_str ( )
194+ . ok_or ( anyhow ! ( "selector required" ) ) ?;
166195 commands:: input:: hover ( client, & session_id, sel) . await
167196 }
168- "snapshot" => {
169- commands:: snapshot:: take_snapshot ( client, & session_id, req. json_output ) . await
170- }
197+ "snapshot" => commands:: snapshot:: take_snapshot ( client, & session_id, req. json_output ) . await ,
171198 "resize" => {
172199 let w = args[ "width" ] . as_u64 ( ) . ok_or ( anyhow ! ( "width required" ) ) ? as u32 ;
173200 let h = args[ "height" ] . as_u64 ( ) . ok_or ( anyhow ! ( "height required" ) ) ? as u32 ;
0 commit comments