from abc import ABC, abstractmethod from typing import Dict, Optional, Protocol from app.config import SandboxSettings from app.sandbox.core.sandbox import DockerSandbox class SandboxFileOperations(Protocol): """Protocol for sandbox file operations.""" async def copy_from(self, container_path: str, local_path: str) -> None: """Copies file from container to local. Args: container_path: File path in container. local_path: Local destination path. """ ... async def copy_to(self, local_path: str, container_path: str) -> None: """Copies file from local to container. Args: local_path: Local source file path. container_path: Destination path in container. """ ... async def read_file(self, path: str) -> str: """Reads file content from container. Args: path: File path in container. Returns: str: File content. """ ... async def write_file(self, path: str, content: str) -> None: """Writes content to file in container. Args: path: File path in container. content: Content to write. """ ... class BaseSandboxClient(ABC): """Base sandbox client interface.""" @abstractmethod async def create( self, config: Optional[SandboxSettings] = None, volume_bindings: Optional[Dict[str, str]] = None, ) -> None: """Creates sandbox.""" @abstractmethod async def run_command(self, command: str, timeout: Optional[int] = None) -> str: """Executes command.""" @abstractmethod async def copy_from(self, container_path: str, local_path: str) -> None: """Copies file from container.""" @abstractmethod async def copy_to(self, local_path: str, container_path: str) -> None: """Copies file to container.""" @abstractmethod async def read_file(self, path: str) -> str: """Reads file.""" @abstractmethod async def write_file(self, path: str, content: str) -> None: """Writes file.""" @abstractmethod async def cleanup(self) -> None: """Cleans up resources.""" class LocalSandboxClient(BaseSandboxClient): """Local sandbox client implementation.""" def __init__(self): """Initializes local sandbox client.""" self.sandbox: Optional[DockerSandbox] = None async def create( self, config: Optional[SandboxSettings] = None, volume_bindings: Optional[Dict[str, str]] = None, ) -> None: """Creates a sandbox. Args: config: Sandbox configuration. volume_bindings: Volume mappings. Raises: RuntimeError: If sandbox creation fails. """ self.sandbox = DockerSandbox(config, volume_bindings) await self.sandbox.create() async def run_command(self, command: str, timeout: Optional[int] = None) -> str: """Runs command in sandbox. Args: command: Command to execute. timeout: Execution timeout in seconds. Returns: Command output. Raises: RuntimeError: If sandbox not initialized. """ if not self.sandbox: raise RuntimeError("Sandbox not initialized") return await self.sandbox.run_command(command, timeout) async def copy_from(self, container_path: str, local_path: str) -> None: """Copies file from container to local. Args: container_path: File path in container. local_path: Local destination path. Raises: RuntimeError: If sandbox not initialized. """ if not self.sandbox: raise RuntimeError("Sandbox not initialized") await self.sandbox.copy_from(container_path, local_path) async def copy_to(self, local_path: str, container_path: str) -> None: """Copies file from local to container. Args: local_path: Local source file path. container_path: Destination path in container. Raises: RuntimeError: If sandbox not initialized. """ if not self.sandbox: raise RuntimeError("Sandbox not initialized") await self.sandbox.copy_to(local_path, container_path) async def read_file(self, path: str) -> str: """Reads file from container. Args: path: File path in container. Returns: File content. Raises: RuntimeError: If sandbox not initialized. """ if not self.sandbox: raise RuntimeError("Sandbox not initialized") return await self.sandbox.read_file(path) async def write_file(self, path: str, content: str) -> None: """Writes file to container. Args: path: File path in container. content: File content. Raises: RuntimeError: If sandbox not initialized. """ if not self.sandbox: raise RuntimeError("Sandbox not initialized") await self.sandbox.write_file(path, content) async def cleanup(self) -> None: """Cleans up resources.""" if self.sandbox: await self.sandbox.cleanup() self.sandbox = None def create_sandbox_client() -> LocalSandboxClient: """Creates a sandbox client. Returns: LocalSandboxClient: Sandbox client instance. """ return LocalSandboxClient() SANDBOX_CLIENT = create_sandbox_client()