//! Pinakes Plugin API //! //! This crate defines the stable plugin interface for Pinakes. //! Plugins can extend Pinakes by implementing one or more of the provided //! traits. use std::{ collections::HashMap, path::{Path, PathBuf}, }; use async_trait::async_trait; use serde::{Deserialize, Serialize}; use thiserror::Error; pub mod manifest; pub mod types; pub mod wasm; pub use manifest::PluginManifest; pub use types::*; pub use wasm::host_functions; /// Plugin API version - plugins must match this version pub const PLUGIN_API_VERSION: &str = "1.0"; /// Result type for plugin operations pub type PluginResult = Result; /// Errors that can occur in plugin operations #[derive(Debug, Error, Serialize, Deserialize)] pub enum PluginError { #[error("Plugin initialization failed: {0}")] InitializationFailed(String), #[error("Unsupported operation: {0}")] UnsupportedOperation(String), #[error("Invalid input: {0}")] InvalidInput(String), #[error("IO error: {0}")] IoError(String), #[error("Metadata extraction failed: {0}")] MetadataExtractionFailed(String), #[error("Thumbnail generation failed: {0}")] ThumbnailGenerationFailed(String), #[error("Search backend error: {0}")] SearchBackendError(String), #[error("Permission denied: {0}")] PermissionDenied(String), #[error("Resource limit exceeded: {0}")] ResourceLimitExceeded(String), #[error("Plugin error: {0}")] Other(String), } /// Context provided to plugins during initialization #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PluginContext { /// Plugin's data directory for persistent storage pub data_dir: PathBuf, /// Plugin's cache directory for temporary data pub cache_dir: PathBuf, /// Plugin configuration from manifest pub config: HashMap, /// Capabilities granted to the plugin pub capabilities: Capabilities, } /// Capabilities that can be granted to plugins #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct Capabilities { /// Filesystem access permissions pub filesystem: FilesystemCapability, /// Network access permissions pub network: NetworkCapability, /// Environment variable access pub environment: EnvironmentCapability, /// Maximum memory usage in bytes pub max_memory_bytes: Option, /// Maximum CPU time in milliseconds pub max_cpu_time_ms: Option, } #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct FilesystemCapability { /// Paths allowed for reading pub read: Vec, /// Paths allowed for writing pub write: Vec, } #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct NetworkCapability { /// Whether network access is allowed pub enabled: bool, /// Allowed domains (if None, all domains allowed when enabled) pub allowed_domains: Option>, } #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct EnvironmentCapability { /// Whether environment variable access is allowed pub enabled: bool, /// Specific environment variables allowed (if None, all allowed when /// enabled) pub allowed_vars: Option>, } /// Base trait that all plugins must implement #[async_trait] pub trait Plugin: Send + Sync { /// Get plugin metadata fn metadata(&self) -> &PluginMetadata; /// Initialize the plugin with provided context async fn initialize(&mut self, context: PluginContext) -> PluginResult<()>; /// Shutdown the plugin gracefully async fn shutdown(&mut self) -> PluginResult<()>; /// Get plugin health status async fn health_check(&self) -> PluginResult; } /// Plugin metadata #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PluginMetadata { pub id: String, pub name: String, pub version: String, pub author: String, pub description: String, pub api_version: String, pub capabilities_required: Capabilities, } /// Health status of a plugin #[derive(Debug, Clone, Serialize, Deserialize)] pub struct HealthStatus { pub healthy: bool, pub message: Option, pub metrics: HashMap, } /// Trait for plugins that provide custom media type support #[async_trait] pub trait MediaTypeProvider: Plugin { /// Get the list of media types this plugin supports fn supported_media_types(&self) -> Vec; /// Check if this plugin can handle the given file async fn can_handle( &self, path: &Path, mime_type: Option<&str>, ) -> PluginResult; } /// Definition of a custom media type #[derive(Debug, Clone, Serialize, Deserialize)] pub struct MediaTypeDefinition { /// Unique identifier for this media type pub id: String, /// Display name pub name: String, /// Category (e.g., "video", "audio", "document", "image") pub category: String, /// File extensions associated with this type pub extensions: Vec, /// MIME types associated with this type pub mime_types: Vec, /// Icon name or path pub icon: Option, } /// Trait for plugins that extract metadata from files #[async_trait] pub trait MetadataExtractor: Plugin { /// Extract metadata from a file async fn extract_metadata( &self, path: &Path, ) -> PluginResult; /// Get the media types this extractor supports fn supported_types(&self) -> Vec; } /// Metadata extracted from a file #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct ExtractedMetadata { pub title: Option, pub description: Option, pub author: Option, pub created_at: Option, pub duration_secs: Option, pub width: Option, pub height: Option, pub file_size_bytes: Option, pub codec: Option, pub bitrate_kbps: Option, /// Custom metadata fields specific to this file type pub custom_fields: HashMap, /// Tags extracted from the file pub tags: Vec, } /// Trait for plugins that generate thumbnails #[async_trait] pub trait ThumbnailGenerator: Plugin { /// Generate a thumbnail for the given file async fn generate_thumbnail( &self, path: &Path, output_path: &Path, options: ThumbnailOptions, ) -> PluginResult; /// Get the media types this generator supports fn supported_types(&self) -> Vec; } /// Options for thumbnail generation #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ThumbnailOptions { pub width: u32, pub height: u32, pub quality: u8, pub format: ThumbnailFormat, } #[derive(Debug, Clone, Serialize, Deserialize)] pub enum ThumbnailFormat { Jpeg, Png, WebP, } /// Information about a generated thumbnail #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ThumbnailInfo { pub path: PathBuf, pub width: u32, pub height: u32, pub file_size_bytes: u64, } /// Trait for plugins that provide custom search backends #[async_trait] pub trait SearchBackend: Plugin { /// Index a media item for search async fn index_item(&self, item: &SearchIndexItem) -> PluginResult<()>; /// Remove an item from the search index async fn remove_item(&self, item_id: &str) -> PluginResult<()>; /// Perform a search query async fn search( &self, query: &SearchQuery, ) -> PluginResult>; /// Get search statistics async fn get_stats(&self) -> PluginResult; } /// Item to be indexed for search #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SearchIndexItem { pub id: String, pub title: Option, pub description: Option, pub content: Option, pub tags: Vec, pub media_type: String, pub metadata: HashMap, } /// Search query #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SearchQuery { pub query_text: String, pub filters: HashMap, pub limit: usize, pub offset: usize, } /// Search result #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SearchResult { pub id: String, pub score: f64, pub highlights: Vec, } /// Search statistics #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SearchStats { pub total_indexed: usize, pub index_size_bytes: u64, pub last_update: Option, } /// Trait for plugins that handle events #[async_trait] pub trait EventHandler: Plugin { /// Handle an event async fn handle_event(&self, event: &Event) -> PluginResult<()>; /// Get the event types this handler is interested in fn interested_events(&self) -> Vec; } /// Event type #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] pub enum EventType { MediaImported, MediaUpdated, MediaDeleted, MediaTagged, MediaUntagged, CollectionCreated, CollectionUpdated, CollectionDeleted, ScanStarted, ScanCompleted, Custom(String), } /// Event data #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Event { pub event_type: EventType, pub timestamp: String, pub data: HashMap, } /// Trait for plugins that provide UI themes #[async_trait] pub trait ThemeProvider: Plugin { /// Get available themes from this provider fn get_themes(&self) -> Vec; /// Load a specific theme by ID async fn load_theme(&self, theme_id: &str) -> PluginResult; } /// Theme definition #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ThemeDefinition { pub id: String, pub name: String, pub description: String, pub author: String, pub preview_url: Option, } /// Theme data #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Theme { pub id: String, pub colors: HashMap, pub fonts: HashMap, pub custom_css: Option, }