Implement auto-update routine
build-windows / build-hello-agent-x64 (push) Successful in 5m5s
build-windows / sign-hello-agent-x64 (push) Successful in 5s
build-windows / validate-hello-agent-x64 (push) Successful in 6s

This commit is contained in:
2026-05-21 13:34:02 +02:00
parent d10e547b70
commit e45abbe64d
10 changed files with 654 additions and 201 deletions
+45 -3
View File
@@ -31,6 +31,13 @@ pub enum Action {
/// — every `Data::FS(...)` frame the server sends is executed here, in
/// the user's security context.
Cm,
/// `--update`. Self-replacement entry point launched as an elevated child
/// by the running service's updater (see `librustdesk::updater`) after it
/// has downloaded and SHA256-verified a new hello-agent.exe from the
/// Gitea releases page. `current_exe()` here points at the staged new
/// binary in `%TEMP%`; it copies itself over the installed location and
/// restarts the service via `librustdesk::platform::update_me`.
Update,
}
#[derive(Debug)]
@@ -47,6 +54,7 @@ impl ParsedArgs {
let mut service = false;
let mut server = false;
let mut cm = false;
let mut update = false;
let mut config_blob: Option<String> = None;
let mut i = 0;
@@ -56,6 +64,7 @@ impl ParsedArgs {
"--uninstall" => uninstall = true,
"--service" => service = true,
"--server" => server = true,
"--update" => update = true,
// Connection-manager popup mode. Treat `--cm-no-ui` (the
// Linux-headless variant librustdesk also tries) as a
// synonym; either way we run cm_popup.
@@ -81,14 +90,21 @@ impl ParsedArgs {
}
// Mutual-exclusion rules. --install + --config is the MDM one-liner;
// everything else is one-action-at-a-time.
let exclusive = [uninstall, service, server, cm].iter().filter(|x| **x).count();
// everything else is one-action-at-a-time. --update is launched by
// the updater as a standalone elevated child, never combined.
let exclusive = [uninstall, service, server, cm, update]
.iter()
.filter(|x| **x)
.count();
if exclusive > 1 {
bail!("--uninstall, --service, --server, --cm are mutually exclusive");
bail!("--uninstall, --service, --server, --cm, --update are mutually exclusive");
}
if uninstall && (install || config_blob.is_some()) {
bail!("--uninstall cannot be combined with other flags");
}
if update && (install || config_blob.is_some()) {
bail!("--update cannot be combined with other flags");
}
let action = if uninstall {
Action::Uninstall
@@ -100,6 +116,8 @@ impl ParsedArgs {
Action::Server
} else if cm {
Action::Cm
} else if update {
Action::Update
} else if config_blob.is_some() {
Action::ConfigOnly
} else {
@@ -131,6 +149,10 @@ OPTIONS:
--service SCM entry point. Do not invoke manually.
--server Worker mode (launched by the service shell into
the active console session).
--update Self-replacement entry point. Launched by the
running service's updater after downloading and
SHA256-verifying a new release from Gitea. Do
not invoke manually.
-h, --help Show this help.
-V, --version Show version.
@@ -191,4 +213,24 @@ mod tests {
fn unknown_arg() {
assert!(parse(&["--no-such-flag"]).is_err());
}
#[test]
fn update_alone() {
assert_eq!(parse(&["--update"]).unwrap().action, Action::Update);
}
#[test]
fn update_install_conflict() {
assert!(parse(&["--update", "--install"]).is_err());
}
#[test]
fn update_service_conflict() {
assert!(parse(&["--update", "--service"]).is_err());
}
#[test]
fn update_config_conflict() {
assert!(parse(&["--update", "--config", "BLOB"]).is_err());
}
}