from __future__ import annotations from dataclasses import dataclass from pathlib import Path from threading import Lock import shutil import subprocess import tempfile import time from typing import Protocol from app.config import SUPPORTED_TARGET_PORTS DEFAULT_DDM_PATH = Path(r"C:\Program Files\Dell\Dell Display Manager 2.0\DDM.exe") ALIENWARE_MODEL_TOKEN = "AW3423DWF" @dataclass(slots=True) class DDMCommandResult: success: bool message: str raw_output: str = "" class DDMBackend(Protocol): def is_available(self) -> bool: ... def supports_monitor_targeting(self) -> bool: ... def resolve_alienware_slot(self, force: bool = False) -> int | None: ... def invalidate_slot(self) -> None: ... def switch_to_port(self, slot: int, port_name: str) -> DDMCommandResult: ... class RealDDMBackend: def __init__( self, executable_path: Path | None = None, max_slots: int = 8, command_timeout_seconds: float = 4.0, log_timeout_seconds: float = 3.0, ): self.executable_path = executable_path or self._find_executable() self.max_slots = max_slots self.command_timeout_seconds = command_timeout_seconds self.log_timeout_seconds = log_timeout_seconds self._cached_slot: int | None = None self._lock = Lock() def is_available(self) -> bool: return self.executable_path is not None and self.executable_path.exists() def supports_monitor_targeting(self) -> bool: return True def invalidate_slot(self) -> None: with self._lock: self._cached_slot = None def resolve_alienware_slot(self, force: bool = False) -> int | None: if not self.is_available(): return None with self._lock: if self._cached_slot is not None and not force: return self._cached_slot for slot in range(1, self.max_slots + 1): result = self._run_logged_command(f"/{slot}:ReadAssetAttributes") line = _extract_result_line(result, f"{slot}:ReadAssetAttributes") if not line: continue if "INVALID COMMAND" in line.upper(): continue if ALIENWARE_MODEL_TOKEN in line.upper(): self._cached_slot = slot return slot self._cached_slot = None return None def switch_to_port(self, slot: int, port_name: str) -> DDMCommandResult: if not self.is_available(): return DDMCommandResult(False, "DDM.exe was not found.") port_spec = SUPPORTED_TARGET_PORTS.get(port_name.upper()) if not port_spec: return DDMCommandResult(False, f"Port {port_name} is not supported.") ddm_input = str(port_spec["ddm_input"]) monitor_selector = f"/MNT:{ALIENWARE_MODEL_TOKEN}" targeted_output = self._run_logged_command( monitor_selector, "/WriteActiveInput", ddm_input, ) targeted_line = _extract_result_line_fragment(targeted_output, "WRITEACTIVEINPUT") if not _output_has_failure(targeted_line, targeted_output): return DDMCommandResult( True, f"Alienware {ALIENWARE_MODEL_TOKEN} was instructed to switch to {ddm_input}.", targeted_output, ) if slot > 0: legacy_output = self._run_logged_command(f"/{slot}:WriteActiveInput", ddm_input) legacy_line = _extract_result_line(legacy_output, f"{slot}:WriteActiveInput") if not _output_has_failure(legacy_line, legacy_output): return DDMCommandResult( True, f"Alienware DDM slot {slot} was instructed to switch to {ddm_input}.", legacy_output, ) merged_output = "\n".join( block for block in [ "[targeted]", targeted_output.strip(), "[legacy]", legacy_output.strip(), ] if block ) return DDMCommandResult(False, "DDM rejected the WriteActiveInput command.", merged_output) return DDMCommandResult(False, "DDM rejected the WriteActiveInput command.", targeted_output) def _run_logged_command(self, *command_args: str) -> str: assert self.executable_path is not None with tempfile.NamedTemporaryFile(delete=False, suffix=".txt") as handle: log_path = Path(handle.name) try: subprocess.run( [str(self.executable_path), "/Log", str(log_path), *command_args], check=False, capture_output=True, text=True, timeout=self.command_timeout_seconds, ) deadline = time.monotonic() + self.log_timeout_seconds while time.monotonic() < deadline: try: contents = log_path.read_text(encoding="utf-8", errors="replace") except OSError: contents = "" if contents.strip(): return contents time.sleep(0.1) try: return log_path.read_text(encoding="utf-8", errors="replace") except OSError: return "" finally: try: log_path.unlink() except OSError: pass def _find_executable(self) -> Path | None: resolved = shutil.which("DDM.exe") if resolved: return Path(resolved) if DEFAULT_DDM_PATH.exists(): return DEFAULT_DDM_PATH return None def _extract_result_line(text: str, prefix: str) -> str: for line in text.splitlines(): normalized = line.strip() if normalized.startswith(prefix): return normalized return "" def _extract_result_line_fragment(text: str, fragment: str) -> str: needle = fragment.upper() for line in text.splitlines(): normalized = line.strip() if needle in normalized.upper(): return normalized return "" def _output_has_failure(line: str, output: str) -> bool: normalized_line = line.upper() normalized_output = output.upper() checks = ( "INVALID COMMAND", "UNSUPPORTED", "NOT FOUND", "FAILED", "FAIL", ) return any(token in normalized_line or token in normalized_output for token in checks)