from abc import ABC, abstractmethod from typing import List, Tuple, Dict, Any, Optional class BaseStorageProvider(ABC): """Abstract interface for OnEver Drive storage backends (Local FS, S3, MinIO, etc.).""" @abstractmethod async def init_session_storage(self, session_code: str) -> None: """Prepares temporary storage directory for an incoming upload session.""" pass @abstractmethod async def save_chunk( self, session_code: str, chunk_index: int, chunk_data: bytes, expected_sha256: Optional[str] = None ) -> bool: """Saves a single chunk, validates its hash, and returns True on success.""" pass @abstractmethod async def get_received_chunks(self, session_code: str) -> List[int]: """Returns the list of indices of all successfully stored chunks for a session.""" pass @abstractmethod async def assemble_file( self, session_code: str, client_code: str, job_code: str, filename: str, total_chunks: int, expected_sha256: str ) -> Tuple[str, str, int]: """ Assembles all stored chunks in order into the final destination file, calculates full streaming SHA-256 hash, and verifies integrity. Returns: (relative_storage_path, actual_sha256, file_size_bytes). Raises ValueError if integrity check fails or chunks are missing. """ pass @abstractmethod async def delete_session_temp(self, session_code: str) -> None: """Cleans up temporary chunks after assembly or cancellation.""" pass @abstractmethod async def delete_backup_file(self, relative_path: str) -> bool: """Deletes a backup file from storage.""" pass @abstractmethod async def get_file_path(self, relative_path: str) -> str: """Resolves absolute path for reading/restoring.""" pass @abstractmethod async def get_storage_stats(self) -> Dict[str, Any]: """Returns storage capacity stats: {total_bytes, used_bytes, free_bytes, usage_percent}.""" pass