new mac service and local config

This commit is contained in:
rustdesk 2022-04-26 11:19:45 +08:00
parent 05ac26e5fe
commit 3566b0ee7a
15 changed files with 308 additions and 419 deletions

70
Cargo.lock generated
View File

@ -1168,25 +1168,6 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "fsevent"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6"
dependencies = [
"bitflags",
"fsevent-sys",
]
[[package]]
name = "fsevent-sys"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0"
dependencies = [
"libc",
]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
@ -1805,26 +1786,6 @@ dependencies = [
"hashbrown",
]
[[package]]
name = "inotify"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f"
dependencies = [
"bitflags",
"inotify-sys",
"libc",
]
[[package]]
name = "inotify-sys"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
dependencies = [
"libc",
]
[[package]]
name = "instant"
version = "0.1.12"
@ -2205,18 +2166,6 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "mio-extras"
version = "2.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19"
dependencies = [
"lazycell",
"log",
"mio 0.6.23",
"slab",
]
[[package]]
name = "mio-named-pipes"
version = "0.1.7"
@ -2368,24 +2317,6 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "notify"
version = "4.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae03c8c853dba7bfd23e571ff0cff7bc9dceb40a4cd684cd1681824183f45257"
dependencies = [
"bitflags",
"filetime",
"fsevent",
"fsevent-sys",
"inotify",
"libc",
"mio 0.6.23",
"mio-extras",
"walkdir",
"winapi 0.3.9",
]
[[package]]
name = "ntapi"
version = "0.3.7"
@ -3349,7 +3280,6 @@ dependencies = [
"mac_address",
"machine-uid",
"magnum-opus",
"notify",
"num_cpus",
"objc",
"parity-tokio-ipc",

View File

@ -72,7 +72,6 @@ cocoa = "0.24"
dispatch = "0.2"
core-foundation = "0.9"
core-graphics = "0.22"
notify = "4.0.17"
include_dir = "0.7.2"
[target.'cfg(target_os = "linux")'.dependencies]
psimple = { package = "libpulse-simple-binding", version = "2.25" }

View File

@ -22,10 +22,7 @@ const SERIAL: i32 = 1;
#[cfg(target_os = "macos")] // 128x128 on 160x160 canvas, then shrink to 128, mac looks better with padding
pub const ICON: &str = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAyVBMVEUAAAAAcf8Acf8Acf8Acv8Acf8Acf8Acf8Acf8AcP8Acf8Ab/8AcP8Acf////8AaP/z+f/o8v/k7v/5/v/T5f8AYP/u9v/X6f+hx/+Kuv95pP8Aef/B1/+TwP9xoP8BdP/g6P+Irv9ZmP8Bgf/E3f98q/9sn/+01f+Es/9nm/9Jif8hhv8off/M4P+syP+avP86iP/c7f+xy/9yqf9Om/9hk/9Rjv+60P99tv9fpf88lv8yjf8Tgf8deP+kvP8BiP8NeP8hkP80gP8oj2VLAAAADXRSTlMA7o7qLvnaxZ1FOxYPjH9HWgAABHJJREFUeNrtm+tW4jAQgBfwuu7MtIUWsOUiCCioIIgLiqvr+z/UHq/LJKVkmwTcc/r9E2nzlU4mSTP9lpGRkZGR8VX5cZjfL+yCEXYL+/nDH//U/Pd8DgyTy39Xbv7oIAcWyB0cqbW/sweW2NtRaj8H1sgpGOwUIAH7Bkd7YJW9dXFwAJY5WNP/cmCZQnJvzIN18on5LwfWySXlxEPYAIcad8D6PdiHDbCfIFCADVBIENiFDbCbIACKPPXrZ+cP8E6/0znvP4EymgIEravIRcTxu8HxNSJ60a8W0AYECKrlAN+YwAthCd9wm1Ug6wKzIn5SgRduXfwkqDasCjx0XFzi9PV6zwNcIuhcWBOg+ikySq8C9UD4dEKWBCoOcspvAuLHTo9sCDQiFPHotRM48j8G5gVur1FdAN2uaYEuiz7xFsgEJ2RUoMUakXuBTHHoGxQYOBhHjeUBAefEnMAowFhaLBOKuOemBBbxLRQrH2PBCgMvNCPQGMeevTb9zLrPxz2Mo+QbEaijzPUcOOHMQZkKGRAIPem39+bypREMPTkQW/oCfk866zAkiIFG4yIKRE/aAnfiSd0WrORY6pFdXQEqi9mvAQm0RIOSnoCcZ8vJoz3diCnjRk+g8VP4/fuQDJ2Lxr6WwG0gXs9aTpDzW0vgDBlVUpixR8gYk44AD8FrUKHr8JQJGgIDnoDqoALxmWPQSi9AVVzm8gKUuEPGr/QCvptwJkbSYT/TC4S8C96DGjTj86aHtAI0x2WaBIq0eSYYpRa4EsdWVVwWu9O0Aj6f6dyBMnwEraeOgSYu0wZlauzA47QCbT7DgAQSE+hZWoEBF/BBmWOewNMK3BsSqKUW4MGcWqCSVmDkbvkXGKQOwg6PAUO9oL3xXhA20yaiCjuwYygRVQlUOTWTCf2SuNJTxeFjgaHByGuAIvd8ItdPLTDhS7IuqEE1YSKVOgbayLhSFQhMzYh8hwfBs1r7c505YVIQYEdNoKwxK06MJiyrpUFHiF0NAfCQUVHoiRclIXJIR6C2fqG37pBHvcWpgwzvAtYwkR5UGV2e42UISdBJETl3mg8ouo54Rcnti1/vaT+iuUQBt500Cgo4U10BeHSkk57FB0JjWkKRMWgLUA0lLodtImAQdaMiiri3+gIAPZQoutHNsgKF1aaDMhMyIdBf8Th+Bh8MTjGWCpl5Wv43tDmnF+IUVMrcZgRoiAxhtrloYizNkZaAnF5leglbNhj0wYCAbCDvGb0mP4nib7O7ZlcYQ2m1gPtIZgVgGNNMeaVAaWR+57TrqgtUnm3sHQ+kYeE6fufUubG1ez50FXbPnWgBlgSABmN3TTcsRl2yWkHRrwbiunvk/W2+Mg1hPZplPDeXRbZzStFH15s1QIVd3UImP5z/bHpeeQLvRJ7XLFUffQIlCvqlXETQbgN9/rlYABGosv+Vi9m2Xs639YLGrZd0br+odetlvdsvbN56abfd4vbCzv9Q3v/ygoOV21A4OPpfXvH4Ai+5ZGRkZGRkbJA/t/I0QMzoMiEAAAAASUVORK5CYII=
";
#[cfg(windows)] // windows, 32x32, bigger very ugly after shrink
pub const ICON: &str = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAolBMVEUAAAAAcf8Acf8Acf8AcP8Acf8Acf8Acf8AcP8Acf/////9/v/7/f+gyv9wr/8Ld/8GdP/A3P+nzv+Qwf9mqv8lhv8UfP+Kvv88k/8zjv/x+P/Y6f/U5//J4f/F3/+x1P+pz/+izP+Cuv9Zov9Qnv9FmP8gg//f7f+42P96tv9fpv8ui//1+f/q8//o8v/Q5f+ax/+Zxv+VxP+Fu/9rrf8rif+x1o3FAAAACXRSTlMAv/RPTPKHioRsIqhAAAABNklEQVQ4y4WT6XaCQAyFB7S2GUD2RaxSKGDV7sv7v1on4djEluL9Ncn5biaZk1FKzSwbRmVbM2V0DRNaGD9Maq6sacBS9jRwpUTw1Ww7SEOvkwQDaeVofQeJ1nrXjgD3pTaqCDCg/xs4OBrlwUGTHvxzoHAx69Y9+Hk5oGdAsCNXSoHfEN1JYEme4KcfvO9WAmtMBNx6jIaCgSPGLbAyvKRhAEcrAxAKTSZiACu+gNSbyWwZeKdQKj91yRXWIOWZTMgATun6EtjgczNQaKMEWD0+xJ6B4AnvECVqdKwYoJ50hIPyw25AANkzpsLB00cYOIUEoHU0uVaQVcMxBwlgVZJ3Orz+3ahH6gP2tBgfYzsZmdo1fGIzRx5Irn2WxKaHeJnKtb/4cS5/PbWACd0oo/n/39/4vwGFYSxtSYV4OAAAAABJRU5ErkJggg==
";
#[cfg(target_os = "linux")] // 128x128 no padding
#[cfg(not(target_os = "macos"))] // 128x128 no padding
pub const ICON: &str = "data:image/png;base64,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
";
#[cfg(target_os = "macos")]
@ -36,6 +33,7 @@ type Size = (i32, i32, i32, i32);
lazy_static::lazy_static! {
static ref CONFIG: Arc<RwLock<Config>> = Arc::new(RwLock::new(Config::load()));
static ref CONFIG2: Arc<RwLock<Config2>> = Arc::new(RwLock::new(Config2::load()));
static ref LOCAL_CONFIG: Arc<RwLock<LocalConfig>> = Arc::new(RwLock::new(LocalConfig::load()));
pub static ref ONLINE: Arc<Mutex<HashMap<String, i64>>> = Default::default();
}
#[cfg(any(target_os = "android", target_os = "ios"))]
@ -61,7 +59,7 @@ pub enum NetworkType {
ProxySocks,
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub struct Config {
#[serde(default)]
id: String,
@ -88,12 +86,8 @@ pub struct Socks5Server {
}
// more variable configs
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub struct Config2 {
#[serde(default)]
remote_id: String, // latest used one
#[serde(default)]
size: Size,
#[serde(default)]
rendezvous_server: String,
#[serde(default)]
@ -193,14 +187,23 @@ impl Config2 {
Config::load_::<Config2>("2")
}
fn reload(&mut self) {
let new_config = Config2::load();
*self = new_config;
pub fn file() -> PathBuf {
Config::file_("2")
}
fn store(&self) {
Config::store_(self, "2");
}
pub fn get() -> Config2 {
return CONFIG2.read().unwrap().clone();
}
pub fn set(cfg: Config2) {
let mut lock = CONFIG2.write().unwrap();
*lock = cfg;
lock.store();
}
}
impl Config {
@ -222,11 +225,6 @@ impl Config {
cfg
}
fn reload(&mut self) {
let new_config = Config::load();
*self = new_config;
}
fn store_<T: serde::Serialize>(config: &T, suffix: &str) {
let file = Self::file_(suffix);
if let Err(err) = confy::store_path(file, config) {
@ -623,33 +621,6 @@ impl Config {
salt
}
pub fn get_size() -> Size {
CONFIG2.read().unwrap().size
}
pub fn set_size(x: i32, y: i32, w: i32, h: i32) {
let mut config = CONFIG2.write().unwrap();
let size = (x, y, w, h);
if size == config.size || size.2 < 300 || size.3 < 300 {
return;
}
config.size = size;
config.store();
}
pub fn set_remote_id(remote_id: &str) {
let mut config = CONFIG2.write().unwrap();
if remote_id == config.remote_id {
return;
}
config.remote_id = remote_id.into();
config.store();
}
pub fn get_remote_id() -> String {
CONFIG2.read().unwrap().remote_id.clone()
}
pub fn set_socks(socks: Option<Socks5Server>) {
let mut config = CONFIG2.write().unwrap();
if config.socks == socks {
@ -670,91 +641,14 @@ impl Config {
}
}
pub fn sync_config_to_user<P: AsRef<Path>>(target_username: String, to_dir: P) -> bool {
let config1_root_file_path = Config::file_("");
let config1_filename = config1_root_file_path.file_name();
let config2_root_file_path = Config::file_("2");
let config2_filename = config2_root_file_path.file_name();
let config1_to_file_path = to_dir
.as_ref()
.join(PathBuf::from(&config1_filename.unwrap()));
let config2_to_file_path = to_dir
.as_ref()
.join(PathBuf::from(&config2_filename.unwrap()));
log::info!(
"config1_root_path:{}",
&config1_root_file_path.as_path().to_str().unwrap()
);
log::info!(
"config2_root_path:{}",
&config2_root_file_path.as_path().to_str().unwrap()
);
log::info!(
"config1_to_path:{}",
&config1_to_file_path.as_path().to_str().unwrap()
);
log::info!(
"config2_to_path:{}",
&config2_to_file_path.as_path().to_str().unwrap()
);
match std::fs::copy(&config1_root_file_path, &config1_to_file_path) {
Err(e) => log::error!(
"copy config {} to user failed: {}",
config1_filename.unwrap().to_str().unwrap(),
e
),
_ => {}
}
match std::fs::copy(&config2_root_file_path, &config2_to_file_path) {
Err(e) => log::error!(
"copy config {} to user failed: {}",
config2_filename.unwrap().to_str().unwrap(),
e
),
_ => {}
}
let success = std::process::Command::new("chown")
.arg(&target_username.to_string())
.arg(&config1_to_file_path.to_str().unwrap().to_string())
.arg(&config2_to_file_path.to_str().unwrap().to_string())
.spawn()
.is_ok();
if success {
CONFIG.write().unwrap().reload();
CONFIG2.write().unwrap().reload();
}
return success;
pub fn get() -> Config {
return CONFIG.read().unwrap().clone();
}
pub fn sync_config_to_root<P: AsRef<Path>>(from_file_path: P) -> bool {
if let Some(filename) = from_file_path.as_ref().file_name() {
let to = Config::path(filename);
return match std::fs::copy(from_file_path, &to) {
Ok(count) => {
if count > 0 {
return std::process::Command::new("chown")
.arg("root")
.arg(&to.to_str().unwrap().to_string())
.spawn()
.is_ok();
}
false
}
Err(e) => {
log::error!("sync_config_to_root failed: {}", e);
false
}
};
}
false
pub fn set(cfg: Config) {
let mut lock = CONFIG.write().unwrap();
*lock = cfg;
lock.store();
}
}
@ -801,9 +695,7 @@ impl PeerConfig {
&& p.extension().map(|p| p.to_str().unwrap_or("")) == Some("toml")
})
.map(|p| {
let t = fs::metadata(p)
.map(|m| m.modified().unwrap_or(SystemTime::UNIX_EPOCH))
.unwrap_or(SystemTime::UNIX_EPOCH);
let t = crate::get_modified_time(&p);
let id = p
.file_stem()
.map(|p| p.to_str().unwrap_or(""))
@ -826,27 +718,84 @@ impl PeerConfig {
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct Fav {
pub struct LocalConfig {
#[serde(default)]
pub peers: Vec<String>,
remote_id: String, // latest used one
#[serde(default)]
size: Size,
#[serde(default)]
pub fav: Vec<String>,
#[serde(default)]
options: HashMap<String, String>,
}
impl Fav {
pub fn load() -> Fav {
let _ = CONFIG.read().unwrap(); // for lock
match confy::load_path(&Config::file_("_fav")) {
Ok(fav) => fav,
Err(err) => {
log::error!("Failed to load fav: {}", err);
Default::default()
}
impl LocalConfig {
fn load() -> LocalConfig {
Config::load_::<LocalConfig>("_local")
}
fn store(&self) {
Config::store_(self, "_local");
}
pub fn get_size() -> Size {
LOCAL_CONFIG.read().unwrap().size
}
pub fn set_size(x: i32, y: i32, w: i32, h: i32) {
let mut config = LOCAL_CONFIG.write().unwrap();
let size = (x, y, w, h);
if size == config.size || size.2 < 300 || size.3 < 300 {
return;
}
config.size = size;
config.store();
}
pub fn set_remote_id(remote_id: &str) {
let mut config = LOCAL_CONFIG.write().unwrap();
if remote_id == config.remote_id {
return;
}
config.remote_id = remote_id.into();
config.store();
}
pub fn get_remote_id() -> String {
LOCAL_CONFIG.read().unwrap().remote_id.clone()
}
pub fn set_fav(fav: Vec<String>) {
let mut lock = LOCAL_CONFIG.write().unwrap();
if lock.fav == fav {
return;
}
lock.fav = fav;
lock.store();
}
pub fn get_fav() -> Vec<String> {
LOCAL_CONFIG.read().unwrap().fav.clone()
}
pub fn get_option(k: &str) -> String {
if let Some(v) = LOCAL_CONFIG.read().unwrap().options.get(k) {
v.clone()
} else {
"".to_owned()
}
}
pub fn store(peers: Vec<String>) {
let f = Fav { peers };
if let Err(err) = confy::store_path(Config::file_("_fav"), f) {
log::error!("Failed to store fav: {}", err);
pub fn set_option(k: String, v: String) {
let mut config = LOCAL_CONFIG.write().unwrap();
let v2 = if v.is_empty() { None } else { Some(&v) };
if v2 != config.options.get(&k) {
if v2.is_none() {
config.options.remove(&k);
} else {
config.options.insert(k, v);
}
config.store();
}
}
}

View File

@ -187,6 +187,12 @@ pub fn get_version_number(v: &str) -> i64 {
n
}
pub fn get_modified_time(path: &std::path::Path) -> SystemTime {
std::fs::metadata(&path)
.map(|m| m.modified().unwrap_or(UNIX_EPOCH))
.unwrap_or(UNIX_EPOCH)
}
#[cfg(test)]
mod tests {
use super::*;

View File

@ -465,3 +465,8 @@ pub fn is_ip(id: &str) -> bool {
.unwrap()
.is_match(id)
}
#[inline]
pub fn get_app_name() -> &'static str {
hbb_common::config::APP_NAME
}

View File

@ -3,7 +3,7 @@ pub use clipboard::ClipbaordFile;
use hbb_common::{
allow_err, bail, bytes,
bytes_codec::BytesCodec,
config::{self, Config},
config::{self, Config, Config2},
futures::StreamExt as _,
futures_util::sink::SinkExt,
log, timeout, tokio,
@ -96,15 +96,8 @@ pub enum Data {
Socks(Option<config::Socks5Server>),
FS(FS),
Test,
SyncConfigToRootReq {
from: String,
},
SyncConfigToRootResp(bool),
SyncConfigToUserReq {
username: String,
to: String,
},
SyncConfigToUserResp(bool),
SyncConfig(Option<(Config, Config2)>),
#[cfg(not(any(target_os = "android", target_os = "ios")))]
ClipbaordFile(ClipbaordFile),
ClipboardFileEnabled(bool),
}
@ -173,6 +166,30 @@ pub async fn new_listener(postfix: &str) -> ResultType<Incoming> {
}
}
pub struct CheckIfRestart(String, Vec<String>, String);
impl CheckIfRestart {
pub fn new() -> CheckIfRestart {
CheckIfRestart(
Config::get_option("stop-service"),
Config::get_rendezvous_servers(),
Config::get_option("audio-input"),
)
}
}
impl Drop for CheckIfRestart {
fn drop(&mut self) {
if self.0 != Config::get_option("stop-service")
|| self.1 != Config::get_rendezvous_servers()
{
RendezvousMediator::restart();
}
if self.2 != Config::get_option("audio-input") {
crate::audio_service::restart();
}
}
}
async fn handle(data: Data, stream: &mut Connection) {
match data {
Data::SystemInfo(_) => {
@ -280,21 +297,15 @@ async fn handle(data: Data, stream: &mut Connection) {
let t = Config::get_nat_type();
allow_err!(stream.send(&Data::NatType(Some(t))).await);
}
Data::SyncConfigToRootReq { from } => {
allow_err!(
stream
.send(&Data::SyncConfigToRootResp(Config::sync_config_to_root(
from
)))
.await
);
Data::SyncConfig(Some((config, config2))) => {
Config::set(config);
Config2::set(config2);
allow_err!(stream.send(&Data::SyncConfig(None)).await);
}
Data::SyncConfigToUserReq { username, to } => {
Data::SyncConfig(None) => {
allow_err!(
stream
.send(&Data::SyncConfigToUserResp(Config::sync_config_to_user(
username, to
)))
.send(&Data::SyncConfig(Some((Config::get(), Config2::get()))))
.await
);
}

View File

@ -1,4 +1,4 @@
use hbb_common::{config::Config, log};
use hbb_common::{config::LocalConfig, log};
use std::ops::Deref;
mod cn;
@ -19,7 +19,7 @@ pub fn translate(name: String) -> String {
}
pub fn translate_locale(name: String, locale: &str) -> String {
let mut lang = Config::get_option("lang");
let mut lang = LocalConfig::get_option("lang");
if lang.is_empty() {
lang = locale
.split("-")

View File

@ -104,11 +104,12 @@ pub fn is_can_screen_recording(prompt: bool) -> bool {
pub fn is_installed_daemon(prompt: bool) -> bool {
let daemon = format!("{}_service.plist", crate::get_full_name());
let agent = format!("{}_server.plist", crate::get_full_name());
let agent_plist_file = format!("/Library/LaunchAgents/{}", agent);
if !prompt {
if !std::path::Path::new(&format!("/Library/LaunchDaemons/{}", daemon)).exists() {
return false;
}
if !std::path::Path::new(&format!("/Library/LaunchAgents/{}", agent)).exists() {
if !std::path::Path::new(&agent_plist_file).exists() {
return false;
}
return true;
@ -123,43 +124,92 @@ pub fn is_installed_daemon(prompt: bool) -> bool {
let agent_plist = PRIVILEGES_SCRIPTS_DIR.get_file(&agent).unwrap();
let agent_plist_body = agent_plist.contents_utf8().unwrap();
match std::process::Command::new("osascript")
.arg("-e")
.arg(install_script_body)
.arg(daemon_plist_body)
.arg(agent_plist_body)
.arg(&get_active_username())
.spawn()
{
Ok(_) => {
std::process::exit(0);
std::thread::spawn(move || {
match std::process::Command::new("osascript")
.arg("-e")
.arg(install_script_body)
.arg(daemon_plist_body)
.arg(agent_plist_body)
.arg(&get_active_username())
.output()
{
Err(e) => {
log::error!("run osascript failed: {}", e);
}
_ => {
if std::path::Path::new(&agent_plist_file).exists() {
std::process::Command::new("osascript")
.arg("-e")
.arg(
PRIVILEGES_SCRIPTS_DIR
.get_file("run.scpt")
.unwrap()
.contents_utf8()
.unwrap(),
)
.arg(&format!(
"sleep 0.5; launchctl load -w {}; sleep 0.5; open /Applications/{}.app",
agent_plist_file,
crate::get_app_name()
))
.spawn()
.ok();
std::thread::sleep(std::time::Duration::from_millis(100)); // avoid exit crash
std::process::exit(0);
}
}
}
Err(e) => {
log::error!("run osascript failed: {}", e);
false
}
}
});
false
}
pub fn launch(load: bool) {
pub fn uninstall() -> bool {
// to-do: do together with win/linux about refactory start/stop service
if !is_installed() || !is_installed_daemon(false) {
return;
}
let mut script_filename = "load.scpt";
if !load {
script_filename = "unload.scpt";
if !is_installed_daemon(false) {
return false;
}
let script_file = PRIVILEGES_SCRIPTS_DIR.get_file(script_filename).unwrap();
let script_file = PRIVILEGES_SCRIPTS_DIR.get_file("uninstall.scpt").unwrap();
let script_body = script_file.contents_utf8().unwrap();
std::process::Command::new("osascript")
.arg("-e")
.arg(script_body)
.arg(&get_active_username())
.spawn()
.ok();
std::thread::spawn(move || {
match std::process::Command::new("osascript")
.arg("-e")
.arg(script_body)
.arg(&get_active_username())
.output()
{
Err(e) => {
log::error!("run osascript failed: {}", e);
}
_ => {
let agent = format!("{}_server.plist", crate::get_full_name());
let agent_plist_file = format!("/Library/LaunchAgents/{}", agent);
if !std::path::Path::new(&agent_plist_file).exists() {
crate::ipc::set_option("stop-service", "Y");
std::process::Command::new("osascript")
.arg("-e")
.arg(
PRIVILEGES_SCRIPTS_DIR
.get_file("run.scpt")
.unwrap()
.contents_utf8()
.unwrap(),
)
.arg(&format!(
"sleep 0.5; launchctl remove {}_server; sleep 0.5; open /Applications/{}.app",
crate::get_full_name(),
crate::get_app_name()
))
.spawn()
.ok();
std::thread::sleep(std::time::Duration::from_millis(100)); // avoid exit crash
std::process::exit(0);
}
}
}
});
true
}
pub fn get_cursor_pos() -> Option<(i32, i32)> {
@ -352,6 +402,24 @@ pub fn lock_screen() {
pub fn start_os_service() {
log::info!("{}", crate::username());
std::thread::spawn(move || loop {
let exe = std::env::current_exe().unwrap_or_default();
let tm0 = hbb_common::get_modified_time(&exe);
loop {
std::thread::sleep(std::time::Duration::from_millis(300));
if hbb_common::get_modified_time(&exe) != tm0 {
log::info!("{:?} updated, will restart", exe);
std::process::Command::new("pkill")
.args(&["-f", exe.to_str().unwrap_or("")])
.output()
.ok();
std::process::exit(0); // self not killed by above pkill
}
}
});
if let Err(err) = crate::ipc::start("_service") {
log::error!("Failed to start ipc_service: {}", err);
}
@ -425,7 +493,7 @@ pub fn is_installed() -> bool {
if let Ok(p) = std::env::current_exe() {
return p.to_str().unwrap_or_default().contains(&format!(
"/Applications/{}.app",
hbb_common::config::APP_NAME
crate::get_app_name(),
));
}
false

View File

@ -1,19 +1,16 @@
on run {daemon_file, agent_file, user}
set sh1 to "echo " & quoted form of daemon_file & " > /Library/LaunchDaemons/com.carriez.RustDesk_service.plist && chown root:wheel /Library/LaunchDaemons/com.carriez.RustDesk_service.plist;"
set sh1 to "echo " & quoted form of daemon_file & " > /Library/LaunchDaemons/com.carriez.RustDesk_service.plist && chown root:wheel /Library/LaunchDaemons/com.carriez.RustDesk_service.plist;"
set sh2 to "echo " & quoted form of agent_file & " > /Library/LaunchAgents/com.carriez.RustDesk_server.plist && chown root:wheel /Library/LaunchAgents/com.carriez.RustDesk_server.plist;"
set sh2 to "echo " & quoted form of agent_file & " > /Library/LaunchAgents/com.carriez.RustDesk_server.plist && chown root:wheel /Library/LaunchAgents/com.carriez.RustDesk_server.plist;"
set sh3 to "cp -rf /Users/" & user & "/Library/Preferences/com.carriez.RustDesk/RustDesk.toml /var/root/Library/Preferences/com.carriez.RustDesk/;"
set sh4 to "cp -rf /Users/" & user & "/Library/Preferences/com.carriez.RustDesk/RustDesk2.toml /var/root/Library/Preferences/com.carriez.RustDesk/;"
set sh5 to "launchctl unload -w /Library/LaunchAgents/com.carriez.RustDesk_server.plist; launchctl load -w /Library/LaunchDaemons/com.carriez.RustDesk_service.plist;"
set sh6 to "pkill -f rustdesk; launchctl unload -w /Library/LaunchAgents/com.carriez.RustDesk_server.plist; launchctl load -w /Library/LaunchAgents/com.carriez.RustDesk_server.plist; open /Applications/RustDesk.app"
set sh5 to "launchctl load -w /Library/LaunchDaemons/com.carriez.RustDesk_service.plist;"
set sh to sh1 & sh2 & sh3 & sh4 & sh5
set sh to sh1 & sh2 & sh3 & sh4 & sh5
do shell script sh with prompt "RustDesk want to install daemon and agent" with administrator privileges
do shell script sh6
do shell script sh with prompt "RustDesk want to install daemon and agent" with administrator privileges
end run

View File

@ -1,16 +0,0 @@
on run {user}
set sh1 to "cp -rf /Users/" & user & "/Library/Preferences/com.carriez.RustDesk/RustDesk.toml /var/root/Library/Preferences/com.carriez.RustDesk/;"
set sh2 to "cp -rf /Users/" & user & "/Library/Preferences/com.carriez.RustDesk/RustDesk2.toml /var/root/Library/Preferences/com.carriez.RustDesk/;"
set sh3 to "launchctl load -w /Library/LaunchDaemons/com.carriez.rustdesk_service.plist;"
set sh4 to "launchctl load -w /Library/LaunchAgents/com.carriez.rustdesk_server.plist;"
set sh to sh1 & sh2 & sh3
do shell script sh with prompt "RustDesk want to launch daemon" with administrator privileges
do shell script sh4
end run

View File

@ -1,6 +0,0 @@
set sh1 to "launchctl unload -w /Library/LaunchDaemons/com.carriez.rustdesk_service.plist;"
set sh2 to "launchctl unload -w /Library/LaunchAgents/com.carriez.rustdesk_server.plist;"
do shell script sh1 with prompt "RustDesk want to unload daemon" with administrator privileges
do shell script sh2

View File

@ -1,12 +1,10 @@
#[cfg(target_os = "macos")]
use crate::ipc::ConnectionTmpl;
use crate::ipc::Data;
use connection::{ConnInner, Connection};
pub use connection::*;
use hbb_common::{
allow_err,
anyhow::{anyhow, Context},
bail,
config::{Config, CONNECT_TIMEOUT, RELAY_PORT},
config::{Config, Config2, CONNECT_TIMEOUT, RELAY_PORT},
log,
message_proto::*,
protobuf::{Message as _, ProtobufEnum},
@ -15,10 +13,6 @@ use hbb_common::{
sodiumoxide::crypto::{box_, secretbox, sign},
timeout, tokio, ResultType, Stream,
};
#[cfg(target_os = "macos")]
use notify::{watcher, RecursiveMode, Watcher};
#[cfg(target_os = "macos")]
use parity_tokio_ipc::ConnectionClient;
use service::{GenericService, Service, ServiceTmpl, Subscriber};
use std::{
collections::HashMap,
@ -339,101 +333,46 @@ async fn sync_and_watch_config_dir() {
return;
}
match crate::ipc::connect(1000, "_service").await {
Ok(mut conn) => {
match sync_config_to_user(&mut conn).await {
Err(e) => log::error!("sync config to user failed:{}", e),
_ => {}
}
tokio::spawn(async move {
log::info!(
"watching config dir: {}",
Config::path("").to_str().unwrap().to_string()
);
let (tx, rx) = std::sync::mpsc::channel();
let mut watcher = watcher(tx, Duration::from_secs(2)).unwrap();
watcher
.watch(Config::path("").as_path(), RecursiveMode::Recursive)
.unwrap();
for i in 1..=6 {
sleep(i as f32 * 0.3).await;
match crate::ipc::connect(1000, "_service").await {
Ok(mut conn) => {
if conn.send(&Data::SyncConfig(None)).await.is_ok() {
if let Ok(Some(data)) = conn.next_timeout(1000).await {
match data {
Data::SyncConfig(Some((config, config2))) => {
let _chk = crate::ipc::CheckIfRestart::new();
Config::set(config);
Config2::set(config2);
log::info!("sync config from root");
}
_ => {}
};
};
}
let mut cfg0 = (Config::get(), Config2::get());
loop {
let ev = rx.recv();
match ev {
Ok(event) => match event {
notify::DebouncedEvent::Write(path) => {
log::info!(
"config file changed, call ipc_service to sync: {}",
path.to_str().unwrap().to_string()
);
match sync_config_to_root(&mut conn, path).await {
Err(e) => log::error!("sync config to root failed: {}", e),
_ => {}
}
sleep(0.3).await;
let cfg = (Config::get(), Config2::get());
if cfg != cfg0 {
cfg0 = cfg;
log::info!("config updated, sync to root");
match conn.send(&Data::SyncConfig(Some(cfg0.clone()))).await {
Err(e) => {
log::error!("sync config to root failed: {}", e);
}
x => {
log::debug!("another {:?}", x)
_ => {
conn.next_timeout(1000).await.ok();
}
},
Err(e) => println!("watch error: {:?}", e),
}
}
}
});
}
Err(_) => {
log::info!("connect ipc_service failed, skip config sync");
return;
}
Err(_) => {
log::info!("#{} try: failed to connect to ipc_service", i);
}
}
}
}
#[cfg(target_os = "macos")]
async fn sync_config_to_user(conn: &mut ConnectionTmpl<ConnectionClient>) -> ResultType<()> {
allow_err!(
conn.send(&Data::SyncConfigToUserReq {
username: crate::username(),
to: Config::path("").to_str().unwrap().to_string(),
})
.await
);
if let Some(data) = conn.next_timeout(2000).await? {
match data {
Data::SyncConfigToUserResp(success) => {
log::info!("copy and reload config dir success: {:?}", success);
}
_ => {}
};
};
Ok(())
}
#[cfg(target_os = "macos")]
async fn sync_config_to_root(
conn: &mut ConnectionTmpl<ConnectionClient>,
from: std::path::PathBuf,
) -> ResultType<()> {
allow_err!(
conn.send(&Data::SyncConfigToRootReq {
from: from.to_str().unwrap().to_string()
})
.await
);
// todo: this code will block outer loop, resolve it later.
// if let Some(data) = conn.next_timeout(2000).await? {
// match data {
// Data::SyncConfigToRootResp(success) => {
// log::info!("copy config to root dir success: {:?}", success);
// }
// x => {
// log::info!("receive another {:?}", x)
// }
// };
// };
Ok(())
log::error!("skipped config sync");
}

View File

@ -8,7 +8,7 @@ use crate::common::SOFTWARE_UPDATE_URL;
use crate::ipc;
use hbb_common::{
allow_err,
config::{self, Config, Fav, PeerConfig, APP_NAME, ICON},
config::{self, Config, LocalConfig, PeerConfig, APP_NAME, ICON},
log, sleep,
tokio::{self, time},
};
@ -221,11 +221,11 @@ impl UI {
}
fn get_remote_id(&mut self) -> String {
Config::get_remote_id()
LocalConfig::get_remote_id()
}
fn set_remote_id(&mut self, id: String) {
Config::set_remote_id(&id);
LocalConfig::set_remote_id(&id);
}
fn goto_install(&mut self) {
@ -275,7 +275,11 @@ impl UI {
}
fn get_local_option(&self, key: String) -> String {
Config::get_option(&key)
LocalConfig::get_option(&key)
}
fn set_local_option(&self, key: String, value: String) {
LocalConfig::set_option(key, value);
}
fn peer_has_password(&self, id: String) -> bool {
@ -353,6 +357,13 @@ impl UI {
}
fn set_option(&self, key: String, value: String) {
#[cfg(target_os = "macos")]
if &key == "stop-service" {
let is_stop = value == "Y";
if is_stop && crate::platform::macos::uninstall() {
return;
}
}
let mut options = self.2.lock().unwrap();
if value.is_empty() {
options.remove(&key);
@ -360,11 +371,6 @@ impl UI {
options.insert(key.clone(), value.clone());
}
ipc::set_options(options.clone()).ok();
#[cfg(target_os = "macos")]
if &key == "stop-service" {
crate::platform::macos::launch(value != "Y");
}
}
// TODO: ui prompt
@ -431,11 +437,11 @@ impl UI {
fn save_size(&mut self, x: i32, y: i32, w: i32, h: i32) {
crate::server::input_service::fix_key_down_timeout_at_exit();
Config::set_size(x, y, w, h);
LocalConfig::set_size(x, y, w, h);
}
fn get_size(&mut self) -> Value {
let s = Config::get_size();
let s = LocalConfig::get_size();
let mut v = Value::array(0);
v.push(s.0);
v.push(s.1);
@ -470,7 +476,7 @@ impl UI {
}
fn get_fav(&self) -> Value {
Value::from_iter(Fav::load().peers)
Value::from_iter(LocalConfig::get_fav())
}
fn store_fav(&self, fav: Value) {
@ -482,10 +488,11 @@ impl UI {
}
}
});
Fav::store(tmp);
LocalConfig::set_fav(tmp);
}
fn get_recent_sessions(&mut self) -> Value {
// to-do: limit number of recent sessions, and remove old peer file
let peers: Vec<Value> = PeerConfig::peers()
.drain(..)
.map(|p| Self::get_peer_value(p.0, p.2))
@ -701,6 +708,7 @@ impl sciter::EventHandler for UI {
fn get_options();
fn get_option(String);
fn get_local_option(String);
fn set_local_option(String, String);
fn get_peer_option(String, String);
fn peer_has_password(String);
fn forget_password(String);
@ -830,7 +838,7 @@ fn check_connect_status(
reconnect: bool,
) -> (Arc<Mutex<(i32, bool)>>, Arc<Mutex<HashMap<String, String>>>) {
let status = Arc::new(Mutex::new((0, false)));
let options = Arc::new(Mutex::new(HashMap::new()));
let options = Arc::new(Mutex::new(Config::get_options()));
let cloned = status.clone();
let cloned_options = options.clone();
std::thread::spawn(move || check_connect_status_(reconnect, cloned, cloned_options));

View File

@ -66,7 +66,7 @@ class SessionStyle: Reactor.Component {
event click $(span.inactive) {
var option = getSessionsStyleOption(this.type);
var sessionsStyle = getSessionsStyle(this.type);
handler.set_option(option, sessionsStyle == "tile" ? "list" : "tile");
handler.set_local_option(option, sessionsStyle == "tile" ? "list" : "tile");
app.multipleSessions.update();
}
}
@ -294,7 +294,7 @@ class MultipleSessions: Reactor.Component {
if (el.id == "lan") {
discover();
}
handler.set_option('show-sessions-type', el.id || "");
handler.set_local_option('show-sessions-type', el.id || "");
this.stupidUpdate();
}

View File

@ -7,7 +7,7 @@ view.windowMinSize = (500, 300);
var app;
var tmp = handler.get_connect_status();
var connect_status = tmp[0];
var service_stopped = false;
var service_stopped = handler.get_option("stop-service") == "Y";
var software_update_url = "";
var key_confirmed = tmp[1];
var system_error = "";
@ -368,7 +368,7 @@ class App: Reactor.Component
{is_win && handler.is_installed() && !software_update_url && handler.is_installed_lower_version() ? <UpgradeMe /> : ""}
{is_can_screen_recording ? "": <CanScreenRecording />}
{is_can_screen_recording && !handler.is_process_trusted(false) ? <TrustMe /> : ""}
{is_can_screen_recording && handler.is_process_trusted(false) && handler.is_installed() && !handler.is_installed_daemon(false) ? <InstallDaemon /> : ""}
{!service_stopped && is_can_screen_recording && handler.is_process_trusted(false) && handler.is_installed() && !handler.is_installed_daemon(false) ? <InstallDaemon /> : ""}
{system_error ? <SystemError /> : ""}
{!system_error && handler.is_login_wayland() && !handler.current_is_wayland() ? <FixWayland /> : ""}
{!system_error && handler.current_is_wayland() ? <ModifyDefaultLogin /> : ""}
@ -772,8 +772,7 @@ function checkConnectStatus() {
var tmp = !!handler.get_option("stop-service");
if (tmp != service_stopped) {
service_stopped = tmp;
app.connect_status.update();
myIdMenu.update();
app.update();
}
tmp = handler.get_connect_status();
if (tmp[0] != connect_status) {