Enforce single instance Local Agent supervisor worker and dashboard

This commit is contained in:
A R R R Associates
2026-09-03 14:03:26 +05:30
parent 010d0969b4
commit 5dce7f16f9
7 changed files with 267 additions and 3 deletions
@@ -1,6 +1,10 @@
from __future__ import annotations
import ctypes
from ctypes import wintypes
import hashlib
import os
import atexit
from pathlib import Path
import subprocess
import sys
@@ -16,6 +20,63 @@ DATA_DIR = INSTALL_ROOT / "data"
SUPERVISOR_LOCK = DATA_DIR / "supervisor.lock"
SUPERVISOR_SCRIPT = INSTALL_ROOT / "ERPAgentSupervisor.pyw"
URL = "http://127.0.0.1:8788"
ERROR_ALREADY_EXISTS = 183
def _dashboard_mutex_name() -> str:
normalized = str(INSTALL_ROOT.resolve()).casefold().encode("utf-8", errors="ignore")
suffix = hashlib.sha256(normalized).hexdigest()[:20]
return f"Local\\ARRR_ERP_Local_Agent_DASHBOARD_{suffix}"
def _acquire_dashboard_mutex():
if os.name != "nt":
return object()
kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)
kernel32.CreateMutexW.argtypes = (ctypes.c_void_p, wintypes.BOOL, wintypes.LPCWSTR)
kernel32.CreateMutexW.restype = wintypes.HANDLE
ctypes.set_last_error(0)
handle = kernel32.CreateMutexW(None, False, _dashboard_mutex_name())
if not handle:
raise ctypes.WinError(ctypes.get_last_error())
if ctypes.get_last_error() == ERROR_ALREADY_EXISTS:
kernel32.CloseHandle(handle)
return None
return handle
def _close_dashboard_mutex(handle) -> None:
if os.name != "nt" or handle is None or not isinstance(handle, int):
return
try:
ctypes.WinDLL("kernel32", use_last_error=True).CloseHandle(handle)
except Exception:
pass
def _focus_existing_dashboard() -> None:
if os.name != "nt":
return
try:
user32 = ctypes.WinDLL("user32", use_last_error=True)
EnumWindowsProc = ctypes.WINFUNCTYPE(wintypes.BOOL, wintypes.HWND, wintypes.LPARAM)
@EnumWindowsProc
def callback(hwnd, _lparam):
length = user32.GetWindowTextLengthW(hwnd)
if length <= 0:
return True
buf = ctypes.create_unicode_buffer(length + 1)
user32.GetWindowTextW(hwnd, buf, length + 1)
if "ERP Local Agent Dashboard" in buf.value:
user32.ShowWindow(hwnd, 9) # SW_RESTORE
user32.SetForegroundWindow(hwnd)
return False
return True
user32.EnumWindows(callback, 0)
except Exception:
pass
def _create_no_window() -> int:
@@ -115,6 +176,11 @@ def _wait_ready(seconds: int = 75) -> bool:
def main() -> None:
dashboard_mutex = _acquire_dashboard_mutex()
if dashboard_mutex is None:
_focus_existing_dashboard()
return
atexit.register(_close_dashboard_mutex, dashboard_mutex)
try:
_ensure_supervisor()
except Exception as exc: