diff --git a/guest_server/main.go b/guest_server/main.go index 26b41201..5ed7179e 100644 --- a/guest_server/main.go +++ b/guest_server/main.go @@ -6,6 +6,7 @@ package main import ( "bytes" "encoding/json" + "fmt" "io" "log" "net/http" @@ -156,6 +157,37 @@ func getRdpConnectedStatus(w http.ResponseWriter, r *http.Request) { w.Write(jsonResponse) } +type ProcessStatusResponse struct { + Running bool `json:"running"` +} + +func getProcessStatus(w http.ResponseWriter, r *http.Request) { + path := r.URL.Query().Get("path") + if path == "" { + http.Error(w, "path query param required", http.StatusBadRequest) + return + } + + // Use PowerShell to check if process with matching path is running + // - Expand environment variables in the input path + // - Use case-insensitive comparison (-ieq) + escapedPath := strings.ReplaceAll(path, "'", "''") + psCommand := fmt.Sprintf( + "$p=[Environment]::ExpandEnvironmentVariables('%s') -replace '/','\\'; if(Get-Process | Where-Object {$_.Path -ieq $p} | Select-Object -First 1){'1'}else{'0'}", + escapedPath, + ) + cmd := exec.Command("powershell", "-NoProfile", "-NoLogo", "-Command", psCommand) + output, _ := cmd.Output() + + response := ProcessStatusResponse{ + Running: strings.TrimSpace(string(output)) == "1", + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(response) +} + func applyUpdate(w http.ResponseWriter, r *http.Request) { // Verify password expectedHash, err := getSecureRegKey(AUTHKEY_HASH_REG) @@ -334,6 +366,7 @@ func main() { r.HandleFunc("/version", getVersion).Methods("GET") r.HandleFunc("/metrics", getMetrics).Methods("GET") r.HandleFunc("/rdp/status", getRdpConnectedStatus).Methods("GET") + r.HandleFunc("/process/status", getProcessStatus).Methods("GET") r.HandleFunc("/update", applyUpdate).Methods("POST") r.HandleFunc("/get-icon", getIcon).Methods("POST") r.HandleFunc("/auth/set-hash", setAuthHash).Methods("POST") diff --git a/src/renderer/lib/winboat.ts b/src/renderer/lib/winboat.ts index 45eed617..3190f3e4 100644 --- a/src/renderer/lib/winboat.ts +++ b/src/renderer/lib/winboat.ts @@ -428,6 +428,25 @@ export class Winboat { return status.rdpConnected; } + /** + * Checks if a process with the given executable path is running in the Windows guest + * @param path The executable path to check + * @returns true if the process is running, false otherwise + */ + async isProcessRunning(path: string): Promise { + try { + const res = await nodeFetch(`${this.apiUrl}/process/status?path=${encodeURIComponent(path)}`, { + signal: AbortSignal.timeout(FETCH_TIMEOUT), + }); + const data = (await res.json()) as { running: boolean }; + logger.info(`Process ${path} is running: ${data.running}`); + return data.running; + } catch (err) { + logger.warn(`isProcessRunning failed for ${path}: ${err}`); + return false; + } + } + static readCompose(composePath: string): ComposeConfig { const composeFile = fs.readFileSync(composePath, "utf-8"); const composeContents = YAML.parse(composeFile) as ComposeConfig; diff --git a/src/renderer/views/Apps.vue b/src/renderer/views/Apps.vue index 9ea75e42..c51b8ca0 100644 --- a/src/renderer/views/Apps.vue +++ b/src/renderer/views/Apps.vue @@ -1,5 +1,23 @@