refactor remote interface

This commit is contained in:
csf 2022-08-31 16:31:31 +08:00
parent 694896abda
commit bdcb848a75
7 changed files with 826 additions and 408 deletions

View File

@ -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);

View File

@ -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,
)));
}
}

View File

@ -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,

View File

@ -48,6 +48,7 @@ mod port_forward;
mod tray;
mod ui_interface;
mod ui_session_interface;
#[cfg(windows)]
pub mod clipboard_file;

View 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(),

File diff suppressed because it is too large Load Diff

257
src/ui_session_interface.rs Normal file
View 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
}
}