from enum import Enum import subprocess from fabric import Connection class MouseClick(Enum): LEFT = 1 MIDDLE = 2 RIGHT = 3 WHEEL_UP = 4 WHEEL_DOWN = 5 class EmulatorSimulator: def __init__(self, vm_name: str, username: str, password: str, host:str, snapshot_name: str = "snapshot"): self.vm_name = vm_name self.username = username self.password = password self.host = host self.snapshot_name = snapshot_name self.ssh_connection = Connection(host=self.host, user=self.username, connect_kwargs={"password": password}) self._execute_command(["VBoxManage", "startvm", self.vm_name]) def _execute_command(self, command: list[str]) -> None: process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = process.communicate() if process.returncode != 0: print(f"Error executing command: {command}") print(stderr.decode()) return None else: return stdout.decode() def _execute_xdotool_command(self, command: list[str]) -> None: result = self.ssh_connection.run(f"DISPLAY=:0 xdotool {command}", hide=True) return result.stdout.strip() def get_logs(self) -> str: pass def load_state(self) -> None: self._execute_command(["VBoxManage", "snapshot", self.vm_name, "restore", self.snapshot_name]) def save_state(self) -> None: self._execute_command(["VBoxManage", "snapshot", self.vm_name, "take", self.snapshot_name]) def click(self, click: MouseClick) -> None: self._execute_xdotool_command(f"click {click.value}") def mousedown(self, click: MouseClick) -> None: self._execute_xdotool_command(f"mousedown {click}") def mouseup(self, click: MouseClick) -> None: self._execute_xdotool_command(f"mouseup {click}") def mouse_move(self, x: int, y: int) -> None: self._execute_xdotool_command(f"mousemove {x} {y}") def key(self, key: str) -> None: self._execute_xdotool_command(f"key {key}") def type(self, text: str) -> None: self._execute_xdotool_command(f"type {text}") def get_screenshot(self) -> str: image_path = "./screenshot.png" self._execute_command(["VBoxManage", "controlvm", self.vm_name, "screenshotpng", image_path]) return image_path def close(self) -> None: pass