diff --git a/packages/pinakes-server/Cargo.toml b/packages/pinakes-server/Cargo.toml index aacccdf..6ead01c 100644 --- a/packages/pinakes-server/Cargo.toml +++ b/packages/pinakes-server/Cargo.toml @@ -7,6 +7,11 @@ license.workspace = true [dependencies] pinakes-core = { workspace = true } pinakes-plugin-api = { workspace = true } +pinakes-types = { workspace = true } +pinakes-enrichment = { workspace = true } +pinakes-metadata = { workspace = true } +pinakes-plugin = { workspace = true } +pinakes-sync = { workspace = true } tokio = { workspace = true } serde = { workspace = true } diff --git a/packages/pinakes-server/src/dto/enrichment.rs b/packages/pinakes-server/src/dto/enrichment.rs index 4e144de..a1f19bd 100644 --- a/packages/pinakes-server/src/dto/enrichment.rs +++ b/packages/pinakes-server/src/dto/enrichment.rs @@ -13,10 +13,8 @@ pub struct ExternalMetadataResponse { pub last_updated: DateTime, } -impl From - for ExternalMetadataResponse -{ - fn from(m: pinakes_core::enrichment::ExternalMetadata) -> Self { +impl From for ExternalMetadataResponse { + fn from(m: pinakes_enrichment::ExternalMetadata) -> Self { let metadata = serde_json::from_str(&m.metadata_json).unwrap_or_else(|e| { tracing::warn!( "failed to deserialize external metadata JSON for media {}: {}", diff --git a/packages/pinakes-server/src/dto/sync.rs b/packages/pinakes-server/src/dto/sync.rs index 34b2056..0f7b172 100644 --- a/packages/pinakes-server/src/dto/sync.rs +++ b/packages/pinakes-server/src/dto/sync.rs @@ -25,8 +25,8 @@ pub struct DeviceResponse { pub created_at: DateTime, } -impl From for DeviceResponse { - fn from(d: pinakes_core::sync::SyncDevice) -> Self { +impl From for DeviceResponse { + fn from(d: pinakes_sync::SyncDevice) -> Self { Self { id: d.id.0.to_string(), name: d.name, @@ -72,8 +72,8 @@ pub struct SyncChangeResponse { pub timestamp: DateTime, } -impl From for SyncChangeResponse { - fn from(e: pinakes_core::sync::SyncLogEntry) -> Self { +impl From for SyncChangeResponse { + fn from(e: pinakes_sync::SyncLogEntry) -> Self { Self { id: e.id.to_string(), sequence: e.sequence, @@ -124,8 +124,8 @@ pub struct ConflictResponse { pub detected_at: DateTime, } -impl From for ConflictResponse { - fn from(c: pinakes_core::sync::SyncConflict) -> Self { +impl From for ConflictResponse { + fn from(c: pinakes_sync::SyncConflict) -> Self { Self { id: c.id.to_string(), path: c.path, @@ -162,8 +162,8 @@ pub struct UploadSessionResponse { pub expires_at: DateTime, } -impl From for UploadSessionResponse { - fn from(s: pinakes_core::sync::UploadSession) -> Self { +impl From for UploadSessionResponse { + fn from(s: pinakes_sync::UploadSession) -> Self { Self { id: s.id.to_string(), target_path: s.target_path, diff --git a/packages/pinakes-server/src/main.rs b/packages/pinakes-server/src/main.rs index 28dbeb9..d48f079 100644 --- a/packages/pinakes-server/src/main.rs +++ b/packages/pinakes-server/src/main.rs @@ -236,10 +236,27 @@ async fn main() -> Result<()> { // Initialize plugin manager if plugins are enabled (needed before job queue) let plugin_manager = if config.plugins.enabled { - match pinakes_core::plugin::PluginManager::new( + let pm_cfg = { + let p = &config.plugins; + pinakes_plugin::PluginManagerConfig { + plugin_dirs: p.plugin_dirs.clone(), + enable_hot_reload: p.enable_hot_reload, + allow_unsigned: p.allow_unsigned, + max_concurrent_ops: p.max_concurrent_ops, + plugin_timeout_secs: p.plugin_timeout_secs, + timeouts: pinakes_types::config::PluginTimeoutConfig { + capability_query_secs: p.timeouts.capability_query_secs, + processing_secs: p.timeouts.processing_secs, + event_handler_secs: p.timeouts.event_handler_secs, + }, + max_consecutive_failures: p.max_consecutive_failures, + trusted_keys: p.trusted_keys.clone(), + } + }; + match pinakes_plugin::PluginManager::new( config.plugins.data_dir.clone(), config.plugins.cache_dir.clone(), - config.plugins.clone().into(), + pm_cfg, ) { Ok(pm) => { tracing::info!("Plugin manager initialized"); @@ -538,15 +555,13 @@ async fn main() -> Result<()> { } }, JobKind::Enrich { media_ids } => { - use pinakes_core::{ - enrichment::{ - MetadataEnricher, - books::BookEnricher, - lastfm::LastFmEnricher, - musicbrainz::MusicBrainzEnricher, - tmdb::TmdbEnricher, - }, - media_type::MediaCategory, + use pinakes_core::media_type::MediaCategory; + use pinakes_enrichment::{ + MetadataEnricher, + books::BookEnricher, + lastfm::LastFmEnricher, + musicbrainz::MusicBrainzEnricher, + tmdb::TmdbEnricher, }; let enrich_cfg = &config.enrichment; @@ -598,7 +613,7 @@ async fn main() -> Result<()> { let category = item.media_type.category(); for enricher in &enrichers { let source = enricher.source(); - use pinakes_core::enrichment::EnrichmentSourceType; + use pinakes_enrichment::EnrichmentSourceType; let applicable = match source { EnrichmentSourceType::MusicBrainz | EnrichmentSourceType::LastFm => { @@ -758,7 +773,7 @@ async fn main() -> Result<()> { let chunked_upload_manager = { let config_read = config_arc.read().await; if config_read.sync.enabled { - let manager = pinakes_core::sync::ChunkedUploadManager::new( + let manager = pinakes_sync::ChunkedUploadManager::new( config_read.sync.temp_upload_dir.clone(), ); match manager.init().await { diff --git a/packages/pinakes-server/src/routes/media.rs b/packages/pinakes-server/src/routes/media.rs index 6aa3ec5..ed4a7be 100644 --- a/packages/pinakes-server/src/routes/media.rs +++ b/packages/pinakes-server/src/routes/media.rs @@ -1258,10 +1258,10 @@ pub async fn rename_media( // Record in sync log let item = state.storage.get_media(media_id).await?; - let change = pinakes_core::sync::SyncLogEntry { + let change = pinakes_sync::SyncLogEntry { id: uuid::Uuid::now_v7(), sequence: 0, - change_type: pinakes_core::sync::SyncChangeType::Moved, + change_type: pinakes_sync::SyncChangeType::Moved, media_id: Some(media_id), path: item.path.to_string_lossy().to_string(), content_hash: Some(item.content_hash.clone()), @@ -1319,10 +1319,10 @@ pub async fn move_media_endpoint( // Record in sync log let item = state.storage.get_media(media_id).await?; - let change = pinakes_core::sync::SyncLogEntry { + let change = pinakes_sync::SyncLogEntry { id: uuid::Uuid::now_v7(), sequence: 0, - change_type: pinakes_core::sync::SyncChangeType::Moved, + change_type: pinakes_sync::SyncChangeType::Moved, media_id: Some(media_id), path: item.path.to_string_lossy().to_string(), content_hash: Some(item.content_hash.clone()), @@ -1404,10 +1404,10 @@ pub async fn batch_move_media( continue; }; let new_path = req.destination.join(file_name); - let change = pinakes_core::sync::SyncLogEntry { + let change = pinakes_sync::SyncLogEntry { id: uuid::Uuid::now_v7(), sequence: 0, - change_type: pinakes_core::sync::SyncChangeType::Moved, + change_type: pinakes_sync::SyncChangeType::Moved, media_id: Some(*media_id), path: new_path.to_string_lossy().to_string(), content_hash: None, @@ -1464,10 +1464,10 @@ pub async fn soft_delete_media( state.storage.soft_delete_media(media_id).await?; // Record in sync log - let change = pinakes_core::sync::SyncLogEntry { + let change = pinakes_sync::SyncLogEntry { id: uuid::Uuid::now_v7(), sequence: 0, - change_type: pinakes_core::sync::SyncChangeType::Deleted, + change_type: pinakes_sync::SyncChangeType::Deleted, media_id: Some(media_id), path: item.path.to_string_lossy().to_string(), content_hash: Some(item.content_hash.clone()), @@ -1524,10 +1524,10 @@ pub async fn restore_media( let item = state.storage.get_media(media_id).await?; // Record in sync log - let change = pinakes_core::sync::SyncLogEntry { + let change = pinakes_sync::SyncLogEntry { id: uuid::Uuid::now_v7(), sequence: 0, - change_type: pinakes_core::sync::SyncChangeType::Created, + change_type: pinakes_sync::SyncChangeType::Created, media_id: Some(media_id), path: item.path.to_string_lossy().to_string(), content_hash: Some(item.content_hash.clone()), @@ -1681,10 +1681,10 @@ pub async fn permanent_delete_media( state.storage.delete_media(media_id).await?; // Record in sync log - let change = pinakes_core::sync::SyncLogEntry { + let change = pinakes_sync::SyncLogEntry { id: uuid::Uuid::now_v7(), sequence: 0, - change_type: pinakes_core::sync::SyncChangeType::Deleted, + change_type: pinakes_sync::SyncChangeType::Deleted, media_id: Some(media_id), path: item.path.to_string_lossy().to_string(), content_hash: Some(item.content_hash.clone()), diff --git a/packages/pinakes-server/src/routes/plugins.rs b/packages/pinakes-server/src/routes/plugins.rs index e2b45b0..e5399d5 100644 --- a/packages/pinakes-server/src/routes/plugins.rs +++ b/packages/pinakes-server/src/routes/plugins.rs @@ -4,7 +4,7 @@ use axum::{ Json, extract::{Path, State}, }; -use pinakes_core::plugin::PluginManager; +use pinakes_plugin::PluginManager; use rustc_hash::FxHashMap; use crate::{ diff --git a/packages/pinakes-server/src/routes/sync.rs b/packages/pinakes-server/src/routes/sync.rs index debc4cd..33a09d6 100644 --- a/packages/pinakes-server/src/routes/sync.rs +++ b/packages/pinakes-server/src/routes/sync.rs @@ -11,19 +11,17 @@ use chrono::Utc; use pinakes_core::{ config::ConflictResolution, model::ContentHash, - sync::{ - DeviceId, - DeviceType, - SyncChangeType, - SyncConflict, - SyncDevice, - SyncLogEntry, - UploadSession, - UploadStatus, - generate_device_token, - hash_device_token, - update_device_cursor, - }, + sync::{generate_device_token, hash_device_token, update_device_cursor}, +}; +use pinakes_sync::{ + DeviceId, + DeviceType, + SyncChangeType, + SyncConflict, + SyncDevice, + SyncLogEntry, + UploadSession, + UploadStatus, }; use tokio::io::{AsyncReadExt, AsyncSeekExt}; use tokio_util::io::ReaderStream; @@ -176,7 +174,7 @@ pub async fn get_device( .map_err(|e| ApiError::not_found(format!("Device not found: {e}")))?; // Verify ownership - if device.user_id != user_id { + if device.user_id.0 != user_id.0 { return Err(ApiError::forbidden("Not authorized to access this device")); } @@ -213,7 +211,7 @@ pub async fn update_device( .map_err(|e| ApiError::not_found(format!("Device not found: {e}")))?; // Verify ownership - if device.user_id != user_id { + if device.user_id.0 != user_id.0 { return Err(ApiError::forbidden("Not authorized to update this device")); } @@ -261,7 +259,7 @@ pub async fn delete_device( .map_err(|e| ApiError::not_found(format!("Device not found: {e}")))?; // Verify ownership - if device.user_id != user_id { + if device.user_id.0 != user_id.0 { return Err(ApiError::forbidden("Not authorized to delete this device")); } @@ -302,7 +300,7 @@ pub async fn regenerate_token( .map_err(|e| ApiError::not_found(format!("Device not found: {e}")))?; // Verify ownership - if device.user_id != user_id { + if device.user_id.0 != user_id.0 { return Err(ApiError::forbidden( "Not authorized to regenerate token for this device", )); diff --git a/packages/pinakes-server/src/state.rs b/packages/pinakes-server/src/state.rs index 2917ed5..eba6994 100644 --- a/packages/pinakes-server/src/state.rs +++ b/packages/pinakes-server/src/state.rs @@ -5,14 +5,15 @@ use pinakes_core::{ config::Config, jobs::JobQueue, managed_storage::ManagedStorageService, - plugin::{PluginManager, PluginPipeline}, + plugin::PluginPipeline, scan::ScanProgress, scheduler::TaskScheduler, storage::DynStorageBackend, - sync::ChunkedUploadManager, transcode::TranscodeService, webhooks::WebhookDispatcher, }; +use pinakes_plugin::PluginManager; +use pinakes_sync::ChunkedUploadManager; use tokio::sync::{RwLock, Semaphore}; // Note: Sessions are now stored in the database via StorageBackend diff --git a/packages/pinakes-server/tests/plugin.rs b/packages/pinakes-server/tests/plugin.rs index 287fef7..36b4be6 100644 --- a/packages/pinakes-server/tests/plugin.rs +++ b/packages/pinakes-server/tests/plugin.rs @@ -17,7 +17,8 @@ use common::{ test_addr, }; use http_body_util::BodyExt; -use pinakes_core::{config::PluginsConfig, plugin::PluginManager}; +use pinakes_core::config::PluginsConfig; +use pinakes_plugin::PluginManager; use tower::ServiceExt; async fn setup_app_with_plugins() @@ -50,7 +51,7 @@ async fn setup_app_with_plugins() max_concurrent_ops: 2, plugin_timeout_secs: 10, timeouts: - pinakes_core::config::PluginTimeoutConfig::default(), + pinakes_types::config::PluginTimeoutConfig::default(), max_consecutive_failures: 5, trusted_keys: vec![], };