| | 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() |
| |
|