@@ -14,15 +14,19 @@ use sanzu_common::{
1414 ReadWrite , Tunnel ,
1515} ;
1616
17+ use serde:: { Deserialize , Serialize } ;
18+
1719use spin_sleep:: LoopHelper ;
1820use std:: {
21+ io:: { self , BufRead , Write } ,
1922 net:: { self , IpAddr , TcpListener } ,
23+ sync:: Mutex ,
2024 time:: Instant ,
2125} ;
2226
2327#[ cfg( unix) ]
2428use std:: {
25- sync:: mpsc:: channel,
29+ sync:: mpsc:: { channel, Sender } ,
2630 thread:: { self } ,
2731} ;
2832
@@ -47,6 +51,21 @@ use crate::server_x11::init_x11rb;
4751#[ cfg( windows) ]
4852use crate :: server_windows:: init_win;
4953
54+ #[ derive( Debug , Serialize , Deserialize , Clone , Default ) ]
55+ struct ServerStats {
56+ fps : u64 ,
57+ frame_time : u64 ,
58+ grab : u64 ,
59+ enc : u64 ,
60+ send : u64 ,
61+ recv : u64 ,
62+ size : ( u16 , u16 ) ,
63+ }
64+
65+ lazy_static ! {
66+ static ref SERVER_STATS : Mutex <ServerStats > = Mutex :: new( ServerStats :: default ( ) ) ;
67+ }
68+
5069/// Tls auth / Kerberos Auth
5170fn auth_client (
5271 config_tls : & ConfigTls ,
@@ -97,6 +116,56 @@ fn auth_client(
97116 Ok ( ( tls_conn, username) )
98117}
99118
119+ /// Handle control api
120+ /// restart => restart encoder
121+ /// stats => send encoding stats
122+ fn control_api ( control_path : & str , control_sender : Sender < ( ) > ) {
123+ let pid = std:: process:: id ( ) ;
124+ let control_path = control_path. replace ( "%PID%" , & format ! ( "{pid}" ) ) ;
125+ // Try to remove path first
126+ let _ = std:: fs:: remove_file ( & control_path) ;
127+ let listener = std:: os:: unix:: net:: UnixListener :: bind ( & control_path)
128+ . unwrap_or_else ( |_| panic ! ( "Cannot bind {:?}" , control_path) ) ;
129+ loop {
130+ let ( mut client, addr) = listener. accept ( ) . expect ( "Error in UnixListener accept" ) ;
131+ info ! ( "Client {:?}" , addr) ;
132+ let control_sender_cp = control_sender. clone ( ) ;
133+ thread:: spawn ( move || {
134+ let mut command = String :: new ( ) ;
135+ if let Ok ( length) = io:: BufReader :: new ( & mut client) . read_line ( & mut command) {
136+ info ! ( "Command: {:?} {}" , command, length) ;
137+ match command. trim_end ( ) {
138+ "restart" => {
139+ info ! ( "Restart encoder requested" ) ;
140+ control_sender_cp. send ( ( ) ) . expect ( "Cannot send control" ) ;
141+ if client. write_all ( "Ok" . as_bytes ( ) ) . is_err ( ) {
142+ warn ! ( "Cannot send ok" ) ;
143+ }
144+ }
145+ "stats" => {
146+ info ! ( "Stats requested" ) ;
147+ let stats = SERVER_STATS . lock ( ) . unwrap ( ) . clone ( ) ;
148+
149+ if let Ok ( stats_str) = serde_json:: to_string ( & stats) {
150+ if client. write_all ( stats_str. as_bytes ( ) ) . is_err ( ) {
151+ warn ! ( "Cannot send stat" ) ;
152+ }
153+ } else {
154+ warn ! ( "Cannot generate stats" ) ;
155+ }
156+ }
157+ _ => {
158+ error ! ( "Unknown command" ) ;
159+ if client. write_all ( "Unknown command" . as_bytes ( ) ) . is_err ( ) {
160+ warn ! ( "Cannot send stat" ) ;
161+ }
162+ }
163+ }
164+ }
165+ } ) ;
166+ }
167+ }
168+
100169/// Exec main loop
101170///
102171pub fn run ( config : & ConfigServer , arguments : & ArgumentsSrv ) -> Result < ( ) > {
@@ -374,34 +443,18 @@ pub fn run_server(config: &ConfigServer, arguments: &ArgumentsSrv) -> Result<()>
374443 let mut loop_helper = LoopHelper :: builder ( ) . build_with_target_rate ( config. video . max_fps as f64 ) ; // limit FPS if possible
375444
376445 let mut new_size = None ;
377- let mut cur_size = None ;
446+ let ( width, height) = server_info. size ( ) ;
447+ let mut cur_size = Some ( ( width as u32 , height as u32 ) ) ;
378448
379449 // Do socket control
380450 #[ cfg( unix) ]
381451 let ( control_sender, control_receiver) = channel ( ) ;
382452 #[ cfg( unix) ]
383453 {
384- let control_path = config
385- . video
386- . control_path
387- . as_ref ( )
388- . map ( |path| path. to_owned ( ) ) ;
389- if let Some ( control_path) = control_path {
454+ if let Some ( control_path) = config. video . control_path . as_ref ( ) . cloned ( ) {
390455 info ! ( "Listening on control path {:?}" , control_path) ;
391456 thread:: spawn ( move || {
392- let pid = std:: process:: id ( ) ;
393- let control_path = control_path. replace ( "%PID%" , & format ! ( "{pid}" ) ) ;
394- // Try to remove path first
395- let _ = std:: fs:: remove_file ( & control_path) ;
396- let listener = std:: os:: unix:: net:: UnixListener :: bind ( & control_path)
397- . unwrap_or_else ( |_| panic ! ( "Cannot bind {:?}" , control_path) ) ;
398- loop {
399- let ( _, addr) = listener. accept ( ) . expect ( "Error in UnixListener accept" ) ;
400- info ! ( "Client {:?}" , addr) ;
401- control_sender
402- . send ( "test" . to_owned ( ) )
403- . expect ( "Cannot send control" ) ;
404- }
457+ control_api ( & control_path. clone ( ) , control_sender) ;
405458 } ) ;
406459 }
407460 }
@@ -563,6 +616,23 @@ pub fn run_server(config: &ConfigServer, arguments: &ArgumentsSrv) -> Result<()>
563616 ) ;
564617 debug ! ( "{}" , msg) ;
565618 msg_stats = msg;
619+ let fps = match frame_time_micro as u64 {
620+ 0 => 0 ,
621+ micros => 1_000_000 / micros,
622+ } ;
623+ let size = match cur_size. as_ref ( ) {
624+ Some ( ( width, height) ) => ( * width as u16 , * height as u16 ) ,
625+ None => ( 0 , 0 ) ,
626+ } ;
627+ * SERVER_STATS . lock ( ) . unwrap ( ) = ServerStats {
628+ fps,
629+ frame_time : ( time_start - prev_time_start) . as_millis ( ) as u64 ,
630+ grab : ( time_grab - time_start) . as_millis ( ) as u64 ,
631+ enc : ( time_encode - time_event) . as_millis ( ) as u64 ,
632+ send : ( time_send - time_sound) . as_millis ( ) as u64 ,
633+ recv : ( time_stop - time_send) . as_millis ( ) as u64 ,
634+ size,
635+ } ;
566636
567637 prev_time_start = time_start;
568638 loop_helper. loop_sleep ( ) ; // sleeps to acheive target FPS rate
0 commit comments