Files
pmomusic/pmocache/ARCHITECTURE.md

176 lines
4.8 KiB
Markdown
Raw Permalink Normal View History

2025-10-12 21:39:20 +02:00
# Architecture du système de cache PMOMusic
## Vue d'ensemble
Le système de cache de PMOMusic est organisé en trois crates modulaires :
```
pmocache (générique)
├── DB générique avec collections
└── Cache générique avec téléchargement
pmocovers (spécialisé images)
├── Utilise pmocache comme base
└── Ajoute conversion WebP + variantes
pmoaudiocache (spécialisé audio)
├── Utilise pmocache comme base
├── Conversion automatique en FLAC (standardisation)
└── Ajoute extraction métadonnées + collections d'albums
```
## Principes de conception
### 1. Synchronisation et partage
Les caches sont conçus pour être utilisés via `Arc<Cache>` :
```rust
// ✅ Bon usage
let cache = Arc::new(Cache::new(config)?);
let cache_clone = Arc::clone(&cache); // Clone léger de l'Arc
// ❌ Mauvais usage (Cache n'implémente pas Clone volontairement)
let cache = Cache::new(config)?;
let cache_clone = cache.clone(); // ❌ Erreur de compilation
```
Pourquoi cette approche ?
- `Cache` contient déjà des `Arc` internes (`Arc<DB>`, `Arc<Mutex<()>>`)
- Pas besoin de double niveau d'Arc (`Arc<Cache>` suffit)
- Les méthodes prennent `&self` et gèrent la synchronisation en interne
- Évite les clonages accidentels
### 2. Collections
Le système de collections permet de regrouper des éléments logiquement :
**Pour les images (pmocovers)** :
- Les collections ne sont généralement pas utilisées
- Chaque image a une clé unique basée sur son URL
**Pour l'audio (pmoaudiocache)** :
- Collections = albums (format : `"artist:album"`)
- Exemple : `"pink_floyd:wish_you_were_here"`
- Génération automatique depuis les métadonnées ID3
### 3. Base de données
Schéma SQLite commun :
```sql
CREATE TABLE {table_name} (
pk TEXT PRIMARY KEY, -- Clé unique (SHA1 de l'URL)
source_url TEXT, -- URL source
collection TEXT, -- Collection (optionnel)
hits INTEGER DEFAULT 0, -- Nombre d'accès
last_used TEXT -- Dernière utilisation (RFC3339)
);
```
Chaque cache a sa propre table :
- `pmocovers` → table "covers"
- `pmoaudiocache` → table "audio_tracks"
### 4. Stockage des fichiers
Structure sur disque :
```
cache_dir/
├── cache.db # Base SQLite
├── {pk}.{extension} # Fichiers cachés
```
Extensions par type :
- Images : `{pk}.orig.webp` (conversion automatique depuis n'importe quel format d'image)
- Audio : `{pk}.flac` (conversion automatique depuis n'importe quel format audio)
## Utilisation
### Cache d'images (pmocovers)
```rust
use pmocovers::Cache;
use std::sync::Arc;
let cache = Arc::new(Cache::new("./covers_cache", 1000)?);
// Ajouter une image
let pk = cache.add_from_url("http://example.com/cover.jpg").await?;
// Récupérer une image
let path = cache.get(&pk).await?;
```
### Cache audio (pmoaudiocache)
```rust
use pmoaudiocache::AudioCache;
use std::sync::Arc;
let cache = Arc::new(AudioCache::new("./audio_cache", 1000)?);
// Ajouter une piste (métadonnées extraites automatiquement)
let (pk, metadata) = cache.add_from_url("http://example.com/track.flac").await?;
// Lister les collections (albums)
let collections = cache.list_collections().await?;
// Récupérer toutes les pistes d'un album
let tracks = cache.get_collection("pink_floyd:wish_you_were_here").await?;
```
### Intégration avec pmoserver
```rust
use pmocovers::CoverCacheExt;
use pmoaudiocache::AudioCacheExt;
use pmoserver::ServerBuilder;
let mut server = ServerBuilder::new_configured().build();
// Initialiser les caches
let covers = server.init_cover_cache_configured().await?;
let audio = server.init_audio_cache_configured().await?;
server.start().await;
```
## Avantages de cette architecture
1. **Modularité** : Chaque cache est indépendant
2. **Réutilisabilité** : `pmocache` peut être utilisé pour d'autres types de caches
3. **Performance** : Utilisation d'`Arc` pour un partage efficace
4. **Sécurité** : Pas de `Clone` accidentel, synchronisation explicite
5. **Extensibilité** : Facile d'ajouter de nouveaux types de caches
## Exemple de nouveau cache
Pour créer un nouveau type de cache (par exemple pour des vidéos) :
```rust
use pmocache::{Cache as GenericCache, CacheConfig};
use std::sync::Arc;
pub struct VideoCache {
cache: GenericCache,
// Champs spécifiques aux vidéos
}
impl VideoCache {
pub fn new(dir: &str, limit: usize) -> Result<Self> {
let config = CacheConfig::new(dir, limit, "videos", "mp4");
let cache = GenericCache::new(config)?;
Ok(Self { cache })
}
// Méthodes spécifiques aux vidéos
pub async fn add_with_transcoding(&self, url: &str) -> Result<String> {
// Télécharger, transcoder, puis utiliser self.cache.add()
todo!()
}
}
```