Files
wehub-resource-sync 91e75e620b
CI: cua-driver distro-compat matrix / debian:12 (glibc 2.36) (push) Has been cancelled
CI: SPDX Headers / Check SPDX headers (warn-only) (push) Has been cancelled
CD: Docs MCP Server / build (linux/amd64) (push) Has been cancelled
CD: Docs MCP Server / build (linux/arm64) (push) Has been cancelled
CD: Docs MCP Server / merge (push) Has been cancelled
CI: cua-driver distro-compat matrix / Resolve release version (push) Has been cancelled
CI: cua-driver distro-compat matrix / fedora:41 (glibc 2.40) (push) Has been cancelled
CI: cua-driver distro-compat matrix / rockylinux:9 (glibc 2.34) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:22.04 (glibc 2.35) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:24.04 (glibc 2.39) (push) Has been cancelled
CI: cua-driver distro-compat matrix / Distro compat summary (push) Has been cancelled
CI: Rust Linux unit / Rust Linux unit and compile (push) Has been cancelled
CI: Rust Windows unit / Rust Windows unit and compile (push) Has been cancelled
CI: Nix Linux Rust source / Nix / compositor build (push) Has been cancelled
CI: Nix Linux Rust source / Nix / driver package (push) Has been cancelled
CI: Nix Linux Rust source / Nix / Rust unit tests (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:03:19 +08:00

122 lines
4.5 KiB
Python

"""Abstract transport protocol.
A Transport moves commands and data between the sandbox client and the
underlying computer (local host, WebSocket to computer-server, or cloud API).
"""
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Any, Dict, Optional
if TYPE_CHECKING:
from cua_sandbox.interfaces.tunnel import TunnelInfo
def convert_screenshot(png_bytes: bytes, format: str, quality: int) -> bytes:
"""Convert raw PNG bytes to the requested format.
Args:
png_bytes: Raw PNG image bytes.
format: "png", "jpeg", or "jpg".
quality: JPEG quality (1-95), ignored for PNG.
"""
fmt = format.lower()
if fmt in ("jpeg", "jpg"):
from io import BytesIO
from PIL import Image as PILImage
img = PILImage.open(BytesIO(png_bytes)).convert("RGB")
buf = BytesIO()
img.save(buf, format="JPEG", quality=quality)
return buf.getvalue()
return png_bytes
class Transport(ABC):
"""Base class for all transports."""
@abstractmethod
async def connect(self) -> None:
"""Establish the transport connection."""
@abstractmethod
async def disconnect(self) -> None:
"""Tear down the transport connection."""
@abstractmethod
async def send(self, action: str, **params: Any) -> Any:
"""Send a command and return the result."""
@abstractmethod
async def screenshot(self, format: str = "png", quality: int = 95) -> bytes:
"""Capture a screenshot and return raw image bytes.
Args:
format: "png" (lossless, default) or "jpeg" (lossy, ~5-10x smaller).
quality: JPEG quality 1-95, ignored for PNG.
"""
@abstractmethod
async def get_screen_size(self) -> Dict[str, int]:
"""Return {"width": ..., "height": ...}."""
@abstractmethod
async def get_environment(self) -> str:
"""Return 'windows', 'mac', 'linux', or 'browser'."""
async def forward_tunnel(self, sandbox_port: int | str) -> "TunnelInfo":
"""Forward *sandbox_port* to an available host port and return info.
Subclasses that support tunnelling must override this method.
The returned :class:`~cua_sandbox.interfaces.tunnel.TunnelInfo` must
have ``host`` and ``port`` set to the host-side address.
"""
raise NotImplementedError(
f"{type(self).__name__} does not support port forwarding. "
"Supported transports: ADBTransport, GRPCEmulatorTransport, SSHTransport."
)
async def close_tunnel(self, info: "TunnelInfo") -> None:
"""Release a previously forwarded port or socket. No-op by default."""
# ── PTY sessions ────────────────────────────────────────────────────
# Transports that support a pseudo-terminal override these. The default
# implementations raise NotImplementedError.
async def pty_create(
self,
command: Optional[str] = None,
cols: int = 120,
rows: int = 40,
cwd: Optional[str] = None,
envs: Optional[Dict[str, str]] = None,
) -> Dict[str, Any]:
"""Spawn a PTY session. Returns {"pid": int, "cols": int, "rows": int}."""
raise NotImplementedError(f"{type(self).__name__} does not support PTY.")
async def pty_send(self, pid: int, data: str) -> None:
"""Write *data* to the PTY session's stdin."""
raise NotImplementedError(f"{type(self).__name__} does not support PTY.")
async def pty_kill(self, pid: int) -> bool:
"""Terminate a PTY session."""
raise NotImplementedError(f"{type(self).__name__} does not support PTY.")
async def pty_info(self, pid: int) -> Optional[Dict[str, Any]]:
"""Return session info if still running, None otherwise."""
raise NotImplementedError(f"{type(self).__name__} does not support PTY.")
async def get_display_url(self, *, share: bool = False) -> str:
"""Return a URL to view this sandbox's display.
Args:
share: If True, return a public link with embedded credentials
(cloud only). If False, return a direct connection URL
(localhost VNC for local runtimes; auth-gated URL for cloud).
Raises NotImplementedError for transports that don't expose a display
(e.g. HTTP, ADB).
"""
raise NotImplementedError(f"{type(self).__name__} does not support get_display_url().")