Files
pmomusic/pmocache/src/lib.rs

147 lines
4.6 KiB
Rust
Raw Normal View History

2025-10-26 13:44:41 +01:00
//! # pmocache Système de cache générique pour PMOMusic
2025-10-12 21:39:20 +02:00
//!
2025-10-26 13:44:41 +01:00
//! Cette crate fournit les briques communes utilisées par les caches de PMOMusic.
//! Elle gère l'association entre fichiers stockés sur disque et métadonnées
//! conservées dans une base SQLite, ainsi que les opérations de téléchargement,
//! d'éviction et de mise à jour.
2025-10-12 21:39:20 +02:00
//!
//! ## Vue d'ensemble
//!
2025-10-26 13:44:41 +01:00
//! `pmocache` met à disposition :
//! - un modèle `Cache` asynchrone pour stocker des fichiers et leurs métadonnées ;
//! - un module `db` encapsulant l'accès SQLite (table `asset` + table `metadata`) ;
//! - des utilitaires de téléchargement (`download`) réutilisables par les caches spécialisés ;
//! - un trait `CacheConfig` permettant de paramétrer l'extension, le nom et le type du cache.
2025-10-12 21:39:20 +02:00
//!
2025-10-26 13:44:41 +01:00
//! Les crates `pmocovers` (images) et `pmoaudiocache` (pistes audio) s'appuient sur ces
//! composants et ajoutent leurs propres contraintes métier (conversion WebP, métadonnées audio…).
2025-10-12 21:39:20 +02:00
//!
2025-10-26 13:44:41 +01:00
//! ## Exemple basique
2025-10-12 21:39:20 +02:00
//!
//! ```rust,no_run
2025-10-17 14:36:39 +02:00
//! use pmocache::{Cache, CacheConfig};
//!
//! struct MyConfig;
//! impl CacheConfig for MyConfig {
//! fn file_extension() -> &'static str { "dat" }
//! }
2025-10-12 21:39:20 +02:00
//!
//! #[tokio::main]
//! async fn main() -> anyhow::Result<()> {
2025-10-26 13:44:41 +01:00
//! let cache = Cache::<MyConfig>::new("./cache", 1000)?;
2025-10-12 21:39:20 +02:00
//!
2025-10-26 13:44:41 +01:00
//! // Ajout d'un fichier depuis une URL
//! let pk = cache.add_from_url("https://example.com/file.dat", None).await?;
//! println!("Fichier ajouté avec la clé {pk}");
2025-10-12 21:39:20 +02:00
//!
2025-10-26 13:44:41 +01:00
//! // Récupération du fichier local
2025-10-12 21:39:20 +02:00
//! let path = cache.get(&pk).await?;
2025-10-26 13:44:41 +01:00
//! println!("Fichier disponible à {path:?}");
2025-10-12 21:39:20 +02:00
//!
//! Ok(())
//! }
//! ```
//!
2025-10-26 13:44:41 +01:00
//! ## Collections
2025-10-12 21:39:20 +02:00
//!
//! ```rust,no_run
2025-10-17 14:36:39 +02:00
//! use pmocache::{Cache, CacheConfig};
//!
//! struct AudioConfig;
//! impl CacheConfig for AudioConfig {
//! fn file_extension() -> &'static str { "flac" }
//! fn cache_type() -> &'static str { "audio" }
2025-10-26 13:44:41 +01:00
//! fn cache_name() -> &'static str { "tracks" }
2025-10-17 14:36:39 +02:00
//! }
2025-10-12 21:39:20 +02:00
//!
//! #[tokio::main]
//! async fn main() -> anyhow::Result<()> {
2025-10-26 13:44:41 +01:00
//! let cache = Cache::<AudioConfig>::new("./audio-cache", 200)?;
2025-10-12 21:39:20 +02:00
//!
2025-10-26 13:44:41 +01:00
//! let album = "album:the_wall";
//! cache.add_from_url("https://example.com/track1.flac", Some(album)).await?;
//! cache.add_from_url("https://example.com/track2.flac", Some(album)).await?;
2025-10-12 21:39:20 +02:00
//!
2025-10-26 13:44:41 +01:00
//! let files = cache.get_collection(album).await?;
//! println!("Album {album} : {} fichiers en cache", files.len());
2025-10-12 21:39:20 +02:00
//!
//! Ok(())
//! }
//! ```
//!
2025-10-26 13:44:41 +01:00
//! ## Structure sur disque
2025-10-12 21:39:20 +02:00
//!
//! ```text
//! cache/
2025-10-26 13:44:41 +01:00
//! ├── cache.db # Base SQLite
//! ├── 1a2b3c4d.orig.dat # Fichier original
//! └── 1a2b3c4d.thumb.dat # Variante (qualifier différent)
2025-10-12 21:39:20 +02:00
//! ```
//!
2025-10-26 13:44:41 +01:00
//! Les métadonnées sont conservées dans deux tables :
2025-10-12 21:39:20 +02:00
//!
//! ```sql
2025-10-26 13:44:41 +01:00
//! CREATE TABLE asset (
//! pk TEXT PRIMARY KEY,
//! collection TEXT,
//! id TEXT,
//! hits INTEGER DEFAULT 0,
//! last_used TEXT
//! );
//!
//! CREATE TABLE metadata (
//! pk TEXT,
//! key TEXT,
//! value_type TEXT CHECK(value_type IN ('string','number','boolean','null')),
//! value TEXT,
//! PRIMARY KEY (pk, key),
//! FOREIGN KEY (pk) REFERENCES asset(pk) ON DELETE CASCADE
2025-10-12 21:39:20 +02:00
//! );
//! ```
//!
2025-10-26 13:44:41 +01:00
//! ## Modules principaux
2025-10-12 21:39:20 +02:00
//!
2025-10-26 13:44:41 +01:00
//! - [`cache`] : gestion du cache sur disque + opérations asynchrones ;
//! - [`db`] : accès SQLite, contraintes et helpers métadonnées ;
//! - [`download`] : primitives de téléchargement et de transformation ;
//! - [`cache_trait`] : trait partagé entre implémentations spécialisées.
2025-10-12 21:39:20 +02:00
//!
2025-10-26 13:44:41 +01:00
//! ## Crates associées
2025-10-12 21:39:20 +02:00
//!
2025-10-26 13:44:41 +01:00
//! - [`pmocovers`] : cache d'images reposant sur `pmocache` ;
//! - [`pmoaudiocache`] : spécialisation audio avec extraction de métadonnées.
2025-10-12 21:39:20 +02:00
pub mod cache;
2025-10-17 14:36:39 +02:00
pub mod cache_trait;
2025-10-19 13:42:29 +02:00
pub mod db;
pub mod download;
2025-10-17 14:36:39 +02:00
#[cfg(feature = "pmoserver")]
pub mod pmoserver_ext;
2025-10-12 21:39:20 +02:00
#[cfg(feature = "pmoserver")]
pub mod api;
#[cfg(feature = "openapi")]
pub mod openapi;
2025-10-25 17:14:24 +02:00
#[cfg(feature = "pmoconfig")]
pub mod config_ext;
pub use cache::{Cache, CacheConfig};
2025-10-25 17:14:24 +02:00
pub use cache_trait::{pk_from_content_header, pk_from_url, FileCache};
2025-10-19 13:42:29 +02:00
pub use db::{CacheEntry, DB};
pub use download::{
download, download_with_transformer, ingest_with_transformer, peek_header, peek_reader_header,
Download, StreamTransformer,
};
#[cfg(feature = "pmoserver")]
2025-10-19 13:42:29 +02:00
pub use pmoserver_ext::{create_api_router, create_file_router, GenericCacheExt};
#[cfg(all(feature = "pmoserver", feature = "openapi"))]
2025-10-19 13:42:29 +02:00
pub use api::{AddItemRequest, AddItemResponse, DeleteItemResponse, DownloadStatus, ErrorResponse};
2025-10-25 17:14:24 +02:00
#[cfg(feature = "pmoconfig")]
pub use config_ext::CacheConfigExt;