2022-05-08 21:01:03 +08:00
|
|
|
|
use std::{
|
|
|
|
|
collections::HashMap,
|
|
|
|
|
ops::Deref,
|
2022-05-23 00:03:38 +08:00
|
|
|
|
sync::{
|
2022-06-23 17:42:30 +08:00
|
|
|
|
atomic::{AtomicBool, AtomicUsize, Ordering},
|
2022-05-23 00:03:38 +08:00
|
|
|
|
Arc, Mutex, RwLock,
|
|
|
|
|
},
|
2021-03-29 15:59:14 +08:00
|
|
|
|
};
|
2022-05-08 21:01:03 +08:00
|
|
|
|
|
|
|
|
|
use sciter::{
|
|
|
|
|
dom::{
|
|
|
|
|
event::{EventReason, BEHAVIOR_EVENTS, EVENT_GROUPS, PHASE_MASK},
|
|
|
|
|
Element, HELEMENT,
|
|
|
|
|
},
|
|
|
|
|
make_args,
|
|
|
|
|
video::{video_destination, AssetPtr, COLOR_SPACE},
|
|
|
|
|
Value,
|
|
|
|
|
};
|
|
|
|
|
|
2022-02-14 17:34:09 +08:00
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
use clipboard::{
|
2022-02-15 15:35:19 +08:00
|
|
|
|
cliprdr::CliprdrClientContext, create_cliprdr_context as create_clipboard_file_context,
|
2022-02-24 11:22:19 +08:00
|
|
|
|
get_rx_clip_client, server_clip_file,
|
2022-02-14 17:34:09 +08:00
|
|
|
|
};
|
2021-03-29 15:59:14 +08:00
|
|
|
|
use enigo::{self, Enigo, KeyboardControllable};
|
2022-04-28 18:23:12 +08:00
|
|
|
|
use hbb_common::fs::{
|
2022-04-24 23:39:15 +08:00
|
|
|
|
can_enable_overwrite_detection, get_job, get_string, new_send_confirm, DigestCheckResult,
|
|
|
|
|
RemoveJobMeta,
|
2022-04-28 18:23:12 +08:00
|
|
|
|
};
|
2021-03-29 15:59:14 +08:00
|
|
|
|
use hbb_common::{
|
|
|
|
|
allow_err,
|
2022-05-18 15:45:45 +08:00
|
|
|
|
config::{Config, LocalConfig, PeerConfig},
|
|
|
|
|
fs, log,
|
2022-01-17 16:53:17 +08:00
|
|
|
|
message_proto::{permission_info::Permission, *},
|
2021-03-29 15:59:14 +08:00
|
|
|
|
protobuf::Message as _,
|
2021-07-27 23:53:12 +08:00
|
|
|
|
rendezvous_proto::ConnType,
|
2021-05-25 12:01:27 +08:00
|
|
|
|
sleep,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
tokio::{
|
|
|
|
|
self,
|
|
|
|
|
sync::mpsc,
|
|
|
|
|
time::{self, Duration, Instant, Interval},
|
|
|
|
|
},
|
|
|
|
|
Stream,
|
|
|
|
|
};
|
2022-05-13 14:46:37 +08:00
|
|
|
|
use hbb_common::{config::TransferSerde, fs::TransferJobMeta};
|
2022-05-08 21:01:03 +08:00
|
|
|
|
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
use crate::clipboard_file::*;
|
|
|
|
|
use crate::{
|
|
|
|
|
client::*,
|
2022-04-24 23:39:15 +08:00
|
|
|
|
common::{self, check_clipboard, update_clipboard, ClipboardContext, CLIPBOARD_INTERVAL},
|
2021-03-29 15:59:14 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
type Video = AssetPtr<video_destination>;
|
|
|
|
|
|
|
|
|
|
lazy_static::lazy_static! {
|
|
|
|
|
static ref ENIGO: Arc<Mutex<Enigo>> = Arc::new(Mutex::new(Enigo::new()));
|
|
|
|
|
static ref VIDEO: Arc<Mutex<Option<Video>>> = Default::default();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_key_state(key: enigo::Key) -> bool {
|
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
|
if key == enigo::Key::NumLock {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
ENIGO.lock().unwrap().get_key_state(key)
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-25 00:18:38 +08:00
|
|
|
|
static IS_IN: AtomicBool = AtomicBool::new(false);
|
2022-05-23 00:03:38 +08:00
|
|
|
|
static KEYBOARD_HOOKED: AtomicBool = AtomicBool::new(false);
|
2022-05-25 00:12:28 +08:00
|
|
|
|
static SERVER_KEYBOARD_ENABLED: AtomicBool = AtomicBool::new(true);
|
2022-05-25 00:15:46 +08:00
|
|
|
|
static SERVER_FILE_TRANSFER_ENABLED: AtomicBool = AtomicBool::new(true);
|
2022-05-25 00:02:33 +08:00
|
|
|
|
static SERVER_CLIPBOARD_ENABLED: AtomicBool = AtomicBool::new(true);
|
2022-03-07 20:16:28 +08:00
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
static mut IS_ALT_GR: bool = false;
|
2022-01-09 19:56:24 +08:00
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
#[derive(Default)]
|
|
|
|
|
pub struct HandlerInner {
|
|
|
|
|
element: Option<Element>,
|
|
|
|
|
sender: Option<mpsc::UnboundedSender<Data>>,
|
|
|
|
|
thread: Option<std::thread::JoinHandle<()>>,
|
|
|
|
|
close_state: HashMap<String, String>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Default)]
|
|
|
|
|
pub struct Handler {
|
|
|
|
|
inner: Arc<RwLock<HandlerInner>>,
|
|
|
|
|
cmd: String,
|
|
|
|
|
id: String,
|
|
|
|
|
args: Vec<String>,
|
|
|
|
|
lc: Arc<RwLock<LoginConfigHandler>>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Deref for Handler {
|
|
|
|
|
type Target = Arc<RwLock<HandlerInner>>;
|
|
|
|
|
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
|
&self.inner
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-12 17:35:25 +08:00
|
|
|
|
impl FileManager for Handler {}
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
impl sciter::EventHandler for Handler {
|
|
|
|
|
fn get_subscription(&mut self) -> Option<EVENT_GROUPS> {
|
|
|
|
|
Some(EVENT_GROUPS::HANDLE_BEHAVIOR_EVENT)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn attached(&mut self, root: HELEMENT) {
|
|
|
|
|
self.write().unwrap().element = Some(Element::from(root));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn detached(&mut self, _root: HELEMENT) {
|
|
|
|
|
self.write().unwrap().element = None;
|
|
|
|
|
self.write().unwrap().sender.take().map(|sender| {
|
|
|
|
|
sender.send(Data::Close).ok();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// https://github.com/sciter-sdk/rust-sciter/blob/master/examples/video.rs
|
|
|
|
|
fn on_event(
|
|
|
|
|
&mut self,
|
|
|
|
|
_root: HELEMENT,
|
|
|
|
|
source: HELEMENT,
|
|
|
|
|
_target: HELEMENT,
|
|
|
|
|
code: BEHAVIOR_EVENTS,
|
|
|
|
|
phase: PHASE_MASK,
|
|
|
|
|
reason: EventReason,
|
|
|
|
|
) -> bool {
|
|
|
|
|
if phase != PHASE_MASK::BUBBLING {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
match code {
|
|
|
|
|
BEHAVIOR_EVENTS::VIDEO_BIND_RQ => {
|
|
|
|
|
let source = Element::from(source);
|
|
|
|
|
log::debug!("[video] {:?} {} ({:?})", code, source, reason);
|
|
|
|
|
if let EventReason::VideoBind(ptr) = reason {
|
|
|
|
|
if ptr.is_null() {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
let site = AssetPtr::adopt(ptr as *mut video_destination);
|
|
|
|
|
log::debug!("[video] start video");
|
|
|
|
|
*VIDEO.lock().unwrap() = Some(site);
|
|
|
|
|
self.reconnect();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
BEHAVIOR_EVENTS::VIDEO_INITIALIZED => {
|
|
|
|
|
log::debug!("[video] {:?}", code);
|
|
|
|
|
}
|
|
|
|
|
BEHAVIOR_EVENTS::VIDEO_STARTED => {
|
|
|
|
|
log::debug!("[video] {:?}", code);
|
|
|
|
|
let source = Element::from(source);
|
|
|
|
|
use sciter::dom::ELEMENT_AREAS;
|
|
|
|
|
let flags = ELEMENT_AREAS::CONTENT_BOX as u32 | ELEMENT_AREAS::SELF_RELATIVE as u32;
|
|
|
|
|
let rc = source.get_location(flags).unwrap();
|
|
|
|
|
log::debug!(
|
|
|
|
|
"[video] start video thread on <{}> which is about {:?} pixels",
|
|
|
|
|
source,
|
|
|
|
|
rc.size()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
BEHAVIOR_EVENTS::VIDEO_STOPPED => {
|
|
|
|
|
log::debug!("[video] {:?}", code);
|
|
|
|
|
}
|
|
|
|
|
_ => return false,
|
|
|
|
|
};
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sciter::dispatch_script_call! {
|
2022-05-12 17:35:25 +08:00
|
|
|
|
fn get_audit_server();
|
|
|
|
|
fn send_note(String);
|
2021-05-02 21:19:48 +08:00
|
|
|
|
fn is_xfce();
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn get_id();
|
|
|
|
|
fn get_default_pi();
|
|
|
|
|
fn get_option(String);
|
2021-12-25 16:45:22 +08:00
|
|
|
|
fn t(String);
|
|
|
|
|
fn set_option(String, String);
|
2022-05-12 17:35:25 +08:00
|
|
|
|
fn input_os_password(String, bool);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn save_close_state(String, String);
|
|
|
|
|
fn is_file_transfer();
|
|
|
|
|
fn is_port_forward();
|
|
|
|
|
fn is_rdp();
|
|
|
|
|
fn login(String, bool);
|
|
|
|
|
fn new_rdp();
|
|
|
|
|
fn send_mouse(i32, i32, i32, bool, bool, bool, bool);
|
2022-01-09 19:56:24 +08:00
|
|
|
|
fn enter();
|
|
|
|
|
fn leave();
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn ctrl_alt_del();
|
|
|
|
|
fn transfer_file();
|
|
|
|
|
fn tunnel();
|
|
|
|
|
fn lock_screen();
|
|
|
|
|
fn reconnect();
|
|
|
|
|
fn get_chatbox();
|
|
|
|
|
fn get_icon();
|
|
|
|
|
fn get_home_dir();
|
|
|
|
|
fn read_dir(String, bool);
|
|
|
|
|
fn remove_dir(i32, String, bool);
|
|
|
|
|
fn create_dir(i32, String, bool);
|
|
|
|
|
fn remove_file(i32, String, i32, bool);
|
|
|
|
|
fn read_remote_dir(String, bool);
|
|
|
|
|
fn send_chat(String);
|
|
|
|
|
fn switch_display(i32);
|
|
|
|
|
fn remove_dir_all(i32, String, bool);
|
|
|
|
|
fn confirm_delete_files(i32, i32);
|
|
|
|
|
fn set_no_confirm(i32);
|
|
|
|
|
fn cancel_job(i32);
|
2022-05-13 11:23:30 +08:00
|
|
|
|
fn send_files(i32, String, String, i32, bool, bool);
|
2022-05-14 11:58:47 +08:00
|
|
|
|
fn add_job(i32, String, String, i32, bool, bool);
|
|
|
|
|
fn resume_job(i32, bool);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn get_platform(bool);
|
|
|
|
|
fn get_path_sep(bool);
|
|
|
|
|
fn get_icon_path(i32, String);
|
|
|
|
|
fn get_char(String, i32);
|
|
|
|
|
fn get_size();
|
|
|
|
|
fn get_port_forwards();
|
|
|
|
|
fn remove_port_forward(i32);
|
|
|
|
|
fn get_args();
|
|
|
|
|
fn add_port_forward(i32, String, i32);
|
|
|
|
|
fn save_size(i32, i32, i32, i32);
|
|
|
|
|
fn get_view_style();
|
|
|
|
|
fn get_image_quality();
|
|
|
|
|
fn get_custom_image_quality();
|
|
|
|
|
fn save_view_style(String);
|
|
|
|
|
fn save_image_quality(String);
|
2022-06-23 17:42:30 +08:00
|
|
|
|
fn save_custom_image_quality(i32);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn refresh_video();
|
|
|
|
|
fn get_toggle_option(String);
|
2022-04-25 12:28:28 +08:00
|
|
|
|
fn is_privacy_mode_supported();
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn toggle_option(String);
|
|
|
|
|
fn get_remember();
|
2022-04-17 23:35:53 +08:00
|
|
|
|
fn peer_platform();
|
2022-04-28 18:09:06 +08:00
|
|
|
|
fn set_write_override(i32, i32, bool, bool, bool);
|
2022-07-09 20:17:10 +08:00
|
|
|
|
fn has_hwcodec();
|
|
|
|
|
fn supported_hwcodec();
|
|
|
|
|
fn change_prefer_codec();
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-05 22:17:34 +08:00
|
|
|
|
#[derive(Debug, Default)]
|
2022-06-23 17:42:30 +08:00
|
|
|
|
struct QualityStatus {
|
2022-07-05 22:17:34 +08:00
|
|
|
|
speed: Option<String>,
|
|
|
|
|
fps: Option<i32>,
|
|
|
|
|
delay: Option<i32>,
|
|
|
|
|
target_bitrate: Option<i32>,
|
|
|
|
|
codec_format: Option<CodecFormat>,
|
2022-06-23 17:42:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
impl Handler {
|
|
|
|
|
pub fn new(cmd: String, id: String, args: Vec<String>) -> Self {
|
|
|
|
|
let me = Self {
|
|
|
|
|
cmd,
|
|
|
|
|
id: id.clone(),
|
|
|
|
|
args,
|
|
|
|
|
..Default::default()
|
|
|
|
|
};
|
|
|
|
|
me.lc
|
|
|
|
|
.write()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.initialize(id, me.is_file_transfer(), me.is_port_forward());
|
|
|
|
|
me
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-23 17:42:30 +08:00
|
|
|
|
fn update_quality_status(&self, status: QualityStatus) {
|
|
|
|
|
self.call2(
|
|
|
|
|
"updateQualityStatus",
|
|
|
|
|
&make_args!(
|
2022-07-05 22:17:34 +08:00
|
|
|
|
status.speed.map_or(Value::null(), |it| it.into()),
|
|
|
|
|
status.fps.map_or(Value::null(), |it| it.into()),
|
|
|
|
|
status.delay.map_or(Value::null(), |it| it.into()),
|
|
|
|
|
status.target_bitrate.map_or(Value::null(), |it| it.into()),
|
|
|
|
|
status
|
|
|
|
|
.codec_format
|
|
|
|
|
.map_or(Value::null(), |it| it.to_string().into())
|
2022-06-23 17:42:30 +08:00
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-09 19:56:24 +08:00
|
|
|
|
fn start_keyboard_hook(&self) {
|
|
|
|
|
if self.is_port_forward() || self.is_file_transfer() {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-05-23 00:03:38 +08:00
|
|
|
|
if KEYBOARD_HOOKED.swap(true, Ordering::SeqCst) {
|
2022-01-09 19:56:24 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
log::info!("keyboard hooked");
|
|
|
|
|
let mut me = self.clone();
|
|
|
|
|
let peer = self.peer_platform();
|
|
|
|
|
let is_win = peer == "Windows";
|
2022-05-12 17:35:25 +08:00
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
crate::platform::windows::enable_lowlevel_keyboard(std::ptr::null_mut() as _);
|
2022-01-09 19:56:24 +08:00
|
|
|
|
std::thread::spawn(move || {
|
|
|
|
|
// This will block.
|
|
|
|
|
std::env::set_var("KEYBOARD_ONLY", "y"); // pass to rdev
|
|
|
|
|
use rdev::{EventType::*, *};
|
|
|
|
|
let func = move |evt: Event| {
|
2022-04-24 23:39:15 +08:00
|
|
|
|
if !IS_IN.load(Ordering::SeqCst) || !SERVER_KEYBOARD_ENABLED.load(Ordering::SeqCst)
|
|
|
|
|
{
|
2022-01-09 19:56:24 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
let (key, down) = match evt.event_type {
|
|
|
|
|
KeyPress(k) => (k, 1),
|
|
|
|
|
KeyRelease(k) => (k, 0),
|
|
|
|
|
_ => return,
|
|
|
|
|
};
|
|
|
|
|
let alt = get_key_state(enigo::Key::Alt);
|
2022-03-07 20:16:28 +08:00
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
let ctrl = {
|
|
|
|
|
let mut tmp = get_key_state(enigo::Key::Control);
|
|
|
|
|
unsafe {
|
|
|
|
|
if IS_ALT_GR {
|
2022-03-07 20:52:12 +08:00
|
|
|
|
if alt || key == Key::AltGr {
|
2022-03-07 20:16:28 +08:00
|
|
|
|
if tmp {
|
|
|
|
|
tmp = false;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
IS_ALT_GR = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
tmp
|
|
|
|
|
};
|
|
|
|
|
#[cfg(not(windows))]
|
2022-01-09 19:56:24 +08:00
|
|
|
|
let ctrl = get_key_state(enigo::Key::Control);
|
|
|
|
|
let shift = get_key_state(enigo::Key::Shift);
|
2022-05-12 17:35:25 +08:00
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
let command = crate::platform::windows::get_win_key_state();
|
|
|
|
|
#[cfg(not(windows))]
|
2022-01-09 19:56:24 +08:00
|
|
|
|
let command = get_key_state(enigo::Key::Meta);
|
|
|
|
|
let control_key = match key {
|
|
|
|
|
Key::Alt => Some(ControlKey::Alt),
|
|
|
|
|
Key::AltGr => Some(ControlKey::RAlt),
|
|
|
|
|
Key::Backspace => Some(ControlKey::Backspace),
|
2022-03-07 16:19:10 +08:00
|
|
|
|
Key::ControlLeft => {
|
|
|
|
|
// when pressing AltGr, an extra VK_LCONTROL with a special
|
|
|
|
|
// scancode with bit 9 set is sent, let's ignore this.
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
if evt.scan_code & 0x200 != 0 {
|
2022-03-07 20:16:28 +08:00
|
|
|
|
unsafe {
|
|
|
|
|
IS_ALT_GR = true;
|
|
|
|
|
}
|
2022-03-07 16:19:10 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
Some(ControlKey::Control)
|
|
|
|
|
}
|
2022-01-09 19:56:24 +08:00
|
|
|
|
Key::ControlRight => Some(ControlKey::RControl),
|
|
|
|
|
Key::DownArrow => Some(ControlKey::DownArrow),
|
|
|
|
|
Key::Escape => Some(ControlKey::Escape),
|
|
|
|
|
Key::F1 => Some(ControlKey::F1),
|
|
|
|
|
Key::F10 => Some(ControlKey::F10),
|
|
|
|
|
Key::F11 => Some(ControlKey::F11),
|
|
|
|
|
Key::F12 => Some(ControlKey::F12),
|
|
|
|
|
Key::F2 => Some(ControlKey::F2),
|
|
|
|
|
Key::F3 => Some(ControlKey::F3),
|
|
|
|
|
Key::F4 => Some(ControlKey::F4),
|
|
|
|
|
Key::F5 => Some(ControlKey::F5),
|
|
|
|
|
Key::F6 => Some(ControlKey::F6),
|
|
|
|
|
Key::F7 => Some(ControlKey::F7),
|
|
|
|
|
Key::F8 => Some(ControlKey::F8),
|
|
|
|
|
Key::F9 => Some(ControlKey::F9),
|
|
|
|
|
Key::LeftArrow => Some(ControlKey::LeftArrow),
|
|
|
|
|
Key::MetaLeft => Some(ControlKey::Meta),
|
|
|
|
|
Key::MetaRight => Some(ControlKey::RWin),
|
|
|
|
|
Key::Return => Some(ControlKey::Return),
|
|
|
|
|
Key::RightArrow => Some(ControlKey::RightArrow),
|
|
|
|
|
Key::ShiftLeft => Some(ControlKey::Shift),
|
|
|
|
|
Key::ShiftRight => Some(ControlKey::RShift),
|
|
|
|
|
Key::Space => Some(ControlKey::Space),
|
|
|
|
|
Key::Tab => Some(ControlKey::Tab),
|
|
|
|
|
Key::UpArrow => Some(ControlKey::UpArrow),
|
2022-01-09 23:59:30 +08:00
|
|
|
|
Key::Delete => {
|
2022-01-09 19:56:24 +08:00
|
|
|
|
if is_win && ctrl && alt {
|
|
|
|
|
me.ctrl_alt_del();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
Some(ControlKey::Delete)
|
|
|
|
|
}
|
|
|
|
|
Key::Apps => Some(ControlKey::Apps),
|
|
|
|
|
Key::Cancel => Some(ControlKey::Cancel),
|
|
|
|
|
Key::Clear => Some(ControlKey::Clear),
|
|
|
|
|
Key::Kana => Some(ControlKey::Kana),
|
|
|
|
|
Key::Hangul => Some(ControlKey::Hangul),
|
|
|
|
|
Key::Junja => Some(ControlKey::Junja),
|
|
|
|
|
Key::Final => Some(ControlKey::Final),
|
|
|
|
|
Key::Hanja => Some(ControlKey::Hanja),
|
|
|
|
|
Key::Hanji => Some(ControlKey::Hanja),
|
|
|
|
|
Key::Convert => Some(ControlKey::Convert),
|
|
|
|
|
Key::Print => Some(ControlKey::Print),
|
|
|
|
|
Key::Select => Some(ControlKey::Select),
|
|
|
|
|
Key::Execute => Some(ControlKey::Execute),
|
2022-01-10 00:33:31 +08:00
|
|
|
|
Key::PrintScreen => Some(ControlKey::Snapshot),
|
2022-01-09 19:56:24 +08:00
|
|
|
|
Key::Help => Some(ControlKey::Help),
|
|
|
|
|
Key::Sleep => Some(ControlKey::Sleep),
|
|
|
|
|
Key::Separator => Some(ControlKey::Separator),
|
|
|
|
|
Key::KpReturn => Some(ControlKey::NumpadEnter),
|
2022-01-09 23:59:30 +08:00
|
|
|
|
Key::Kp0 => Some(ControlKey::Numpad0),
|
|
|
|
|
Key::Kp1 => Some(ControlKey::Numpad1),
|
|
|
|
|
Key::Kp2 => Some(ControlKey::Numpad2),
|
|
|
|
|
Key::Kp3 => Some(ControlKey::Numpad3),
|
|
|
|
|
Key::Kp4 => Some(ControlKey::Numpad4),
|
|
|
|
|
Key::Kp5 => Some(ControlKey::Numpad5),
|
|
|
|
|
Key::Kp6 => Some(ControlKey::Numpad6),
|
|
|
|
|
Key::Kp7 => Some(ControlKey::Numpad7),
|
|
|
|
|
Key::Kp8 => Some(ControlKey::Numpad8),
|
|
|
|
|
Key::Kp9 => Some(ControlKey::Numpad9),
|
|
|
|
|
Key::KpDivide => Some(ControlKey::Divide),
|
2022-03-08 15:42:58 +08:00
|
|
|
|
Key::KpMultiply => Some(ControlKey::Multiply),
|
2022-01-09 23:59:30 +08:00
|
|
|
|
Key::KpDecimal => Some(ControlKey::Decimal),
|
|
|
|
|
Key::KpMinus => Some(ControlKey::Subtract),
|
|
|
|
|
Key::KpPlus => Some(ControlKey::Add),
|
2022-01-09 19:56:24 +08:00
|
|
|
|
Key::CapsLock | Key::NumLock | Key::ScrollLock => {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-01-12 18:11:42 +08:00
|
|
|
|
Key::Home => Some(ControlKey::Home),
|
|
|
|
|
Key::End => Some(ControlKey::End),
|
|
|
|
|
Key::Insert => Some(ControlKey::Insert),
|
|
|
|
|
Key::PageUp => Some(ControlKey::PageUp),
|
|
|
|
|
Key::PageDown => Some(ControlKey::PageDown),
|
|
|
|
|
Key::Pause => Some(ControlKey::Pause),
|
2022-01-09 19:56:24 +08:00
|
|
|
|
_ => None,
|
|
|
|
|
};
|
|
|
|
|
let mut key_event = KeyEvent::new();
|
|
|
|
|
if let Some(k) = control_key {
|
|
|
|
|
key_event.set_control_key(k);
|
|
|
|
|
} else {
|
2022-02-21 09:39:01 +08:00
|
|
|
|
let mut chr = match evt.name {
|
|
|
|
|
Some(ref s) => {
|
2022-02-24 11:22:19 +08:00
|
|
|
|
if s.len() <= 2 {
|
|
|
|
|
// exclude chinese characters
|
2022-02-21 09:39:01 +08:00
|
|
|
|
s.chars().next().unwrap_or('\0')
|
|
|
|
|
} else {
|
|
|
|
|
'\0'
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-09 19:56:24 +08:00
|
|
|
|
_ => '\0',
|
|
|
|
|
};
|
2022-02-24 11:22:19 +08:00
|
|
|
|
if chr == '·' {
|
|
|
|
|
// special for Chinese
|
2022-02-21 09:39:01 +08:00
|
|
|
|
chr = '`';
|
|
|
|
|
}
|
|
|
|
|
if chr == '\0' {
|
|
|
|
|
chr = match key {
|
|
|
|
|
Key::Num1 => '1',
|
|
|
|
|
Key::Num2 => '2',
|
|
|
|
|
Key::Num3 => '3',
|
|
|
|
|
Key::Num4 => '4',
|
|
|
|
|
Key::Num5 => '5',
|
|
|
|
|
Key::Num6 => '6',
|
|
|
|
|
Key::Num7 => '7',
|
|
|
|
|
Key::Num8 => '8',
|
|
|
|
|
Key::Num9 => '9',
|
|
|
|
|
Key::Num0 => '0',
|
|
|
|
|
Key::KeyA => 'a',
|
|
|
|
|
Key::KeyB => 'b',
|
|
|
|
|
Key::KeyC => 'c',
|
|
|
|
|
Key::KeyD => 'd',
|
|
|
|
|
Key::KeyE => 'e',
|
|
|
|
|
Key::KeyF => 'f',
|
|
|
|
|
Key::KeyG => 'g',
|
|
|
|
|
Key::KeyH => 'h',
|
|
|
|
|
Key::KeyI => 'i',
|
|
|
|
|
Key::KeyJ => 'j',
|
|
|
|
|
Key::KeyK => 'k',
|
|
|
|
|
Key::KeyL => 'l',
|
|
|
|
|
Key::KeyM => 'm',
|
|
|
|
|
Key::KeyN => 'n',
|
|
|
|
|
Key::KeyO => 'o',
|
|
|
|
|
Key::KeyP => 'p',
|
|
|
|
|
Key::KeyQ => 'q',
|
|
|
|
|
Key::KeyR => 'r',
|
|
|
|
|
Key::KeyS => 's',
|
|
|
|
|
Key::KeyT => 't',
|
|
|
|
|
Key::KeyU => 'u',
|
|
|
|
|
Key::KeyV => 'v',
|
|
|
|
|
Key::KeyW => 'w',
|
|
|
|
|
Key::KeyX => 'x',
|
|
|
|
|
Key::KeyY => 'y',
|
|
|
|
|
Key::KeyZ => 'z',
|
|
|
|
|
Key::Comma => ',',
|
|
|
|
|
Key::Dot => '.',
|
|
|
|
|
Key::SemiColon => ';',
|
|
|
|
|
Key::Quote => '\'',
|
|
|
|
|
Key::LeftBracket => '[',
|
|
|
|
|
Key::RightBracket => ']',
|
|
|
|
|
Key::BackSlash => '\\',
|
|
|
|
|
Key::Minus => '-',
|
|
|
|
|
Key::Equal => '=',
|
|
|
|
|
Key::BackQuote => '`',
|
|
|
|
|
_ => '\0',
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-09 19:56:24 +08:00
|
|
|
|
if chr != '\0' {
|
|
|
|
|
if chr == 'l' && is_win && command {
|
|
|
|
|
me.lock_screen();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
key_event.set_chr(chr as _);
|
|
|
|
|
} else {
|
|
|
|
|
log::error!("Unknown key {:?}", evt);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
me.key_down_or_up(down, key_event, alt, ctrl, shift, command);
|
|
|
|
|
};
|
|
|
|
|
if let Err(error) = rdev::listen(func) {
|
|
|
|
|
log::error!("rdev: {:?}", error);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn get_view_style(&mut self) -> String {
|
|
|
|
|
return self.lc.read().unwrap().view_style.clone();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_image_quality(&mut self) -> String {
|
|
|
|
|
return self.lc.read().unwrap().image_quality.clone();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_custom_image_quality(&mut self) -> Value {
|
|
|
|
|
let mut v = Value::array(0);
|
|
|
|
|
for x in self.lc.read().unwrap().custom_image_quality.iter() {
|
|
|
|
|
v.push(x);
|
|
|
|
|
}
|
|
|
|
|
v
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2022-04-25 12:28:28 +08:00
|
|
|
|
pub(super) fn save_config(&self, config: PeerConfig) {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
self.lc.write().unwrap().save_config(config);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn save_view_style(&mut self, value: String) {
|
|
|
|
|
self.lc.write().unwrap().save_view_style(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2022-04-25 12:28:28 +08:00
|
|
|
|
pub(super) fn load_config(&self) -> PeerConfig {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
load_config(&self.id)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn toggle_option(&mut self, name: String) {
|
2022-02-15 15:35:19 +08:00
|
|
|
|
let msg = self.lc.write().unwrap().toggle_option(name.clone());
|
|
|
|
|
if name == "enable-file-transfer" {
|
|
|
|
|
self.send(Data::ToggleClipboardFile);
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
if let Some(msg) = msg {
|
|
|
|
|
self.send(Data::Message(msg));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_toggle_option(&mut self, name: String) -> bool {
|
|
|
|
|
self.lc.read().unwrap().get_toggle_option(&name)
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-25 12:28:28 +08:00
|
|
|
|
fn is_privacy_mode_supported(&self) -> bool {
|
|
|
|
|
self.lc.read().unwrap().is_privacy_mode_supported()
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn refresh_video(&mut self) {
|
|
|
|
|
self.send(Data::Message(LoginConfigHandler::refresh()));
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-23 17:42:30 +08:00
|
|
|
|
fn save_custom_image_quality(&mut self, custom_image_quality: i32) {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let msg = self
|
|
|
|
|
.lc
|
|
|
|
|
.write()
|
|
|
|
|
.unwrap()
|
2022-06-27 18:30:46 +08:00
|
|
|
|
.save_custom_image_quality(custom_image_quality);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
self.send(Data::Message(msg));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn save_image_quality(&mut self, value: String) {
|
|
|
|
|
let msg = self.lc.write().unwrap().save_image_quality(value);
|
|
|
|
|
if let Some(msg) = msg {
|
|
|
|
|
self.send(Data::Message(msg));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_remember(&mut self) -> bool {
|
|
|
|
|
self.lc.read().unwrap().remember
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-26 14:56:15 +08:00
|
|
|
|
fn set_write_override(
|
|
|
|
|
&mut self,
|
|
|
|
|
job_id: i32,
|
|
|
|
|
file_num: i32,
|
|
|
|
|
is_override: bool,
|
|
|
|
|
remember: bool,
|
2022-04-28 17:42:22 +08:00
|
|
|
|
is_upload: bool,
|
2022-04-26 14:56:15 +08:00
|
|
|
|
) -> bool {
|
|
|
|
|
self.send(Data::SetConfirmOverrideFile((
|
|
|
|
|
job_id,
|
|
|
|
|
file_num,
|
|
|
|
|
is_override,
|
|
|
|
|
remember,
|
2022-04-28 17:42:22 +08:00
|
|
|
|
is_upload,
|
2022-04-26 14:56:15 +08:00
|
|
|
|
)));
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-09 20:17:10 +08:00
|
|
|
|
fn has_hwcodec(&self) -> bool {
|
|
|
|
|
#[cfg(not(feature = "hwcodec"))]
|
|
|
|
|
return false;
|
|
|
|
|
#[cfg(feature = "hwcodec")]
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn supported_hwcodec(&self) -> Value {
|
|
|
|
|
#[cfg(feature = "hwcodec")]
|
|
|
|
|
{
|
|
|
|
|
let mut v = Value::array(0);
|
|
|
|
|
let decoder = scrap::codec::Decoder::video_codec_state(&self.id);
|
|
|
|
|
let mut h264 = decoder.score_h264 > 0;
|
|
|
|
|
let mut h265 = decoder.score_h265 > 0;
|
|
|
|
|
if let Some((encoding_264, encoding_265)) = self.lc.read().unwrap().supported_encoding {
|
|
|
|
|
h264 = h264 && encoding_264;
|
|
|
|
|
h265 = h265 && encoding_265;
|
|
|
|
|
}
|
|
|
|
|
v.push(h264);
|
|
|
|
|
v.push(h265);
|
|
|
|
|
v
|
|
|
|
|
}
|
|
|
|
|
#[cfg(not(feature = "hwcodec"))]
|
|
|
|
|
{
|
|
|
|
|
let mut v = Value::array(0);
|
|
|
|
|
v.push(false);
|
|
|
|
|
v.push(false);
|
|
|
|
|
v
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn change_prefer_codec(&self) {
|
|
|
|
|
let msg = self.lc.write().unwrap().change_prefer_codec();
|
|
|
|
|
self.send(Data::Message(msg));
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-25 16:45:22 +08:00
|
|
|
|
fn t(&self, name: String) -> String {
|
|
|
|
|
crate::client::translate(name)
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-12 17:35:25 +08:00
|
|
|
|
fn get_audit_server(&self) -> String {
|
|
|
|
|
if self.lc.read().unwrap().conn_id <= 0
|
|
|
|
|
|| LocalConfig::get_option("access_token").is_empty()
|
|
|
|
|
{
|
|
|
|
|
return "".to_owned();
|
|
|
|
|
}
|
|
|
|
|
crate::get_audit_server(
|
|
|
|
|
Config::get_option("api-server"),
|
|
|
|
|
Config::get_option("custom-rendezvous-server"),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn send_note(&self, note: String) {
|
|
|
|
|
let url = self.get_audit_server();
|
|
|
|
|
let id = self.id.clone();
|
|
|
|
|
let conn_id = self.lc.read().unwrap().conn_id;
|
|
|
|
|
std::thread::spawn(move || {
|
|
|
|
|
send_note(url, id, conn_id, note);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-02 21:19:48 +08:00
|
|
|
|
fn is_xfce(&self) -> bool {
|
|
|
|
|
crate::platform::is_xfce()
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn save_size(&mut self, x: i32, y: i32, w: i32, h: i32) {
|
|
|
|
|
let size = (x, y, w, h);
|
|
|
|
|
let mut config = self.load_config();
|
|
|
|
|
if self.is_file_transfer() {
|
|
|
|
|
let close_state = self.read().unwrap().close_state.clone();
|
|
|
|
|
let mut has_change = false;
|
2022-04-07 22:13:30 +08:00
|
|
|
|
for (k, mut v) in close_state {
|
|
|
|
|
if k == "remote_dir" {
|
|
|
|
|
v = self.lc.read().unwrap().get_all_remote_dir(v);
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let v2 = if v.is_empty() { None } else { Some(&v) };
|
|
|
|
|
if v2 != config.options.get(&k) {
|
|
|
|
|
has_change = true;
|
|
|
|
|
if v2.is_none() {
|
|
|
|
|
config.options.remove(&k);
|
|
|
|
|
} else {
|
|
|
|
|
config.options.insert(k, v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if size == config.size_ft && !has_change {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
config.size_ft = size;
|
|
|
|
|
} else if self.is_port_forward() {
|
|
|
|
|
if size == config.size_pf {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
config.size_pf = size;
|
|
|
|
|
} else {
|
|
|
|
|
if size == config.size {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
config.size = size;
|
|
|
|
|
}
|
|
|
|
|
self.save_config(config);
|
|
|
|
|
log::info!("size saved");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_port_forwards(&mut self) -> Value {
|
|
|
|
|
let port_forwards = self.lc.read().unwrap().port_forwards.clone();
|
|
|
|
|
let mut v = Value::array(0);
|
|
|
|
|
for (port, remote_host, remote_port) in port_forwards {
|
|
|
|
|
let mut v2 = Value::array(0);
|
|
|
|
|
v2.push(port);
|
|
|
|
|
v2.push(remote_host);
|
|
|
|
|
v2.push(remote_port);
|
|
|
|
|
v.push(v2);
|
|
|
|
|
}
|
|
|
|
|
v
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_args(&mut self) -> Value {
|
|
|
|
|
let mut v = Value::array(0);
|
|
|
|
|
for x in self.args.iter() {
|
|
|
|
|
v.push(x);
|
|
|
|
|
}
|
|
|
|
|
v
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn remove_port_forward(&mut self, port: i32) {
|
|
|
|
|
let mut config = self.load_config();
|
|
|
|
|
config.port_forwards = config
|
|
|
|
|
.port_forwards
|
|
|
|
|
.drain(..)
|
|
|
|
|
.filter(|x| x.0 != port)
|
|
|
|
|
.collect();
|
|
|
|
|
self.save_config(config);
|
|
|
|
|
self.send(Data::RemovePortForward(port));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn add_port_forward(&mut self, port: i32, remote_host: String, remote_port: i32) {
|
|
|
|
|
let mut config = self.load_config();
|
|
|
|
|
if config
|
|
|
|
|
.port_forwards
|
|
|
|
|
.iter()
|
|
|
|
|
.filter(|x| x.0 == port)
|
|
|
|
|
.next()
|
|
|
|
|
.is_some()
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
let pf = (port, remote_host, remote_port);
|
|
|
|
|
config.port_forwards.push(pf.clone());
|
|
|
|
|
self.save_config(config);
|
|
|
|
|
self.send(Data::AddPortForward(pf));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_size(&mut self) -> Value {
|
|
|
|
|
let s = if self.is_file_transfer() {
|
|
|
|
|
self.lc.read().unwrap().size_ft
|
|
|
|
|
} else if self.is_port_forward() {
|
|
|
|
|
self.lc.read().unwrap().size_pf
|
|
|
|
|
} else {
|
|
|
|
|
self.lc.read().unwrap().size
|
|
|
|
|
};
|
|
|
|
|
let mut v = Value::array(0);
|
|
|
|
|
v.push(s.0);
|
|
|
|
|
v.push(s.1);
|
|
|
|
|
v.push(s.2);
|
|
|
|
|
v.push(s.3);
|
|
|
|
|
v
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_id(&mut self) -> String {
|
|
|
|
|
self.id.clone()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_default_pi(&mut self) -> Value {
|
|
|
|
|
let mut pi = Value::map();
|
|
|
|
|
let info = self.lc.read().unwrap().info.clone();
|
|
|
|
|
pi.set_item("username", info.username.clone());
|
|
|
|
|
pi.set_item("hostname", info.hostname.clone());
|
|
|
|
|
pi.set_item("platform", info.platform.clone());
|
|
|
|
|
pi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_option(&self, k: String) -> String {
|
|
|
|
|
self.lc.read().unwrap().get_option(&k)
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-25 16:45:22 +08:00
|
|
|
|
fn set_option(&self, k: String, v: String) {
|
|
|
|
|
self.lc.write().unwrap().set_option(k, v);
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-12 17:35:25 +08:00
|
|
|
|
fn input_os_password(&mut self, pass: String, activate: bool) {
|
|
|
|
|
input_os_password(pass, activate, self.clone());
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn save_close_state(&self, k: String, v: String) {
|
|
|
|
|
self.write().unwrap().close_state.insert(k, v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_chatbox(&mut self) -> String {
|
|
|
|
|
#[cfg(feature = "inline")]
|
|
|
|
|
return super::inline::get_chatbox();
|
|
|
|
|
#[cfg(not(feature = "inline"))]
|
|
|
|
|
return "".to_owned();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_icon(&mut self) -> String {
|
2022-05-12 17:35:25 +08:00
|
|
|
|
crate::get_icon()
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn send_chat(&mut self, text: String) {
|
|
|
|
|
let mut misc = Misc::new();
|
|
|
|
|
misc.set_chat_message(ChatMessage {
|
|
|
|
|
text,
|
|
|
|
|
..Default::default()
|
|
|
|
|
});
|
|
|
|
|
let mut msg_out = Message::new();
|
|
|
|
|
msg_out.set_misc(misc);
|
|
|
|
|
self.send(Data::Message(msg_out));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn switch_display(&mut self, display: i32) {
|
|
|
|
|
let mut misc = Misc::new();
|
|
|
|
|
misc.set_switch_display(SwitchDisplay {
|
|
|
|
|
display,
|
|
|
|
|
..Default::default()
|
|
|
|
|
});
|
|
|
|
|
let mut msg_out = Message::new();
|
|
|
|
|
msg_out.set_misc(misc);
|
|
|
|
|
self.send(Data::Message(msg_out));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 reconnect(&mut self) {
|
2022-04-29 16:47:45 +08:00
|
|
|
|
println!("reconnecting");
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let cloned = self.clone();
|
|
|
|
|
let mut lock = self.write().unwrap();
|
|
|
|
|
lock.thread.take().map(|t| t.join());
|
|
|
|
|
lock.thread = Some(std::thread::spawn(move || {
|
|
|
|
|
io_loop(cloned);
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn peer_platform(&self) -> String {
|
|
|
|
|
self.lc.read().unwrap().info.platform.clone()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_platform(&mut self, is_remote: bool) -> String {
|
|
|
|
|
if is_remote {
|
|
|
|
|
self.peer_platform()
|
|
|
|
|
} else {
|
|
|
|
|
whoami::platform().to_string()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_path_sep(&mut self, is_remote: bool) -> &'static str {
|
|
|
|
|
let p = self.get_platform(is_remote);
|
|
|
|
|
if &p == "Windows" {
|
|
|
|
|
return "\\";
|
|
|
|
|
} else {
|
|
|
|
|
return "/";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_icon_path(&mut self, file_type: i32, ext: String) -> String {
|
|
|
|
|
let mut path = Config::icon_path();
|
|
|
|
|
if file_type == FileType::DirLink as i32 {
|
|
|
|
|
let new_path = path.join("dir_link");
|
|
|
|
|
if !std::fs::metadata(&new_path).is_ok() {
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
allow_err!(std::os::windows::fs::symlink_file(&path, &new_path));
|
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
|
allow_err!(std::os::unix::fs::symlink(&path, &new_path));
|
|
|
|
|
}
|
|
|
|
|
path = new_path;
|
|
|
|
|
} else if file_type == FileType::File as i32 {
|
|
|
|
|
if !ext.is_empty() {
|
|
|
|
|
path = path.join(format!("file.{}", ext));
|
|
|
|
|
} else {
|
|
|
|
|
path = path.join("file");
|
|
|
|
|
}
|
|
|
|
|
if !std::fs::metadata(&path).is_ok() {
|
|
|
|
|
allow_err!(std::fs::File::create(&path));
|
|
|
|
|
}
|
|
|
|
|
} else if file_type == FileType::FileLink as i32 {
|
|
|
|
|
let new_path = path.join("file_link");
|
|
|
|
|
if !std::fs::metadata(&new_path).is_ok() {
|
|
|
|
|
path = path.join("file");
|
|
|
|
|
if !std::fs::metadata(&path).is_ok() {
|
|
|
|
|
allow_err!(std::fs::File::create(&path));
|
|
|
|
|
}
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
allow_err!(std::os::windows::fs::symlink_file(&path, &new_path));
|
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
|
allow_err!(std::os::unix::fs::symlink(&path, &new_path));
|
|
|
|
|
}
|
|
|
|
|
path = new_path;
|
|
|
|
|
} else if file_type == FileType::DirDrive as i32 {
|
|
|
|
|
if cfg!(windows) {
|
|
|
|
|
path = fs::get_path("C:");
|
|
|
|
|
} else if cfg!(target_os = "macos") {
|
|
|
|
|
if let Ok(entries) = fs::get_path("/Volumes/").read_dir() {
|
|
|
|
|
for entry in entries {
|
|
|
|
|
if let Ok(entry) = entry {
|
|
|
|
|
path = entry.path();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fs::get_string(&path)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn login(&mut self, password: String, remember: bool) {
|
|
|
|
|
self.send(Data::Login((password, remember)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn new_rdp(&mut self) {
|
|
|
|
|
self.send(Data::NewRDP);
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-09 19:56:24 +08:00
|
|
|
|
fn enter(&mut self) {
|
2022-05-12 17:35:25 +08:00
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
crate::platform::windows::stop_system_key_propagate(true);
|
2022-05-25 00:18:38 +08:00
|
|
|
|
IS_IN.store(true, Ordering::SeqCst);
|
2022-01-09 19:56:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn leave(&mut self) {
|
2022-05-12 17:35:25 +08:00
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
crate::platform::windows::stop_system_key_propagate(false);
|
2022-05-25 00:18:38 +08:00
|
|
|
|
IS_IN.store(false, Ordering::SeqCst);
|
2022-01-09 19:56:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn send_mouse(
|
|
|
|
|
&mut self,
|
|
|
|
|
mask: i32,
|
|
|
|
|
x: i32,
|
|
|
|
|
y: i32,
|
|
|
|
|
alt: bool,
|
|
|
|
|
ctrl: bool,
|
|
|
|
|
shift: bool,
|
|
|
|
|
command: bool,
|
|
|
|
|
) {
|
2022-05-12 17:35:25 +08:00
|
|
|
|
#[allow(unused_mut)]
|
|
|
|
|
let mut command = command;
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
{
|
|
|
|
|
if !command && crate::platform::windows::get_win_key_state() {
|
|
|
|
|
command = true;
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
2022-05-12 17:35:25 +08:00
|
|
|
|
|
|
|
|
|
send_mouse(mask, x, y, alt, ctrl, shift, command, self);
|
|
|
|
|
// on macos, ctrl + left button down = right button down, up won't emit, so we need to
|
2021-03-29 15:59:14 +08:00
|
|
|
|
// emit up myself if peer is not macos
|
|
|
|
|
// to-do: how about ctrl + left from win to macos
|
|
|
|
|
if cfg!(target_os = "macos") {
|
|
|
|
|
let buttons = mask >> 3;
|
|
|
|
|
let evt_type = mask & 0x7;
|
|
|
|
|
if buttons == 1 && evt_type == 1 && ctrl && self.peer_platform() != "Mac OS" {
|
|
|
|
|
self.send_mouse((1 << 3 | 2) as _, x, y, alt, ctrl, shift, command);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_cursor_data(&mut self, cd: CursorData) {
|
2022-04-24 14:53:19 +08:00
|
|
|
|
let mut colors = hbb_common::compress::decompress(&cd.colors);
|
|
|
|
|
if colors.iter().filter(|x| **x != 0).next().is_none() {
|
|
|
|
|
log::info!("Fix transparent");
|
|
|
|
|
// somehow all 0 images shows black rect, here is a workaround
|
|
|
|
|
colors[3] = 1;
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let mut png = Vec::new();
|
|
|
|
|
if let Ok(()) = repng::encode(&mut png, cd.width as _, cd.height as _, &colors) {
|
|
|
|
|
self.call(
|
|
|
|
|
"setCursorData",
|
|
|
|
|
&make_args!(
|
|
|
|
|
cd.id.to_string(),
|
|
|
|
|
cd.hotx,
|
|
|
|
|
cd.hoty,
|
|
|
|
|
cd.width,
|
|
|
|
|
cd.height,
|
|
|
|
|
&png[..]
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_key_event(&self, down_or_up: i32, name: &str, code: i32) -> Option<KeyEvent> {
|
|
|
|
|
let mut key_event = KeyEvent::new();
|
|
|
|
|
if down_or_up == 2 {
|
|
|
|
|
/* windows send both keyup/keydown and keychar, so here we avoid keychar
|
2021-11-14 23:22:05 +08:00
|
|
|
|
for <= 0xFF, best practice should only avoid those not on keyboard, but
|
|
|
|
|
for now, we have no way to test, so avoid <= 0xFF totally
|
2021-03-29 15:59:14 +08:00
|
|
|
|
*/
|
|
|
|
|
if code <= 0xFF {
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
key_event.set_unicode(code.clone() as _);
|
|
|
|
|
} else if let Some(key) = KEY_MAP.get(name) {
|
|
|
|
|
match key {
|
|
|
|
|
Key::Chr(chr) => {
|
|
|
|
|
key_event.set_chr(chr.clone());
|
|
|
|
|
}
|
|
|
|
|
Key::ControlKey(key) => {
|
|
|
|
|
key_event.set_control_key(key.clone());
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if cfg!(target_os = "macos") {
|
|
|
|
|
match code {
|
|
|
|
|
0x4C => key_event.set_control_key(ControlKey::NumpadEnter), // numpad enter
|
|
|
|
|
0x69 => key_event.set_control_key(ControlKey::Snapshot),
|
|
|
|
|
0x72 => key_event.set_control_key(ControlKey::Help),
|
2021-05-26 12:42:21 +08:00
|
|
|
|
0x6E => key_event.set_control_key(ControlKey::Apps),
|
2021-03-29 15:59:14 +08:00
|
|
|
|
0x47 => {
|
|
|
|
|
key_event.set_control_key(if self.peer_platform() == "Mac OS" {
|
|
|
|
|
ControlKey::Clear
|
|
|
|
|
} else {
|
|
|
|
|
ControlKey::NumLock
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
0x51 => key_event.set_control_key(ControlKey::Equals),
|
|
|
|
|
0x2F => key_event.set_chr('.' as _),
|
|
|
|
|
0x32 => key_event.set_chr('`' as _),
|
|
|
|
|
_ => {
|
|
|
|
|
log::error!("Unknown key code {}", code);
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if cfg!(windows) {
|
|
|
|
|
match code {
|
|
|
|
|
0x2C => key_event.set_control_key(ControlKey::Snapshot),
|
|
|
|
|
0x91 => key_event.set_control_key(ControlKey::Scroll),
|
|
|
|
|
0x90 => key_event.set_control_key(ControlKey::NumLock),
|
|
|
|
|
0x5C => key_event.set_control_key(ControlKey::RWin),
|
2021-05-26 12:42:21 +08:00
|
|
|
|
0x5B => key_event.set_control_key(ControlKey::Meta),
|
2021-03-29 15:59:14 +08:00
|
|
|
|
0x5D => key_event.set_control_key(ControlKey::Apps),
|
|
|
|
|
0xBE => key_event.set_chr('.' as _),
|
|
|
|
|
0xC0 => key_event.set_chr('`' as _),
|
|
|
|
|
_ => {
|
|
|
|
|
log::error!("Unknown key code {}", code);
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-05-26 12:42:21 +08:00
|
|
|
|
} else if cfg!(target_os = "linux") {
|
|
|
|
|
match code {
|
|
|
|
|
65300 => key_event.set_control_key(ControlKey::Scroll),
|
|
|
|
|
65421 => key_event.set_control_key(ControlKey::NumpadEnter), // numpad enter
|
|
|
|
|
65407 => key_event.set_control_key(ControlKey::NumLock),
|
2021-12-23 23:03:43 +08:00
|
|
|
|
65515 => key_event.set_control_key(ControlKey::Meta),
|
2021-05-26 12:42:21 +08:00
|
|
|
|
65516 => key_event.set_control_key(ControlKey::RWin),
|
|
|
|
|
65513 => key_event.set_control_key(ControlKey::Alt),
|
|
|
|
|
65514 => key_event.set_control_key(ControlKey::RAlt),
|
|
|
|
|
65508 => key_event.set_control_key(ControlKey::RControl),
|
|
|
|
|
65506 => key_event.set_control_key(ControlKey::RShift),
|
|
|
|
|
96 => key_event.set_chr('`' as _),
|
|
|
|
|
46 => key_event.set_chr('.' as _),
|
|
|
|
|
126 => key_event.set_chr('`' as _),
|
|
|
|
|
33 => key_event.set_chr('1' as _),
|
|
|
|
|
64 => key_event.set_chr('2' as _),
|
|
|
|
|
35 => key_event.set_chr('3' as _),
|
|
|
|
|
36 => key_event.set_chr('4' as _),
|
|
|
|
|
37 => key_event.set_chr('5' as _),
|
|
|
|
|
94 => key_event.set_chr('6' as _),
|
|
|
|
|
38 => key_event.set_chr('7' as _),
|
|
|
|
|
42 => key_event.set_chr('8' as _),
|
|
|
|
|
40 => key_event.set_chr('9' as _),
|
|
|
|
|
41 => key_event.set_chr('0' as _),
|
|
|
|
|
95 => key_event.set_chr('-' as _),
|
|
|
|
|
43 => key_event.set_chr('=' as _),
|
|
|
|
|
123 => key_event.set_chr('[' as _),
|
|
|
|
|
125 => key_event.set_chr(']' as _),
|
|
|
|
|
124 => key_event.set_chr('\\' as _),
|
|
|
|
|
58 => key_event.set_chr(';' as _),
|
|
|
|
|
34 => key_event.set_chr('\'' as _),
|
|
|
|
|
60 => key_event.set_chr(',' as _),
|
|
|
|
|
62 => key_event.set_chr('.' as _),
|
|
|
|
|
63 => key_event.set_chr('/' as _),
|
|
|
|
|
_ => {
|
|
|
|
|
log::error!("Unknown key code {}", code);
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
} else {
|
|
|
|
|
log::error!("Unknown key code {}", code);
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Some(key_event)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_char(&mut self, name: String, code: i32) -> String {
|
|
|
|
|
if let Some(key_event) = self.get_key_event(1, &name, code) {
|
|
|
|
|
match key_event.union {
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(key_event::Union::Chr(chr)) => {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
if let Some(chr) = std::char::from_u32(chr as _) {
|
|
|
|
|
return chr.to_string();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
"".to_owned()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn ctrl_alt_del(&mut self) {
|
|
|
|
|
if self.peer_platform() == "Windows" {
|
2022-01-09 19:56:24 +08:00
|
|
|
|
let mut key_event = KeyEvent::new();
|
|
|
|
|
key_event.set_control_key(ControlKey::CtrlAltDel);
|
|
|
|
|
self.key_down_or_up(1, key_event, false, false, false, false);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
} else {
|
2022-01-09 19:56:24 +08:00
|
|
|
|
let mut key_event = KeyEvent::new();
|
|
|
|
|
key_event.set_control_key(ControlKey::Delete);
|
|
|
|
|
self.key_down_or_up(3, key_event, true, true, false, false);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn lock_screen(&mut self) {
|
2022-01-09 19:56:24 +08:00
|
|
|
|
let mut key_event = KeyEvent::new();
|
|
|
|
|
key_event.set_control_key(ControlKey::LockScreen);
|
|
|
|
|
self.key_down_or_up(1, key_event, false, false, false, false);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn transfer_file(&mut self) {
|
|
|
|
|
let id = self.get_id();
|
|
|
|
|
let args = vec!["--file-transfer", &id];
|
|
|
|
|
if let Err(err) = crate::run_me(args) {
|
|
|
|
|
log::error!("Failed to spawn file transfer: {}", err);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn tunnel(&mut self) {
|
|
|
|
|
let id = self.get_id();
|
|
|
|
|
let args = vec!["--port-forward", &id];
|
|
|
|
|
if let Err(err) = crate::run_me(args) {
|
|
|
|
|
log::error!("Failed to spawn IP tunneling: {}", err);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn key_down_or_up(
|
|
|
|
|
&mut self,
|
|
|
|
|
down_or_up: i32,
|
2022-01-09 19:56:24 +08:00
|
|
|
|
evt: KeyEvent,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
alt: bool,
|
|
|
|
|
ctrl: bool,
|
|
|
|
|
shift: bool,
|
|
|
|
|
command: bool,
|
|
|
|
|
) {
|
2022-01-09 19:56:24 +08:00
|
|
|
|
let mut key_event = evt;
|
2021-03-29 15:59:14 +08:00
|
|
|
|
|
2022-01-09 19:56:24 +08:00
|
|
|
|
if alt
|
|
|
|
|
&& !crate::is_control_key(&key_event, &ControlKey::Alt)
|
|
|
|
|
&& !crate::is_control_key(&key_event, &ControlKey::RAlt)
|
|
|
|
|
{
|
|
|
|
|
key_event.modifiers.push(ControlKey::Alt.into());
|
2021-06-14 15:29:36 +08:00
|
|
|
|
}
|
2022-01-09 19:56:24 +08:00
|
|
|
|
if shift
|
|
|
|
|
&& !crate::is_control_key(&key_event, &ControlKey::Shift)
|
|
|
|
|
&& !crate::is_control_key(&key_event, &ControlKey::RShift)
|
|
|
|
|
{
|
|
|
|
|
key_event.modifiers.push(ControlKey::Shift.into());
|
2021-06-14 15:29:36 +08:00
|
|
|
|
}
|
2022-01-09 19:56:24 +08:00
|
|
|
|
if ctrl
|
|
|
|
|
&& !crate::is_control_key(&key_event, &ControlKey::Control)
|
|
|
|
|
&& !crate::is_control_key(&key_event, &ControlKey::RControl)
|
|
|
|
|
{
|
|
|
|
|
key_event.modifiers.push(ControlKey::Control.into());
|
2021-08-10 12:18:10 +08:00
|
|
|
|
}
|
2022-01-09 19:56:24 +08:00
|
|
|
|
if command
|
|
|
|
|
&& !crate::is_control_key(&key_event, &ControlKey::Meta)
|
|
|
|
|
&& !crate::is_control_key(&key_event, &ControlKey::RWin)
|
|
|
|
|
{
|
|
|
|
|
key_event.modifiers.push(ControlKey::Meta.into());
|
2021-05-26 12:42:21 +08:00
|
|
|
|
}
|
2022-01-10 01:06:31 +08:00
|
|
|
|
if get_key_state(enigo::Key::CapsLock) {
|
2022-01-09 19:56:24 +08:00
|
|
|
|
key_event.modifiers.push(ControlKey::CapsLock.into());
|
|
|
|
|
}
|
|
|
|
|
if self.peer_platform() != "Mac OS" {
|
2022-01-10 01:06:31 +08:00
|
|
|
|
if get_key_state(enigo::Key::NumLock) && common::valid_for_numlock(&key_event) {
|
2022-01-09 19:56:24 +08:00
|
|
|
|
key_event.modifiers.push(ControlKey::NumLock.into());
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-09 19:56:24 +08:00
|
|
|
|
if down_or_up == 1 {
|
|
|
|
|
key_event.down = true;
|
|
|
|
|
} else if down_or_up == 3 {
|
|
|
|
|
key_event.press = true;
|
|
|
|
|
}
|
|
|
|
|
let mut msg_out = Message::new();
|
|
|
|
|
msg_out.set_key_event(key_event);
|
|
|
|
|
log::debug!("{:?}", msg_out);
|
|
|
|
|
self.send(Data::Message(msg_out));
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn set_cursor_id(&mut self, id: String) {
|
|
|
|
|
self.call("setCursorId", &make_args!(id));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn set_cursor_position(&mut self, cd: CursorPosition) {
|
|
|
|
|
self.call("setCursorPosition", &make_args!(cd.x, cd.y));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn call(&self, func: &str, args: &[Value]) {
|
2022-03-22 17:09:45 +08:00
|
|
|
|
let r = self.read().unwrap();
|
|
|
|
|
if let Some(ref e) = r.element {
|
|
|
|
|
allow_err!(e.call_method(func, args));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn call2(&self, func: &str, args: &[Value]) {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let r = self.read().unwrap();
|
|
|
|
|
if let Some(ref e) = r.element {
|
2022-02-06 18:19:06 +08:00
|
|
|
|
allow_err!(e.call_method(func, &super::value_crash_workaround(args)[..]));
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn set_display(&self, x: i32, y: i32, w: i32, h: i32) {
|
|
|
|
|
self.call("setDisplay", &make_args!(x, y, w, h));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const MILLI1: Duration = Duration::from_millis(1);
|
|
|
|
|
|
|
|
|
|
async fn start_one_port_forward(
|
|
|
|
|
handler: Handler,
|
|
|
|
|
port: i32,
|
|
|
|
|
remote_host: String,
|
|
|
|
|
remote_port: i32,
|
|
|
|
|
receiver: mpsc::UnboundedReceiver<Data>,
|
2022-05-12 17:35:25 +08:00
|
|
|
|
key: &str,
|
|
|
|
|
token: &str,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
) {
|
|
|
|
|
handler.lc.write().unwrap().port_forward = (remote_host, remote_port);
|
2022-05-12 17:35:25 +08:00
|
|
|
|
if let Err(err) = crate::port_forward::listen(
|
|
|
|
|
handler.id.clone(),
|
|
|
|
|
port,
|
|
|
|
|
handler.clone(),
|
|
|
|
|
receiver,
|
|
|
|
|
key,
|
|
|
|
|
token,
|
|
|
|
|
)
|
|
|
|
|
.await
|
2021-03-29 15:59:14 +08:00
|
|
|
|
{
|
|
|
|
|
handler.on_error(&format!("Failed to listen on {}: {}", port, err));
|
|
|
|
|
}
|
|
|
|
|
log::info!("port forward (:{}) exit", port);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-25 19:42:51 +08:00
|
|
|
|
#[tokio::main(flavor = "current_thread")]
|
2021-03-29 15:59:14 +08:00
|
|
|
|
async fn io_loop(handler: Handler) {
|
|
|
|
|
let (sender, mut receiver) = mpsc::unbounded_channel::<Data>();
|
|
|
|
|
handler.write().unwrap().sender = Some(sender.clone());
|
2022-05-12 17:35:25 +08:00
|
|
|
|
let mut options = crate::ipc::get_options_async().await;
|
|
|
|
|
let mut key = options.remove("key").unwrap_or("".to_owned());
|
|
|
|
|
let token = LocalConfig::get_option("access_token");
|
|
|
|
|
if key.is_empty() {
|
|
|
|
|
key = crate::platform::get_license_key();
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
if handler.is_port_forward() {
|
|
|
|
|
if handler.is_rdp() {
|
2022-05-12 17:35:25 +08:00
|
|
|
|
let port = handler
|
|
|
|
|
.get_option("rdp_port".to_owned())
|
|
|
|
|
.parse::<i32>()
|
|
|
|
|
.unwrap_or(3389);
|
|
|
|
|
std::env::set_var(
|
|
|
|
|
"rdp_username",
|
|
|
|
|
handler.get_option("rdp_username".to_owned()),
|
|
|
|
|
);
|
|
|
|
|
std::env::set_var(
|
|
|
|
|
"rdp_password",
|
|
|
|
|
handler.get_option("rdp_password".to_owned()),
|
|
|
|
|
);
|
|
|
|
|
log::info!("Remote rdp port: {}", port);
|
|
|
|
|
start_one_port_forward(handler, 0, "".to_owned(), port, receiver, &key, &token).await;
|
2021-03-29 15:59:14 +08:00
|
|
|
|
} else if handler.args.len() == 0 {
|
|
|
|
|
let pfs = handler.lc.read().unwrap().port_forwards.clone();
|
|
|
|
|
let mut queues = HashMap::<i32, mpsc::UnboundedSender<Data>>::new();
|
|
|
|
|
for d in pfs {
|
|
|
|
|
sender.send(Data::AddPortForward(d)).ok();
|
|
|
|
|
}
|
|
|
|
|
loop {
|
|
|
|
|
match receiver.recv().await {
|
|
|
|
|
Some(Data::AddPortForward((port, remote_host, remote_port))) => {
|
|
|
|
|
if port <= 0 || remote_port <= 0 {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
let (sender, receiver) = mpsc::unbounded_channel::<Data>();
|
|
|
|
|
queues.insert(port, sender);
|
|
|
|
|
let handler = handler.clone();
|
2022-05-12 17:35:25 +08:00
|
|
|
|
let key = key.clone();
|
|
|
|
|
let token = token.clone();
|
2021-03-29 15:59:14 +08:00
|
|
|
|
tokio::spawn(async move {
|
|
|
|
|
start_one_port_forward(
|
|
|
|
|
handler,
|
|
|
|
|
port,
|
|
|
|
|
remote_host,
|
|
|
|
|
remote_port,
|
|
|
|
|
receiver,
|
2022-05-12 17:35:25 +08:00
|
|
|
|
&key,
|
|
|
|
|
&token,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
)
|
|
|
|
|
.await;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
Some(Data::RemovePortForward(port)) => {
|
|
|
|
|
if let Some(s) = queues.remove(&port) {
|
|
|
|
|
s.send(Data::Close).ok();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Some(Data::Close) => {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
Some(d) => {
|
|
|
|
|
for (_, s) in queues.iter() {
|
|
|
|
|
s.send(d.clone()).ok();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
let port = handler.args[0].parse::<i32>().unwrap_or(0);
|
|
|
|
|
if handler.args.len() != 3
|
|
|
|
|
|| handler.args[2].parse::<i32>().unwrap_or(0) <= 0
|
|
|
|
|
|| port <= 0
|
|
|
|
|
{
|
|
|
|
|
handler.on_error("Invalid arguments, usage:<br><br> rustdesk --port-forward remote-id listen-port remote-host remote-port");
|
|
|
|
|
}
|
|
|
|
|
let remote_host = handler.args[1].clone();
|
|
|
|
|
let remote_port = handler.args[2].parse::<i32>().unwrap_or(0);
|
2022-05-12 17:35:25 +08:00
|
|
|
|
start_one_port_forward(
|
|
|
|
|
handler,
|
|
|
|
|
port,
|
|
|
|
|
remote_host,
|
|
|
|
|
remote_port,
|
|
|
|
|
receiver,
|
|
|
|
|
&key,
|
|
|
|
|
&token,
|
|
|
|
|
)
|
|
|
|
|
.await;
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-06-23 17:42:30 +08:00
|
|
|
|
let frame_count = Arc::new(AtomicUsize::new(0));
|
|
|
|
|
let frame_count_cl = frame_count.clone();
|
|
|
|
|
let (video_sender, audio_sender) = start_video_audio_threads(move |data: &[u8]| {
|
|
|
|
|
frame_count_cl.fetch_add(1, Ordering::Relaxed);
|
2022-01-30 21:16:08 +08:00
|
|
|
|
VIDEO
|
|
|
|
|
.lock()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.as_mut()
|
|
|
|
|
.map(|v| v.render_frame(data).ok());
|
|
|
|
|
});
|
2022-02-14 17:34:09 +08:00
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let mut remote = Remote {
|
|
|
|
|
handler,
|
2022-01-30 21:16:08 +08:00
|
|
|
|
video_sender,
|
|
|
|
|
audio_sender,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
receiver,
|
|
|
|
|
sender,
|
|
|
|
|
old_clipboard: Default::default(),
|
|
|
|
|
read_jobs: Vec::new(),
|
|
|
|
|
write_jobs: Vec::new(),
|
|
|
|
|
remove_jobs: Default::default(),
|
|
|
|
|
timer: time::interval(SEC30),
|
|
|
|
|
last_update_jobs_status: (Instant::now(), Default::default()),
|
|
|
|
|
first_frame: false,
|
2022-02-14 17:34:09 +08:00
|
|
|
|
#[cfg(windows)]
|
2022-02-15 15:35:19 +08:00
|
|
|
|
clipboard_file_context: None,
|
2022-06-23 17:42:30 +08:00
|
|
|
|
data_count: Arc::new(AtomicUsize::new(0)),
|
|
|
|
|
frame_count,
|
2022-07-05 22:17:34 +08:00
|
|
|
|
video_format: CodecFormat::Unknown,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
};
|
2022-05-12 17:35:25 +08:00
|
|
|
|
remote.io_loop(&key, &token).await;
|
2022-05-13 15:11:56 +08:00
|
|
|
|
remote.sync_jobs_status_to_local().await;
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct RemoveJob {
|
|
|
|
|
files: Vec<FileEntry>,
|
|
|
|
|
path: String,
|
|
|
|
|
sep: &'static str,
|
|
|
|
|
is_remote: bool,
|
|
|
|
|
no_confirm: bool,
|
|
|
|
|
last_update_job_status: Instant,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl RemoveJob {
|
|
|
|
|
fn new(files: Vec<FileEntry>, path: String, sep: &'static str, is_remote: bool) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
files,
|
|
|
|
|
path,
|
|
|
|
|
sep,
|
|
|
|
|
is_remote,
|
|
|
|
|
no_confirm: false,
|
|
|
|
|
last_update_job_status: Instant::now(),
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-05-08 21:01:03 +08:00
|
|
|
|
|
2022-05-18 15:45:45 +08:00
|
|
|
|
pub fn _gen_meta(&self) -> RemoveJobMeta {
|
2022-05-08 21:01:03 +08:00
|
|
|
|
RemoveJobMeta {
|
|
|
|
|
path: self.path.clone(),
|
|
|
|
|
is_remote: self.is_remote,
|
|
|
|
|
no_confirm: self.no_confirm,
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct Remote {
|
|
|
|
|
handler: Handler,
|
2022-01-30 21:16:08 +08:00
|
|
|
|
video_sender: MediaSender,
|
|
|
|
|
audio_sender: MediaSender,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
receiver: mpsc::UnboundedReceiver<Data>,
|
|
|
|
|
sender: mpsc::UnboundedSender<Data>,
|
|
|
|
|
old_clipboard: Arc<Mutex<String>>,
|
|
|
|
|
read_jobs: Vec<fs::TransferJob>,
|
|
|
|
|
write_jobs: Vec<fs::TransferJob>,
|
|
|
|
|
remove_jobs: HashMap<i32, RemoveJob>,
|
|
|
|
|
timer: Interval,
|
|
|
|
|
last_update_jobs_status: (Instant, HashMap<i32, u64>),
|
|
|
|
|
first_frame: bool,
|
2022-02-14 17:34:09 +08:00
|
|
|
|
#[cfg(windows)]
|
2022-02-15 14:46:08 +08:00
|
|
|
|
clipboard_file_context: Option<Box<CliprdrClientContext>>,
|
2022-06-23 17:42:30 +08:00
|
|
|
|
data_count: Arc<AtomicUsize>,
|
|
|
|
|
frame_count: Arc<AtomicUsize>,
|
2022-07-05 22:17:34 +08:00
|
|
|
|
video_format: CodecFormat,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Remote {
|
2022-05-12 17:35:25 +08:00
|
|
|
|
async fn io_loop(&mut self, key: &str, token: &str) {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let stop_clipboard = self.start_clipboard();
|
|
|
|
|
let mut last_recv_time = Instant::now();
|
2021-07-27 23:53:12 +08:00
|
|
|
|
let conn_type = if self.handler.is_file_transfer() {
|
|
|
|
|
ConnType::FILE_TRANSFER
|
|
|
|
|
} else {
|
|
|
|
|
ConnType::default()
|
|
|
|
|
};
|
2022-05-12 17:35:25 +08:00
|
|
|
|
match Client::start(&self.handler.id, key, token, conn_type).await {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
Ok((mut peer, direct)) => {
|
2022-05-25 00:15:46 +08:00
|
|
|
|
SERVER_KEYBOARD_ENABLED.store(true, Ordering::SeqCst);
|
|
|
|
|
SERVER_CLIPBOARD_ENABLED.store(true, Ordering::SeqCst);
|
|
|
|
|
SERVER_FILE_TRANSFER_ENABLED.store(true, Ordering::SeqCst);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
self.handler
|
|
|
|
|
.call("setConnectionType", &make_args!(peer.is_secured(), direct));
|
2022-02-14 17:34:09 +08:00
|
|
|
|
|
|
|
|
|
// just build for now
|
|
|
|
|
#[cfg(not(windows))]
|
2022-03-03 20:25:23 +08:00
|
|
|
|
let (_tx_holder, mut rx_clip_client) = mpsc::unbounded_channel::<i32>();
|
2022-02-14 17:34:09 +08:00
|
|
|
|
#[cfg(windows)]
|
2022-02-22 14:17:50 +08:00
|
|
|
|
let mut rx_clip_client = get_rx_clip_client().lock().await;
|
2022-02-14 17:34:09 +08:00
|
|
|
|
|
2022-06-23 17:42:30 +08:00
|
|
|
|
let mut status_timer = time::interval(Duration::new(1, 0));
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
loop {
|
|
|
|
|
tokio::select! {
|
|
|
|
|
res = peer.next() => {
|
|
|
|
|
if let Some(res) = res {
|
|
|
|
|
match res {
|
|
|
|
|
Err(err) => {
|
|
|
|
|
log::error!("Connection closed: {}", err);
|
|
|
|
|
self.handler.msgbox("error", "Connection Error", &err.to_string());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
Ok(ref bytes) => {
|
|
|
|
|
last_recv_time = Instant::now();
|
2022-06-23 17:42:30 +08:00
|
|
|
|
self.data_count.fetch_add(bytes.len(), Ordering::Relaxed);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
if !self.handle_msg_from_peer(bytes, &mut peer).await {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
log::info!("Reset by the peer");
|
|
|
|
|
self.handler.msgbox("error", "Connection Error", "Reset by the peer");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
d = self.receiver.recv() => {
|
|
|
|
|
if let Some(d) = d {
|
|
|
|
|
if !self.handle_msg_from_ui(d, &mut peer).await {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-02-22 14:17:50 +08:00
|
|
|
|
_msg = rx_clip_client.recv() => {
|
2022-02-14 17:34:09 +08:00
|
|
|
|
#[cfg(windows)]
|
2022-02-15 14:46:08 +08:00
|
|
|
|
match _msg {
|
2022-02-24 11:22:19 +08:00
|
|
|
|
Some((_, clip)) => {
|
|
|
|
|
allow_err!(peer.send(&clip_2_msg(clip)).await);
|
2022-02-14 17:34:09 +08:00
|
|
|
|
}
|
|
|
|
|
None => {
|
2022-02-15 14:46:08 +08:00
|
|
|
|
// unreachable!()
|
2022-02-14 17:34:09 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
_ = self.timer.tick() => {
|
|
|
|
|
if last_recv_time.elapsed() >= SEC30 {
|
|
|
|
|
self.handler.msgbox("error", "Connection Error", "Timeout");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if !self.read_jobs.is_empty() {
|
|
|
|
|
if let Err(err) = fs::handle_read_jobs(&mut self.read_jobs, &mut peer).await {
|
|
|
|
|
self.handler.msgbox("error", "Connection Error", &err.to_string());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
self.update_jobs_status();
|
|
|
|
|
} else {
|
|
|
|
|
self.timer = time::interval_at(Instant::now() + SEC30, SEC30);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-06-23 17:42:30 +08:00
|
|
|
|
_ = status_timer.tick() => {
|
|
|
|
|
let speed = self.data_count.swap(0, Ordering::Relaxed);
|
|
|
|
|
let speed = format!("{:.2}kB/s", speed as f32 / 1024 as f32);
|
|
|
|
|
let fps = self.frame_count.swap(0, Ordering::Relaxed) as _;
|
|
|
|
|
self.handler.update_quality_status(QualityStatus {
|
2022-07-05 22:17:34 +08:00
|
|
|
|
speed:Some(speed),
|
|
|
|
|
fps:Some(fps),
|
2022-06-23 17:42:30 +08:00
|
|
|
|
..Default::default()
|
|
|
|
|
});
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
log::debug!("Exit io_loop of id={}", self.handler.id);
|
|
|
|
|
}
|
|
|
|
|
Err(err) => {
|
|
|
|
|
self.handler
|
|
|
|
|
.msgbox("error", "Connection Error", &err.to_string());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if let Some(stop) = stop_clipboard {
|
|
|
|
|
stop.send(()).ok();
|
|
|
|
|
}
|
2022-05-25 00:15:46 +08:00
|
|
|
|
SERVER_KEYBOARD_ENABLED.store(false, Ordering::SeqCst);
|
|
|
|
|
SERVER_CLIPBOARD_ENABLED.store(false, Ordering::SeqCst);
|
|
|
|
|
SERVER_FILE_TRANSFER_ENABLED.store(false, Ordering::SeqCst);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn handle_job_status(&mut self, id: i32, file_num: i32, err: Option<String>) {
|
|
|
|
|
if let Some(job) = self.remove_jobs.get_mut(&id) {
|
|
|
|
|
if job.no_confirm {
|
|
|
|
|
let file_num = (file_num + 1) as usize;
|
|
|
|
|
if file_num < job.files.len() {
|
|
|
|
|
let path = format!("{}{}{}", job.path, job.sep, job.files[file_num].name);
|
|
|
|
|
self.sender
|
|
|
|
|
.send(Data::RemoveFile((id, path, file_num as i32, job.is_remote)))
|
|
|
|
|
.ok();
|
|
|
|
|
let elapsed = job.last_update_job_status.elapsed().as_millis() as i32;
|
|
|
|
|
if elapsed >= 1000 {
|
|
|
|
|
job.last_update_job_status = Instant::now();
|
|
|
|
|
} else {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
self.remove_jobs.remove(&id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if let Some(err) = err {
|
|
|
|
|
self.handler
|
|
|
|
|
.call("jobError", &make_args!(id, err, file_num));
|
|
|
|
|
} else {
|
|
|
|
|
self.handler.call("jobDone", &make_args!(id, file_num));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn start_clipboard(&mut self) -> Option<std::sync::mpsc::Sender<()>> {
|
2021-05-25 12:01:27 +08:00
|
|
|
|
if self.handler.is_file_transfer() || self.handler.is_port_forward() {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
let (tx, rx) = std::sync::mpsc::channel();
|
|
|
|
|
let old_clipboard = self.old_clipboard.clone();
|
|
|
|
|
let tx_protobuf = self.sender.clone();
|
|
|
|
|
let lc = self.handler.lc.clone();
|
|
|
|
|
match ClipboardContext::new() {
|
|
|
|
|
Ok(mut ctx) => {
|
|
|
|
|
// ignore clipboard update before service start
|
|
|
|
|
check_clipboard(&mut ctx, Some(&old_clipboard));
|
|
|
|
|
std::thread::spawn(move || loop {
|
|
|
|
|
std::thread::sleep(Duration::from_millis(CLIPBOARD_INTERVAL));
|
|
|
|
|
match rx.try_recv() {
|
|
|
|
|
Ok(_) | Err(std::sync::mpsc::TryRecvError::Disconnected) => {
|
|
|
|
|
log::debug!("Exit clipboard service of client");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
2022-05-25 00:02:33 +08:00
|
|
|
|
if !SERVER_CLIPBOARD_ENABLED.load(Ordering::SeqCst)
|
2022-05-25 00:12:28 +08:00
|
|
|
|
|| !SERVER_KEYBOARD_ENABLED.load(Ordering::SeqCst)
|
2021-03-29 15:59:14 +08:00
|
|
|
|
|| lc.read().unwrap().disable_clipboard
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if let Some(msg) = check_clipboard(&mut ctx, Some(&old_clipboard)) {
|
|
|
|
|
tx_protobuf.send(Data::Message(msg)).ok();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
Err(err) => {
|
|
|
|
|
log::error!("Failed to start clipboard service of client: {}", err);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Some(tx)
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-12 15:55:36 +08:00
|
|
|
|
async fn load_last_jobs(&mut self) {
|
2022-05-13 10:37:16 +08:00
|
|
|
|
log::info!("start load last jobs");
|
2022-05-13 14:46:37 +08:00
|
|
|
|
self.handler.call("clearAllJobs", &make_args!());
|
2022-05-12 15:55:36 +08:00
|
|
|
|
let pc = self.handler.load_config();
|
|
|
|
|
if pc.transfer.write_jobs.is_empty() && pc.transfer.read_jobs.is_empty() {
|
|
|
|
|
// no last jobs
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// TODO: can add a confirm dialog
|
2022-05-13 10:37:16 +08:00
|
|
|
|
let mut cnt = 1;
|
2022-05-13 09:30:52 +08:00
|
|
|
|
for job_str in pc.transfer.read_jobs.iter() {
|
|
|
|
|
let job: Result<TransferJobMeta, serde_json::Error> = serde_json::from_str(&job_str);
|
|
|
|
|
if let Ok(job) = job {
|
2022-05-13 14:46:37 +08:00
|
|
|
|
self.handler.call(
|
|
|
|
|
"addJob",
|
|
|
|
|
&make_args!(
|
|
|
|
|
cnt,
|
|
|
|
|
job.to.clone(),
|
|
|
|
|
job.remote.clone(),
|
|
|
|
|
job.file_num,
|
|
|
|
|
job.show_hidden,
|
|
|
|
|
false
|
|
|
|
|
),
|
|
|
|
|
);
|
2022-05-13 09:30:52 +08:00
|
|
|
|
cnt += 1;
|
2022-05-13 14:46:37 +08:00
|
|
|
|
println!("restore read_job: {:?}", job);
|
2022-05-13 09:30:52 +08:00
|
|
|
|
}
|
2022-05-12 15:55:36 +08:00
|
|
|
|
}
|
2022-05-13 09:30:52 +08:00
|
|
|
|
for job_str in pc.transfer.write_jobs.iter() {
|
|
|
|
|
let job: Result<TransferJobMeta, serde_json::Error> = serde_json::from_str(&job_str);
|
|
|
|
|
if let Ok(job) = job {
|
2022-05-13 14:46:37 +08:00
|
|
|
|
self.handler.call(
|
|
|
|
|
"addJob",
|
|
|
|
|
&make_args!(
|
|
|
|
|
cnt,
|
|
|
|
|
job.remote.clone(),
|
|
|
|
|
job.to.clone(),
|
|
|
|
|
job.file_num,
|
|
|
|
|
job.show_hidden,
|
|
|
|
|
true
|
|
|
|
|
),
|
|
|
|
|
);
|
2022-05-13 09:30:52 +08:00
|
|
|
|
cnt += 1;
|
2022-05-13 14:46:37 +08:00
|
|
|
|
println!("restore write_job: {:?}", job);
|
2022-05-13 09:30:52 +08:00
|
|
|
|
}
|
2022-05-12 15:55:36 +08:00
|
|
|
|
}
|
|
|
|
|
self.handler.call("updateTransferList", &make_args!());
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
async fn handle_msg_from_ui(&mut self, data: Data, peer: &mut Stream) -> bool {
|
2022-04-27 10:45:20 +08:00
|
|
|
|
// log::info!("new msg from ui, {}",data);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
match data {
|
|
|
|
|
Data::Close => {
|
2022-07-18 11:05:19 +08:00
|
|
|
|
let mut misc = Misc::new();
|
|
|
|
|
misc.set_close_reason("".to_owned());
|
|
|
|
|
let mut msg = Message::new();
|
|
|
|
|
msg.set_misc(misc);
|
|
|
|
|
allow_err!(peer.send(&msg).await);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
Data::Login((password, remember)) => {
|
|
|
|
|
self.handler
|
|
|
|
|
.handle_login_from_ui(password, remember, peer)
|
|
|
|
|
.await;
|
|
|
|
|
}
|
2022-02-15 15:35:19 +08:00
|
|
|
|
Data::ToggleClipboardFile => {
|
|
|
|
|
self.check_clipboard_file_context();
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
Data::Message(msg) => {
|
|
|
|
|
allow_err!(peer.send(&msg).await);
|
|
|
|
|
}
|
2022-05-13 14:46:37 +08:00
|
|
|
|
Data::SendFiles((id, path, to, file_num, include_hidden, is_remote)) => {
|
2022-04-28 18:23:12 +08:00
|
|
|
|
log::info!("send files, is remote {}", is_remote);
|
|
|
|
|
let od = can_enable_overwrite_detection(self.handler.lc.read().unwrap().version);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
if is_remote {
|
2022-04-28 18:23:12 +08:00
|
|
|
|
log::debug!("New job {}, write to {} from remote {}", id, to, path);
|
2022-05-13 14:46:37 +08:00
|
|
|
|
self.write_jobs.push(fs::TransferJob::new_write(
|
|
|
|
|
id,
|
|
|
|
|
path.clone(),
|
|
|
|
|
to,
|
|
|
|
|
file_num,
|
|
|
|
|
include_hidden,
|
|
|
|
|
is_remote,
|
|
|
|
|
Vec::new(),
|
|
|
|
|
od,
|
|
|
|
|
));
|
|
|
|
|
allow_err!(
|
|
|
|
|
peer.send(&fs::new_send(id, path, file_num, include_hidden))
|
|
|
|
|
.await
|
|
|
|
|
);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
} else {
|
2022-05-13 14:46:37 +08:00
|
|
|
|
match fs::TransferJob::new_read(
|
|
|
|
|
id,
|
|
|
|
|
to.clone(),
|
|
|
|
|
path.clone(),
|
|
|
|
|
file_num,
|
|
|
|
|
include_hidden,
|
|
|
|
|
is_remote,
|
|
|
|
|
od,
|
|
|
|
|
) {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
Err(err) => {
|
|
|
|
|
self.handle_job_status(id, -1, Some(err.to_string()));
|
|
|
|
|
}
|
|
|
|
|
Ok(job) => {
|
2022-04-28 18:23:12 +08:00
|
|
|
|
log::debug!(
|
2021-03-29 15:59:14 +08:00
|
|
|
|
"New job {}, read {} to remote {}, {} files",
|
|
|
|
|
id,
|
|
|
|
|
path,
|
|
|
|
|
to,
|
|
|
|
|
job.files().len()
|
|
|
|
|
);
|
|
|
|
|
let m = make_fd(job.id(), job.files(), true);
|
|
|
|
|
self.handler.call("updateFolderFiles", &make_args!(m));
|
2022-05-20 11:31:09 +08:00
|
|
|
|
#[cfg(not(windows))]
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let files = job.files().clone();
|
2022-05-20 11:31:09 +08:00
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
let mut files = job.files().clone();
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
if self.handler.peer_platform() != "Windows" {
|
|
|
|
|
// peer is not windows, need transform \ to /
|
|
|
|
|
fs::transform_windows_path(&mut files);
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
self.read_jobs.push(job);
|
|
|
|
|
self.timer = time::interval(MILLI1);
|
2022-05-13 11:23:30 +08:00
|
|
|
|
allow_err!(peer.send(&fs::new_receive(id, to, file_num, files)).await);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-05-14 11:58:47 +08:00
|
|
|
|
Data::AddJob((id, path, to, file_num, include_hidden, is_remote)) => {
|
|
|
|
|
let od = can_enable_overwrite_detection(self.handler.lc.read().unwrap().version);
|
|
|
|
|
if is_remote {
|
2022-04-24 23:39:15 +08:00
|
|
|
|
log::debug!(
|
|
|
|
|
"new write waiting job {}, write to {} from remote {}",
|
|
|
|
|
id,
|
|
|
|
|
to,
|
|
|
|
|
path
|
|
|
|
|
);
|
2022-05-14 11:58:47 +08:00
|
|
|
|
let mut job = fs::TransferJob::new_write(
|
|
|
|
|
id,
|
|
|
|
|
path.clone(),
|
|
|
|
|
to,
|
|
|
|
|
file_num,
|
|
|
|
|
include_hidden,
|
|
|
|
|
is_remote,
|
|
|
|
|
Vec::new(),
|
|
|
|
|
od,
|
|
|
|
|
);
|
|
|
|
|
job.is_last_job = true;
|
|
|
|
|
self.write_jobs.push(job);
|
|
|
|
|
} else {
|
|
|
|
|
match fs::TransferJob::new_read(
|
|
|
|
|
id,
|
|
|
|
|
to.clone(),
|
|
|
|
|
path.clone(),
|
|
|
|
|
file_num,
|
|
|
|
|
include_hidden,
|
|
|
|
|
is_remote,
|
|
|
|
|
od,
|
|
|
|
|
) {
|
|
|
|
|
Err(err) => {
|
|
|
|
|
self.handle_job_status(id, -1, Some(err.to_string()));
|
|
|
|
|
}
|
|
|
|
|
Ok(mut job) => {
|
|
|
|
|
log::debug!(
|
|
|
|
|
"new read waiting job {}, read {} to remote {}, {} files",
|
|
|
|
|
id,
|
|
|
|
|
path,
|
|
|
|
|
to,
|
|
|
|
|
job.files().len()
|
|
|
|
|
);
|
|
|
|
|
let m = make_fd(job.id(), job.files(), true);
|
|
|
|
|
self.handler.call("updateFolderFiles", &make_args!(m));
|
|
|
|
|
job.is_last_job = true;
|
|
|
|
|
self.read_jobs.push(job);
|
|
|
|
|
self.timer = time::interval(MILLI1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Data::ResumeJob((id, is_remote)) => {
|
|
|
|
|
if is_remote {
|
|
|
|
|
if let Some(job) = get_job(id, &mut self.write_jobs) {
|
|
|
|
|
job.is_last_job = false;
|
|
|
|
|
allow_err!(
|
2022-04-24 23:39:15 +08:00
|
|
|
|
peer.send(&fs::new_send(
|
|
|
|
|
id,
|
|
|
|
|
job.remote.clone(),
|
|
|
|
|
job.file_num,
|
|
|
|
|
job.show_hidden
|
|
|
|
|
))
|
2022-05-25 00:02:33 +08:00
|
|
|
|
.await
|
2022-05-14 11:58:47 +08:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if let Some(job) = get_job(id, &mut self.read_jobs) {
|
|
|
|
|
job.is_last_job = false;
|
2022-04-24 23:39:15 +08:00
|
|
|
|
allow_err!(
|
|
|
|
|
peer.send(&fs::new_receive(
|
|
|
|
|
id,
|
|
|
|
|
job.path.to_string_lossy().to_string(),
|
|
|
|
|
job.file_num,
|
|
|
|
|
job.files.clone()
|
|
|
|
|
))
|
|
|
|
|
.await
|
|
|
|
|
);
|
2022-05-14 11:58:47 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
Data::SetNoConfirm(id) => {
|
|
|
|
|
if let Some(job) = self.remove_jobs.get_mut(&id) {
|
|
|
|
|
job.no_confirm = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Data::ConfirmDeleteFiles((id, file_num)) => {
|
|
|
|
|
if let Some(job) = self.remove_jobs.get_mut(&id) {
|
|
|
|
|
let i = file_num as usize;
|
|
|
|
|
if i < job.files.len() {
|
|
|
|
|
self.handler.call(
|
|
|
|
|
"confirmDeleteFiles",
|
|
|
|
|
&make_args!(id, file_num, job.files[i].name.clone()),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-04-28 17:42:22 +08:00
|
|
|
|
Data::SetConfirmOverrideFile((id, file_num, need_override, remember, is_upload)) => {
|
|
|
|
|
if is_upload {
|
|
|
|
|
if let Some(job) = fs::get_job(id, &mut self.read_jobs) {
|
|
|
|
|
if remember {
|
|
|
|
|
job.set_overwrite_strategy(Some(need_override));
|
|
|
|
|
}
|
|
|
|
|
job.confirm(&FileTransferSendConfirmRequest {
|
|
|
|
|
id,
|
|
|
|
|
file_num,
|
|
|
|
|
union: if need_override {
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(file_transfer_send_confirm_request::Union::OffsetBlk(0))
|
2022-04-28 17:42:22 +08:00
|
|
|
|
} else {
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(file_transfer_send_confirm_request::Union::Skip(true))
|
2022-04-28 17:42:22 +08:00
|
|
|
|
},
|
|
|
|
|
..Default::default()
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if let Some(job) = fs::get_job(id, &mut self.write_jobs) {
|
|
|
|
|
if remember {
|
|
|
|
|
job.set_overwrite_strategy(Some(need_override));
|
|
|
|
|
}
|
|
|
|
|
let mut msg = Message::new();
|
|
|
|
|
let mut file_action = FileAction::new();
|
|
|
|
|
file_action.set_send_confirm(FileTransferSendConfirmRequest {
|
|
|
|
|
id,
|
|
|
|
|
file_num,
|
|
|
|
|
union: if need_override {
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(file_transfer_send_confirm_request::Union::OffsetBlk(0))
|
2022-04-28 17:42:22 +08:00
|
|
|
|
} else {
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(file_transfer_send_confirm_request::Union::Skip(true))
|
2022-04-28 17:42:22 +08:00
|
|
|
|
},
|
|
|
|
|
..Default::default()
|
|
|
|
|
});
|
|
|
|
|
msg.set_file_action(file_action);
|
|
|
|
|
allow_err!(peer.send(&msg).await);
|
2022-04-26 14:56:15 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
Data::RemoveDirAll((id, path, is_remote)) => {
|
|
|
|
|
let sep = self.handler.get_path_sep(is_remote);
|
|
|
|
|
if is_remote {
|
|
|
|
|
let mut msg_out = Message::new();
|
|
|
|
|
let mut file_action = FileAction::new();
|
|
|
|
|
file_action.set_all_files(ReadAllFiles {
|
|
|
|
|
id,
|
|
|
|
|
path: path.clone(),
|
|
|
|
|
include_hidden: true,
|
|
|
|
|
..Default::default()
|
|
|
|
|
});
|
|
|
|
|
msg_out.set_file_action(file_action);
|
|
|
|
|
allow_err!(peer.send(&msg_out).await);
|
|
|
|
|
self.remove_jobs
|
|
|
|
|
.insert(id, RemoveJob::new(Vec::new(), path, sep, is_remote));
|
|
|
|
|
} else {
|
|
|
|
|
match fs::get_recursive_files(&path, true) {
|
|
|
|
|
Ok(entries) => {
|
|
|
|
|
let m = make_fd(id, &entries, true);
|
|
|
|
|
self.handler.call("updateFolderFiles", &make_args!(m));
|
|
|
|
|
self.remove_jobs
|
|
|
|
|
.insert(id, RemoveJob::new(entries, path, sep, is_remote));
|
|
|
|
|
}
|
|
|
|
|
Err(err) => {
|
|
|
|
|
self.handle_job_status(id, -1, Some(err.to_string()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Data::CancelJob(id) => {
|
|
|
|
|
let mut msg_out = Message::new();
|
|
|
|
|
let mut file_action = FileAction::new();
|
|
|
|
|
file_action.set_cancel(FileTransferCancel {
|
|
|
|
|
id: id,
|
|
|
|
|
..Default::default()
|
|
|
|
|
});
|
|
|
|
|
msg_out.set_file_action(file_action);
|
|
|
|
|
allow_err!(peer.send(&msg_out).await);
|
|
|
|
|
if let Some(job) = fs::get_job(id, &mut self.write_jobs) {
|
|
|
|
|
job.remove_download_file();
|
|
|
|
|
fs::remove_job(id, &mut self.write_jobs);
|
|
|
|
|
}
|
|
|
|
|
fs::remove_job(id, &mut self.read_jobs);
|
|
|
|
|
self.remove_jobs.remove(&id);
|
|
|
|
|
}
|
|
|
|
|
Data::RemoveDir((id, path)) => {
|
|
|
|
|
let mut msg_out = Message::new();
|
|
|
|
|
let mut file_action = FileAction::new();
|
|
|
|
|
file_action.set_remove_dir(FileRemoveDir {
|
|
|
|
|
id,
|
|
|
|
|
path,
|
|
|
|
|
recursive: true,
|
|
|
|
|
..Default::default()
|
|
|
|
|
});
|
|
|
|
|
msg_out.set_file_action(file_action);
|
|
|
|
|
allow_err!(peer.send(&msg_out).await);
|
|
|
|
|
}
|
|
|
|
|
Data::RemoveFile((id, path, file_num, is_remote)) => {
|
|
|
|
|
if is_remote {
|
|
|
|
|
let mut msg_out = Message::new();
|
|
|
|
|
let mut file_action = FileAction::new();
|
|
|
|
|
file_action.set_remove_file(FileRemoveFile {
|
|
|
|
|
id,
|
|
|
|
|
path,
|
|
|
|
|
file_num,
|
|
|
|
|
..Default::default()
|
|
|
|
|
});
|
|
|
|
|
msg_out.set_file_action(file_action);
|
|
|
|
|
allow_err!(peer.send(&msg_out).await);
|
|
|
|
|
} else {
|
|
|
|
|
match fs::remove_file(&path) {
|
|
|
|
|
Err(err) => {
|
|
|
|
|
self.handle_job_status(id, file_num, Some(err.to_string()));
|
|
|
|
|
}
|
|
|
|
|
Ok(()) => {
|
|
|
|
|
self.handle_job_status(id, file_num, None);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Data::CreateDir((id, path, is_remote)) => {
|
|
|
|
|
if is_remote {
|
|
|
|
|
let mut msg_out = Message::new();
|
|
|
|
|
let mut file_action = FileAction::new();
|
|
|
|
|
file_action.set_create(FileDirCreate {
|
|
|
|
|
id,
|
|
|
|
|
path,
|
|
|
|
|
..Default::default()
|
|
|
|
|
});
|
|
|
|
|
msg_out.set_file_action(file_action);
|
|
|
|
|
allow_err!(peer.send(&msg_out).await);
|
|
|
|
|
} else {
|
|
|
|
|
match fs::create_dir(&path) {
|
|
|
|
|
Err(err) => {
|
|
|
|
|
self.handle_job_status(id, -1, Some(err.to_string()));
|
|
|
|
|
}
|
|
|
|
|
Ok(()) => {
|
|
|
|
|
self.handle_job_status(id, -1, None);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn update_job_status(
|
|
|
|
|
job: &fs::TransferJob,
|
|
|
|
|
elapsed: i32,
|
|
|
|
|
last_update_jobs_status: &mut (Instant, HashMap<i32, u64>),
|
|
|
|
|
handler: &mut Handler,
|
|
|
|
|
) {
|
|
|
|
|
if elapsed <= 0 {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-11-14 23:22:05 +08:00
|
|
|
|
let transferred = job.transferred();
|
|
|
|
|
let last_transferred = {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
if let Some(v) = last_update_jobs_status.1.get(&job.id()) {
|
|
|
|
|
v.to_owned()
|
|
|
|
|
} else {
|
|
|
|
|
0
|
|
|
|
|
}
|
|
|
|
|
};
|
2021-11-14 23:22:05 +08:00
|
|
|
|
last_update_jobs_status.1.insert(job.id(), transferred);
|
|
|
|
|
let speed = (transferred - last_transferred) as f64 / (elapsed as f64 / 1000.);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let file_num = job.file_num() - 1;
|
|
|
|
|
handler.call(
|
|
|
|
|
"jobProgress",
|
|
|
|
|
&make_args!(job.id(), file_num, speed, job.finished_size() as f64),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn update_jobs_status(&mut self) {
|
|
|
|
|
let elapsed = self.last_update_jobs_status.0.elapsed().as_millis() as i32;
|
|
|
|
|
if elapsed >= 1000 {
|
|
|
|
|
for job in self.read_jobs.iter() {
|
|
|
|
|
Self::update_job_status(
|
|
|
|
|
job,
|
|
|
|
|
elapsed,
|
|
|
|
|
&mut self.last_update_jobs_status,
|
|
|
|
|
&mut self.handler,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
for job in self.write_jobs.iter() {
|
|
|
|
|
Self::update_job_status(
|
|
|
|
|
job,
|
|
|
|
|
elapsed,
|
|
|
|
|
&mut self.last_update_jobs_status,
|
|
|
|
|
&mut self.handler,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
self.last_update_jobs_status.0 = Instant::now();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-08 21:01:03 +08:00
|
|
|
|
async fn sync_jobs_status_to_local(&mut self) -> bool {
|
2022-05-13 11:40:56 +08:00
|
|
|
|
log::info!("sync transfer job status");
|
2022-05-08 21:01:03 +08:00
|
|
|
|
let mut config: PeerConfig = self.handler.load_config();
|
|
|
|
|
let mut transfer_metas = TransferSerde::default();
|
|
|
|
|
for job in self.read_jobs.iter() {
|
2022-06-30 01:19:38 +08:00
|
|
|
|
let json_str = serde_json::to_string(&job.gen_meta()).unwrap_or_default();
|
2022-05-13 09:30:52 +08:00
|
|
|
|
transfer_metas.read_jobs.push(json_str);
|
2022-05-08 21:01:03 +08:00
|
|
|
|
}
|
|
|
|
|
for job in self.write_jobs.iter() {
|
2022-06-30 01:19:38 +08:00
|
|
|
|
let json_str = serde_json::to_string(&job.gen_meta()).unwrap_or_default();
|
2022-05-13 09:30:52 +08:00
|
|
|
|
transfer_metas.write_jobs.push(json_str);
|
2022-05-08 21:01:03 +08:00
|
|
|
|
}
|
2022-05-25 00:02:33 +08:00
|
|
|
|
log::info!("meta: {:?}", transfer_metas);
|
2022-05-08 21:01:03 +08:00
|
|
|
|
config.transfer = transfer_metas;
|
|
|
|
|
self.handler.save_config(config);
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
async fn handle_msg_from_peer(&mut self, data: &[u8], peer: &mut Stream) -> bool {
|
|
|
|
|
if let Ok(msg_in) = Message::parse_from_bytes(&data) {
|
|
|
|
|
match msg_in.union {
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(message::Union::VideoFrame(vf)) => {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
if !self.first_frame {
|
|
|
|
|
self.first_frame = true;
|
2022-03-22 17:09:45 +08:00
|
|
|
|
self.handler.call2("closeSuccess", &make_args!());
|
2021-03-29 15:59:14 +08:00
|
|
|
|
self.handler.call("adaptSize", &make_args!());
|
|
|
|
|
}
|
2022-07-05 22:17:34 +08:00
|
|
|
|
let incomming_format = CodecFormat::from(&vf);
|
|
|
|
|
if self.video_format != incomming_format {
|
|
|
|
|
self.video_format = incomming_format.clone();
|
|
|
|
|
self.handler.update_quality_status(QualityStatus {
|
|
|
|
|
codec_format: Some(incomming_format),
|
|
|
|
|
..Default::default()
|
|
|
|
|
})
|
|
|
|
|
};
|
2022-01-30 21:16:08 +08:00
|
|
|
|
self.video_sender.send(MediaData::VideoFrame(vf)).ok();
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(message::Union::Hash(hash)) => {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
self.handler.handle_hash(hash, peer).await;
|
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(message::Union::LoginResponse(lr)) => match lr.union {
|
|
|
|
|
Some(login_response::Union::Error(err)) => {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
if !self.handler.handle_login_error(&err) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(login_response::Union::PeerInfo(pi)) => {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
self.handler.handle_peer_info(pi);
|
2022-02-15 22:20:28 +08:00
|
|
|
|
self.check_clipboard_file_context();
|
2021-05-25 12:01:27 +08:00
|
|
|
|
if !(self.handler.is_file_transfer()
|
|
|
|
|
|| self.handler.is_port_forward()
|
2022-05-25 00:02:33 +08:00
|
|
|
|
|| !SERVER_CLIPBOARD_ENABLED.load(Ordering::SeqCst)
|
2022-05-25 00:12:28 +08:00
|
|
|
|
|| !SERVER_KEYBOARD_ENABLED.load(Ordering::SeqCst)
|
2021-05-25 12:01:27 +08:00
|
|
|
|
|| self.handler.lc.read().unwrap().disable_clipboard)
|
|
|
|
|
{
|
|
|
|
|
let txt = self.old_clipboard.lock().unwrap().clone();
|
|
|
|
|
if !txt.is_empty() {
|
|
|
|
|
let msg_out = crate::create_clipboard_msg(txt);
|
|
|
|
|
let sender = self.sender.clone();
|
|
|
|
|
tokio::spawn(async move {
|
|
|
|
|
// due to clipboard service interval time
|
|
|
|
|
sleep(common::CLIPBOARD_INTERVAL as f32 / 1_000.).await;
|
|
|
|
|
sender.send(Data::Message(msg_out)).ok();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-05-13 10:37:16 +08:00
|
|
|
|
|
|
|
|
|
if self.handler.is_file_transfer() {
|
|
|
|
|
self.load_last_jobs().await;
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
},
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(message::Union::CursorData(cd)) => {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
self.handler.set_cursor_data(cd);
|
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(message::Union::CursorId(id)) => {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
self.handler.set_cursor_id(id.to_string());
|
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(message::Union::CursorPosition(cp)) => {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
self.handler.set_cursor_position(cp);
|
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(message::Union::Clipboard(cb)) => {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
if !self.handler.lc.read().unwrap().disable_clipboard {
|
|
|
|
|
update_clipboard(cb, Some(&self.old_clipboard));
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-02-15 14:46:08 +08:00
|
|
|
|
#[cfg(windows)]
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(message::Union::Cliprdr(clip)) => {
|
2022-02-14 17:34:09 +08:00
|
|
|
|
if !self.handler.lc.read().unwrap().disable_clipboard {
|
2022-02-15 14:46:08 +08:00
|
|
|
|
if let Some(context) = &mut self.clipboard_file_context {
|
2022-02-22 14:17:50 +08:00
|
|
|
|
if let Some(clip) = msg_2_clip(clip) {
|
2022-02-24 11:22:19 +08:00
|
|
|
|
server_clip_file(context, 0, clip);
|
2022-02-22 14:17:50 +08:00
|
|
|
|
}
|
2022-02-14 17:34:09 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(message::Union::FileResponse(fr)) => {
|
2022-04-29 00:42:06 +08:00
|
|
|
|
match fr.union {
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(file_response::Union::Dir(fd)) => {
|
2022-04-24 23:39:15 +08:00
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
let entries = fd.entries.to_vec();
|
|
|
|
|
#[cfg(not(windows))]
|
2022-05-20 10:51:13 +08:00
|
|
|
|
let mut entries = fd.entries.to_vec();
|
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
|
{
|
|
|
|
|
if self.handler.peer_platform() == "Windows" {
|
|
|
|
|
fs::transform_windows_path(&mut entries);
|
|
|
|
|
}
|
2022-05-25 00:02:33 +08:00
|
|
|
|
}
|
2022-04-29 00:42:06 +08:00
|
|
|
|
let mut m = make_fd(fd.id, &entries, fd.id > 0);
|
|
|
|
|
if fd.id <= 0 {
|
|
|
|
|
m.set_item("path", fd.path);
|
2022-04-28 17:42:22 +08:00
|
|
|
|
}
|
2022-04-29 00:42:06 +08:00
|
|
|
|
self.handler.call("updateFolderFiles", &make_args!(m));
|
|
|
|
|
if let Some(job) = fs::get_job(fd.id, &mut self.write_jobs) {
|
2022-05-13 14:46:37 +08:00
|
|
|
|
log::info!("job set_files: {:?}", entries);
|
2022-04-29 00:42:06 +08:00
|
|
|
|
job.set_files(entries);
|
|
|
|
|
} else if let Some(job) = self.remove_jobs.get_mut(&fd.id) {
|
|
|
|
|
job.files = entries;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(file_response::Union::Digest(digest)) => {
|
2022-04-29 00:42:06 +08:00
|
|
|
|
if digest.is_upload {
|
|
|
|
|
if let Some(job) = fs::get_job(digest.id, &mut self.read_jobs) {
|
|
|
|
|
if let Some(file) = job.files().get(digest.file_num as usize) {
|
|
|
|
|
let read_path = get_string(&job.join(&file.name));
|
|
|
|
|
let overwrite_strategy = job.default_overwrite_strategy();
|
|
|
|
|
if let Some(overwrite) = overwrite_strategy {
|
|
|
|
|
let req = FileTransferSendConfirmRequest {
|
|
|
|
|
id: digest.id,
|
|
|
|
|
file_num: digest.file_num,
|
|
|
|
|
union: Some(if overwrite {
|
2022-07-14 17:20:01 +08:00
|
|
|
|
file_transfer_send_confirm_request::Union::OffsetBlk(0)
|
2022-04-28 17:42:22 +08:00
|
|
|
|
} else {
|
2022-07-14 17:20:01 +08:00
|
|
|
|
file_transfer_send_confirm_request::Union::Skip(
|
2022-04-29 00:42:06 +08:00
|
|
|
|
true,
|
|
|
|
|
)
|
|
|
|
|
}),
|
|
|
|
|
..Default::default()
|
|
|
|
|
};
|
|
|
|
|
job.confirm(&req);
|
|
|
|
|
let msg = new_send_confirm(req);
|
|
|
|
|
allow_err!(peer.send(&msg).await);
|
|
|
|
|
} else {
|
|
|
|
|
self.handler.call(
|
|
|
|
|
"overrideFileConfirm",
|
|
|
|
|
&make_args!(
|
|
|
|
|
digest.id,
|
|
|
|
|
digest.file_num,
|
|
|
|
|
read_path,
|
|
|
|
|
true
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if let Some(job) = fs::get_job(digest.id, &mut self.write_jobs) {
|
|
|
|
|
if let Some(file) = job.files().get(digest.file_num as usize) {
|
|
|
|
|
let write_path = get_string(&job.join(&file.name));
|
|
|
|
|
let overwrite_strategy = job.default_overwrite_strategy();
|
|
|
|
|
match fs::is_write_need_confirmation(&write_path, &digest) {
|
|
|
|
|
Ok(res) => match res {
|
|
|
|
|
DigestCheckResult::IsSame => {
|
|
|
|
|
let msg= new_send_confirm(FileTransferSendConfirmRequest {
|
|
|
|
|
id: digest.id,
|
|
|
|
|
file_num: digest.file_num,
|
2022-07-14 17:20:01 +08:00
|
|
|
|
union: Some(file_transfer_send_confirm_request::Union::Skip(true)),
|
2022-04-29 00:42:06 +08:00
|
|
|
|
..Default::default()
|
|
|
|
|
});
|
|
|
|
|
allow_err!(peer.send(&msg).await);
|
|
|
|
|
}
|
|
|
|
|
DigestCheckResult::NeedConfirm(digest) => {
|
|
|
|
|
if let Some(overwrite) = overwrite_strategy {
|
|
|
|
|
let msg = new_send_confirm(
|
|
|
|
|
FileTransferSendConfirmRequest {
|
|
|
|
|
id: digest.id,
|
|
|
|
|
file_num: digest.file_num,
|
|
|
|
|
union: Some(if overwrite {
|
2022-07-14 17:20:01 +08:00
|
|
|
|
file_transfer_send_confirm_request::Union::OffsetBlk(0)
|
2022-04-29 00:42:06 +08:00
|
|
|
|
} else {
|
2022-07-14 17:20:01 +08:00
|
|
|
|
file_transfer_send_confirm_request::Union::Skip(true)
|
2022-04-29 00:42:06 +08:00
|
|
|
|
}),
|
|
|
|
|
..Default::default()
|
2022-04-28 17:42:22 +08:00
|
|
|
|
},
|
2022-04-29 00:42:06 +08:00
|
|
|
|
);
|
|
|
|
|
allow_err!(peer.send(&msg).await);
|
|
|
|
|
} else {
|
|
|
|
|
self.handler.call(
|
|
|
|
|
"overrideFileConfirm",
|
|
|
|
|
&make_args!(
|
|
|
|
|
digest.id,
|
|
|
|
|
digest.file_num,
|
|
|
|
|
write_path,
|
|
|
|
|
false
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
DigestCheckResult::NoSuchFile => {
|
|
|
|
|
let msg = new_send_confirm(
|
|
|
|
|
FileTransferSendConfirmRequest {
|
|
|
|
|
id: digest.id,
|
|
|
|
|
file_num: digest.file_num,
|
2022-07-14 17:20:01 +08:00
|
|
|
|
union: Some(file_transfer_send_confirm_request::Union::OffsetBlk(0)),
|
2022-04-29 00:42:06 +08:00
|
|
|
|
..Default::default()
|
|
|
|
|
},
|
|
|
|
|
);
|
2022-04-28 17:42:22 +08:00
|
|
|
|
allow_err!(peer.send(&msg).await);
|
|
|
|
|
}
|
2022-04-29 00:42:06 +08:00
|
|
|
|
},
|
|
|
|
|
Err(err) => {
|
|
|
|
|
println!("error recving digest: {}", err);
|
2022-04-28 17:42:22 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-04-26 14:56:15 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(file_response::Union::Block(block)) => {
|
2022-05-13 14:46:37 +08:00
|
|
|
|
log::info!(
|
|
|
|
|
"file response block, file id:{}, file num: {}",
|
|
|
|
|
block.id,
|
|
|
|
|
block.file_num
|
|
|
|
|
);
|
2022-04-29 00:42:06 +08:00
|
|
|
|
if let Some(job) = fs::get_job(block.id, &mut self.write_jobs) {
|
|
|
|
|
if let Err(_err) = job.write(block, None).await {
|
|
|
|
|
// to-do: add "skip" for writing job
|
|
|
|
|
}
|
|
|
|
|
self.update_jobs_status();
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(file_response::Union::Done(d)) => {
|
2022-04-29 00:42:06 +08:00
|
|
|
|
if let Some(job) = fs::get_job(d.id, &mut self.write_jobs) {
|
|
|
|
|
job.modify_time();
|
|
|
|
|
fs::remove_job(d.id, &mut self.write_jobs);
|
|
|
|
|
}
|
|
|
|
|
self.handle_job_status(d.id, d.file_num, None);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(file_response::Union::Error(e)) => {
|
2022-04-29 00:42:06 +08:00
|
|
|
|
self.handle_job_status(e.id, e.file_num, Some(e.error));
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
2022-04-29 00:42:06 +08:00
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(message::Union::Misc(misc)) => match misc.union {
|
|
|
|
|
Some(misc::Union::AudioFormat(f)) => {
|
2022-01-30 21:16:08 +08:00
|
|
|
|
self.audio_sender.send(MediaData::AudioFormat(f)).ok();
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(misc::Union::ChatMessage(c)) => {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
self.handler.call("newMessage", &make_args!(c.text));
|
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(misc::Union::PermissionInfo(p)) => {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
log::info!("Change permission {:?} -> {}", p.permission, p.enabled);
|
|
|
|
|
match p.permission.enum_value_or_default() {
|
|
|
|
|
Permission::Keyboard => {
|
2022-05-25 00:12:28 +08:00
|
|
|
|
SERVER_KEYBOARD_ENABLED.store(p.enabled, Ordering::SeqCst);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
self.handler
|
2022-03-22 17:09:45 +08:00
|
|
|
|
.call2("setPermission", &make_args!("keyboard", p.enabled));
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
Permission::Clipboard => {
|
2022-05-25 00:02:33 +08:00
|
|
|
|
SERVER_CLIPBOARD_ENABLED.store(p.enabled, Ordering::SeqCst);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
self.handler
|
2022-03-22 17:09:45 +08:00
|
|
|
|
.call2("setPermission", &make_args!("clipboard", p.enabled));
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
Permission::Audio => {
|
|
|
|
|
self.handler
|
2022-03-22 17:09:45 +08:00
|
|
|
|
.call2("setPermission", &make_args!("audio", p.enabled));
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
2022-02-15 14:46:08 +08:00
|
|
|
|
Permission::File => {
|
2022-05-25 00:15:46 +08:00
|
|
|
|
SERVER_FILE_TRANSFER_ENABLED.store(p.enabled, Ordering::SeqCst);
|
2022-03-22 17:09:45 +08:00
|
|
|
|
if !p.enabled && self.handler.is_file_transfer() {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2022-02-15 15:35:19 +08:00
|
|
|
|
self.check_clipboard_file_context();
|
2022-02-15 14:46:08 +08:00
|
|
|
|
self.handler
|
2022-03-22 17:09:45 +08:00
|
|
|
|
.call2("setPermission", &make_args!("file", p.enabled));
|
2022-02-15 14:46:08 +08:00
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(misc::Union::SwitchDisplay(s)) => {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
self.handler.call("switchDisplay", &make_args!(s.display));
|
2022-01-30 21:16:08 +08:00
|
|
|
|
self.video_sender.send(MediaData::Reset).ok();
|
2021-03-29 15:59:14 +08:00
|
|
|
|
if s.width > 0 && s.height > 0 {
|
|
|
|
|
VIDEO.lock().unwrap().as_mut().map(|v| {
|
|
|
|
|
v.stop_streaming().ok();
|
|
|
|
|
let ok = v.start_streaming(
|
|
|
|
|
(s.width, s.height),
|
|
|
|
|
COLOR_SPACE::Rgb32,
|
|
|
|
|
None,
|
|
|
|
|
);
|
|
|
|
|
log::info!("[video] reinitialized: {:?}", ok);
|
|
|
|
|
});
|
|
|
|
|
self.handler.set_display(s.x, s.y, s.width, s.height);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(misc::Union::CloseReason(c)) => {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
self.handler.msgbox("error", "Connection Error", &c);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(misc::Union::BackNotification(notification)) => {
|
2022-04-25 12:28:28 +08:00
|
|
|
|
if !self.handle_back_notification(notification).await {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-01-15 16:31:21 +08:00
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
_ => {}
|
|
|
|
|
},
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(message::Union::TestDelay(t)) => {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
self.handler.handle_test_delay(t, peer).await;
|
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(message::Union::AudioFrame(frame)) => {
|
2022-01-30 21:16:08 +08:00
|
|
|
|
if !self.handler.lc.read().unwrap().disable_audio {
|
|
|
|
|
self.audio_sender.send(MediaData::AudioFrame(frame)).ok();
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(message::Union::FileAction(action)) => match action.union {
|
|
|
|
|
Some(file_action::Union::SendConfirm(c)) => {
|
2022-04-27 10:45:20 +08:00
|
|
|
|
if let Some(job) = fs::get_job(c.id, &mut self.read_jobs) {
|
|
|
|
|
job.confirm(&c);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
},
|
2021-03-29 15:59:14 +08:00
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
true
|
|
|
|
|
}
|
2022-02-15 15:35:19 +08:00
|
|
|
|
|
2022-04-25 12:28:28 +08:00
|
|
|
|
async fn handle_back_notification(&mut self, notification: BackNotification) -> bool {
|
|
|
|
|
match notification.union {
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(back_notification::Union::BlockInputState(state)) => {
|
2022-04-25 12:28:28 +08:00
|
|
|
|
self.handle_back_msg_block_input(
|
|
|
|
|
state.enum_value_or(back_notification::BlockInputState::StateUnknown),
|
|
|
|
|
)
|
|
|
|
|
.await;
|
|
|
|
|
}
|
2022-07-14 17:20:01 +08:00
|
|
|
|
Some(back_notification::Union::PrivacyModeState(state)) => {
|
2022-04-25 12:28:28 +08:00
|
|
|
|
if !self
|
|
|
|
|
.handle_back_msg_privacy_mode(
|
|
|
|
|
state.enum_value_or(back_notification::PrivacyModeState::StateUnknown),
|
|
|
|
|
)
|
|
|
|
|
.await
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
|
fn update_block_input_state(&mut self, on: bool) {
|
|
|
|
|
self.handler.call("updateBlockInputState", &make_args!(on));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn handle_back_msg_block_input(&mut self, state: back_notification::BlockInputState) {
|
|
|
|
|
match state {
|
|
|
|
|
back_notification::BlockInputState::OnSucceeded => {
|
|
|
|
|
self.update_block_input_state(true);
|
|
|
|
|
}
|
|
|
|
|
back_notification::BlockInputState::OnFailed => {
|
|
|
|
|
self.handler
|
|
|
|
|
.msgbox("custom-error", "Block user input", "Failed");
|
|
|
|
|
self.update_block_input_state(false);
|
|
|
|
|
}
|
|
|
|
|
back_notification::BlockInputState::OffSucceeded => {
|
|
|
|
|
self.update_block_input_state(false);
|
|
|
|
|
}
|
|
|
|
|
back_notification::BlockInputState::OffFailed => {
|
|
|
|
|
self.handler
|
|
|
|
|
.msgbox("custom-error", "Unblock user input", "Failed");
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
|
fn update_privacy_mode(&mut self, on: bool) {
|
|
|
|
|
let mut config = self.handler.load_config();
|
|
|
|
|
config.privacy_mode = on;
|
|
|
|
|
self.handler.save_config(config);
|
|
|
|
|
|
|
|
|
|
self.handler.call("updatePrivacyMode", &[]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn handle_back_msg_privacy_mode(
|
|
|
|
|
&mut self,
|
|
|
|
|
state: back_notification::PrivacyModeState,
|
|
|
|
|
) -> bool {
|
|
|
|
|
match state {
|
|
|
|
|
back_notification::PrivacyModeState::OnByOther => {
|
|
|
|
|
self.handler.msgbox(
|
|
|
|
|
"error",
|
|
|
|
|
"Connecting...",
|
|
|
|
|
"Someone turns on privacy mode, exit",
|
|
|
|
|
);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
back_notification::PrivacyModeState::NotSupported => {
|
|
|
|
|
self.handler
|
|
|
|
|
.msgbox("custom-error", "Privacy mode", "Unsupported");
|
|
|
|
|
self.update_privacy_mode(false);
|
|
|
|
|
}
|
|
|
|
|
back_notification::PrivacyModeState::OnSucceeded => {
|
2022-05-31 12:01:22 +08:00
|
|
|
|
self.handler
|
|
|
|
|
.msgbox("custom-nocancel", "Privacy mode", "In privacy mode");
|
2022-04-25 12:28:28 +08:00
|
|
|
|
self.update_privacy_mode(true);
|
|
|
|
|
}
|
|
|
|
|
back_notification::PrivacyModeState::OnFailedDenied => {
|
|
|
|
|
self.handler
|
|
|
|
|
.msgbox("custom-error", "Privacy mode", "Peer denied");
|
|
|
|
|
self.update_privacy_mode(false);
|
|
|
|
|
}
|
|
|
|
|
back_notification::PrivacyModeState::OnFailedPlugin => {
|
|
|
|
|
self.handler
|
|
|
|
|
.msgbox("custom-error", "Privacy mode", "Please install plugins");
|
|
|
|
|
self.update_privacy_mode(false);
|
|
|
|
|
}
|
|
|
|
|
back_notification::PrivacyModeState::OnFailed => {
|
|
|
|
|
self.handler
|
|
|
|
|
.msgbox("custom-error", "Privacy mode", "Failed");
|
|
|
|
|
self.update_privacy_mode(false);
|
|
|
|
|
}
|
|
|
|
|
back_notification::PrivacyModeState::OffSucceeded => {
|
2022-05-31 12:01:22 +08:00
|
|
|
|
self.handler
|
2022-06-23 17:42:30 +08:00
|
|
|
|
.msgbox("custom-nocancel", "Privacy mode", "Out privacy mode");
|
2022-04-25 12:28:28 +08:00
|
|
|
|
self.update_privacy_mode(false);
|
|
|
|
|
}
|
|
|
|
|
back_notification::PrivacyModeState::OffByPeer => {
|
|
|
|
|
self.handler
|
|
|
|
|
.msgbox("custom-error", "Privacy mode", "Peer exit");
|
|
|
|
|
self.update_privacy_mode(false);
|
|
|
|
|
}
|
|
|
|
|
back_notification::PrivacyModeState::OffFailed => {
|
|
|
|
|
self.handler
|
|
|
|
|
.msgbox("custom-error", "Privacy mode", "Failed to turn off");
|
|
|
|
|
}
|
|
|
|
|
back_notification::PrivacyModeState::OffUnknown => {
|
|
|
|
|
self.handler
|
|
|
|
|
.msgbox("custom-error", "Privacy mode", "Turned off");
|
|
|
|
|
// log::error!("Privacy mode is turned off with unknown reason");
|
|
|
|
|
self.update_privacy_mode(false);
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-15 15:35:19 +08:00
|
|
|
|
fn check_clipboard_file_context(&mut self) {
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
{
|
2022-05-25 00:15:46 +08:00
|
|
|
|
let enabled = SERVER_FILE_TRANSFER_ENABLED.load(Ordering::SeqCst)
|
2022-02-15 15:35:19 +08:00
|
|
|
|
&& self.handler.lc.read().unwrap().enable_file_transfer;
|
|
|
|
|
if enabled == self.clipboard_file_context.is_none() {
|
|
|
|
|
self.clipboard_file_context = if enabled {
|
|
|
|
|
match create_clipboard_file_context(true, false) {
|
|
|
|
|
Ok(context) => {
|
|
|
|
|
log::info!("clipboard context for file transfer created.");
|
|
|
|
|
Some(context)
|
|
|
|
|
}
|
|
|
|
|
Err(err) => {
|
|
|
|
|
log::error!(
|
|
|
|
|
"Create clipboard context for file transfer: {}",
|
|
|
|
|
err.to_string()
|
|
|
|
|
);
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
log::info!("clipboard context for file transfer destroyed.");
|
|
|
|
|
None
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-05-12 17:35:25 +08:00
|
|
|
|
pub fn make_fd(id: i32, entries: &Vec<FileEntry>, only_count: bool) -> Value {
|
2021-03-29 15:59:14 +08:00
|
|
|
|
let mut m = Value::map();
|
|
|
|
|
m.set_item("id", id);
|
|
|
|
|
let mut a = Value::array(0);
|
|
|
|
|
let mut n: u64 = 0;
|
|
|
|
|
for entry in entries {
|
|
|
|
|
n += entry.size;
|
|
|
|
|
if only_count {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
let mut e = Value::map();
|
|
|
|
|
e.set_item("name", entry.name.to_owned());
|
2022-01-21 12:52:08 +08:00
|
|
|
|
let tmp = entry.entry_type.value();
|
|
|
|
|
e.set_item("type", if tmp == 0 { 1 } else { tmp });
|
2021-03-29 15:59:14 +08:00
|
|
|
|
e.set_item("time", entry.modified_time as f64);
|
|
|
|
|
e.set_item("size", entry.size as f64);
|
|
|
|
|
a.push(e);
|
|
|
|
|
}
|
|
|
|
|
if only_count {
|
|
|
|
|
m.set_item("num_entries", entries.len() as i32);
|
|
|
|
|
} else {
|
|
|
|
|
m.set_item("entries", a);
|
|
|
|
|
}
|
|
|
|
|
m.set_item("total_size", n as f64);
|
|
|
|
|
m
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[async_trait]
|
|
|
|
|
impl Interface for Handler {
|
2022-05-12 17:35:25 +08:00
|
|
|
|
fn send(&self, data: Data) {
|
|
|
|
|
if let Some(ref sender) = self.read().unwrap().sender {
|
|
|
|
|
sender.send(data).ok();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
|
fn msgbox(&self, msgtype: &str, title: &str, text: &str) {
|
2021-08-11 01:28:53 +08:00
|
|
|
|
let retry = check_if_retry(msgtype, title, text);
|
2022-03-22 17:09:45 +08:00
|
|
|
|
self.call2("msgbox_retry", &make_args!(msgtype, title, text, retry));
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 self.is_file_transfer() {
|
|
|
|
|
if pi.username.is_empty() {
|
2021-05-25 12:01:27 +08:00
|
|
|
|
self.on_error("No active console user logged on, please connect and logon first.");
|
2021-03-29 15:59:14 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else if !self.is_port_forward() {
|
|
|
|
|
if pi.displays.is_empty() {
|
|
|
|
|
self.lc.write().unwrap().handle_peer_info(username, pi);
|
2022-04-25 12:28:28 +08:00
|
|
|
|
self.call("updatePrivacyMode", &[]);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
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);
|
|
|
|
|
});
|
2022-05-12 17:35:25 +08:00
|
|
|
|
let p = self.lc.read().unwrap().should_auto_login();
|
|
|
|
|
if !p.is_empty() {
|
|
|
|
|
input_os_password(p, true, self.clone());
|
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
self.lc.write().unwrap().handle_peer_info(username, pi);
|
2022-04-25 12:28:28 +08:00
|
|
|
|
self.call("updatePrivacyMode", &[]);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
self.call("updatePi", &make_args!(pi_sciter));
|
|
|
|
|
if self.is_file_transfer() {
|
2022-03-22 17:09:45 +08:00
|
|
|
|
self.call2("closeSuccess", &make_args!());
|
2021-03-29 15:59:14 +08:00
|
|
|
|
} 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);
|
2022-05-12 17:35:25 +08:00
|
|
|
|
let path = path.with_extension(crate::get_app_name().to_lowercase());
|
2021-03-29 15:59:14 +08:00
|
|
|
|
std::fs::File::create(&path).ok();
|
|
|
|
|
if let Some(path) = path.to_str() {
|
|
|
|
|
crate::platform::windows::add_recent_document(&path);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-09 19:56:24 +08:00
|
|
|
|
self.start_keyboard_hook();
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn handle_hash(&mut self, hash: Hash, peer: &mut Stream) {
|
|
|
|
|
handle_hash(self.lc.clone(), 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) {
|
2022-06-23 17:42:30 +08:00
|
|
|
|
if !t.from_client {
|
|
|
|
|
self.update_quality_status(QualityStatus {
|
2022-07-05 22:17:34 +08:00
|
|
|
|
delay: Some(t.last_delay as _),
|
|
|
|
|
target_bitrate: Some(t.target_bitrate as _),
|
2022-06-23 17:42:30 +08:00
|
|
|
|
..Default::default()
|
|
|
|
|
});
|
2022-06-30 20:48:29 +08:00
|
|
|
|
handle_test_delay(t, peer).await;
|
2022-06-23 17:42:30 +08:00
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Handler {
|
|
|
|
|
fn on_error(&self, err: &str) {
|
|
|
|
|
self.msgbox("error", "Error", err);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-05-12 17:35:25 +08:00
|
|
|
|
|
|
|
|
|
#[tokio::main(flavor = "current_thread")]
|
|
|
|
|
async fn send_note(url: String, id: String, conn_id: i32, note: String) {
|
|
|
|
|
let body = serde_json::json!({ "id": id, "Id": conn_id, "note": note });
|
|
|
|
|
allow_err!(crate::post_request(url, body.to_string(), "").await);
|
|
|
|
|
}
|