refactor remote interface
This commit is contained in:
		
							parent
							
								
									694896abda
								
							
						
					
					
						commit
						bdcb848a75
					
				| @ -1651,6 +1651,12 @@ pub trait Interface: Send + Clone + 'static + Sized { | ||||
|     fn handle_login_error(&mut self, err: &str) -> bool; | ||||
|     fn handle_peer_info(&mut self, pi: PeerInfo); | ||||
|     fn set_force_relay(&mut self, direct: bool, received: bool); | ||||
|     fn is_file_transfer(&self) -> bool; | ||||
|     fn is_port_forward(&self) -> bool; | ||||
|     fn is_rdp(&self) -> bool; | ||||
|     fn on_error(&self, err: &str) { | ||||
|         self.msgbox("error", "Error", err); | ||||
|     } | ||||
|     fn is_force_relay(&self) -> bool; | ||||
|     async fn handle_hash(&mut self, pass: &str, hash: Hash, peer: &mut Stream); | ||||
|     async fn handle_login_from_ui(&mut self, password: String, remember: bool, peer: &mut Stream); | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| use hbb_common::{fs, message_proto::*}; | ||||
| use hbb_common::{fs, message_proto::*, log}; | ||||
| 
 | ||||
| use super::{Data, Interface}; | ||||
| 
 | ||||
| @ -114,4 +114,26 @@ pub trait FileManager: Interface { | ||||
|     fn resume_job(&self, id: i32, is_remote: bool) { | ||||
|         self.send(Data::ResumeJob((id, is_remote))); | ||||
|     } | ||||
| 
 | ||||
|     fn set_confirm_override_file( | ||||
|         &self, | ||||
|         id: i32, | ||||
|         file_num: i32, | ||||
|         need_override: bool, | ||||
|         remember: bool, | ||||
|         is_upload: bool, | ||||
|     ) { | ||||
|         log::info!( | ||||
|             "confirm file transfer, job: {}, need_override: {}", | ||||
|             id, | ||||
|             need_override | ||||
|         ); | ||||
|         self.send(Data::SetConfirmOverrideFile(( | ||||
|             id, | ||||
|             file_num, | ||||
|             need_override, | ||||
|             remember, | ||||
|             is_upload, | ||||
|         ))); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -39,8 +39,9 @@ pub(super) const APP_TYPE_MAIN: &str = "main"; | ||||
| pub(super) const APP_TYPE_DESKTOP_REMOTE: &str = "remote"; | ||||
| pub(super) const APP_TYPE_DESKTOP_FILE_TRANSFER: &str = "file transfer"; | ||||
| 
 | ||||
| const MILLI1: Duration = Duration::from_millis(1); | ||||
| 
 | ||||
| lazy_static::lazy_static! { | ||||
|     // static ref SESSION: Arc<RwLock<Option<Session>>> = Default::default();
 | ||||
|     pub static ref SESSIONS: RwLock<HashMap<String,Session>> = Default::default(); | ||||
|     pub static ref GLOBAL_EVENT_STREAM: RwLock<HashMap<String, StreamSink<String>>> = Default::default(); // rust to dart event channel
 | ||||
| } | ||||
| @ -48,9 +49,6 @@ lazy_static::lazy_static! { | ||||
| static SERVER_CLIPBOARD_ENABLED: AtomicBool = AtomicBool::new(true); | ||||
| static SERVER_KEYBOARD_ENABLED: AtomicBool = AtomicBool::new(true); | ||||
| 
 | ||||
| // pub fn get_session<'a>(id: &str) -> Option<&'a Session> {
 | ||||
| //     SESSIONS.read().unwrap().get(id)
 | ||||
| // }
 | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| pub struct Session { | ||||
| @ -113,10 +111,6 @@ impl Session { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Get the current session instance.
 | ||||
|     // pub fn get() -> Arc<RwLock<Option<Session>>> {
 | ||||
|     //     SESSION.clone()
 | ||||
|     // }
 | ||||
| 
 | ||||
|     /// Get the option of the current session.
 | ||||
|     ///
 | ||||
| @ -252,57 +246,6 @@ impl Session { | ||||
|         self.send_msg(msg_out); | ||||
|     } | ||||
| 
 | ||||
|     // file trait
 | ||||
|     /// Send file over the current session.
 | ||||
|     // pub fn send_files(
 | ||||
|     //     id: i32,
 | ||||
|     //     path: String,
 | ||||
|     //     to: String,
 | ||||
|     //     file_num: i32,
 | ||||
|     //     include_hidden: bool,
 | ||||
|     //     is_remote: bool,
 | ||||
|     // ) {
 | ||||
|     //     if let Some(session) = SESSION.write().unwrap().as_mut() {
 | ||||
|     //         session.send_files(id, path, to, file_num, include_hidden, is_remote);
 | ||||
|     //     }
 | ||||
|     // }
 | ||||
| 
 | ||||
|     // TODO into file trait
 | ||||
|     /// Confirm file override.
 | ||||
|     pub fn set_confirm_override_file( | ||||
|         &self, | ||||
|         id: i32, | ||||
|         file_num: i32, | ||||
|         need_override: bool, | ||||
|         remember: bool, | ||||
|         is_upload: bool, | ||||
|     ) { | ||||
|         log::info!( | ||||
|             "confirm file transfer, job: {}, need_override: {}", | ||||
|             id, | ||||
|             need_override | ||||
|         ); | ||||
|         self.send(Data::SetConfirmOverrideFile(( | ||||
|             id, | ||||
|             file_num, | ||||
|             need_override, | ||||
|             remember, | ||||
|             is_upload, | ||||
|         ))); | ||||
|     } | ||||
| 
 | ||||
|     /// Static method to send message over the current session.
 | ||||
|     ///
 | ||||
|     /// # Arguments
 | ||||
|     ///
 | ||||
|     /// * `msg` - The message to send.
 | ||||
|     // #[inline]
 | ||||
|     // pub fn send_msg_static(msg: Message) {
 | ||||
|     //     if let Some(session) = SESSION.read().unwrap().as_ref() {
 | ||||
|     //         session.send_msg(msg);
 | ||||
|     //     }
 | ||||
|     // }
 | ||||
| 
 | ||||
|     /// Push an event to the event queue.
 | ||||
|     /// An event is stored as json in the event queue.
 | ||||
|     ///
 | ||||
| @ -595,6 +538,18 @@ impl Interface for Session { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn is_file_transfer(&self) -> bool { | ||||
|         todo!() | ||||
|     } | ||||
| 
 | ||||
|     fn is_port_forward(&self) -> bool { | ||||
|         todo!() | ||||
|     } | ||||
| 
 | ||||
|     fn is_rdp(&self) -> bool { | ||||
|         todo!() | ||||
|     } | ||||
| 
 | ||||
|     fn msgbox(&self, msgtype: &str, title: &str, text: &str) { | ||||
|         let has_retry = if check_if_retry(msgtype, title, text) { | ||||
|             "true" | ||||
| @ -706,7 +661,6 @@ impl Interface for Session { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| const MILLI1: Duration = Duration::from_millis(1); | ||||
| 
 | ||||
| struct Connection { | ||||
|     video_handler: VideoHandler, | ||||
|  | ||||
| @ -48,6 +48,7 @@ mod port_forward; | ||||
| mod tray; | ||||
| 
 | ||||
| mod ui_interface; | ||||
| mod ui_session_interface; | ||||
| 
 | ||||
| #[cfg(windows)] | ||||
| pub mod clipboard_file; | ||||
|  | ||||
| @ -146,7 +146,7 @@ pub fn start(args: &mut [String]) { | ||||
|         let args: Vec<String> = iter.map(|x| x.clone()).collect(); | ||||
|         frame.set_title(&id); | ||||
|         frame.register_behavior("native-remote", move || { | ||||
|             Box::new(remote::Handler::new( | ||||
|             Box::new(remote::SciterSession::new( | ||||
|                 cmd.clone(), | ||||
|                 id.clone(), | ||||
|                 pass.clone(), | ||||
|  | ||||
							
								
								
									
										870
									
								
								src/ui/remote.rs
									
									
									
									
									
								
							
							
						
						
									
										870
									
								
								src/ui/remote.rs
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										257
									
								
								src/ui_session_interface.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								src/ui_session_interface.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,257 @@ | ||||
| use crate::client::{ | ||||
|     self, check_if_retry, handle_hash, handle_login_from_ui, handle_test_delay, input_os_password, | ||||
|     FileManager, LoginConfigHandler, QualityStatus, load_config, | ||||
| }; | ||||
| use crate::{client::Data, client::Interface}; | ||||
| use async_trait::async_trait; | ||||
| use hbb_common::config::PeerConfig; | ||||
| use hbb_common::message_proto::{CursorData, Hash, PeerInfo, TestDelay, CursorPosition}; | ||||
| use hbb_common::tokio::{ | ||||
|     self, | ||||
|     sync::mpsc, | ||||
|     time::{self, Duration, Instant, Interval}, | ||||
| }; | ||||
| use hbb_common::{get_version_number, log, Stream}; | ||||
| use std::ops::{Deref, DerefMut}; | ||||
| use std::sync::{Arc, RwLock}; | ||||
| 
 | ||||
| #[derive(Clone, Default)] | ||||
| pub struct Session<T: InvokeUi> { | ||||
|     pub cmd: String, | ||||
|     pub id: String, | ||||
|     pub password: String, | ||||
|     pub args: Vec<String>, | ||||
|     pub lc: Arc<RwLock<LoginConfigHandler>>, | ||||
|     pub sender: Arc<RwLock<Option<mpsc::UnboundedSender<Data>>>>, | ||||
|     pub ui_handler: T, | ||||
| } | ||||
| 
 | ||||
| impl<T: InvokeUi> Session<T> { | ||||
|     pub fn get_option(&self, k: String) -> String { | ||||
|         self.lc.read().unwrap().get_option(&k) | ||||
|     } | ||||
| 
 | ||||
|     pub fn set_option(&self, k: String, v: String) { | ||||
|         self.lc.write().unwrap().set_option(k, v); | ||||
|     } | ||||
|     
 | ||||
|     #[inline] | ||||
|     pub fn load_config(&self) -> PeerConfig { | ||||
|         load_config(&self.id) | ||||
|     } | ||||
| 
 | ||||
|     #[inline] | ||||
|     pub(super) fn save_config(&self, config: PeerConfig) { | ||||
|         self.lc.write().unwrap().save_config(config); | ||||
|     } | ||||
| 
 | ||||
|     pub fn is_restarting_remote_device(&self) -> bool { | ||||
|         self.lc.read().unwrap().restarting_remote_device | ||||
|     } | ||||
| 
 | ||||
|     #[inline] | ||||
|     pub fn peer_platform(&self) -> String { | ||||
|         self.lc.read().unwrap().info.platform.clone() | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_platform(&mut self, is_remote: bool) -> String { | ||||
|         if is_remote { | ||||
|             self.peer_platform() | ||||
|         } else { | ||||
|             whoami::platform().to_string() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_path_sep(&mut self, is_remote: bool) -> &'static str { | ||||
|         let p = self.get_platform(is_remote); | ||||
|         if &p == "Windows" { | ||||
|             return "\\"; | ||||
|         } else { | ||||
|             return "/"; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub trait InvokeUi: Send + Sync + Clone + 'static + Sized + Default { | ||||
|     fn set_cursor_data(&self, cd: CursorData); | ||||
|     fn set_cursor_id(&self, id: String); | ||||
|     fn set_cursor_position(&self, cp:CursorPosition); | ||||
|     fn set_display(&self, x: i32, y: i32, w: i32, h: i32); | ||||
|     fn update_privacy_mode(&self); | ||||
|     fn set_permission(&self, name: &str, value: bool); | ||||
|     fn update_pi(&self, pi: PeerInfo); | ||||
|     fn close_success(&self); | ||||
|     fn update_quality_status(&self, qs: QualityStatus); | ||||
|     fn set_connection_type(&self,is_secured: bool, direct: bool); | ||||
|     fn job_error(&self,id:i32, err:String, file_num:i32); | ||||
|     fn job_done(&self,id:i32, file_num:i32); | ||||
|     fn clear_all_jobs(&self); | ||||
|     fn add_job(&self, id:i32, path:String, to:String, file_num:i32, show_hidden:bool, is_remote:bool); | ||||
|     fn update_transfer_list(&self); | ||||
|     // fn update_folder_files(&self); // TODO
 | ||||
|     fn confirm_delete_files(&self,id:i32, i:i32, name:String); | ||||
|     fn override_file_confirm(&self, id:i32, file_num:i32, to:String, is_upload:bool); | ||||
|     fn job_progress(&self, id:i32, file_num:i32, speed:f64, finished_size:f64); | ||||
|     fn adapt_size(&self); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| impl<T: InvokeUi> Deref for Session<T> { | ||||
|     type Target = T; | ||||
| 
 | ||||
|     fn deref(&self) -> &Self::Target { | ||||
|         &self.ui_handler | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T: InvokeUi> DerefMut for Session<T> { | ||||
|     fn deref_mut(&mut self) -> &mut Self::Target { | ||||
|         &mut self.ui_handler | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T: InvokeUi> FileManager for Session<T> {} | ||||
| 
 | ||||
| #[async_trait] | ||||
| impl<T: InvokeUi> Interface for Session<T> { | ||||
|     fn send(&self, data: Data) { | ||||
|         if let Some(sender) = self.sender.read().unwrap().as_ref() { | ||||
|             sender.send(data).ok(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn is_file_transfer(&self) -> bool { | ||||
|         self.cmd == "--file-transfer" | ||||
|     } | ||||
| 
 | ||||
|     fn is_port_forward(&self) -> bool { | ||||
|         self.cmd == "--port-forward" || self.is_rdp() | ||||
|     } | ||||
| 
 | ||||
|     fn is_rdp(&self) -> bool { | ||||
|         self.cmd == "--rdp" | ||||
|     } | ||||
| 
 | ||||
|     fn msgbox(&self, msgtype: &str, title: &str, text: &str) { | ||||
|         let retry = check_if_retry(msgtype, title, text); | ||||
|         // self.call2("msgbox_retry", &make_args!(msgtype, title, text, retry));
 | ||||
|     } | ||||
| 
 | ||||
|     fn handle_login_error(&mut self, err: &str) -> bool { | ||||
|         self.lc.write().unwrap().handle_login_error(err, self) | ||||
|     } | ||||
| 
 | ||||
|     fn handle_peer_info(&mut self, pi: PeerInfo) { | ||||
|         // let mut pi_sciter = Value::map();
 | ||||
|         let username = self.lc.read().unwrap().get_username(&pi); | ||||
|         // pi_sciter.set_item("username", username.clone());
 | ||||
|         // pi_sciter.set_item("hostname", pi.hostname.clone());
 | ||||
|         // pi_sciter.set_item("platform", pi.platform.clone());
 | ||||
|         // pi_sciter.set_item("sas_enabled", pi.sas_enabled);
 | ||||
|         if get_version_number(&pi.version) < get_version_number("1.1.10") { | ||||
|             self.set_permission("restart", false); | ||||
|         } | ||||
|         if self.is_file_transfer() { | ||||
|             if pi.username.is_empty() { | ||||
|                 self.on_error("No active console user logged on, please connect and logon first."); | ||||
|                 return; | ||||
|             } | ||||
|         } else if !self.is_port_forward() { | ||||
|             if pi.displays.is_empty() { | ||||
|                 self.lc.write().unwrap().handle_peer_info(username, pi); | ||||
|                 self.update_privacy_mode(); | ||||
|                 self.msgbox("error", "Remote Error", "No Display"); | ||||
|                 return; | ||||
|             } | ||||
|             // let mut displays = Value::array(0);
 | ||||
|             // for ref d in pi.displays.iter() {
 | ||||
|             //     let mut display = Value::map();
 | ||||
|             //     display.set_item("x", d.x);
 | ||||
|             //     display.set_item("y", d.y);
 | ||||
|             //     display.set_item("width", d.width);
 | ||||
|             //     display.set_item("height", d.height);
 | ||||
|             //     displays.push(display);
 | ||||
|             // }
 | ||||
|             // pi_sciter.set_item("displays", displays);
 | ||||
|             let mut current = pi.current_display as usize; | ||||
|             if current >= pi.displays.len() { | ||||
|                 current = 0; | ||||
|             } | ||||
|             // pi_sciter.set_item("current_display", current as i32);
 | ||||
|             let current = &pi.displays[current]; | ||||
|             self.set_display(current.x, current.y, current.width, current.height); | ||||
|             // https://sciter.com/forums/topic/color_spaceiyuv-crash
 | ||||
|             // Nothing spectacular in decoder – done on CPU side.
 | ||||
|             // So if you can do BGRA translation on your side – the better.
 | ||||
|             // BGRA is used as internal image format so it will not require additional transformations.
 | ||||
|             // VIDEO.lock().unwrap().as_mut().map(|v| {
 | ||||
|             //     let ok = v.start_streaming(
 | ||||
|             //         (current.width as _, current.height as _),
 | ||||
|             //         COLOR_SPACE::Rgb32,
 | ||||
|             //         None,
 | ||||
|             //     );
 | ||||
|             //     log::info!("[video] initialized: {:?}", ok);
 | ||||
|             // });
 | ||||
|             let p = self.lc.read().unwrap().should_auto_login(); | ||||
|             if !p.is_empty() { | ||||
|                 input_os_password(p, true, self.clone()); | ||||
|             } | ||||
|         } | ||||
|         self.lc.write().unwrap().handle_peer_info(username, pi); | ||||
|         self.update_privacy_mode(); | ||||
|         // self.update_pi(pi);
 | ||||
|         if self.is_file_transfer() { | ||||
|             self.close_success(); | ||||
|         } else if !self.is_port_forward() { | ||||
|             self.msgbox("success", "Successful", "Connected, waiting for image..."); | ||||
|         } | ||||
|         #[cfg(windows)] | ||||
|         { | ||||
|             let mut path = std::env::temp_dir(); | ||||
|             path.push(&self.id); | ||||
|             let path = path.with_extension(crate::get_app_name().to_lowercase()); | ||||
|             std::fs::File::create(&path).ok(); | ||||
|             if let Some(path) = path.to_str() { | ||||
|                 crate::platform::windows::add_recent_document(&path); | ||||
|             } | ||||
|         } | ||||
|         // self.start_keyboard_hook(); // TODO
 | ||||
|     } | ||||
| 
 | ||||
|     async fn handle_hash(&mut self, pass: &str, hash: Hash, peer: &mut Stream) { | ||||
|         handle_hash(self.lc.clone(), pass, hash, self, peer).await; | ||||
|     } | ||||
| 
 | ||||
|     async fn handle_login_from_ui(&mut self, password: String, remember: bool, peer: &mut Stream) { | ||||
|         handle_login_from_ui(self.lc.clone(), password, remember, peer).await; | ||||
|     } | ||||
| 
 | ||||
|     async fn handle_test_delay(&mut self, t: TestDelay, peer: &mut Stream) { | ||||
|         if !t.from_client { | ||||
|             self.update_quality_status(QualityStatus { | ||||
|                 delay: Some(t.last_delay as _), | ||||
|                 target_bitrate: Some(t.target_bitrate as _), | ||||
|                 ..Default::default() | ||||
|             }); | ||||
|             handle_test_delay(t, peer).await; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn set_force_relay(&mut self, direct: bool, received: bool) { | ||||
|         let mut lc = self.lc.write().unwrap(); | ||||
|         lc.force_relay = false; | ||||
|         if direct && !received { | ||||
|             let errno = errno::errno().0; | ||||
|             log::info!("errno is {}", errno); | ||||
|             // TODO: check mac and ios
 | ||||
|             if cfg!(windows) && errno == 10054 || !cfg!(windows) && errno == 104 { | ||||
|                 lc.force_relay = true; | ||||
|                 lc.set_option("force-always-relay".to_owned(), "Y".to_owned()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn is_force_relay(&self) -> bool { | ||||
|         self.lc.read().unwrap().force_relay | ||||
|     } | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user