2022-07-18 18:20:00 +08:00
|
|
|
use std::{
|
|
|
|
collections::HashMap,
|
|
|
|
iter::FromIterator,
|
2022-08-01 14:33:08 +08:00
|
|
|
process::Child,
|
2022-07-18 18:20:00 +08:00
|
|
|
sync::{Arc, Mutex},
|
|
|
|
};
|
|
|
|
|
|
|
|
use sciter::Value;
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
use hbb_common::{
|
|
|
|
allow_err,
|
2023-02-25 22:39:12 +08:00
|
|
|
config::{LocalConfig, PeerConfig},
|
2022-05-12 17:35:25 +08:00
|
|
|
log,
|
2021-03-29 15:59:14 +08:00
|
|
|
};
|
2022-08-01 14:33:08 +08:00
|
|
|
|
2023-01-20 21:03:30 +08:00
|
|
|
#[cfg(not(any(feature = "flutter", feature = "cli")))]
|
|
|
|
use crate::ui_session_interface::Session;
|
|
|
|
use crate::{common::get_app_name, ipc, ui_interface::*};
|
2022-08-01 14:33:08 +08:00
|
|
|
|
|
|
|
mod cm;
|
|
|
|
#[cfg(feature = "inline")]
|
2022-09-08 18:21:17 +08:00
|
|
|
pub mod inline;
|
2022-08-01 14:33:08 +08:00
|
|
|
pub mod remote;
|
2022-05-12 17:35:25 +08:00
|
|
|
|
2022-11-10 21:25:12 +08:00
|
|
|
pub type Children = Arc<Mutex<(bool, HashMap<(String, String), Child>)>>;
|
|
|
|
#[allow(dead_code)]
|
2022-05-12 17:35:25 +08:00
|
|
|
type Status = (i32, bool, i64, String);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
2022-02-06 18:19:06 +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();
|
2022-05-25 23:09:14 +08:00
|
|
|
}
|
|
|
|
|
2023-01-20 21:03:30 +08:00
|
|
|
#[cfg(not(any(feature = "flutter", feature = "cli")))]
|
|
|
|
lazy_static::lazy_static! {
|
|
|
|
pub static ref CUR_SESSION: Arc<Mutex<Option<Session<remote::SciterHandler>>>> = Default::default();
|
2023-02-10 17:09:31 +08:00
|
|
|
static ref CHILDREN : Children = Default::default();
|
2023-01-20 21:03:30 +08:00
|
|
|
}
|
|
|
|
|
2021-12-10 22:36:34 +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")]
|
2023-03-02 13:32:21 +08:00
|
|
|
crate::platform::delegate::show_dock();
|
2022-04-18 15:45:12 +08:00
|
|
|
#[cfg(all(target_os = "linux", feature = "inline"))]
|
2022-05-29 10:14:22 +08:00
|
|
|
{
|
2022-06-09 17:30:26 +08:00
|
|
|
#[cfg(feature = "appimage")]
|
2022-05-29 10:14:22 +08:00
|
|
|
let prefix = std::env::var("APPDIR").unwrap_or("".to_string());
|
2022-06-09 17:30:26 +08:00
|
|
|
#[cfg(not(feature = "appimage"))]
|
|
|
|
let prefix = "".to_string();
|
2022-09-10 06:44:35 +08:00
|
|
|
#[cfg(feature = "flatpak")]
|
|
|
|
let dir = "/app";
|
|
|
|
#[cfg(not(feature = "flatpak"))]
|
|
|
|
let dir = "/usr";
|
|
|
|
sciter::set_library(&(prefix + dir + "/lib/rustdesk/libsciter-gtk.so")).ok();
|
2022-05-29 10:14:22 +08:00
|
|
|
}
|
2023-03-27 11:21:23 +08:00
|
|
|
#[cfg(windows)]
|
|
|
|
// Check if there is a sciter.dll nearby.
|
|
|
|
if let Ok(exe) = std::env::current_exe() {
|
|
|
|
if let Some(parent) = exe.parent() {
|
|
|
|
let sciter_dll_path = parent.join("sciter.dll");
|
|
|
|
if sciter_dll_path.exists() {
|
|
|
|
// Try to set the sciter dll.
|
|
|
|
let p = sciter_dll_path.to_string_lossy().to_string();
|
2023-03-29 09:38:24 +08:00
|
|
|
log::debug!("Found dll:{}, \n {:?}", p, sciter::set_library(&p));
|
2023-03-27 11:21:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-07-25 02:06:20 +08:00
|
|
|
// 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
|
|
|
|
)));
|
2021-03-29 15:59:14 +08:00
|
|
|
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")]
|
2023-03-02 13:32:21 +08:00
|
|
|
crate::platform::delegate::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() {
|
2023-08-01 22:19:38 +08:00
|
|
|
std::thread::spawn(move || check_zombie());
|
2021-03-29 15:59:14 +08:00
|
|
|
crate::common::check_software_update();
|
2022-05-25 23:09:14 +08:00
|
|
|
frame.event_handler(UI {});
|
2021-12-10 22:36:34 +08:00
|
|
|
frame.sciter_handler(UIHostHandler {});
|
2021-03-29 15:59:14 +08:00
|
|
|
page = "index.html";
|
2023-01-30 11:15:47 +08:00
|
|
|
// Start pulse audio local server.
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
std::thread::spawn(crate::ipc::start_pa);
|
2021-03-29 15:59:14 +08:00
|
|
|
} else if args[0] == "--install" {
|
2022-05-25 23:09:14 +08:00
|
|
|
frame.event_handler(UI {});
|
2021-12-10 22:36:34 +08:00
|
|
|
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 || {
|
2022-09-05 19:41:09 +08:00
|
|
|
Box::new(cm::SciterConnectionManager::new())
|
2021-03-29 15:59:14 +08:00
|
|
|
});
|
|
|
|
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();
|
2023-07-22 14:16:41 +08:00
|
|
|
let Some(cmd) = iter.next() else {
|
|
|
|
log::error!("Failed to get cmd arg");
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
let cmd = cmd.to_owned();
|
|
|
|
let Some(id) = iter.next() else {
|
|
|
|
log::error!("Failed to get id arg");
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
let id = id.to_owned();
|
2022-07-27 00:31:20 +08:00
|
|
|
let pass = iter.next().unwrap_or(&"".to_owned()).clone();
|
2021-03-29 15:59:14 +08:00
|
|
|
let args: Vec<String> = iter.map(|x| x.clone()).collect();
|
|
|
|
frame.set_title(&id);
|
|
|
|
frame.register_behavior("native-remote", move || {
|
2022-12-28 13:52:13 +08:00
|
|
|
let handler =
|
|
|
|
remote::SciterSession::new(cmd.clone(), id.clone(), pass.clone(), args.clone());
|
2023-01-20 21:03:30 +08:00
|
|
|
#[cfg(not(any(feature = "flutter", feature = "cli")))]
|
|
|
|
{
|
|
|
|
*CUR_SESSION.lock().unwrap() = Some(handler.inner());
|
|
|
|
}
|
2022-12-09 21:16:09 +08:00
|
|
|
Box::new(handler)
|
2021-03-29 15:59:14 +08:00
|
|
|
});
|
|
|
|
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-08-01 14:33:08 +08:00
|
|
|
ipc::get_id()
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
2022-07-24 16:41:12 +08:00
|
|
|
fn temporary_password(&mut self) -> String {
|
2022-08-01 14:33:08 +08:00
|
|
|
temporary_password()
|
2022-07-24 16:41:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn update_temporary_password(&self) {
|
2022-08-01 14:33:08 +08:00
|
|
|
update_temporary_password()
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
2022-07-24 16:41:12 +08:00
|
|
|
fn permanent_password(&self) -> String {
|
2022-08-01 14:33:08 +08:00
|
|
|
permanent_password()
|
2022-06-20 10:41:46 +08:00
|
|
|
}
|
|
|
|
|
2022-07-24 16:41:12 +08:00
|
|
|
fn set_permanent_password(&self, password: String) {
|
2022-08-01 20:42:30 +08:00
|
|
|
set_permanent_password(password);
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn get_remote_id(&mut self) -> String {
|
2023-02-10 17:09:31 +08:00
|
|
|
LocalConfig::get_remote_id()
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn set_remote_id(&mut self, id: String) {
|
2023-02-10 17:09:31 +08:00
|
|
|
LocalConfig::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-06-27 11:50:15 +08:00
|
|
|
install_me(_options, _path, false, false);
|
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 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
|
|
|
}
|
|
|
|
|
2021-12-29 17:53:36 +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);
|
2021-12-29 17:53:36 +08:00
|
|
|
}
|
|
|
|
|
2022-01-02 15:09:44 +08:00
|
|
|
fn peer_has_password(&self, id: String) -> bool {
|
2022-05-25 23:09:14 +08:00
|
|
|
peer_has_password(id)
|
2022-01-02 15:09:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn forget_password(&self, id: String) {
|
2022-05-25 23:09:14 +08:00
|
|
|
forget_password(id)
|
2022-01-02 15:09:44 +08:00
|
|
|
}
|
|
|
|
|
2021-06-14 18:27:09 +08:00
|
|
|
fn get_peer_option(&self, id: String, name: String) -> String {
|
2022-05-25 23:09:14 +08:00
|
|
|
get_peer_option(id, name)
|
2021-06-14 18:27:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2021-06-14 18:27:09 +08:00
|
|
|
}
|
|
|
|
|
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 {
|
2023-07-22 14:16:41 +08:00
|
|
|
let hashmap: HashMap<String, String> =
|
|
|
|
serde_json::from_str(&get_options()).unwrap_or_default();
|
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-09-27 13:30:49 +08:00
|
|
|
fn is_root(&self) -> bool {
|
|
|
|
is_root()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_release(&self) -> bool {
|
2023-02-10 17:09:31 +08:00
|
|
|
#[cfg(not(debug_assertions))]
|
|
|
|
return true;
|
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
return false;
|
2022-09-27 13:30:49 +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
|
|
|
}
|
|
|
|
|
2022-04-28 21:32:44 +08:00
|
|
|
fn closing(&mut self, x: i32, y: i32, w: i32, h: i32) {
|
2023-02-10 17:09:31 +08:00
|
|
|
crate::server::input_service::fix_key_down_timeout_at_exit();
|
|
|
|
LocalConfig::set_size(x, y, w, h);
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn get_size(&mut self) -> Value {
|
2023-02-10 17:09:31 +08:00
|
|
|
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);
|
|
|
|
Value::from_iter(v)
|
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();
|
2023-06-24 21:09:45 +08:00
|
|
|
v.push(x.status_num);
|
|
|
|
v.push(x.key_confirmed);
|
|
|
|
v.push(x.id);
|
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
|
2023-08-02 22:25:54 +08:00
|
|
|
let peers: Vec<Value> = PeerConfig::peers(None)
|
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 {
|
2023-02-11 00:21:19 +08:00
|
|
|
get_icon()
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn remove_peer(&mut self, id: String) {
|
2023-02-10 17:09:31 +08:00
|
|
|
PeerConfig::remove(&id);
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
2022-07-13 18:06:19 +08:00
|
|
|
fn remove_discovered(&mut self, id: String) {
|
2023-02-24 13:13:51 +08:00
|
|
|
remove_discovered(id);
|
2022-07-13 18:06:19 +08:00
|
|
|
}
|
|
|
|
|
2022-07-14 10:34:56 +08:00
|
|
|
fn send_wol(&mut self, id: String) {
|
2022-07-15 20:39:42 +08:00
|
|
|
crate::lan::send_wol(id)
|
2022-07-14 10:34:56 +08:00
|
|
|
}
|
|
|
|
|
2023-02-26 11:23:43 +08:00
|
|
|
fn new_remote(&mut self, id: String, remote_type: String, force_relay: bool) {
|
|
|
|
new_remote(id, remote_type, force_relay)
|
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
|
|
|
}
|
|
|
|
|
2021-09-09 15:07:09 +08:00
|
|
|
fn current_is_wayland(&mut self) -> bool {
|
2022-05-25 23:09:14 +08:00
|
|
|
current_is_wayland()
|
2021-09-09 15:07:09 +08:00
|
|
|
}
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
fn get_software_update_url(&self) -> String {
|
2023-02-10 17:09:31 +08:00
|
|
|
crate::SOFTWARE_UPDATE_URL.lock().unwrap().clone()
|
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
|
|
|
}
|
|
|
|
|
2023-04-19 14:39:22 +08:00
|
|
|
fn get_fingerprint(&self) -> String {
|
|
|
|
get_fingerprint()
|
|
|
|
}
|
|
|
|
|
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 {
|
2023-02-10 17:09:31 +08:00
|
|
|
#[cfg(windows)]
|
|
|
|
let p = "exe";
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
let p = "dmg";
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
let p = "deb";
|
|
|
|
p.to_owned()
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn get_software_store_path(&self) -> String {
|
2023-02-10 17:09:31 +08:00
|
|
|
let mut p = std::env::temp_dir();
|
|
|
|
let name = crate::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(), self.get_software_ext())
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
2021-07-27 23:53:12 +08:00
|
|
|
fn create_shortcut(&self, _id: String) {
|
2023-02-10 17:09:31 +08:00
|
|
|
#[cfg(windows)]
|
2022-05-25 23:09:14 +08:00
|
|
|
create_shortcut(_id)
|
2021-06-14 17:51:45 +08:00
|
|
|
}
|
|
|
|
|
2022-01-12 03:10:15 +08:00
|
|
|
fn discover(&self) {
|
2022-08-02 13:10:09 +08:00
|
|
|
std::thread::spawn(move || {
|
|
|
|
allow_err!(crate::lan::discover());
|
|
|
|
});
|
2022-01-12 03:10:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn get_lan_peers(&self) -> String {
|
2022-10-26 21:40:22 +08:00
|
|
|
// let peers = get_lan_peers()
|
|
|
|
// .into_iter()
|
|
|
|
// .map(|mut peer| {
|
|
|
|
// (
|
|
|
|
// peer.remove("id").unwrap_or_default(),
|
|
|
|
// peer.remove("username").unwrap_or_default(),
|
|
|
|
// peer.remove("hostname").unwrap_or_default(),
|
|
|
|
// peer.remove("platform").unwrap_or_default(),
|
|
|
|
// )
|
|
|
|
// })
|
|
|
|
// .collect::<Vec<(String, String, String, String)>>();
|
2022-09-21 21:20:19 +08:00
|
|
|
serde_json::to_string(&get_lan_peers()).unwrap_or_default()
|
2022-01-12 03:10:15 +08:00
|
|
|
}
|
|
|
|
|
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) {
|
2023-02-10 17:09:31 +08:00
|
|
|
#[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());
|
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) {
|
2023-06-25 13:14:21 +08:00
|
|
|
reset_async_job_status();
|
2022-08-01 14:33:08 +08:00
|
|
|
let old_id = self.get_id();
|
2022-12-28 13:52:13 +08:00
|
|
|
change_id_shared(id, old_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 {
|
2023-07-02 17:13:23 +08:00
|
|
|
hbb_common::machine_uid::get().is_ok()
|
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 {
|
2023-02-10 17:09:31 +08:00
|
|
|
crate::client::translate(name)
|
2021-12-25 16:45:22 +08:00
|
|
|
}
|
|
|
|
|
2021-05-02 21:19:48 +08:00
|
|
|
fn is_xfce(&self) -> bool {
|
2023-02-10 17:09:31 +08:00
|
|
|
crate::platform::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
|
|
|
}
|
2022-06-30 16:19:36 +08:00
|
|
|
|
|
|
|
fn has_hwcodec(&self) -> bool {
|
2022-08-15 11:08:42 +08:00
|
|
|
has_hwcodec()
|
2022-06-30 16:19:36 +08:00
|
|
|
}
|
2022-07-06 18:57:14 +08:00
|
|
|
|
2022-06-30 01:19:38 +08:00
|
|
|
fn get_langs(&self) -> String {
|
2022-08-13 12:43:35 +08:00
|
|
|
get_langs()
|
2022-06-30 01:19:38 +08:00
|
|
|
}
|
2022-09-15 17:31:28 +08:00
|
|
|
|
|
|
|
fn default_video_save_directory(&self) -> String {
|
|
|
|
default_video_save_directory()
|
|
|
|
}
|
2023-02-26 11:23:43 +08:00
|
|
|
|
|
|
|
fn handle_relay_id(&self, id: String) -> String {
|
|
|
|
handle_relay_id(id)
|
|
|
|
}
|
2023-06-20 10:29:27 +08:00
|
|
|
|
2023-08-11 19:28:25 +08:00
|
|
|
fn get_login_device_info(&self) -> String {
|
|
|
|
get_login_device_info_json()
|
2023-06-20 10:29:27 +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();
|
2022-07-24 16:41:12 +08:00
|
|
|
fn temporary_password();
|
|
|
|
fn update_temporary_password();
|
|
|
|
fn permanent_password();
|
|
|
|
fn set_permanent_password(String);
|
2021-03-29 15:59:14 +08:00
|
|
|
fn get_remote_id();
|
|
|
|
fn set_remote_id(String);
|
2022-04-28 21:32:44 +08:00
|
|
|
fn closing(i32, i32, i32, i32);
|
2021-03-29 15:59:14 +08:00
|
|
|
fn get_size();
|
2023-02-26 11:23:43 +08:00
|
|
|
fn new_remote(String, String, bool);
|
2022-07-14 10:34:56 +08:00
|
|
|
fn send_wol(String);
|
2021-03-29 15:59:14 +08:00
|
|
|
fn remove_peer(String);
|
2022-07-13 18:06:19 +08:00
|
|
|
fn remove_discovered(String);
|
2021-03-29 15:59:14 +08:00
|
|
|
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-09-27 13:30:49 +08:00
|
|
|
fn is_root();
|
|
|
|
fn is_release();
|
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();
|
2021-09-09 15:07:09 +08:00
|
|
|
fn current_is_wayland();
|
2021-03-29 15:59:14 +08:00
|
|
|
fn get_options();
|
|
|
|
fn get_option(String);
|
2021-12-29 17:53:36 +08:00
|
|
|
fn get_local_option(String);
|
2022-04-26 11:19:45 +08:00
|
|
|
fn set_local_option(String, String);
|
2021-06-14 18:27:09 +08:00
|
|
|
fn get_peer_option(String, String);
|
2022-01-02 15:09:44 +08:00
|
|
|
fn peer_has_password(String);
|
|
|
|
fn forget_password(String);
|
2021-06-14 18:27:09 +08:00
|
|
|
fn set_peer_option(String, String, String);
|
2022-05-12 17:35:25 +08:00
|
|
|
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();
|
2023-04-19 14:39:22 +08:00
|
|
|
fn get_fingerprint();
|
2021-03-29 15:59:14 +08:00
|
|
|
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();
|
2021-06-14 17:51:45 +08:00
|
|
|
fn create_shortcut(String);
|
2022-01-12 03:10:15 +08:00
|
|
|
fn discover();
|
|
|
|
fn get_lan_peers();
|
2022-05-12 17:35:25 +08:00
|
|
|
fn get_uuid();
|
2022-06-30 16:19:36 +08:00
|
|
|
fn has_hwcodec();
|
2022-06-30 01:19:38 +08:00
|
|
|
fn get_langs();
|
2022-09-15 17:31:28 +08:00
|
|
|
fn default_video_save_directory();
|
2023-02-26 11:23:43 +08:00
|
|
|
fn handle_relay_id(String);
|
2023-08-11 19:28:25 +08:00
|
|
|
fn get_login_device_info();
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-10 22:36:34 +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
|
|
|
#[cfg(not(target_os = "linux"))]
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
fn get_sound_inputs() -> Vec<String> {
|
|
|
|
crate::platform::linux::get_pa_sources()
|
|
|
|
.drain(..)
|
|
|
|
.map(|x| x.1)
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
2022-02-06 18:19:06 +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
|
|
|
|
}
|
2023-02-10 17:09:31 +08:00
|
|
|
|
2023-02-11 00:21:19 +08:00
|
|
|
pub fn get_icon() -> String {
|
|
|
|
// 128x128
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
// 128x128 on 160x160 canvas, then shrink to 128, mac looks better with padding
|
|
|
|
{
|
|
|
|
"data:image/png;base64,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
|
|
|
|
}
|
|
|
|
#[cfg(not(target_os = "macos"))] // 128x128 no padding
|
|
|
|
{
|
|
|
|
"data:image/png;base64,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
|
|
|
|
}
|
|
|
|
}
|