fix: persist should_be_connected state to disk, restore on manager restart
This commit is contained in:
+28
-9
@@ -19,9 +19,27 @@ RDP_PASSWORD = os.environ.get("RDP_PASSWORD", "")
|
|||||||
RDP_DOMAIN = os.environ.get("RDP_DOMAIN", "")
|
RDP_DOMAIN = os.environ.get("RDP_DOMAIN", "")
|
||||||
RDP_SECURITY = os.environ.get("RDP_SECURITY", "")
|
RDP_SECURITY = os.environ.get("RDP_SECURITY", "")
|
||||||
|
|
||||||
|
STATE_FILE = "/tmp/rdp_state.json"
|
||||||
|
|
||||||
_lock = threading.Lock()
|
_lock = threading.Lock()
|
||||||
_proc: subprocess.Popen | None = None
|
_proc: subprocess.Popen | None = None
|
||||||
_should_be_connected = False # set True on /connect, False on /disconnect
|
_should_be_connected = False
|
||||||
|
|
||||||
|
|
||||||
|
def _save_state():
|
||||||
|
try:
|
||||||
|
with open(STATE_FILE, "w") as f:
|
||||||
|
json.dump({"should_be_connected": _should_be_connected}, f)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def _load_state() -> bool:
|
||||||
|
try:
|
||||||
|
with open(STATE_FILE) as f:
|
||||||
|
return json.load(f).get("should_be_connected", False)
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def _build_args():
|
def _build_args():
|
||||||
@@ -57,7 +75,6 @@ def _launch():
|
|||||||
|
|
||||||
|
|
||||||
def _monitor_loop():
|
def _monitor_loop():
|
||||||
"""Auto-reconnect if xfreerdp crashes while session should be active."""
|
|
||||||
while True:
|
while True:
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
with _lock:
|
with _lock:
|
||||||
@@ -69,9 +86,7 @@ def _monitor_loop():
|
|||||||
_launch()
|
_launch()
|
||||||
|
|
||||||
|
|
||||||
threading.Thread(target=_monitor_loop, daemon=True).start()
|
|
||||||
def _anti_idle_loop():
|
def _anti_idle_loop():
|
||||||
"""Move mouse inside xfreerdp window every 30s — works on any remote OS."""
|
|
||||||
env = {**os.environ, "DISPLAY": DISPLAY}
|
env = {**os.environ, "DISPLAY": DISPLAY}
|
||||||
toggle = False
|
toggle = False
|
||||||
while True:
|
while True:
|
||||||
@@ -87,29 +102,27 @@ def _anti_idle_loop():
|
|||||||
)
|
)
|
||||||
win_id = r.stdout.decode().strip().splitlines()[0] if r.stdout.strip() else ""
|
win_id = r.stdout.decode().strip().splitlines()[0] if r.stdout.strip() else ""
|
||||||
if win_id:
|
if win_id:
|
||||||
# Чередуем позицию — tiny mouse jiggle внутри окна xfreerdp
|
|
||||||
x, y = (960, 540) if toggle else (970, 550)
|
x, y = (960, 540) if toggle else (970, 550)
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
["xdotool", "mousemove", "--window", win_id, str(x), str(y)],
|
["xdotool", "mousemove", "--window", win_id, str(x), str(y)],
|
||||||
env=env, capture_output=True, timeout=5,
|
env=env, capture_output=True, timeout=5,
|
||||||
)
|
)
|
||||||
toggle = not toggle
|
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
["xdotool", "key", "--window", win_id, "--clearmodifiers", "shift"],
|
["xdotool", "key", "--window", win_id, "--clearmodifiers", "shift"],
|
||||||
env=env, capture_output=True, timeout=5,
|
env=env, capture_output=True, timeout=5,
|
||||||
)
|
)
|
||||||
log.debug("anti_idle mousemove window=%s pos=%s,%s", win_id, x, y)
|
toggle = not toggle
|
||||||
|
log.debug("anti_idle jiggle window=%s pos=%s,%s", win_id, x, y)
|
||||||
else:
|
else:
|
||||||
log.debug("anti_idle: xfreerdp window not found")
|
log.debug("anti_idle: xfreerdp window not found")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.debug("anti_idle error: %s", e)
|
log.debug("anti_idle error: %s", e)
|
||||||
|
|
||||||
|
|
||||||
|
threading.Thread(target=_monitor_loop, daemon=True).start()
|
||||||
threading.Thread(target=_anti_idle_loop, daemon=True).start()
|
threading.Thread(target=_anti_idle_loop, daemon=True).start()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Handler(BaseHTTPRequestHandler):
|
class Handler(BaseHTTPRequestHandler):
|
||||||
def log_message(self, fmt, *args):
|
def log_message(self, fmt, *args):
|
||||||
pass
|
pass
|
||||||
@@ -141,6 +154,7 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
if self.path == "/connect":
|
if self.path == "/connect":
|
||||||
with _lock:
|
with _lock:
|
||||||
_should_be_connected = True
|
_should_be_connected = True
|
||||||
|
_save_state()
|
||||||
if _proc is not None and _proc.poll() is None:
|
if _proc is not None and _proc.poll() is None:
|
||||||
self._json(200, {"ok": True, "pid": _proc.pid, "already": True})
|
self._json(200, {"ok": True, "pid": _proc.pid, "already": True})
|
||||||
return
|
return
|
||||||
@@ -149,6 +163,7 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
elif self.path == "/disconnect":
|
elif self.path == "/disconnect":
|
||||||
with _lock:
|
with _lock:
|
||||||
_should_be_connected = False
|
_should_be_connected = False
|
||||||
|
_save_state()
|
||||||
if _proc is not None:
|
if _proc is not None:
|
||||||
_proc.terminate()
|
_proc.terminate()
|
||||||
try:
|
try:
|
||||||
@@ -165,5 +180,9 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
if not RDP_HOST:
|
if not RDP_HOST:
|
||||||
log.warning("RDP_HOST not set — connect calls will fail")
|
log.warning("RDP_HOST not set — connect calls will fail")
|
||||||
|
if _load_state():
|
||||||
|
log.info("restoring state: reconnecting xfreerdp")
|
||||||
|
_should_be_connected = True
|
||||||
|
_launch()
|
||||||
log.info("manager started on :7001")
|
log.info("manager started on :7001")
|
||||||
HTTPServer(("0.0.0.0", 7001), Handler).serve_forever()
|
HTTPServer(("0.0.0.0", 7001), Handler).serve_forever()
|
||||||
|
|||||||
Reference in New Issue
Block a user