refactor mac service

This commit is contained in:
rustdesk 2022-01-17 12:05:06 +08:00
parent a12f24bf16
commit 5af1258454
22 changed files with 173 additions and 171 deletions

View File

@ -445,6 +445,15 @@ async fn _check_software_update() -> hbb_common::ResultType<()> {
Ok(())
}
#[cfg(target_os = "macos")]
pub fn get_full_name() -> String {
format!(
"{}.{}",
hbb_common::config::ORG,
hbb_common::config::APP_NAME,
)
}
pub fn is_ip(id: &str) -> bool {
hbb_common::regex::Regex::new(r"^\d+\.\d+\.\d+\.\d+$")
.unwrap()

View File

@ -23,7 +23,8 @@ pub fn translate_locale(name: String, locale: &str) -> String {
.unwrap_or_default()
.to_owned();
}
let m = match lang.to_lowercase().as_str() {
let lang = lang.to_lowercase();
let m = match lang.as_str() {
"fr" => fr::T.deref(),
"cn" => cn::T.deref(),
"it" => it::T.deref(),
@ -32,6 +33,11 @@ pub fn translate_locale(name: String, locale: &str) -> String {
if let Some(v) = m.get(&name as &str) {
v.to_string()
} else {
if lang != "en" {
if let Some(v) = en::T.get(&name as &str) {
return v.to_string();
}
}
name
}
}

View File

@ -3,7 +3,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
[
("Status", "状态"),
("Your Desktop", "你的桌面"),
("desk_tip", "你的桌面可以通过下面的 ID和密码访问。"),
("desk_tip", "你的桌面可以通过下面的ID和密码访问。"),
("Password", "密码"),
("Ready", "就绪"),
("connecting_status", "正在接入RustDesk网络..."),
@ -109,6 +109,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("OS Password", "操作系统密码"),
("install_tip", "你正在运行未安装版本由于UAC限制作为被控端会在某些情况下无法控制鼠标键盘或者录制屏幕请点击下面的按钮将RustDesk安装到系统从而规避上述问题。"),
("Click to upgrade", "点击这里升级"),
("Click to download", "点击这里下载"),
("Click to update", "点击这里更新"),
("Configuration Permissions", "配置权限"),
("Configure", "配置"),
("config_acc", "为了能够远程控制你的桌面, 请给予RustDesk\"辅助功能\" 权限。"),
@ -197,6 +199,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Socks5 Proxy", "Socks5 代理"),
("Hostname", "主机名"),
("Discovered", "已发现"),
("install_daemon","为了能够提供更好的\n远程桌面访问功能RustDesk\n需要\"安装系统服务\"")
("install_daemon_tip","为了开机启动,请安装系统服务")
].iter().cloned().collect();
}

View File

@ -16,5 +16,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("whitelist_sep", "Seperated by comma, semicolon, spaces or new line"),
("Wrong credentials", "Wrong username or password"),
("invalid_http", "must start with http:// or https://"),
("install_daemon_tip","For starting on boot, you need to install system service.")
].iter().cloned().collect();
}

View File

@ -109,6 +109,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("OS Password", "Mot de passe du système d'exploitation"),
("install_tip", "Vous utilisez une version désinstallée. En raison des restrictions UAC, en tant que terminal contrôlé, dans certains cas, il ne sera pas en mesure de contrôler la souris et le clavier ou d'enregistrer l'écran. Veuillez cliquer sur le bouton ci-dessous pour installer RustDesk au système pour éviter la question ci-dessus."),
("Click to upgrade", "Cliquez pour mettre à niveau"),
("Click to download", "Cliquez pour télécharger"),
("Click to update", "Cliquez pour mettre à jour"),
("Configuration Permissions", "Autorisations de configuration"),
("Configure", "Configurer"),
("config_acc", "Afin de pouvoir contrôler votre bureau à distance, veuillez donner l'autorisation\"accessibilité\" à RustDesk."),

View File

@ -109,6 +109,8 @@ lazy_static::lazy_static! {
("OS Password", "Password del sistema operativo"),
("install_tip", "A causa del Controllo Account Utente, RustDesk potrebbe non funzionare correttamente come desktop remoto. Per evitare questo problema, fai click sul tasto qui sotto per installare RustDesk a livello di sistema."),
("Click to upgrade", "Fai click per aggiornare"),
("Click to download", "Cliquez per scaricare"),
("Click to update", "Fare clic per aggiornare"),
("Configuration Permissions", "Permessi di configurazione"),
("Configure", "Configura"),
("config_acc", "Per controllare il tuo desktop dall'esterno, devi fornire a RustDesk il permesso \"Accessibilità\"."),
@ -193,4 +195,4 @@ lazy_static::lazy_static! {
("Discovered", "Scoperto"),
].iter().cloned().collect();
}

View File

@ -102,13 +102,6 @@ fn main() {
}
return;
}
#[cfg(target_os = "macos")]
if args[0] == "--daemon" {
log::info!("start --daemon");
crate::platform::start_daemon();
return;
}
}
ui::start(&mut args[..]);
}

View File

@ -240,7 +240,7 @@ pub fn start_os_service() {
if let Some(ps) = server.take().as_mut() {
allow_err!(ps.kill());
}
println!("Exit");
log::info!("Exit");
}
fn get_active_userid() -> String {

View File

@ -16,7 +16,7 @@ use core_graphics::{
display::{kCGNullWindowID, kCGWindowListOptionOnScreenOnly, CGWindowListCopyWindowInfo},
window::{kCGWindowName, kCGWindowOwnerPID},
};
use hbb_common::{allow_err, bail, log};
use hbb_common::{bail, log};
use include_dir::{include_dir, Dir};
use objc::{class, msg_send, sel, sel_impl};
use scrap::{libc::c_void, quartz::ffi::*};
@ -102,55 +102,38 @@ 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());
if !prompt {
if !std::path::Path::new("/Library/LaunchDaemons/com.carriez.rustdesk.daemon.plist")
.exists()
{
if !std::path::Path::new(&format!("/Library/LaunchDaemons/{}", daemon)).exists() {
return false;
}
if !std::path::Path::new("/Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist")
.exists()
{
if !std::path::Path::new(&format!("/Library/LaunchAgents/{}", agent)).exists() {
return false;
}
if !std::path::Path::new("/Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist")
.exists()
{
return false;
}
return true;
}
let install_script = PRIVILEGES_SCRIPTS_DIR.get_file("install.scpt").unwrap();
let install_script_body = install_script.contents_utf8().unwrap();
let daemon_plist = PRIVILEGES_SCRIPTS_DIR
.get_file("com.carriez.rustdesk.daemon.plist")
.unwrap();
let daemon_plist = PRIVILEGES_SCRIPTS_DIR.get_file(&daemon).unwrap();
let daemon_plist_body = daemon_plist.contents_utf8().unwrap();
let root_agent_plist = PRIVILEGES_SCRIPTS_DIR
.get_file("com.carriez.rustdesk.agent.root.plist")
.unwrap();
let root_agent_plist_body = root_agent_plist.contents_utf8().unwrap();
let user_agent_plist = PRIVILEGES_SCRIPTS_DIR
.get_file("com.carriez.rustdesk.agent.user.plist")
.unwrap();
let user_agent_plist_body = user_agent_plist.contents_utf8().unwrap();
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(root_agent_plist_body)
.arg(user_agent_plist_body)
.arg(agent_plist_body)
.arg(&get_active_username())
.spawn()
{
Ok(mut proc) => proc.wait().is_ok(),
Ok(mut proc) => {
std::process::exit(0);
}
Err(e) => {
log::error!("run osascript failed: {}", e);
false
@ -158,10 +141,14 @@ pub fn is_installed_daemon(prompt: bool) -> bool {
}
}
pub fn launch_or_stop_daemon(launch: bool) {
let mut script_filename = "launch_service.scpt";
if !launch {
script_filename = "stop_service.scpt";
pub fn launch(load: 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";
}
let script_file = PRIVILEGES_SCRIPTS_DIR.get_file(script_filename).unwrap();
@ -363,39 +350,66 @@ pub fn lock_screen() {
}
pub fn start_os_service() {
let mut server: Option<std::process::Child> = None;
let mut uid = "".to_owned();
loop {
let tmp = get_active_userid();
let mut start_new = false;
if tmp != uid && !tmp.is_empty() {
uid = tmp;
log::info!("active uid: {}", uid);
if let Some(ps) = server.as_mut() {
allow_err!(ps.kill());
}
}
if let Some(ps) = server.as_mut() {
match ps.try_wait() {
Ok(Some(_)) => {
server = None;
start_new = true;
}
_ => {}
}
} else {
start_new = true;
}
if start_new {
match crate::run_me(vec!["--server"]) {
Ok(ps) => server = Some(ps),
Err(err) => {
log::error!("Failed to start server: {}", err);
}
}
}
std::thread::sleep(std::time::Duration::from_millis(super::SERVICE_INTERVAL));
log::info!("{}", crate::username());
if let Err(err) = crate::ipc::start("_service") {
log::error!("Failed to start ipc_service: {}", err);
}
/* // somehow, below works fine if user logged in, but mouse/keyboard not work under prelogin.
// one solution to run --server as agent in prelogin,
// and run --server under --service via run_as_user if not in prelogin
// so that no multiple --server if multiple logged-in users
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
let running = Arc::new(AtomicBool::new(true));
let r = running.clone();
let mut uid = "".to_owned();
let mut server: Option<std::process::Child> = None;
if let Err(err) = ctrlc::set_handler(move || {
r.store(false, Ordering::SeqCst);
}) {
println!("Failed to set Ctrl-C handler: {}", err);
}
while running.load(Ordering::SeqCst) {
let tmp = get_active_userid();
let mut start_new = false;
if tmp != uid && !tmp.is_empty() {
uid = tmp;
log::info!("active uid: {}", uid);
if let Some(ps) = server.as_mut() {
hbb_common::allow_err!(ps.kill());
}
}
if let Some(ps) = server.as_mut() {
match ps.try_wait() {
Ok(Some(_)) => {
server = None;
start_new = true;
}
_ => {}
}
} else {
start_new = true;
}
if start_new {
match run_as_user("--server") {
Ok(Some(ps)) => server = Some(ps),
Err(err) => {
log::error!("Failed to start server: {}", err);
}
_ => { /*no hapen*/ }
}
}
std::thread::sleep(std::time::Duration::from_millis(super::SERVICE_INTERVAL));
}
if let Some(ps) = server.take().as_mut() {
hbb_common::allow_err!(ps.kill());
}
log::info!("Exit");
*/
}
pub fn toggle_blank_screen(_v: bool) {
@ -407,13 +421,11 @@ pub fn block_input(_v: bool) -> bool {
}
pub fn is_installed() -> bool {
true
}
pub fn start_daemon() {
log::info!("{}", crate::username());
if let Err(err) = crate::ipc::start("_daemon") {
log::error!("Failed to start ipc_daemon: {}", err);
std::process::exit(-1);
if let Ok(p) = std::env::current_exe() {
return p.to_str().unwrap_or_default().contains(&format!(
"/Applications/{}.app",
hbb_common::config::APP_NAME
));
}
false
}

View File

@ -3,10 +3,11 @@
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.carriez.rustdesk.agent.root</string>
<string>com.carriez.RustDesk_server</string>
<key>LimitLoadToSessionType</key>
<array>
<string>LoginWindow</string>
<string>LoginWindow</string>
<string>Aqua</string>
</array>
<key>KeepAlive</key>
<dict>
@ -25,4 +26,4 @@
<key>WorkingDirectory</key>
<string>/Applications/RustDesk.app/Contents/MacOS/</string>
</dict>
</plist>
</plist>

View File

@ -3,17 +3,17 @@
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.carriez.rustdesk.daemon</string>
<string>com.carriez.RustDesk_service</string>
<key>KeepAlive</key>
<true/>
<key>ProgramArguments</key>
<array>
<string>/Applications/RustDesk.app/Contents/MacOS/rustdesk</string>
<string>--daemon</string>
<string>--service</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>WorkingDirectory</key>
<string>/Applications/RustDesk.app/Contents/MacOS/</string>
</dict>
</plist>
</plist>

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.carriez.rustdesk.agent.user</string>
<key>LimitLoadToSessionType</key>
<array>
<string>Aqua</string>
</array>
<key>KeepAlive</key>
<dict>
<key>SuccessfulExit</key>
<false />
<key>AfterInitialDemand</key>
<false />
</dict>
<key>RunAtLoad</key>
<true />
<key>ProgramArguments</key>
<array>
<string>/Applications/RustDesk.app/Contents/MacOS/rustdesk</string>
<string>--server</string>
</array>
<key>WorkingDirectory</key>
<string>/Applications/RustDesk.app/Contents/MacOS/</string>
</dict>
</plist>

View File

@ -1,19 +1,19 @@
on run {daemon_file, root_agent_file, user_agent_file}
on run {daemon_file, agent_file, user}
set sh1 to "echo " & quoted form of daemon_file & " > /Library/LaunchDaemons/com.carriez.rustdesk.daemon.plist && chown root:wheel /Library/LaunchDaemons/com.carriez.rustdesk.daemon.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 root_agent_file & " > /Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist && chown root:wheel /Library/LaunchAgents/com.carriez.rustdesk.agent.root.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 "echo " & quoted form of user_agent_file & " > /Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist && chown root:wheel /Library/LaunchAgents/com.carriez.rustdesk.agent.user.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 "launchctl load -w /Library/LaunchDaemons/com.carriez.rustdesk.daemon.plist;"
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 load -w /Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist;"
set sh6 to "launchctl load -w /Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist;"
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 sh to sh1 & sh2 & sh3 & sh4 & sh5
do shell script sh with prompt "RustDesk want to install services" with administrator privileges
do shell script sh with prompt "RustDesk want to install daemon and agent" with administrator privileges
do shell script sh6
end run
end run

View File

@ -1,7 +0,0 @@
set sh1 to "launchctl load -w /Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist;"
set sh2 to "launchctl load -w /Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist;"
do shell script sh1 with prompt "RustDesk want to launch services" with administrator privileges
do shell script sh2

View File

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

View File

@ -1,7 +0,0 @@
set sh1 to "launchctl unload -w /Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist;"
set sh2 to "launchctl unload -w /Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist;"
do shell script sh1 with prompt "RustDesk want to stop services" with administrator privileges
do shell script sh2

View File

@ -0,0 +1,6 @@
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

@ -333,7 +333,7 @@ async fn sync_and_watch_config_dir() {
return;
}
match crate::ipc::connect(1000, "_daemon").await {
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),
@ -358,7 +358,7 @@ async fn sync_and_watch_config_dir() {
Ok(event) => match event {
notify::DebouncedEvent::Write(path) => {
log::info!(
"config file changed, call ipc_daemon to sync: {}",
"config file changed, call ipc_service to sync: {}",
path.to_str().unwrap().to_string()
);
@ -377,7 +377,7 @@ async fn sync_and_watch_config_dir() {
});
}
Err(_) => {
log::info!("connect ipc_daemon failed, skip config sync");
log::info!("connect ipc_service failed, skip config sync");
return;
}
}

View File

@ -366,7 +366,7 @@ impl UI {
#[cfg(target_os = "macos")]
if &key == "stop-service" {
crate::platform::macos::launch_or_stop_daemon(value != "Y");
crate::platform::macos::launch(value != "Y");
}
}

View File

@ -25,6 +25,11 @@ body {
color: color(text);
}
div {
word-wrap: break-word;
// word-break: break-all; // this will break english word
}
button.button {
height: 2em;
border-radius: 0.5em;
@ -257,8 +262,6 @@ div.msgbox div.right-side div {
div.msgbox div.text {
margin-top: 0.5em;
word-wrap: break-word;
word-break: break-all;
}
@media platform != "OSX" {

View File

@ -324,9 +324,11 @@ div.install-me, div.trust-me {
background: linear-gradient(left,#e242bc,#f4727c);
}
div.trust-me > div:nth-child(1),
div.install-me > div:nth-child(1) {
font-size: 1.2em;
font-weight: bold;
text-align: center;
margin-bottom: 0.5em;
}
@ -334,19 +336,16 @@ div.install-me > div:nth-child(2) {
line-height: 1.4em;
}
div.trust-me > div:nth-child(1) {
font-size: 1.2em;
text-align: center;
font-weight: bold;
margin-bottom: 0.5em;
#install-me.link {
margin-top: 0.5em;
}
div.trust-me > div:nth-child(2) {
text-align: center;
font-size: 0.9em;
margin-bottom: 1em;
}
div#install-me.link,
div.trust-me > div:nth-child(3) {
text-align: center;
font-size: 1.5em;

View File

@ -302,12 +302,12 @@ class App: Reactor.Component
<Password />
</div>
</div>
{handler.is_installed() ? "": <InstallMe />}
{handler.is_installed() && software_update_url ? <UpdateMe /> : ""}
{handler.is_installed() && !software_update_url && handler.is_installed_lower_version() ? <UpgradeMe /> : ""}
{!is_win || handler.is_installed() ? "": <InstallMe />}
{software_update_url ? <UpdateMe /> : ""}
{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_daemon(false) ? <InstallDaemon /> : ""}
{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 /> : ""}
@ -347,7 +347,7 @@ class InstallMe: Reactor.Component {
return <div .install-me>
<span />
<div>{translate('install_tip')}</div>
<div style="text-align: center; margin-top: 1em;"><button #install-me .button>{translate('Install')}</button></div>
<div><button #install-me .button>{translate('Install')}</button></div>
</div>;
}
@ -404,7 +404,7 @@ class UpgradeMe: Reactor.Component {
return <div .install-me>
<div>{translate('Status')}</div>
<div>{translate('Your installation is lower version.')}</div>
<div #install-me .link style="padding-top: 1em">{translate('Click to upgrade')}</div>
<div #install-me.link>{translate('Click to upgrade')}</div>
</div>;
}
@ -419,7 +419,7 @@ class UpdateMe: Reactor.Component {
return <div .install-me>
<div>{translate('Status')}</div>
<div>There is a newer version of {handler.get_app_name()} ({handler.get_new_version()}) available.</div>
<div #install-me .link style="padding-top: 1em">Click to {update_or_download}</div>
<div #install-me.link>{translate('Click to ' + update_or_download)}</div>
<div #download-percent style="display:hidden; padding-top: 1em;" />
</div>;
}
@ -494,16 +494,15 @@ class CanScreenRecording: Reactor.Component {
class InstallDaemon: Reactor.Component {
function render() {
return <div .trust-me>
<div>{translate('Configuration Permissions')}</div>
<div>{translate('install_daemon')}</div>
<div #install-daemon .link>{translate('Configure')}</div>
return <div .install-me>
<span />
<div>{translate('install_daemon_tip')}</div>
<div #install-me.link>{translate('Install')}</div>
</div>;
}
event click $(#install-daemon) {
event click $(#install-me) {
handler.is_installed_daemon(true);
watch_trust();
}
}
@ -543,14 +542,17 @@ class ModifyDefaultLogin: Reactor.Component {
function watch_trust() {
// not use TrustMe::update, because it is buggy
var trusted = handler.is_process_trusted(false) && handler.is_installed_daemon(false);
var trusted = handler.is_process_trusted(false);
var el = $(div.trust-me);
if (el) {
el.style.set {
display: trusted ? "none" : "block",
};
}
// if (trusted) return;
if (trusted) {
app.update();
return;
}
self.timer(1s, watch_trust);
}