@@ -650,6 +650,14 @@ struct DaemonMetadata {
650650 project_root : PathBuf ,
651651 pid : u32 ,
652652 http_url : String ,
653+ #[ serde( default = "default_daemon_port" ) ]
654+ port : u16 ,
655+ #[ serde( default = "default_daemon_bind" ) ]
656+ bind : IpAddr ,
657+ #[ serde( default , skip_serializing_if = "Option::is_none" ) ]
658+ advertise_host : Option < String > ,
659+ #[ serde( default , skip_serializing_if = "Option::is_none" ) ]
660+ client_root : Option < PathBuf > ,
653661 access_token : String ,
654662 #[ serde( default , skip_serializing_if = "Option::is_none" ) ]
655663 pairing_code : Option < String > ,
@@ -669,6 +677,14 @@ struct DaemonMetadata {
669677 local_stream_fps : Option < u32 > ,
670678}
671679
680+ fn default_daemon_port ( ) -> u16 {
681+ 4310
682+ }
683+
684+ fn default_daemon_bind ( ) -> IpAddr {
685+ IpAddr :: V4 ( Ipv4Addr :: LOCALHOST )
686+ }
687+
672688#[ derive( Clone , Debug ) ]
673689struct DaemonLaunchOptions {
674690 port : u16 ,
@@ -914,11 +930,11 @@ fn start_project_daemon(options: DaemonLaunchOptions) -> anyhow::Result<DaemonMe
914930 args. push ( "--local-stream-fps" . to_owned ( ) ) ;
915931 args. push ( local_stream_fps. to_string ( ) ) ;
916932 }
917- if let Some ( advertise_host) = options. advertise_host {
933+ if let Some ( advertise_host) = & options. advertise_host {
918934 args. push ( "--advertise-host" . to_owned ( ) ) ;
919- args. push ( advertise_host) ;
935+ args. push ( advertise_host. clone ( ) ) ;
920936 }
921- if let Some ( client_root) = options. client_root {
937+ if let Some ( client_root) = & options. client_root {
922938 args. push ( "--client-root" . to_owned ( ) ) ;
923939 args. push ( client_root. to_string_lossy ( ) . into_owned ( ) ) ;
924940 }
@@ -1003,6 +1019,10 @@ done
10031019 project_root,
10041020 pid : child. id ( ) ,
10051021 http_url : format ! ( "http://127.0.0.1:{port}" ) ,
1022+ port,
1023+ bind : options. bind ,
1024+ advertise_host : options. advertise_host ,
1025+ client_root : options. client_root ,
10061026 access_token,
10071027 pairing_code : Some ( pairing_code) ,
10081028 binary_path : executable,
@@ -1147,10 +1167,14 @@ fn daemon_is_healthy(metadata: &DaemonMetadata) -> bool {
11471167}
11481168
11491169fn daemon_matches_launch_options ( metadata : & DaemonMetadata , options : & DaemonLaunchOptions ) -> bool {
1150- metadata
1151- . video_codec
1152- . as_deref ( )
1153- . is_some_and ( |codec| codec == options. video_codec . as_env_value ( ) )
1170+ metadata. port == options. port
1171+ && metadata. bind == options. bind
1172+ && metadata. advertise_host == options. advertise_host
1173+ && metadata. client_root == options. client_root
1174+ && metadata
1175+ . video_codec
1176+ . as_deref ( )
1177+ . is_some_and ( |codec| codec == options. video_codec . as_env_value ( ) )
11541178 && metadata. low_latency == options. low_latency
11551179 && metadata. realtime_stream
11561180 == ( options. realtime_stream || options. stream_quality_profile . is_some ( ) )
@@ -1366,6 +1390,10 @@ fn run_foreground_ui(selector: Option<String>) -> anyhow::Result<()> {
13661390 project_root : project_root. clone ( ) ,
13671391 pid : std:: process:: id ( ) ,
13681392 http_url : format ! ( "http://127.0.0.1:{port}" ) ,
1393+ port,
1394+ bind,
1395+ advertise_host : Some ( advertise_host. clone ( ) ) ,
1396+ client_root : None ,
13691397 access_token : access_token. clone ( ) ,
13701398 pairing_code : Some ( pairing_code. clone ( ) ) ,
13711399 binary_path : executable,
@@ -1923,6 +1951,10 @@ fn main() -> anyhow::Result<()> {
19231951 project_root,
19241952 pid : supervised_daemon_metadata_pid ( ) . unwrap_or_else ( std:: process:: id) ,
19251953 http_url : format ! ( "http://127.0.0.1:{port}" ) ,
1954+ port,
1955+ bind,
1956+ advertise_host : advertise_host. clone ( ) ,
1957+ client_root : client_root. clone ( ) ,
19261958 access_token : access_token. clone ( ) ,
19271959 pairing_code : pairing_code. clone ( ) ,
19281960 binary_path : env:: current_exe ( ) . context ( "resolve daemon executable" ) ?,
@@ -5519,13 +5551,61 @@ fn default_client_root() -> anyhow::Result<PathBuf> {
55195551#[ cfg( test) ]
55205552mod tests {
55215553 use super :: {
5522- batch_line_to_json_step, normalize_accessibility_point_for_display,
5523- server_health_watchdog_should_restart, service_post_error_is_retryable,
5524- studio_daemon_restart_args, Cli , Command , DaemonCommand , StreamQualityProfileArg ,
5525- StudioExposeOptions , VideoCodecMode , SERVER_HEALTH_WATCHDOG_FAILURE_THRESHOLD ,
5526- SERVER_HEALTH_WATCHDOG_HTTP_FAILURE_THRESHOLD ,
5554+ batch_line_to_json_step, daemon_matches_launch_options,
5555+ normalize_accessibility_point_for_display, server_health_watchdog_should_restart,
5556+ service_post_error_is_retryable, studio_daemon_restart_args, Cli , Command , DaemonCommand ,
5557+ DaemonLaunchOptions , DaemonMetadata , StreamQualityProfileArg , StudioExposeOptions ,
5558+ VideoCodecMode , DEFAULT_LOCAL_STREAM_QUALITY_PROFILE ,
5559+ SERVER_HEALTH_WATCHDOG_FAILURE_THRESHOLD , SERVER_HEALTH_WATCHDOG_HTTP_FAILURE_THRESHOLD ,
55275560 } ;
55285561 use clap:: Parser ;
5562+ use std:: path:: PathBuf ;
5563+
5564+ fn daemon_metadata_for_test (
5565+ port : u16 ,
5566+ bind : & str ,
5567+ advertise_host : Option < & str > ,
5568+ client_root : Option < & str > ,
5569+ ) -> DaemonMetadata {
5570+ DaemonMetadata {
5571+ project_root : PathBuf :: from ( "/tmp/project" ) ,
5572+ pid : 42 ,
5573+ http_url : format ! ( "http://127.0.0.1:{port}" ) ,
5574+ port,
5575+ bind : bind. parse ( ) . unwrap ( ) ,
5576+ advertise_host : advertise_host. map ( str:: to_owned) ,
5577+ client_root : client_root. map ( PathBuf :: from) ,
5578+ access_token : "token" . to_owned ( ) ,
5579+ pairing_code : Some ( "123456" . to_owned ( ) ) ,
5580+ binary_path : PathBuf :: from ( "/tmp/simdeck-bin" ) ,
5581+ started_at : 1 ,
5582+ log_path : None ,
5583+ video_codec : Some ( VideoCodecMode :: Auto . as_env_value ( ) . to_owned ( ) ) ,
5584+ low_latency : false ,
5585+ realtime_stream : true ,
5586+ stream_quality_profile : Some ( DEFAULT_LOCAL_STREAM_QUALITY_PROFILE . to_owned ( ) ) ,
5587+ local_stream_fps : None ,
5588+ }
5589+ }
5590+
5591+ fn daemon_launch_options_for_test (
5592+ port : u16 ,
5593+ bind : & str ,
5594+ advertise_host : Option < & str > ,
5595+ client_root : Option < & str > ,
5596+ ) -> DaemonLaunchOptions {
5597+ DaemonLaunchOptions {
5598+ port,
5599+ bind : bind. parse ( ) . unwrap ( ) ,
5600+ advertise_host : advertise_host. map ( str:: to_owned) ,
5601+ client_root : client_root. map ( PathBuf :: from) ,
5602+ video_codec : VideoCodecMode :: Auto ,
5603+ low_latency : false ,
5604+ realtime_stream : false ,
5605+ stream_quality_profile : Some ( DEFAULT_LOCAL_STREAM_QUALITY_PROFILE . to_owned ( ) ) ,
5606+ local_stream_fps : None ,
5607+ }
5608+ }
55295609
55305610 #[ test]
55315611 fn local_daemon_start_defaults_to_auto_video_codec ( ) {
@@ -5584,6 +5664,56 @@ mod tests {
55845664 ) ;
55855665 }
55865666
5667+ #[ test]
5668+ fn daemon_launch_options_match_listener_metadata ( ) {
5669+ let metadata = daemon_metadata_for_test ( 4310 , "127.0.0.1" , None , None ) ;
5670+ let options = daemon_launch_options_for_test ( 4310 , "127.0.0.1" , None , None ) ;
5671+
5672+ assert ! ( daemon_matches_launch_options( & metadata, & options) ) ;
5673+ }
5674+
5675+ #[ test]
5676+ fn daemon_launch_options_reject_different_port ( ) {
5677+ let metadata = daemon_metadata_for_test ( 4310 , "127.0.0.1" , None , None ) ;
5678+ let options = daemon_launch_options_for_test ( 4320 , "127.0.0.1" , None , None ) ;
5679+
5680+ assert ! ( !daemon_matches_launch_options( & metadata, & options) ) ;
5681+ }
5682+
5683+ #[ test]
5684+ fn daemon_launch_options_reject_different_bind_or_client ( ) {
5685+ let metadata =
5686+ daemon_metadata_for_test ( 4310 , "127.0.0.1" , Some ( "127.0.0.1" ) , Some ( "/tmp/client-a" ) ) ;
5687+
5688+ assert ! ( !daemon_matches_launch_options(
5689+ & metadata,
5690+ & daemon_launch_options_for_test(
5691+ 4310 ,
5692+ "0.0.0.0" ,
5693+ Some ( "127.0.0.1" ) ,
5694+ Some ( "/tmp/client-a" ) ,
5695+ ) ,
5696+ ) ) ;
5697+ assert ! ( !daemon_matches_launch_options(
5698+ & metadata,
5699+ & daemon_launch_options_for_test(
5700+ 4310 ,
5701+ "127.0.0.1" ,
5702+ Some ( "localhost" ) ,
5703+ Some ( "/tmp/client-a" ) ,
5704+ ) ,
5705+ ) ) ;
5706+ assert ! ( !daemon_matches_launch_options(
5707+ & metadata,
5708+ & daemon_launch_options_for_test(
5709+ 4310 ,
5710+ "127.0.0.1" ,
5711+ Some ( "127.0.0.1" ) ,
5712+ Some ( "/tmp/client-b" ) ,
5713+ ) ,
5714+ ) ) ;
5715+ }
5716+
55875717 #[ test]
55885718 fn lifecycle_service_posts_retry_connection_resets ( ) {
55895719 assert ! ( service_post_error_is_retryable(
0 commit comments