treewide: fix various UI bugs; optimize crypto dependencies & format
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: If8fe8b38c1d9c4fecd40ff71f88d2ae06a6a6964
This commit is contained in:
parent
764aafa88d
commit
3ccddce7fd
178 changed files with 58342 additions and 54241 deletions
|
|
@ -1,12 +1,16 @@
|
|||
//! 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.
|
||||
//! 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 std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
use thiserror::Error;
|
||||
|
||||
pub mod manifest;
|
||||
|
|
@ -26,350 +30,361 @@ pub type PluginResult<T> = Result<T, PluginError>;
|
|||
/// Errors that can occur in plugin operations
|
||||
#[derive(Debug, Error, Serialize, Deserialize)]
|
||||
pub enum PluginError {
|
||||
#[error("Plugin initialization failed: {0}")]
|
||||
InitializationFailed(String),
|
||||
#[error("Plugin initialization failed: {0}")]
|
||||
InitializationFailed(String),
|
||||
|
||||
#[error("Unsupported operation: {0}")]
|
||||
UnsupportedOperation(String),
|
||||
#[error("Unsupported operation: {0}")]
|
||||
UnsupportedOperation(String),
|
||||
|
||||
#[error("Invalid input: {0}")]
|
||||
InvalidInput(String),
|
||||
#[error("Invalid input: {0}")]
|
||||
InvalidInput(String),
|
||||
|
||||
#[error("IO error: {0}")]
|
||||
IoError(String),
|
||||
#[error("IO error: {0}")]
|
||||
IoError(String),
|
||||
|
||||
#[error("Metadata extraction failed: {0}")]
|
||||
MetadataExtractionFailed(String),
|
||||
#[error("Metadata extraction failed: {0}")]
|
||||
MetadataExtractionFailed(String),
|
||||
|
||||
#[error("Thumbnail generation failed: {0}")]
|
||||
ThumbnailGenerationFailed(String),
|
||||
#[error("Thumbnail generation failed: {0}")]
|
||||
ThumbnailGenerationFailed(String),
|
||||
|
||||
#[error("Search backend error: {0}")]
|
||||
SearchBackendError(String),
|
||||
#[error("Search backend error: {0}")]
|
||||
SearchBackendError(String),
|
||||
|
||||
#[error("Permission denied: {0}")]
|
||||
PermissionDenied(String),
|
||||
#[error("Permission denied: {0}")]
|
||||
PermissionDenied(String),
|
||||
|
||||
#[error("Resource limit exceeded: {0}")]
|
||||
ResourceLimitExceeded(String),
|
||||
#[error("Resource limit exceeded: {0}")]
|
||||
ResourceLimitExceeded(String),
|
||||
|
||||
#[error("Plugin error: {0}")]
|
||||
Other(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 data directory for persistent storage
|
||||
pub data_dir: PathBuf,
|
||||
|
||||
/// Plugin's cache directory for temporary data
|
||||
pub cache_dir: PathBuf,
|
||||
/// Plugin's cache directory for temporary data
|
||||
pub cache_dir: PathBuf,
|
||||
|
||||
/// Plugin configuration from manifest
|
||||
pub config: HashMap<String, serde_json::Value>,
|
||||
/// Plugin configuration from manifest
|
||||
pub config: HashMap<String, serde_json::Value>,
|
||||
|
||||
/// Capabilities granted to the plugin
|
||||
pub capabilities: Capabilities,
|
||||
/// 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,
|
||||
/// Filesystem access permissions
|
||||
pub filesystem: FilesystemCapability,
|
||||
|
||||
/// Network access permissions
|
||||
pub network: NetworkCapability,
|
||||
/// Network access permissions
|
||||
pub network: NetworkCapability,
|
||||
|
||||
/// Environment variable access
|
||||
pub environment: EnvironmentCapability,
|
||||
/// Environment variable access
|
||||
pub environment: EnvironmentCapability,
|
||||
|
||||
/// Maximum memory usage in bytes
|
||||
pub max_memory_bytes: Option<usize>,
|
||||
/// Maximum memory usage in bytes
|
||||
pub max_memory_bytes: Option<usize>,
|
||||
|
||||
/// Maximum CPU time in milliseconds
|
||||
pub max_cpu_time_ms: Option<u64>,
|
||||
/// Maximum CPU time in milliseconds
|
||||
pub max_cpu_time_ms: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct FilesystemCapability {
|
||||
/// Paths allowed for reading
|
||||
pub read: Vec<PathBuf>,
|
||||
/// Paths allowed for reading
|
||||
pub read: Vec<PathBuf>,
|
||||
|
||||
/// Paths allowed for writing
|
||||
pub write: Vec<PathBuf>,
|
||||
/// Paths allowed for writing
|
||||
pub write: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct NetworkCapability {
|
||||
/// Whether network access is allowed
|
||||
pub enabled: bool,
|
||||
/// Whether network access is allowed
|
||||
pub enabled: bool,
|
||||
|
||||
/// Allowed domains (if None, all domains allowed when enabled)
|
||||
pub allowed_domains: Option<Vec<String>>,
|
||||
/// Allowed domains (if None, all domains allowed when enabled)
|
||||
pub allowed_domains: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct EnvironmentCapability {
|
||||
/// Whether environment variable access is allowed
|
||||
pub enabled: bool,
|
||||
/// Whether environment variable access is allowed
|
||||
pub enabled: bool,
|
||||
|
||||
/// Specific environment variables allowed (if None, all allowed when enabled)
|
||||
pub allowed_vars: Option<Vec<String>>,
|
||||
/// Specific environment variables allowed (if None, all allowed when
|
||||
/// enabled)
|
||||
pub allowed_vars: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
/// Base trait that all plugins must implement
|
||||
#[async_trait]
|
||||
pub trait Plugin: Send + Sync {
|
||||
/// Get plugin metadata
|
||||
fn metadata(&self) -> &PluginMetadata;
|
||||
/// Get plugin metadata
|
||||
fn metadata(&self) -> &PluginMetadata;
|
||||
|
||||
/// Initialize the plugin with provided context
|
||||
async fn initialize(&mut self, context: PluginContext) -> PluginResult<()>;
|
||||
/// Initialize the plugin with provided context
|
||||
async fn initialize(&mut self, context: PluginContext) -> PluginResult<()>;
|
||||
|
||||
/// Shutdown the plugin gracefully
|
||||
async fn shutdown(&mut self) -> PluginResult<()>;
|
||||
/// Shutdown the plugin gracefully
|
||||
async fn shutdown(&mut self) -> PluginResult<()>;
|
||||
|
||||
/// Get plugin health status
|
||||
async fn health_check(&self) -> PluginResult<HealthStatus>;
|
||||
/// Get plugin health status
|
||||
async fn health_check(&self) -> PluginResult<HealthStatus>;
|
||||
}
|
||||
|
||||
/// 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,
|
||||
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<String>,
|
||||
pub metrics: HashMap<String, f64>,
|
||||
pub healthy: bool,
|
||||
pub message: Option<String>,
|
||||
pub metrics: HashMap<String, f64>,
|
||||
}
|
||||
|
||||
/// 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<MediaTypeDefinition>;
|
||||
/// Get the list of media types this plugin supports
|
||||
fn supported_media_types(&self) -> Vec<MediaTypeDefinition>;
|
||||
|
||||
/// Check if this plugin can handle the given file
|
||||
async fn can_handle(&self, path: &Path, mime_type: Option<&str>) -> PluginResult<bool>;
|
||||
/// Check if this plugin can handle the given file
|
||||
async fn can_handle(
|
||||
&self,
|
||||
path: &Path,
|
||||
mime_type: Option<&str>,
|
||||
) -> PluginResult<bool>;
|
||||
}
|
||||
|
||||
/// Definition of a custom media type
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct MediaTypeDefinition {
|
||||
/// Unique identifier for this media type
|
||||
pub id: String,
|
||||
/// Unique identifier for this media type
|
||||
pub id: String,
|
||||
|
||||
/// Display name
|
||||
pub name: String,
|
||||
/// Display name
|
||||
pub name: String,
|
||||
|
||||
/// Category (e.g., "video", "audio", "document", "image")
|
||||
pub category: String,
|
||||
/// Category (e.g., "video", "audio", "document", "image")
|
||||
pub category: String,
|
||||
|
||||
/// File extensions associated with this type
|
||||
pub extensions: Vec<String>,
|
||||
/// File extensions associated with this type
|
||||
pub extensions: Vec<String>,
|
||||
|
||||
/// MIME types associated with this type
|
||||
pub mime_types: Vec<String>,
|
||||
/// MIME types associated with this type
|
||||
pub mime_types: Vec<String>,
|
||||
|
||||
/// Icon name or path
|
||||
pub icon: Option<String>,
|
||||
/// Icon name or path
|
||||
pub icon: Option<String>,
|
||||
}
|
||||
|
||||
/// 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<ExtractedMetadata>;
|
||||
/// Extract metadata from a file
|
||||
async fn extract_metadata(
|
||||
&self,
|
||||
path: &Path,
|
||||
) -> PluginResult<ExtractedMetadata>;
|
||||
|
||||
/// Get the media types this extractor supports
|
||||
fn supported_types(&self) -> Vec<String>;
|
||||
/// Get the media types this extractor supports
|
||||
fn supported_types(&self) -> Vec<String>;
|
||||
}
|
||||
|
||||
/// Metadata extracted from a file
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct ExtractedMetadata {
|
||||
pub title: Option<String>,
|
||||
pub description: Option<String>,
|
||||
pub author: Option<String>,
|
||||
pub created_at: Option<String>,
|
||||
pub duration_secs: Option<f64>,
|
||||
pub width: Option<u32>,
|
||||
pub height: Option<u32>,
|
||||
pub file_size_bytes: Option<u64>,
|
||||
pub codec: Option<String>,
|
||||
pub bitrate_kbps: Option<u32>,
|
||||
pub title: Option<String>,
|
||||
pub description: Option<String>,
|
||||
pub author: Option<String>,
|
||||
pub created_at: Option<String>,
|
||||
pub duration_secs: Option<f64>,
|
||||
pub width: Option<u32>,
|
||||
pub height: Option<u32>,
|
||||
pub file_size_bytes: Option<u64>,
|
||||
pub codec: Option<String>,
|
||||
pub bitrate_kbps: Option<u32>,
|
||||
|
||||
/// Custom metadata fields specific to this file type
|
||||
pub custom_fields: HashMap<String, serde_json::Value>,
|
||||
/// Custom metadata fields specific to this file type
|
||||
pub custom_fields: HashMap<String, serde_json::Value>,
|
||||
|
||||
/// Tags extracted from the file
|
||||
pub tags: Vec<String>,
|
||||
/// Tags extracted from the file
|
||||
pub tags: Vec<String>,
|
||||
}
|
||||
|
||||
/// 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<ThumbnailInfo>;
|
||||
/// Generate a thumbnail for the given file
|
||||
async fn generate_thumbnail(
|
||||
&self,
|
||||
path: &Path,
|
||||
output_path: &Path,
|
||||
options: ThumbnailOptions,
|
||||
) -> PluginResult<ThumbnailInfo>;
|
||||
|
||||
/// Get the media types this generator supports
|
||||
fn supported_types(&self) -> Vec<String>;
|
||||
/// Get the media types this generator supports
|
||||
fn supported_types(&self) -> Vec<String>;
|
||||
}
|
||||
|
||||
/// Options for thumbnail generation
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ThumbnailOptions {
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub quality: u8,
|
||||
pub format: ThumbnailFormat,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub quality: u8,
|
||||
pub format: ThumbnailFormat,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum ThumbnailFormat {
|
||||
Jpeg,
|
||||
Png,
|
||||
WebP,
|
||||
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,
|
||||
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<()>;
|
||||
/// 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<()>;
|
||||
/// 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<Vec<SearchResult>>;
|
||||
/// Perform a search query
|
||||
async fn search(
|
||||
&self,
|
||||
query: &SearchQuery,
|
||||
) -> PluginResult<Vec<SearchResult>>;
|
||||
|
||||
/// Get search statistics
|
||||
async fn get_stats(&self) -> PluginResult<SearchStats>;
|
||||
/// Get search statistics
|
||||
async fn get_stats(&self) -> PluginResult<SearchStats>;
|
||||
}
|
||||
|
||||
/// Item to be indexed for search
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SearchIndexItem {
|
||||
pub id: String,
|
||||
pub title: Option<String>,
|
||||
pub description: Option<String>,
|
||||
pub content: Option<String>,
|
||||
pub tags: Vec<String>,
|
||||
pub media_type: String,
|
||||
pub metadata: HashMap<String, serde_json::Value>,
|
||||
pub id: String,
|
||||
pub title: Option<String>,
|
||||
pub description: Option<String>,
|
||||
pub content: Option<String>,
|
||||
pub tags: Vec<String>,
|
||||
pub media_type: String,
|
||||
pub metadata: HashMap<String, serde_json::Value>,
|
||||
}
|
||||
|
||||
/// Search query
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SearchQuery {
|
||||
pub query_text: String,
|
||||
pub filters: HashMap<String, serde_json::Value>,
|
||||
pub limit: usize,
|
||||
pub offset: usize,
|
||||
pub query_text: String,
|
||||
pub filters: HashMap<String, serde_json::Value>,
|
||||
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<String>,
|
||||
pub id: String,
|
||||
pub score: f64,
|
||||
pub highlights: Vec<String>,
|
||||
}
|
||||
|
||||
/// Search statistics
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SearchStats {
|
||||
pub total_indexed: usize,
|
||||
pub index_size_bytes: u64,
|
||||
pub last_update: Option<String>,
|
||||
pub total_indexed: usize,
|
||||
pub index_size_bytes: u64,
|
||||
pub last_update: Option<String>,
|
||||
}
|
||||
|
||||
/// Trait for plugins that handle events
|
||||
#[async_trait]
|
||||
pub trait EventHandler: Plugin {
|
||||
/// Handle an event
|
||||
async fn handle_event(&self, event: &Event) -> PluginResult<()>;
|
||||
/// 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<EventType>;
|
||||
/// Get the event types this handler is interested in
|
||||
fn interested_events(&self) -> Vec<EventType>;
|
||||
}
|
||||
|
||||
/// 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),
|
||||
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<String, serde_json::Value>,
|
||||
pub event_type: EventType,
|
||||
pub timestamp: String,
|
||||
pub data: HashMap<String, serde_json::Value>,
|
||||
}
|
||||
|
||||
/// Trait for plugins that provide UI themes
|
||||
#[async_trait]
|
||||
pub trait ThemeProvider: Plugin {
|
||||
/// Get available themes from this provider
|
||||
fn get_themes(&self) -> Vec<ThemeDefinition>;
|
||||
/// Get available themes from this provider
|
||||
fn get_themes(&self) -> Vec<ThemeDefinition>;
|
||||
|
||||
/// Load a specific theme by ID
|
||||
async fn load_theme(&self, theme_id: &str) -> PluginResult<Theme>;
|
||||
/// Load a specific theme by ID
|
||||
async fn load_theme(&self, theme_id: &str) -> PluginResult<Theme>;
|
||||
}
|
||||
|
||||
/// 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<String>,
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub author: String,
|
||||
pub preview_url: Option<String>,
|
||||
}
|
||||
|
||||
/// Theme data
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Theme {
|
||||
pub id: String,
|
||||
pub colors: HashMap<String, String>,
|
||||
pub fonts: HashMap<String, String>,
|
||||
pub custom_css: Option<String>,
|
||||
pub id: String,
|
||||
pub colors: HashMap<String, String>,
|
||||
pub fonts: HashMap<String, String>,
|
||||
pub custom_css: Option<String>,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue