rustdesk/src/ui.rs

1363 lines
36 KiB
Rust
Raw Normal View History

2021-03-29 15:59:14 +08:00
mod cm;
#[cfg(feature = "inline")]
mod inline;
#[cfg(target_os = "macos")]
mod macos;
2022-05-12 17:35:25 +08:00
pub mod remote;
2021-03-29 15:59:14 +08:00
use crate::common::SOFTWARE_UPDATE_URL;
use crate::ipc;
use hbb_common::{
allow_err,
2022-05-12 17:35:25 +08:00
config::{self, Config, LocalConfig, PeerConfig, RENDEZVOUS_PORT, RENDEZVOUS_TIMEOUT},
futures::future::join_all,
log,
protobuf::Message as _,
rendezvous_proto::*,
sleep,
tcp::FramedStream,
tokio::{self, sync::mpsc, time},
2021-03-29 15:59:14 +08:00
};
use sciter::Value;
use std::{
collections::HashMap,
iter::FromIterator,
process::Child,
sync::{Arc, Mutex},
2022-05-25 23:09:14 +08:00
time::SystemTime,
2021-03-29 15:59:14 +08:00
};
2022-05-12 17:35:25 +08:00
type Message = RendezvousMessage;
2021-03-29 15:59:14 +08:00
pub type Childs = Arc<Mutex<(bool, HashMap<(String, String), Child>)>>;
type Status = (i32, bool, i64, String); // (status_num, key_confirmed, mouse_time, id)
2021-03-29 15:59:14 +08:00
lazy_static::lazy_static! {
// stupid workaround for https://sciter.com/forums/topic/crash-on-latest-tis-mac-sdk-sometimes/
static ref STUPID_VALUES: Mutex<Vec<Arc<Vec<Value>>>> = Default::default();
pub static ref CHILDS : Childs = Default::default();
pub static ref UI_STATUS : Arc<Mutex<Status>> = Arc::new(Mutex::new((0, false, 0, "".to_owned())));
pub static ref OPTIONS : Arc<Mutex<HashMap<String, String>>> = Arc::new(Mutex::new(Config::get_options()));
pub static ref ASYNC_JOB_STATUS : Arc<Mutex<String>> = Default::default();
pub static ref SENDER : Mutex<mpsc::UnboundedSender<ipc::Data>> = Mutex::new(check_connect_status(true));
}
// struct UI(
// Childs,
// Arc<Mutex<Status>>,
// Arc<Mutex<HashMap<String, String>>>, options
// Arc<Mutex<String>>, async_job_status
// mpsc::UnboundedSender<ipc::Data>, Sender
// );
2022-05-25 23:09:14 +08:00
pub fn recent_sessions_updated() -> bool {
let mut childs = CHILDS.lock().unwrap();
if childs.0 {
childs.0 = false;
2022-05-25 23:09:14 +08:00
true
} else {
false
}
}
pub fn get_id() -> String {
ipc::get_id()
}
pub fn get_password() -> String {
ipc::get_password()
}
pub fn update_password(password: String) {
if password.is_empty() {
allow_err!(ipc::set_password(Config::get_auto_password()));
} else {
allow_err!(ipc::set_password(password));
}
}
pub fn get_remote_id() -> String {
LocalConfig::get_remote_id()
}
pub fn set_remote_id(id: String) {
LocalConfig::set_remote_id(&id);
}
pub fn goto_install() {
allow_err!(crate::run_me(vec!["--install"]));
}
pub fn install_me(_options: String, _path: String) {
#[cfg(windows)]
std::thread::spawn(move || {
allow_err!(crate::platform::windows::install_me(&_options, _path));
std::process::exit(0);
});
}
pub fn update_me(_path: String) {
#[cfg(target_os = "linux")]
{
std::process::Command::new("pkexec")
.args(&["apt", "install", "-f", &_path])
.spawn()
.ok();
std::fs::remove_file(&_path).ok();
crate::run_me(Vec::<&str>::new()).ok();
}
#[cfg(windows)]
{
let mut path = _path;
if path.is_empty() {
if let Ok(tmp) = std::env::current_exe() {
path = tmp.to_string_lossy().to_string();
}
}
std::process::Command::new(path)
.arg("--update")
.spawn()
.ok();
std::process::exit(0);
}
}
pub fn run_without_install() {
crate::run_me(vec!["--noinstall"]).ok();
std::process::exit(0);
}
pub fn show_run_without_install() -> bool {
let mut it = std::env::args();
if let Some(tmp) = it.next() {
if crate::is_setup(&tmp) {
return it.next() == None;
}
}
false
}
pub fn has_rendezvous_service() -> bool {
#[cfg(all(windows, feature = "hbbs"))]
return crate::platform::is_win_server() && crate::platform::windows::get_license().is_some();
return false;
}
pub fn get_license() -> String {
#[cfg(windows)]
if let Some(lic) = crate::platform::windows::get_license() {
return format!(
"<br /> Key: {} <br /> Host: {} Api: {}",
lic.key, lic.host, lic.api
);
}
Default::default()
}
2022-05-25 23:22:14 +08:00
pub fn get_option(key: String) -> String {
get_option_(&key)
}
fn get_option_(key: &str) -> String {
let map = OPTIONS.lock().unwrap();
2022-05-25 23:09:14 +08:00
if let Some(v) = map.get(key) {
v.to_owned()
} else {
"".to_owned()
}
}
pub fn get_local_option(key: String) -> String {
LocalConfig::get_option(&key)
}
pub fn set_local_option(key: String, value: String) {
LocalConfig::set_option(key, value);
}
pub fn peer_has_password(id: String) -> bool {
!PeerConfig::load(&id).password.is_empty()
}
pub fn forget_password(id: String) {
let mut c = PeerConfig::load(&id);
c.password.clear();
c.store(&id);
}
pub fn get_peer_option(id: String, name: String) -> String {
let c = PeerConfig::load(&id);
c.options.get(&name).unwrap_or(&"".to_owned()).to_owned()
}
pub fn set_peer_option(id: String, name: String, value: String) {
let mut c = PeerConfig::load(&id);
if value.is_empty() {
c.options.remove(&name);
} else {
c.options.insert(name, value);
}
c.store(&id);
}
pub fn using_public_server() -> bool {
2022-05-25 23:22:14 +08:00
crate::get_custom_rendezvous_server(get_option_("custom-rendezvous-server")).is_empty()
2022-05-25 23:09:14 +08:00
}
pub fn get_options() -> HashMap<String, String> {
// TODO Vec<(String,String)>
let options = OPTIONS.lock().unwrap();
2022-05-25 23:09:14 +08:00
let mut m = HashMap::new();
for (k, v) in options.iter() {
2022-05-25 23:09:14 +08:00
m.insert(k.into(), v.into());
}
m
}
pub fn test_if_valid_server(host: String) -> String {
hbb_common::socket_client::test_if_valid_server(&host)
}
pub fn get_sound_inputs() -> Vec<String> {
let mut a = Vec::new();
#[cfg(windows)]
{
// TODO TEST
fn get_sound_inputs_() -> Vec<String> {
let mut out = Vec::new();
use cpal::traits::{DeviceTrait, HostTrait};
let host = cpal::default_host();
if let Ok(devices) = host.devices() {
for device in devices {
if device.default_input_config().is_err() {
continue;
}
if let Ok(name) = device.name() {
out.push(name);
}
}
}
out
}
let inputs = Arc::new(Mutex::new(Vec::new()));
let cloned = inputs.clone();
// can not call below in UI thread, because conflict with sciter sound com initialization
std::thread::spawn(move || *cloned.lock().unwrap() = get_sound_inputs_())
.join()
.ok();
for name in inputs.lock().unwrap().drain(..) {
a.push(name);
}
}
#[cfg(not(windows))]
{
let inputs: Vec<String> = crate::platform::linux::get_pa_sources()
.drain(..)
.map(|x| x.1)
.collect();
for name in inputs {
a.push(name);
}
}
a
}
pub fn set_options(m: HashMap<String, String>) {
*OPTIONS.lock().unwrap() = m.clone();
2022-05-25 23:09:14 +08:00
ipc::set_options(m).ok();
}
pub fn set_option(key: String, value: String) {
let mut options = OPTIONS.lock().unwrap();
2022-05-25 23:09:14 +08:00
#[cfg(target_os = "macos")]
if &key == "stop-service" {
let is_stop = value == "Y";
if is_stop && crate::platform::macos::uninstall() {
return;
}
}
if value.is_empty() {
options.remove(&key);
} else {
options.insert(key.clone(), value.clone());
}
ipc::set_options(options.clone()).ok();
}
pub fn install_path() -> String {
#[cfg(windows)]
return crate::platform::windows::get_install_info().1;
#[cfg(not(windows))]
return "".to_owned();
}
pub fn get_socks() -> Vec<String> {
let s = ipc::get_socks();
match s {
None => Vec::new(),
Some(s) => {
let mut v = Vec::new();
v.push(s.proxy);
v.push(s.username);
v.push(s.password);
v
}
}
}
pub fn set_socks(proxy: String, username: String, password: String) {
ipc::set_socks(config::Socks5Server {
proxy,
username,
password,
})
.ok();
}
pub fn is_installed() -> bool {
crate::platform::is_installed()
}
pub fn is_rdp_service_open() -> bool {
#[cfg(windows)]
return self.is_installed() && crate::platform::windows::is_rdp_service_open();
#[cfg(not(windows))]
return false;
}
pub fn is_share_rdp() -> bool {
#[cfg(windows)]
return crate::platform::windows::is_share_rdp();
#[cfg(not(windows))]
return false;
}
pub fn set_share_rdp(_enable: bool) {
#[cfg(windows)]
crate::platform::windows::set_share_rdp(_enable);
}
pub fn is_installed_lower_version() -> bool {
#[cfg(not(windows))]
return false;
#[cfg(windows)]
{
let installed_version = crate::platform::windows::get_installed_version();
let a = hbb_common::get_version_number(crate::VERSION);
let b = hbb_common::get_version_number(&installed_version);
return a > b;
}
}
pub fn closing(x: i32, y: i32, w: i32, h: i32) {
crate::server::input_service::fix_key_down_timeout_at_exit();
LocalConfig::set_size(x, y, w, h);
}
pub fn get_size() -> Vec<i32> {
let s = LocalConfig::get_size();
let mut v = Vec::new();
v.push(s.0);
v.push(s.1);
v.push(s.2);
v.push(s.3);
v
}
pub fn get_mouse_time() -> f64 {
let ui_status = UI_STATUS.lock().unwrap();
let res = ui_status.2 as f64;
2022-05-25 23:09:14 +08:00
return res;
}
pub fn check_mouse_time() {
let sender = SENDER.lock().unwrap();
allow_err!(sender.send(ipc::Data::MouseMoveTime(0)));
2022-05-25 23:09:14 +08:00
}
pub fn get_connect_status() -> Status {
let ui_statue = UI_STATUS.lock().unwrap();
let res = ui_statue.clone();
2022-05-25 23:09:14 +08:00
res
}
pub fn get_peer(id: String) -> PeerConfig {
PeerConfig::load(&id)
}
pub fn get_fav() -> Vec<String> {
LocalConfig::get_fav()
}
pub fn store_fav(fav: Vec<String>) {
LocalConfig::set_fav(fav);
}
pub fn get_recent_sessions() -> Vec<(String, SystemTime, PeerConfig)> {
PeerConfig::peers()
}
pub fn get_icon() -> String {
crate::get_icon()
}
pub fn remove_peer(id: String) {
PeerConfig::remove(&id);
}
pub fn new_remote(id: String, remote_type: String) {
let mut lock = CHILDS.lock().unwrap();
2022-05-25 23:09:14 +08:00
let args = vec![format!("--{}", remote_type), id.clone()];
let key = (id.clone(), remote_type.clone());
if let Some(c) = lock.1.get_mut(&key) {
if let Ok(Some(_)) = c.try_wait() {
lock.1.remove(&key);
} else {
if remote_type == "rdp" {
allow_err!(c.kill());
std::thread::sleep(std::time::Duration::from_millis(30));
c.try_wait().ok();
lock.1.remove(&key);
} else {
return;
}
}
}
match crate::run_me(args) {
Ok(child) => {
lock.1.insert(key, child);
}
Err(err) => {
log::error!("Failed to spawn remote: {}", err);
}
}
}
pub fn is_process_trusted(_prompt: bool) -> bool {
#[cfg(target_os = "macos")]
return crate::platform::macos::is_process_trusted(_prompt);
#[cfg(not(target_os = "macos"))]
return true;
}
pub fn is_can_screen_recording(_prompt: bool) -> bool {
#[cfg(target_os = "macos")]
return crate::platform::macos::is_can_screen_recording(_prompt);
#[cfg(not(target_os = "macos"))]
return true;
}
pub fn is_installed_daemon(_prompt: bool) -> bool {
#[cfg(target_os = "macos")]
return crate::platform::macos::is_installed_daemon(_prompt);
#[cfg(not(target_os = "macos"))]
return true;
}
pub fn get_error() -> String {
#[cfg(target_os = "linux")]
{
let dtype = crate::platform::linux::get_display_server();
if "wayland" == dtype {
return "".to_owned();
}
if dtype != "x11" {
return format!(
"{} {}, {}",
t("Unsupported display server ".to_owned()),
dtype,
t("x11 expected".to_owned()),
);
}
}
return "".to_owned();
}
pub fn is_login_wayland() -> bool {
#[cfg(target_os = "linux")]
return crate::platform::linux::is_login_wayland();
#[cfg(not(target_os = "linux"))]
return false;
}
pub fn fix_login_wayland() {
#[cfg(target_os = "linux")]
crate::platform::linux::fix_login_wayland();
}
pub fn current_is_wayland() -> bool {
#[cfg(target_os = "linux")]
return crate::platform::linux::current_is_wayland();
#[cfg(not(target_os = "linux"))]
return false;
}
pub fn modify_default_login() -> String {
#[cfg(target_os = "linux")]
return crate::platform::linux::modify_default_login();
#[cfg(not(target_os = "linux"))]
return "".to_owned();
}
pub fn get_software_update_url() -> String {
SOFTWARE_UPDATE_URL.lock().unwrap().clone()
}
pub fn get_new_version() -> String {
hbb_common::get_version_from_url(&*SOFTWARE_UPDATE_URL.lock().unwrap())
}
pub fn get_version() -> String {
crate::VERSION.to_owned()
}
pub fn get_app_name() -> String {
crate::get_app_name()
}
pub fn get_software_ext() -> String {
#[cfg(windows)]
let p = "exe";
#[cfg(target_os = "macos")]
let p = "dmg";
#[cfg(target_os = "linux")]
let p = "deb";
p.to_owned()
}
pub fn get_software_store_path() -> String {
let mut p = std::env::temp_dir();
let name = SOFTWARE_UPDATE_URL
.lock()
.unwrap()
.split("/")
.last()
.map(|x| x.to_owned())
.unwrap_or(crate::get_app_name());
p.push(name);
format!("{}.{}", p.to_string_lossy(), get_software_ext())
}
pub fn create_shortcut(_id: String) {
#[cfg(windows)]
crate::platform::windows::create_shortcut(&_id).ok();
}
pub fn discover() {
std::thread::spawn(move || {
allow_err!(crate::rendezvous_mediator::discover());
});
}
pub fn get_lan_peers() -> String {
config::LanPeers::load().peers
}
pub fn get_uuid() -> String {
base64::encode(crate::get_uuid())
}
pub fn open_url(url: String) {
#[cfg(windows)]
let p = "explorer";
#[cfg(target_os = "macos")]
let p = "open";
#[cfg(target_os = "linux")]
let p = if std::path::Path::new("/usr/bin/firefox").exists() {
"firefox"
} else {
"xdg-open"
};
allow_err!(std::process::Command::new(p).arg(url).spawn());
}
pub fn change_id(id: String) {
*ASYNC_JOB_STATUS.lock().unwrap() = " ".to_owned();
2022-05-25 23:09:14 +08:00
let old_id = get_id();
std::thread::spawn(move || {
*ASYNC_JOB_STATUS.lock().unwrap() = change_id_(id, old_id).to_owned();
2022-05-25 23:09:14 +08:00
});
}
pub fn post_request(url: String, body: String, header: String) {
*ASYNC_JOB_STATUS.lock().unwrap() = " ".to_owned();
2022-05-25 23:09:14 +08:00
std::thread::spawn(move || {
*ASYNC_JOB_STATUS.lock().unwrap() = match crate::post_request_sync(url, body, &header) {
2022-05-25 23:09:14 +08:00
Err(err) => err.to_string(),
Ok(text) => text,
};
});
}
pub fn is_ok_change_id() -> bool {
machine_uid::get().is_ok()
}
pub fn get_async_job_status() -> String {
ASYNC_JOB_STATUS.lock().unwrap().clone()
2022-05-25 23:09:14 +08:00
}
pub fn t(name: String) -> String {
crate::client::translate(name)
}
pub fn is_xfce() -> bool {
crate::platform::is_xfce()
}
pub fn get_api_server() -> String {
crate::get_api_server(
2022-05-25 23:22:14 +08:00
get_option_("api-server"),
get_option_("custom-rendezvous-server"),
2022-05-25 23:09:14 +08:00
)
}
// pub struct UIData(
// Status, // 1
// HashMap<String, String>, // 2 options
// String, // 3
// mpsc::UnboundedSender<ipc::Data>, // 4
// );
// pub struct UIData {
// status: Status, // 1 arc
// options: HashMap<String, String>, // 2 arc options
// _3: String, // 3 arc async_job_status
// _4: mpsc::UnboundedSender<ipc::Data>, // 4
// }
// impl UIData {
// fn new(childs: Childs) -> Self {
// let res = check_connect_status(true);
// Self(childs, res.0, res.1, Default::default(), res.2)
// }
// }
2022-05-25 23:09:14 +08:00
struct UIHostHandler;
2021-03-29 15:59:14 +08:00
pub fn start(args: &mut [String]) {
2022-04-28 21:54:27 +08:00
#[cfg(target_os = "macos")]
2022-04-29 16:21:18 +08:00
if args.len() == 1 && args[0] == "--server" {
macos::make_tray();
return;
2022-04-29 16:21:18 +08:00
} else {
macos::show_dock();
2022-04-27 19:21:38 +08:00
}
2022-04-18 15:45:12 +08:00
#[cfg(all(target_os = "linux", feature = "inline"))]
sciter::set_library("/usr/lib/rustdesk/libsciter-gtk.so").ok();
// https://github.com/c-smile/sciter-sdk/blob/master/include/sciter-x-types.h
// https://github.com/rustdesk/rustdesk/issues/132#issuecomment-886069737
#[cfg(windows)]
allow_err!(sciter::set_options(sciter::RuntimeOptions::GfxLayer(
sciter::GFX_LAYER::WARP
)));
2022-05-12 17:35:25 +08:00
#[cfg(all(windows, not(feature = "inline")))]
unsafe {
winapi::um::shellscalingapi::SetProcessDpiAwareness(2);
}
2021-03-29 15:59:14 +08:00
#[cfg(windows)]
if args.len() > 0 && args[0] == "--tray" {
2022-05-12 17:35:25 +08:00
let options = check_connect_status(false).1;
crate::tray::start_tray(options);
2021-03-29 15:59:14 +08:00
return;
}
use sciter::SCRIPT_RUNTIME_FEATURES::*;
allow_err!(sciter::set_options(sciter::RuntimeOptions::ScriptFeatures(
ALLOW_FILE_IO as u8 | ALLOW_SOCKET_IO as u8 | ALLOW_EVAL as u8 | ALLOW_SYSINFO as u8
)));
let mut frame = sciter::WindowBuilder::main_window().create();
#[cfg(windows)]
allow_err!(sciter::set_options(sciter::RuntimeOptions::UxTheming(true)));
2022-04-29 16:21:18 +08:00
frame.set_title(&crate::get_app_name());
2021-03-29 15:59:14 +08:00
#[cfg(target_os = "macos")]
2022-04-29 16:21:18 +08:00
macos::make_menubar(frame.get_host(), args.is_empty());
2021-03-29 15:59:14 +08:00
let page;
if args.len() > 1 && args[0] == "--play" {
args[0] = "--connect".to_owned();
let path: std::path::PathBuf = (&args[1]).into();
let id = path
.file_stem()
.map(|p| p.to_str().unwrap_or(""))
.unwrap_or("")
.to_owned();
args[1] = id;
}
2022-04-29 16:21:18 +08:00
if args.is_empty() {
let cloned = CHILDS.clone();
2021-03-29 15:59:14 +08:00
std::thread::spawn(move || check_zombie(cloned));
crate::common::check_software_update();
2022-05-25 23:09:14 +08:00
frame.event_handler(UI {});
frame.sciter_handler(UIHostHandler {});
2021-03-29 15:59:14 +08:00
page = "index.html";
} else if args[0] == "--install" {
2022-05-25 23:09:14 +08:00
frame.event_handler(UI {});
frame.sciter_handler(UIHostHandler {});
2021-03-29 15:59:14 +08:00
page = "install.html";
} else if args[0] == "--cm" {
frame.register_behavior("connection-manager", move || {
Box::new(cm::ConnectionManager::new())
});
page = "cm.html";
} else if (args[0] == "--connect"
|| args[0] == "--file-transfer"
|| args[0] == "--port-forward"
|| args[0] == "--rdp")
&& args.len() > 1
{
2022-05-12 17:35:25 +08:00
#[cfg(windows)]
{
let hw = frame.get_host().get_hwnd();
crate::platform::windows::enable_lowlevel_keyboard(hw as _);
}
2021-03-29 15:59:14 +08:00
let mut iter = args.iter();
let cmd = iter.next().unwrap().clone();
let id = iter.next().unwrap().clone();
let args: Vec<String> = iter.map(|x| x.clone()).collect();
frame.set_title(&id);
frame.register_behavior("native-remote", move || {
Box::new(remote::Handler::new(cmd.clone(), id.clone(), args.clone()))
});
page = "remote.html";
} else {
log::error!("Wrong command: {:?}", args);
return;
}
#[cfg(feature = "inline")]
{
let html = if page == "index.html" {
inline::get_index()
} else if page == "cm.html" {
inline::get_cm()
} else if page == "install.html" {
inline::get_install()
} else {
inline::get_remote()
};
frame.load_html(html.as_bytes(), Some(page));
}
#[cfg(not(feature = "inline"))]
frame.load_file(&format!(
"file://{}/src/ui/{}",
std::env::current_dir()
.map(|c| c.display().to_string())
.unwrap_or("".to_owned()),
page
));
2022-04-29 16:21:18 +08:00
frame.run_app();
2021-03-29 15:59:14 +08:00
}
2022-05-25 23:09:14 +08:00
struct UI {}
2021-03-29 15:59:14 +08:00
2022-05-25 23:09:14 +08:00
impl UI {
fn recent_sessions_updated(&self) -> bool {
recent_sessions_updated()
2021-03-29 15:59:14 +08:00
}
2022-05-12 17:35:25 +08:00
fn get_id(&self) -> String {
2022-05-25 23:09:14 +08:00
get_id()
2021-03-29 15:59:14 +08:00
}
fn get_password(&mut self) -> String {
2022-05-25 23:09:14 +08:00
get_password()
2021-03-29 15:59:14 +08:00
}
fn update_password(&mut self, password: String) {
2022-05-25 23:09:14 +08:00
update_password(password)
2021-03-29 15:59:14 +08:00
}
fn get_remote_id(&mut self) -> String {
2022-05-25 23:09:14 +08:00
get_remote_id()
2021-03-29 15:59:14 +08:00
}
fn set_remote_id(&mut self, id: String) {
2022-05-25 23:09:14 +08:00
set_remote_id(id);
2021-03-29 15:59:14 +08:00
}
fn goto_install(&mut self) {
2022-05-25 23:09:14 +08:00
goto_install();
2021-03-29 15:59:14 +08:00
}
2022-05-12 17:35:25 +08:00
fn install_me(&mut self, _options: String, _path: String) {
2022-05-25 23:09:14 +08:00
install_me(_options, _path);
2021-03-29 15:59:14 +08:00
}
fn update_me(&self, _path: String) {
2022-05-25 23:09:14 +08:00
update_me(_path);
2021-03-29 15:59:14 +08:00
}
2022-05-12 17:35:25 +08:00
fn run_without_install(&self) {
2022-05-25 23:09:14 +08:00
run_without_install();
2022-05-12 17:35:25 +08:00
}
fn show_run_without_install(&self) -> bool {
2022-05-25 23:09:14 +08:00
show_run_without_install()
2022-05-12 17:35:25 +08:00
}
fn has_rendezvous_service(&self) -> bool {
2022-05-25 23:09:14 +08:00
has_rendezvous_service()
2022-05-12 17:35:25 +08:00
}
fn get_license(&self) -> String {
2022-05-25 23:09:14 +08:00
get_license()
2022-05-12 17:35:25 +08:00
}
2021-03-29 15:59:14 +08:00
fn get_option(&self, key: String) -> String {
2022-05-25 23:22:14 +08:00
get_option(key)
2021-03-29 15:59:14 +08:00
}
fn get_local_option(&self, key: String) -> String {
2022-05-25 23:09:14 +08:00
get_local_option(key)
2022-04-26 11:19:45 +08:00
}
fn set_local_option(&self, key: String, value: String) {
2022-05-25 23:09:14 +08:00
set_local_option(key, value);
}
fn peer_has_password(&self, id: String) -> bool {
2022-05-25 23:09:14 +08:00
peer_has_password(id)
}
fn forget_password(&self, id: String) {
2022-05-25 23:09:14 +08:00
forget_password(id)
}
fn get_peer_option(&self, id: String, name: String) -> String {
2022-05-25 23:09:14 +08:00
get_peer_option(id, name)
}
fn set_peer_option(&self, id: String, name: String, value: String) {
2022-05-25 23:09:14 +08:00
set_peer_option(id, name, value)
}
2022-05-12 17:35:25 +08:00
fn using_public_server(&self) -> bool {
2022-05-25 23:09:14 +08:00
using_public_server()
2022-05-12 17:35:25 +08:00
}
2021-03-29 15:59:14 +08:00
fn get_options(&self) -> Value {
2022-05-25 23:09:14 +08:00
let hashmap = get_options();
2021-03-29 15:59:14 +08:00
let mut m = Value::map();
2022-05-25 23:09:14 +08:00
for (k, v) in hashmap {
2021-03-29 15:59:14 +08:00
m.set_item(k, v);
}
m
}
fn test_if_valid_server(&self, host: String) -> String {
2022-05-25 23:09:14 +08:00
test_if_valid_server(host)
2021-03-29 15:59:14 +08:00
}
fn get_sound_inputs(&self) -> Value {
2022-05-25 23:09:14 +08:00
Value::from_iter(get_sound_inputs())
2021-03-29 15:59:14 +08:00
}
fn set_options(&self, v: Value) {
let mut m = HashMap::new();
for (k, v) in v.items() {
if let Some(k) = k.as_string() {
if let Some(v) = v.as_string() {
if !v.is_empty() {
m.insert(k, v);
}
}
}
}
2022-05-25 23:09:14 +08:00
set_options(m);
2021-03-29 15:59:14 +08:00
}
2021-10-08 00:16:10 +08:00
fn set_option(&self, key: String, value: String) {
2022-05-25 23:09:14 +08:00
set_option(key, value);
2021-10-08 00:16:10 +08:00
}
2021-03-29 15:59:14 +08:00
fn install_path(&mut self) -> String {
2022-05-25 23:09:14 +08:00
install_path()
2021-03-29 15:59:14 +08:00
}
2022-01-05 18:34:30 +08:00
fn get_socks(&self) -> Value {
2022-05-25 23:09:14 +08:00
Value::from_iter(get_socks())
2022-01-05 18:34:30 +08:00
}
fn set_socks(&self, proxy: String, username: String, password: String) {
2022-05-25 23:09:14 +08:00
set_socks(proxy, username, password)
2022-01-05 18:34:30 +08:00
}
2022-05-12 17:35:25 +08:00
fn is_installed(&self) -> bool {
2022-05-25 23:09:14 +08:00
is_installed()
2021-03-29 15:59:14 +08:00
}
2022-05-12 17:35:25 +08:00
fn is_rdp_service_open(&self) -> bool {
2022-05-25 23:09:14 +08:00
is_rdp_service_open()
2022-05-12 17:35:25 +08:00
}
fn is_share_rdp(&self) -> bool {
2022-05-25 23:09:14 +08:00
is_share_rdp()
2022-05-12 17:35:25 +08:00
}
fn set_share_rdp(&self, _enable: bool) {
2022-05-25 23:09:14 +08:00
set_share_rdp(_enable);
2022-05-12 17:35:25 +08:00
}
2021-03-29 15:59:14 +08:00
fn is_installed_lower_version(&self) -> bool {
2022-05-25 23:09:14 +08:00
is_installed_lower_version()
2021-03-29 15:59:14 +08:00
}
fn closing(&mut self, x: i32, y: i32, w: i32, h: i32) {
2022-05-25 23:09:14 +08:00
closing(x, y, w, h)
2021-03-29 15:59:14 +08:00
}
fn get_size(&mut self) -> Value {
2022-05-25 23:09:14 +08:00
Value::from_iter(get_size())
2021-03-29 15:59:14 +08:00
}
2022-05-12 17:35:25 +08:00
fn get_mouse_time(&self) -> f64 {
2022-05-25 23:09:14 +08:00
get_mouse_time()
2022-05-12 17:35:25 +08:00
}
fn check_mouse_time(&self) {
2022-05-25 23:09:14 +08:00
check_mouse_time()
2022-05-12 17:35:25 +08:00
}
2021-03-29 15:59:14 +08:00
fn get_connect_status(&mut self) -> Value {
let mut v = Value::array(0);
2022-05-25 23:09:14 +08:00
let x = get_connect_status();
2021-03-29 15:59:14 +08:00
v.push(x.0);
v.push(x.1);
2022-05-12 17:35:25 +08:00
v.push(x.3);
2021-03-29 15:59:14 +08:00
v
}
2022-01-02 21:56:04 +08:00
#[inline]
fn get_peer_value(id: String, p: PeerConfig) -> Value {
let values = vec![
id,
p.info.username.clone(),
p.info.hostname.clone(),
p.info.platform.clone(),
p.options.get("alias").unwrap_or(&"".to_owned()).to_owned(),
];
Value::from_iter(values)
}
fn get_peer(&self, id: String) -> Value {
2022-05-25 23:09:14 +08:00
let c = get_peer(id.clone());
2022-01-02 21:56:04 +08:00
Self::get_peer_value(id, c)
}
fn get_fav(&self) -> Value {
2022-05-25 23:09:14 +08:00
Value::from_iter(get_fav())
2022-01-02 21:56:04 +08:00
}
fn store_fav(&self, fav: Value) {
let mut tmp = vec![];
fav.values().for_each(|v| {
if let Some(v) = v.as_string() {
if !v.is_empty() {
tmp.push(v);
}
}
});
2022-05-25 23:09:14 +08:00
store_fav(tmp);
2022-01-02 21:56:04 +08:00
}
2021-03-29 15:59:14 +08:00
fn get_recent_sessions(&mut self) -> Value {
2022-04-26 11:19:45 +08:00
// to-do: limit number of recent sessions, and remove old peer file
2022-05-25 23:09:14 +08:00
let peers: Vec<Value> = get_recent_sessions()
2022-01-02 21:56:04 +08:00
.drain(..)
.map(|p| Self::get_peer_value(p.0, p.2))
2021-03-29 15:59:14 +08:00
.collect();
Value::from_iter(peers)
}
fn get_icon(&mut self) -> String {
2022-05-25 23:09:14 +08:00
get_icon()
2021-03-29 15:59:14 +08:00
}
fn remove_peer(&mut self, id: String) {
2022-05-25 23:09:14 +08:00
remove_peer(id)
2021-03-29 15:59:14 +08:00
}
fn new_remote(&mut self, id: String, remote_type: String) {
2022-05-25 23:09:14 +08:00
new_remote(id, remote_type)
2021-03-29 15:59:14 +08:00
}
fn is_process_trusted(&mut self, _prompt: bool) -> bool {
2022-05-25 23:09:14 +08:00
is_process_trusted(_prompt)
2021-03-29 15:59:14 +08:00
}
fn is_can_screen_recording(&mut self, _prompt: bool) -> bool {
2022-05-25 23:09:14 +08:00
is_can_screen_recording(_prompt)
2021-03-29 15:59:14 +08:00
}
2022-01-13 19:23:41 +08:00
fn is_installed_daemon(&mut self, _prompt: bool) -> bool {
2022-05-25 23:09:14 +08:00
is_installed_daemon(_prompt)
2022-01-13 19:23:41 +08:00
}
2021-03-29 15:59:14 +08:00
fn get_error(&mut self) -> String {
2022-05-25 23:09:14 +08:00
get_error()
2021-03-29 15:59:14 +08:00
}
fn is_login_wayland(&mut self) -> bool {
2022-05-25 23:09:14 +08:00
is_login_wayland()
2021-03-29 15:59:14 +08:00
}
fn fix_login_wayland(&mut self) {
2022-05-25 23:09:14 +08:00
fix_login_wayland()
2021-03-29 15:59:14 +08:00
}
2021-10-01 22:48:04 +03:30
fn current_is_wayland(&mut self) -> bool {
2022-05-25 23:09:14 +08:00
current_is_wayland()
}
fn modify_default_login(&mut self) -> String {
2022-05-25 23:09:14 +08:00
modify_default_login()
}
2021-03-29 15:59:14 +08:00
fn get_software_update_url(&self) -> String {
2022-05-25 23:09:14 +08:00
get_software_update_url()
2021-03-29 15:59:14 +08:00
}
fn get_new_version(&self) -> String {
2022-05-25 23:09:14 +08:00
get_new_version()
2021-03-29 15:59:14 +08:00
}
fn get_version(&self) -> String {
2022-05-25 23:09:14 +08:00
get_version()
2021-03-29 15:59:14 +08:00
}
fn get_app_name(&self) -> String {
2022-05-25 23:09:14 +08:00
get_app_name()
2021-03-29 15:59:14 +08:00
}
fn get_software_ext(&self) -> String {
2022-05-25 23:09:14 +08:00
get_software_ext()
2021-03-29 15:59:14 +08:00
}
fn get_software_store_path(&self) -> String {
2022-05-25 23:09:14 +08:00
get_software_store_path()
2021-03-29 15:59:14 +08:00
}
2021-07-27 23:53:12 +08:00
fn create_shortcut(&self, _id: String) {
2022-05-25 23:09:14 +08:00
create_shortcut(_id)
}
fn discover(&self) {
2022-05-25 23:09:14 +08:00
discover()
}
fn get_lan_peers(&self) -> String {
2022-05-25 23:09:14 +08:00
get_lan_peers()
}
2022-05-12 17:35:25 +08:00
fn get_uuid(&self) -> String {
2022-05-25 23:09:14 +08:00
get_uuid()
2022-05-12 17:35:25 +08:00
}
2021-03-29 15:59:14 +08:00
fn open_url(&self, url: String) {
2022-05-25 23:09:14 +08:00
open_url(url)
2021-03-29 15:59:14 +08:00
}
2021-05-02 21:19:48 +08:00
2022-05-12 17:35:25 +08:00
fn change_id(&self, id: String) {
2022-05-25 23:09:14 +08:00
change_id(id)
2022-05-12 17:35:25 +08:00
}
fn post_request(&self, url: String, body: String, header: String) {
2022-05-25 23:09:14 +08:00
post_request(url, body, header)
2022-05-12 17:35:25 +08:00
}
fn is_ok_change_id(&self) -> bool {
2022-05-25 23:09:14 +08:00
is_ok_change_id()
2022-05-12 17:35:25 +08:00
}
fn get_async_job_status(&self) -> String {
2022-05-25 23:09:14 +08:00
get_async_job_status()
2022-05-12 17:35:25 +08:00
}
2021-12-25 16:45:22 +08:00
fn t(&self, name: String) -> String {
2022-05-25 23:09:14 +08:00
t(name)
2021-12-25 16:45:22 +08:00
}
2021-05-02 21:19:48 +08:00
fn is_xfce(&self) -> bool {
2022-05-25 23:09:14 +08:00
is_xfce()
2021-05-02 21:19:48 +08:00
}
2022-05-12 17:35:25 +08:00
fn get_api_server(&self) -> String {
2022-05-25 23:09:14 +08:00
get_api_server()
2022-05-12 17:35:25 +08:00
}
2021-03-29 15:59:14 +08:00
}
impl sciter::EventHandler for UI {
sciter::dispatch_script_call! {
2021-12-25 16:45:22 +08:00
fn t(String);
2022-05-12 17:35:25 +08:00
fn get_api_server();
2021-05-02 21:19:48 +08:00
fn is_xfce();
2022-05-12 17:35:25 +08:00
fn using_public_server();
2021-03-29 15:59:14 +08:00
fn get_id();
fn get_password();
fn update_password(String);
fn get_remote_id();
fn set_remote_id(String);
fn closing(i32, i32, i32, i32);
2021-03-29 15:59:14 +08:00
fn get_size();
fn new_remote(String, bool);
fn remove_peer(String);
fn get_connect_status();
2022-05-12 17:35:25 +08:00
fn get_mouse_time();
fn check_mouse_time();
2021-03-29 15:59:14 +08:00
fn get_recent_sessions();
2022-01-02 21:56:04 +08:00
fn get_peer(String);
fn get_fav();
fn store_fav(Value);
2021-03-29 15:59:14 +08:00
fn recent_sessions_updated();
fn get_icon();
2022-05-12 17:35:25 +08:00
fn install_me(String, String);
2021-03-29 15:59:14 +08:00
fn is_installed();
2022-01-05 18:34:30 +08:00
fn set_socks(String, String, String);
fn get_socks();
2022-05-12 17:35:25 +08:00
fn is_rdp_service_open();
fn is_share_rdp();
fn set_share_rdp(bool);
2021-03-29 15:59:14 +08:00
fn is_installed_lower_version();
fn install_path();
fn goto_install();
fn is_process_trusted(bool);
fn is_can_screen_recording(bool);
2022-01-13 19:23:41 +08:00
fn is_installed_daemon(bool);
2021-03-29 15:59:14 +08:00
fn get_error();
fn is_login_wayland();
fn fix_login_wayland();
fn current_is_wayland();
fn modify_default_login();
2021-03-29 15:59:14 +08:00
fn get_options();
fn get_option(String);
fn get_local_option(String);
2022-04-26 11:19:45 +08:00
fn set_local_option(String, String);
fn get_peer_option(String, String);
fn peer_has_password(String);
fn forget_password(String);
fn set_peer_option(String, String, String);
2022-05-12 17:35:25 +08:00
fn has_rendezvous_service();
fn get_license();
2021-03-29 15:59:14 +08:00
fn test_if_valid_server(String);
fn get_sound_inputs();
fn set_options(Value);
2021-10-08 00:16:10 +08:00
fn set_option(String, String);
2021-03-29 15:59:14 +08:00
fn get_software_update_url();
fn get_new_version();
fn get_version();
fn update_me(String);
2022-05-12 17:35:25 +08:00
fn show_run_without_install();
fn run_without_install();
2021-03-29 15:59:14 +08:00
fn get_app_name();
fn get_software_store_path();
fn get_software_ext();
fn open_url(String);
2022-05-12 17:35:25 +08:00
fn change_id(String);
fn get_async_job_status();
fn post_request(String, String, String);
fn is_ok_change_id();
fn create_shortcut(String);
fn discover();
fn get_lan_peers();
2022-05-12 17:35:25 +08:00
fn get_uuid();
2021-03-29 15:59:14 +08:00
}
}
impl sciter::host::HostHandler for UIHostHandler {
fn on_graphics_critical_failure(&mut self) {
log::error!("Critical rendering error: e.g. DirectX gfx driver error. Most probably bad gfx drivers.");
}
}
2021-03-29 15:59:14 +08:00
pub fn check_zombie(childs: Childs) {
let mut deads = Vec::new();
loop {
let mut lock = childs.lock().unwrap();
let mut n = 0;
for (id, c) in lock.1.iter_mut() {
if let Ok(Some(_)) = c.try_wait() {
deads.push(id.clone());
n += 1;
}
}
for ref id in deads.drain(..) {
lock.1.remove(id);
}
if n > 0 {
lock.0 = true;
}
drop(lock);
std::thread::sleep(std::time::Duration::from_millis(100));
}
}
2022-05-12 17:35:25 +08:00
// notice: avoiding create ipc connecton repeatly,
2021-03-29 15:59:14 +08:00
// because windows named pipe has serious memory leak issue.
2021-06-25 19:42:51 +08:00
#[tokio::main(flavor = "current_thread")]
async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver<ipc::Data>) {
2021-03-29 15:59:14 +08:00
let mut key_confirmed = false;
2022-05-12 17:35:25 +08:00
let mut rx = rx;
let mut mouse_time = 0;
let mut id = "".to_owned();
2021-03-29 15:59:14 +08:00
loop {
if let Ok(mut c) = ipc::connect(1000, "").await {
let mut timer = time::interval(time::Duration::from_secs(1));
loop {
tokio::select! {
res = c.next() => {
match res {
Err(err) => {
log::error!("ipc connection closed: {}", err);
break;
}
2022-05-12 17:35:25 +08:00
Ok(Some(ipc::Data::MouseMoveTime(v))) => {
mouse_time = v;
UI_STATUS.lock().unwrap().2 = v;
2022-05-12 17:35:25 +08:00
}
2021-03-29 15:59:14 +08:00
Ok(Some(ipc::Data::Options(Some(v)))) => {
*OPTIONS.lock().unwrap() = v
2021-03-29 15:59:14 +08:00
}
2022-05-12 17:35:25 +08:00
Ok(Some(ipc::Data::Config((name, Some(value))))) => {
if name == "id" {
id = value;
}
}
2021-03-29 15:59:14 +08:00
Ok(Some(ipc::Data::OnlineStatus(Some((mut x, c))))) => {
if x > 0 {
x = 1
}
key_confirmed = c;
*UI_STATUS.lock().unwrap() = (x as _, key_confirmed, mouse_time, id.clone());
2021-03-29 15:59:14 +08:00
}
_ => {}
}
}
2022-05-12 17:35:25 +08:00
Some(data) = rx.recv() => {
allow_err!(c.send(&data).await);
}
2021-03-29 15:59:14 +08:00
_ = timer.tick() => {
c.send(&ipc::Data::OnlineStatus(None)).await.ok();
c.send(&ipc::Data::Options(None)).await.ok();
2022-05-12 17:35:25 +08:00
c.send(&ipc::Data::Config(("id".to_owned(), None))).await.ok();
2021-03-29 15:59:14 +08:00
}
}
}
}
if !reconnect {
OPTIONS
2022-05-12 17:35:25 +08:00
.lock()
.unwrap()
.insert("ipc-closed".to_owned(), "Y".to_owned());
break;
2021-03-29 15:59:14 +08:00
}
*UI_STATUS.lock().unwrap() = (-1, key_confirmed, mouse_time, id.clone());
2021-03-29 15:59:14 +08:00
sleep(1.).await;
}
}
fn check_connect_status(reconnect: bool) -> mpsc::UnboundedSender<ipc::Data> {
2022-05-12 17:35:25 +08:00
let (tx, rx) = mpsc::unbounded_channel::<ipc::Data>();
std::thread::spawn(move || check_connect_status_(reconnect, rx));
tx
2022-05-12 17:35:25 +08:00
}
const INVALID_FORMAT: &'static str = "Invalid format";
const UNKNOWN_ERROR: &'static str = "Unknown error";
#[tokio::main(flavor = "current_thread")]
2022-05-25 23:09:14 +08:00
async fn change_id_(id: String, old_id: String) -> &'static str {
2022-05-12 17:35:25 +08:00
if !hbb_common::is_valid_custom_id(&id) {
return INVALID_FORMAT;
}
let uuid = machine_uid::get().unwrap_or("".to_owned());
if uuid.is_empty() {
return UNKNOWN_ERROR;
}
let rendezvous_servers = crate::ipc::get_rendezvous_servers(1_000).await;
let mut futs = Vec::new();
let err: Arc<Mutex<&str>> = Default::default();
for rendezvous_server in rendezvous_servers {
let err = err.clone();
let id = id.to_owned();
let uuid = uuid.clone();
let old_id = old_id.clone();
futs.push(tokio::spawn(async move {
let tmp = check_id(rendezvous_server, old_id, id, uuid).await;
if !tmp.is_empty() {
*err.lock().unwrap() = tmp;
}
}));
}
join_all(futs).await;
let err = *err.lock().unwrap();
if err.is_empty() {
crate::ipc::set_config_async("id", id.to_owned()).await.ok();
}
err
}
async fn check_id(
rendezvous_server: String,
old_id: String,
id: String,
uuid: String,
) -> &'static str {
let any_addr = Config::get_any_listen_addr();
if let Ok(mut socket) = FramedStream::new(
crate::check_port(rendezvous_server, RENDEZVOUS_PORT),
any_addr,
RENDEZVOUS_TIMEOUT,
)
.await
{
let mut msg_out = Message::new();
msg_out.set_register_pk(RegisterPk {
old_id,
id,
uuid: uuid.into(),
..Default::default()
});
let mut ok = false;
if socket.send(&msg_out).await.is_ok() {
if let Some(Ok(bytes)) = socket.next_timeout(3_000).await {
if let Ok(msg_in) = RendezvousMessage::parse_from_bytes(&bytes) {
match msg_in.union {
Some(rendezvous_message::Union::register_pk_response(rpr)) => {
match rpr.result.enum_value_or_default() {
register_pk_response::Result::OK => {
ok = true;
}
register_pk_response::Result::ID_EXISTS => {
return "Not available";
}
register_pk_response::Result::TOO_FREQUENT => {
return "Too frequent";
}
register_pk_response::Result::NOT_SUPPORT => {
2022-05-13 18:10:32 +08:00
return "server_not_support";
2022-05-12 17:35:25 +08:00
}
register_pk_response::Result::INVALID_ID_FORMAT => {
return INVALID_FORMAT;
}
_ => {}
}
}
_ => {}
}
}
}
}
if !ok {
return UNKNOWN_ERROR;
}
} else {
return "Failed to connect to rendezvous server";
}
""
2021-03-29 15:59:14 +08:00
}
// sacrifice some memory
pub fn value_crash_workaround(values: &[Value]) -> Arc<Vec<Value>> {
let persist = Arc::new(values.to_vec());
STUPID_VALUES.lock().unwrap().push(persist.clone());
persist
}