diff --git a/apps/desktop/src-tauri/src/rustdesk.rs b/apps/desktop/src-tauri/src/rustdesk.rs index 461792d..c9a83b1 100644 --- a/apps/desktop/src-tauri/src/rustdesk.rs +++ b/apps/desktop/src-tauri/src/rustdesk.rs @@ -431,6 +431,23 @@ fn ensure_service_running(exe_path: &Path) -> Result<(), RustdeskError> { } Err(error) => Err(error), } + + // Revalida se o serviço realmente subiu; se não, reinstala e tenta novamente. + match query_service_state() { + Some(state) if state.eq_ignore_ascii_case("running") => Ok(()), + _ => { + log_event("Serviço RustDesk não está em execução após tentativa de start; reaplicando --install-service e start"); + let _ = run_with_args(exe_path, &["--install-service"]); + let _ = run_sc(&["config", SERVICE_NAME, &format!("start= {}", "auto")]); + start_sequence().or_else(|error| { + log_event(&format!( + "Falha ao subir o serviço RustDesk mesmo após reinstalação: {error}" + )); + Ok(()) + })?; + Ok(()) + } + } } fn configure_service_startup() -> Result<(), RustdeskError> { @@ -451,6 +468,30 @@ fn configure_service_startup() -> Result<(), RustdeskError> { Ok(()) } +fn query_service_state() -> Option { + let output = hidden_command("sc") + .args(["query", SERVICE_NAME]) + .output() + .ok()?; + if !output.status.success() { + return None; + } + let stdout = String::from_utf8_lossy(&output.stdout); + for line in stdout.lines() { + if let Some(pos) = line.find("STATE") { + // Example: " STATE : 4 RUNNING" + let state = line[pos..].to_string(); + if state.to_lowercase().contains("running") { + return Some("running".to_string()); + } + if state.to_lowercase().contains("stopped") { + return Some("stopped".to_string()); + } + } + } + None +} + fn stop_rustdesk_processes() -> Result<(), RustdeskError> { if let Err(error) = try_stop_service() { log_event(&format!( diff --git a/docs/RUSTDESK-PROVISIONING.md b/docs/RUSTDESK-PROVISIONING.md index 6e6788c..42a50ee 100644 --- a/docs/RUSTDESK-PROVISIONING.md +++ b/docs/RUSTDESK-PROVISIONING.md @@ -54,7 +54,7 @@ Fluxo ideal: - Reinicia serviço `RustDesk` (`sc start RustDesk` — pode falhar com `status Some(5)` se não há privilégio admin). Mesmo com falha, a CLI continua e grava o ID nos arquivos. - **Autoelevação única**: na primeira execução do botão “Preparar”, o Raven dispara um PowerShell elevado (`takeown + icacls`) para liberar ACL dos perfis `LocalService` e `LocalSystem`. O sucesso grava `rustdeskAclUnlockedAt` dentro de `%LOCALAPPDATA%\br.com.esdrasrenan.sistemadechamados\machine-agent.json` e cria o flag `rustdesk_acl_unlocked.flag`, evitando novos prompts de UAC nas execuções seguintes. - **Kill/restart seguro**: antes de tocar nos TOML, o Raven roda `sc stop RustDesk` + `taskkill /F /T /IM rustdesk.exe`. Isso garante que nenhum cliente sobrescreva o `RustDesk_local.toml` enquanto aplicamos a senha. - - **Serviço em background reforçado**: `ensure_service_running` sempre instala o serviço, força `start= auto` e aplica `sc failure ... actions= restart/5000/...` para reiniciar o RustDesk automaticamente em caso de falha. Assim ele permanece no background/bandeja após boot, sem depender do usuário abrir a UI. + - **Serviço em background reforçado**: `ensure_service_running` sempre instala o serviço, força `start= auto`, aplica `sc failure ... actions= restart/5000/...` e revalida se o serviço ficou em `RUNNING`. Se não subir, reaplica `--install-service` + `sc start` antes de seguir. Assim ele permanece no background/bandeja após boot, sem depender do usuário abrir a UI. - **Replicação completa de perfis**: após aplicar `--password`, limpamos quaisquer arquivos antigos (`RustDesk*.toml`, `password`, `passwd*`) em `%APPDATA%`, `ProgramData`, `LocalService` e `LocalSystem` e, em seguida, reescrevemos tudo. Agora os `RustDesk2.toml` herdados recebem `verification-method = "use-permanent-password"` e `approve-mode = "password"` no bloco `[options]` antes mesmo do serviço subir, evitando que o RustDesk volte para "Use both". - **Validação por arquivo**: o Raven agora registra no `rustdesk.log` se o `password` gravado em cada `RustDesk_local.toml` coincide com o PIN configurado. Para inspecionar manualmente, rode no PowerShell (e valide que todas as linhas exibem o PIN esperado):