app
Adom Desktop - RustDesk Bridge
Public Made by Adomby adom
Drive RustDesk remote-desktop sessions from cloud Claude via Adom Desktop — connect out to any host by ID or IP (with a password), and list/close sessions. Works where RDP can't (Windows Home).
← Commit history
Ship 0.3.1 client-side idle auto-disconnect safeguard (GetLastInputInfo); host untouched
2 files changed
+50−4
BRIDGE_VERSION+1−1@@ -1 +1 @@-0.3.0+0.3.1
server.py+49−3@@ -23,10 +23,11 @@ import sys import threading import time import urllib.request+import ctypes from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer BRIDGE_NAME = "rustdesk"-BRIDGE_VERSION = "0.3.0"+BRIDGE_VERSION = "0.3.1" DEFAULT_PORT = 8810 RUSTDESK_DL_URL = "https://github.com/rustdesk/rustdesk/releases/download/1.4.8/rustdesk-1.4.8-x86_64.exe" @@ -38,6 +39,13 @@ _START = time.time() _dl_lock = threading.Lock() _dl = {"state": "idle", "pct": 0, "path": None, "error": None} +# ---- safeguard: auto-disconnect a session when THIS (client) machine goes idle ----+# A live RustDesk client session keeps the local display awake (like media playback).+# So if the user walks away (no input on this laptop) we drop the session -> the screen+# can sleep/screensaver normally. Active use resets the timer (mouse/keys into the+# session ARE local input). The HOST is untouched. 0 disables. Default 10 min.+IDLE_DISCONNECT_SECS = int(os.environ.get("RUSTDESK_IDLE_DISCONNECT_SECS", "600"))+ # ---------------------------------------------------------------- helpers def _candidate_exes():@@ -114,6 +122,42 @@ def _download_client(): _dl.update(state="error", error=str(e)) +def _user_idle_secs():+ """Seconds since the last user input on THIS (client) machine. 0 on non-Windows/error."""+ try:+ class _LII(ctypes.Structure):+ _fields_ = [("cbSize", ctypes.c_uint), ("dwTime", ctypes.c_uint)]+ lii = _LII()+ lii.cbSize = ctypes.sizeof(lii)+ if ctypes.windll.user32.GetLastInputInfo(ctypes.byref(lii)):+ tick = ctypes.windll.kernel32.GetTickCount()+ return max(0, (int(tick) - int(lii.dwTime)) // 1000)+ except Exception:+ pass+ return 0+++def _idle_monitor():+ """Drop active sessions once the local user has been idle past IDLE_DISCONNECT_SECS,+ so the client's screen can sleep. Never touches the host side."""+ while True:+ time.sleep(30)+ limit = IDLE_DISCONNECT_SECS+ if limit <= 0:+ continue+ sess = _sessions()+ if sess and _user_idle_secs() >= limit:+ for s in sess:+ try:+ subprocess.run(["taskkill", "/PID", str(s["pid"]), "/F"],+ capture_output=True, timeout=10, creationflags=_NO_WINDOW)+ except Exception:+ pass+ sys.stderr.write("rustdesk bridge: auto-disconnected %d idle session(s) after %ds idle\n"+ % (len(sess), limit))+ sys.stderr.flush()++ # ---------------------------------------------------------------- verbs def v_connect(args): to = (args.get("to") or args.get("id") or args.get("ip") or "").strip()@@ -136,7 +180,7 @@ def v_connect(args): "_hint": "The client exe was found but wouldn't launch. Check rustdesk_client_status; the exe path may be stale."} return {"success": True, "output": "connecting to %s" % to, "to": to, "pid": p.pid, "withPassword": bool(pw), "exe": exe,- "_hint": "Session window opens as '%s - Remote Desktop - RustDesk'. Confirm with rustdesk_client_status; close with rustdesk_disconnect. Without a password it waits at a prompt on the controlling machine." % to}+ "_hint": "Session window opens as '%s - Remote Desktop - RustDesk'. NOTE: while open this keeps the CONTROLLING machine's display awake (RustDesk treats it like live playback) - the bridge auto-disconnects after %ds of local idle so the screen can still sleep; close sooner with rustdesk_disconnect. Confirm with rustdesk_client_status; without a password it waits at a prompt on the controlling machine." % (to, IDLE_DISCONNECT_SECS)} def v_disconnect(args):@@ -366,8 +410,10 @@ def _parse_port(argv): def main(): port = _parse_port(sys.argv[1:]) srv = ThreadingHTTPServer(("127.0.0.1", port), Handler)- sys.stderr.write("rustdesk bridge v%s listening on 127.0.0.1:%d\n" % (BRIDGE_VERSION, port))+ sys.stderr.write("rustdesk bridge v%s listening on 127.0.0.1:%d (idle-disconnect %ds)\n"+ % (BRIDGE_VERSION, port, IDLE_DISCONNECT_SECS)) sys.stderr.flush()+ threading.Thread(target=_idle_monitor, daemon=True).start() srv.serve_forever()