From 8c8e7a6147787c1b2e915a76bcf2cb26411df9e0 Mon Sep 17 00:00:00 2001 From: alexveley Date: Wed, 24 Jun 2026 01:58:34 -0400 Subject: [PATCH] Update pve RustDesk GA sync scripts --- blair-sync-rustdesk-via-ga.sh | 80 ++++++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 25 deletions(-) diff --git a/blair-sync-rustdesk-via-ga.sh b/blair-sync-rustdesk-via-ga.sh index 168938e..5d34460 100644 --- a/blair-sync-rustdesk-via-ga.sh +++ b/blair-sync-rustdesk-via-ga.sh @@ -14,6 +14,7 @@ fi exec python3 - <<'PY' import base64 +import binascii import json import os import re @@ -173,26 +174,51 @@ def guest_exec_text(vmid: int, command: list[str], timeout: int = 90) -> tuple[s return None, 'guest exec timeout' +def decode_agent_file_content(raw) -> str | None: + if raw is None: + return None + if isinstance(raw, bytes): + return raw.decode('utf-8-sig', errors='replace') + text = str(raw).strip() + if not text: + return None + # pvesh may return decoded file body (JSON/TOML/plain text). + if text[0] in '{[#' or 'rustdesk_id' in text or re.search(r'(?m)^\s*id\s*=', text): + return text.lstrip('\ufeff') + ascii_blob = ''.join(text.split()) + if not ascii_blob: + return None + try: + decoded = base64.b64decode(ascii_blob, validate=True) + return decoded.decode('utf-8-sig', errors='replace') + except (ValueError, binascii.Error): + return text.lstrip('\ufeff') + + def guest_file_read(vmid: int, guest_path: str) -> tuple[str | None, str | None]: for path in {guest_path, guest_path.replace('\\', '/')}: - proc = subprocess.run( - [ - 'pvesh', 'get', f'/nodes/{NODE}/qemu/{vmid}/agent/file-read', - '--file', path, '--output-format', 'json', - ], - capture_output=True, text=True, check=False, - ) - if proc.returncode != 0: - continue try: + proc = subprocess.run( + [ + 'pvesh', 'get', f'/nodes/{NODE}/qemu/{vmid}/agent/file-read', + '--file', path, '--output-format', 'json', + ], + capture_output=True, text=True, check=False, + ) + if proc.returncode != 0: + continue payload = json.loads(proc.stdout) - except json.JSONDecodeError: + data = payload.get('data', payload) + if not isinstance(data, dict): + continue + raw = data.get('content') + if raw is None: + continue + text = decode_agent_file_content(raw) + if text: + return text, None + except (json.JSONDecodeError, ValueError, UnicodeError): continue - data = payload.get('data', payload) - content_b64 = data.get('content') if isinstance(data, dict) else None - if not content_b64: - continue - return base64.b64decode(content_b64).decode('utf-8', errors='replace'), None return None, f'file-read failed for {guest_path}' @@ -230,17 +256,21 @@ def guest_exec_powershell(vmid: int) -> tuple[str | None, str | None]: def read_rustdesk_id(vmid: int) -> tuple[str | None, str | None]: errors: list[str] = [] for path in GUEST_READ_PATHS: - text, err = guest_file_read(vmid, path) - if not text: - if VERBOSE: - errors.append(f'{path}: {err}') + try: + text, err = guest_file_read(vmid, path) + if not text: + if VERBOSE: + errors.append(f'{path}: {err}') + continue + rid = parse_id_from_content(text, path) + if rid: + if VERBOSE: + log(f'VM {vmid}: ID {rid} from file-read {path}') + return rid, None + errors.append(f'{path}: no id in file') + except Exception as exc: # noqa: BLE001 — keep sync loop alive + errors.append(f'{path}: {exc}') continue - rid = parse_id_from_content(text, path) - if rid: - if VERBOSE: - log(f'VM {vmid}: ID {rid} from file-read {path}') - return rid, None - errors.append(f'{path}: no id in file') rid, err = guest_exec_powershell(vmid) if rid: