From a6cb7ac5e1376eed35d5be00403b57e3a1ef9cec Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 5 Nov 2025 20:02:01 +0000 Subject: [PATCH 1/3] Add register_audio_cache to pmoplaylist (fix circular dependency) Fix "PlaylistManager not initialized" error without creating circular dependency between pmoparadise and pmoupnp. Changes: - Add AUDIO_CACHE static to pmoplaylist/manager.rs - Add register_audio_cache() function to register cache - Export register_audio_cache from pmoplaylist lib.rs - Update audio_cache() to check local registry first, then pmoupnp - Update play_and_cache example to use pmoplaylist::register_audio_cache - Remove pmoupnp::register_*_cache functions (not needed) The example now calls pmoplaylist::register_audio_cache() to make the cache available for pk validation in WriteHandle::push(). --- pmoparadise/examples/play_and_cache.rs | 7 +++--- pmoplaylist/src/lib.rs | 2 +- pmoplaylist/src/manager.rs | 31 +++++++++++++++++++++++++- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/pmoparadise/examples/play_and_cache.rs b/pmoparadise/examples/play_and_cache.rs index 6a8b77f8..57354fa6 100644 --- a/pmoparadise/examples/play_and_cache.rs +++ b/pmoparadise/examples/play_and_cache.rs @@ -100,11 +100,10 @@ async fn main() -> Result<(), Box> { )?); tracing::debug!("Cover cache initialized at: {}", cover_cache_dir); - // Enregistrer les caches dans le registre global pmoupnp + // Enregistrer le cache audio dans pmoplaylist // (requis par pmoplaylist pour valider les pks) - pmoupnp::register_audio_cache(audio_cache.clone()); - pmoupnp::register_cover_cache(cover_cache.clone()); - tracing::debug!("Caches registered in pmoupnp global registry"); + pmoplaylist::register_audio_cache(audio_cache.clone()); + tracing::debug!("Audio cache registered in pmoplaylist"); // Utiliser le gestionnaire de playlist singleton tracing::info!("Getting playlist manager..."); diff --git a/pmoplaylist/src/lib.rs b/pmoplaylist/src/lib.rs index a54349b9..19d03899 100644 --- a/pmoplaylist/src/lib.rs +++ b/pmoplaylist/src/lib.rs @@ -57,7 +57,7 @@ mod config_ext; // Réexports publics pub use error::{Error, Result}; pub use handle::{ReadHandle, WriteHandle}; -pub use manager::{PlaylistManager, PlaylistManager as Manager}; +pub use manager::{register_audio_cache, PlaylistManager, PlaylistManager as Manager}; pub use track::PlaylistTrack; #[cfg(feature = "pmoconfig")] diff --git a/pmoplaylist/src/manager.rs b/pmoplaylist/src/manager.rs index e622b2b1..7a4e148c 100644 --- a/pmoplaylist/src/manager.rs +++ b/pmoplaylist/src/manager.rs @@ -15,6 +15,9 @@ use tokio::sync::RwLock; /// Singleton PlaylistManager static PLAYLIST_MANAGER: OnceCell = OnceCell::new(); +/// Registre global du cache audio +static AUDIO_CACHE: OnceCell> = OnceCell::new(); + /// Structure interne du manager struct ManagerInner { playlists: RwLock>>, @@ -284,9 +287,35 @@ pub(crate) async fn delete_playlist_internal(id: &str) -> Result<()> { PlaylistManager::get().delete_playlist(id).await } +/// Enregistre le cache audio global +/// +/// Cette fonction doit être appelée au démarrage de l'application +/// pour rendre le cache audio disponible au PlaylistManager. +/// +/// # Examples +/// +/// ```rust,ignore +/// use pmoplaylist::register_audio_cache; +/// use pmoaudiocache::Cache as AudioCache; +/// use std::sync::Arc; +/// +/// let audio_cache = Arc::new(AudioCache::new("./cache", 1000)?); +/// register_audio_cache(audio_cache); +/// ``` +pub fn register_audio_cache(cache: Arc) { + let _ = AUDIO_CACHE.set(cache); +} + /// Helper pour acc�der au cache audio pub(crate) fn audio_cache() -> Result> { - pmoupnp::get_audio_cache().ok_or_else(|| crate::Error::ManagerNotInitialized) + AUDIO_CACHE + .get() + .cloned() + .or_else(|| { + // Fallback: essayer pmoupnp si disponible + pmoupnp::get_audio_cache() + }) + .ok_or_else(|| crate::Error::ManagerNotInitialized) } /// Fonction raccourcie pour acc�der au singleton From e06a8d95df3d91d2d343b12a442e1163a8e05a9a Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 5 Nov 2025 20:48:52 +0000 Subject: [PATCH 2/3] =?UTF-8?q?D=C3=A9placer=20cache=20registry=20dans=20l?= =?UTF-8?q?es=20crates=20individuelles=20(pattern=20singleton)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Au lieu d'avoir un cache_registry centralisé dans pmoupnp qui créait des dépendances circulaires, chaque crate a maintenant son propre singleton global : - pmoaudiocache : register_audio_cache() + get_audio_cache() - pmocovers : register_cover_cache() + get_cover_cache() Changes: - Add singleton pattern to pmoaudiocache/src/lib.rs - Add singleton pattern to pmocovers/src/lib.rs - Add once_cell dependency to both crates - Update pmoplaylist to use pmoaudiocache::get_audio_cache() as fallback - Update pmoupnp/upnp_server.rs to use register_* functions - Update pmoupnp/lib.rs to reexport only get_* (not register_*) - Remove pmoupnp/src/cache_registry.rs (no longer needed) pmoupnp réexporte get_audio_cache() et get_cover_cache() pour compatibilité avec le code existant (pmosource, etc.). --- Cargo.lock | 2 + pmoaudiocache/Cargo.toml | 3 + pmoaudiocache/src/lib.rs | 44 +++++- pmocovers/Cargo.toml | 3 + pmocovers/src/lib.rs | 46 ++++++- pmoplaylist/src/manager.rs | 4 +- pmoupnp/src/cache_registry.rs | 250 ---------------------------------- pmoupnp/src/lib.rs | 8 +- pmoupnp/src/upnp_server.rs | 21 +-- 9 files changed, 107 insertions(+), 274 deletions(-) delete mode 100644 pmoupnp/src/cache_registry.rs diff --git a/Cargo.lock b/Cargo.lock index 1c60e85e..b4fc4f12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2890,6 +2890,7 @@ dependencies = [ "chrono", "futures-util", "lofty", + "once_cell", "paste", "pmocache", "pmoconfig", @@ -2959,6 +2960,7 @@ dependencies = [ "anyhow", "axum 0.8.6", "image", + "once_cell", "pmocache", "pmoconfig", "pmoserver", diff --git a/pmoaudiocache/Cargo.toml b/pmoaudiocache/Cargo.toml index c04f343a..49dc679e 100644 --- a/pmoaudiocache/Cargo.toml +++ b/pmoaudiocache/Cargo.toml @@ -36,6 +36,9 @@ async-trait = "0.1" # Async tokio = { version = "1.0", features = ["full"] } +# Singleton +once_cell = "1.20" + # Serveur HTTP (optionnel pour l'extension) pmoserver = { path = "../pmoserver", optional = true } pmoconfig = { path = "../pmoconfig", optional = true } diff --git a/pmoaudiocache/src/lib.rs b/pmoaudiocache/src/lib.rs index 16e8888a..5b65f018 100755 --- a/pmoaudiocache/src/lib.rs +++ b/pmoaudiocache/src/lib.rs @@ -100,6 +100,48 @@ pub use config_ext::AudioCacheConfigExt; #[cfg(feature = "pmoserver")] pub use openapi::ApiDoc; +// ============================================================================ +// Registre global singleton +// ============================================================================ + +use once_cell::sync::OnceCell; +use std::sync::Arc; + +static AUDIO_CACHE: OnceCell> = OnceCell::new(); + +/// Enregistre le cache audio global +/// +/// Cette fonction doit être appelée au démarrage de l'application +/// pour rendre le cache audio disponible globalement. +/// +/// # Examples +/// +/// ```rust,ignore +/// use pmoaudiocache::{new_cache, register_audio_cache}; +/// use std::sync::Arc; +/// +/// let cache = Arc::new(new_cache("./cache", 1000)?); +/// register_audio_cache(cache); +/// ``` +pub fn register_audio_cache(cache: Arc) { + let _ = AUDIO_CACHE.set(cache); +} + +/// Accès global au cache audio +/// +/// # Examples +/// +/// ```rust,ignore +/// use pmoaudiocache::get_audio_cache; +/// +/// if let Some(cache) = get_audio_cache() { +/// // Utiliser le cache +/// } +/// ``` +pub fn get_audio_cache() -> Option> { + AUDIO_CACHE.get().cloned() +} + // ============================================================================ // Extension pmoserver (inline comme pmocovers) // ============================================================================ @@ -132,8 +174,6 @@ pub trait AudioCacheExt { #[cfg(feature = "pmoserver")] use pmocache::pmoserver_ext::{create_api_router, create_file_router}; #[cfg(feature = "pmoserver")] -use std::sync::Arc; -#[cfg(feature = "pmoserver")] use utoipa::OpenApi; #[cfg(feature = "pmoserver")] diff --git a/pmocovers/Cargo.toml b/pmocovers/Cargo.toml index a9a237bc..eea54228 100644 --- a/pmocovers/Cargo.toml +++ b/pmocovers/Cargo.toml @@ -21,6 +21,9 @@ serde = { version = "1.0", features = ["derive"] } # Async tokio = { version = "1.0", features = ["full"] } +# Singleton +once_cell = "1.20" + # Serveur HTTP (optionnel pour l'extension) pmoserver = { path = "../pmoserver", optional = true } pmoconfig = { path = "../pmoconfig", optional = true } diff --git a/pmocovers/src/lib.rs b/pmocovers/src/lib.rs index 104371a1..a9e2cd5b 100644 --- a/pmocovers/src/lib.rs +++ b/pmocovers/src/lib.rs @@ -68,8 +68,52 @@ pub use openapi::ApiDoc; #[cfg(feature = "pmoconfig")] pub use config_ext::CoverCacheConfigExt; -#[cfg(feature = "pmoserver")] +// ============================================================================ +// Registre global singleton +// ============================================================================ + +use once_cell::sync::OnceCell; use std::sync::Arc; + +static COVER_CACHE: OnceCell> = OnceCell::new(); + +/// Enregistre le cache de couvertures global +/// +/// Cette fonction doit être appelée au démarrage de l'application +/// pour rendre le cache de couvertures disponible globalement. +/// +/// # Examples +/// +/// ```rust,ignore +/// use pmocovers::{new_cache, register_cover_cache}; +/// use std::sync::Arc; +/// +/// let cache = Arc::new(new_cache("./covers", 100)?); +/// register_cover_cache(cache); +/// ``` +pub fn register_cover_cache(cache: Arc) { + let _ = COVER_CACHE.set(cache); +} + +/// Accès global au cache de couvertures +/// +/// # Examples +/// +/// ```rust,ignore +/// use pmocovers::get_cover_cache; +/// +/// if let Some(cache) = get_cover_cache() { +/// // Utiliser le cache +/// } +/// ``` +pub fn get_cover_cache() -> Option> { + COVER_CACHE.get().cloned() +} + +// ============================================================================ +// Extension pmoserver +// ============================================================================ + #[cfg(feature = "pmoserver")] use utoipa::OpenApi; diff --git a/pmoplaylist/src/manager.rs b/pmoplaylist/src/manager.rs index 7a4e148c..2daf75f8 100644 --- a/pmoplaylist/src/manager.rs +++ b/pmoplaylist/src/manager.rs @@ -312,8 +312,8 @@ pub(crate) fn audio_cache() -> Result> { .get() .cloned() .or_else(|| { - // Fallback: essayer pmoupnp si disponible - pmoupnp::get_audio_cache() + // Fallback: essayer le registre global de pmoaudiocache + pmoaudiocache::get_audio_cache() }) .ok_or_else(|| crate::Error::ManagerNotInitialized) } diff --git a/pmoupnp/src/cache_registry.rs b/pmoupnp/src/cache_registry.rs deleted file mode 100644 index 8c4d87da..00000000 --- a/pmoupnp/src/cache_registry.rs +++ /dev/null @@ -1,250 +0,0 @@ -//! Registre centralisé des caches pour le serveur UPnP -//! -//! Ce module gère les caches partagés entre toutes les sources musicales : -//! - Cache de couvertures d'albums (WebP) -//! - Cache de pistes audio (FLAC) -//! -//! Les caches supportent les collections, permettant à chaque source -//! d'avoir sa propre collection dans le cache partagé. - -use once_cell::sync::Lazy; -use pmoaudiocache::Cache as AudioCache; -use pmocache::FileCache; -use pmocovers::Cache as CoverCache; -use std::sync::Arc; -use std::sync::RwLock; - -/// Registre global des caches -/// -/// Contient les instances partagées des caches de couvertures et audio. -/// Ces caches sont uniques et partagés entre toutes les sources musicales. -pub struct CacheRegistry { - /// URL de base du serveur (ex: "http://localhost:8080") - base_url: Option, - - /// Cache de couvertures (WebP) - cover_cache: Option>, - - /// Cache audio (FLAC) - audio_cache: Option>, -} - -impl CacheRegistry { - /// Créer un nouveau registre vide - pub fn new() -> Self { - Self { - base_url: None, - cover_cache: None, - audio_cache: None, - } - } - - /// Définir l'URL de base du serveur - pub fn set_base_url(&mut self, url: String) { - self.base_url = Some(url); - } - - /// Récupérer l'URL de base du serveur - pub fn base_url(&self) -> Option<&str> { - self.base_url.as_deref() - } - - /// Enregistrer le cache de couvertures - pub fn set_cover_cache(&mut self, cache: Arc) { - self.cover_cache = Some(cache); - } - - /// Récupérer le cache de couvertures - pub fn cover_cache(&self) -> Option> { - self.cover_cache.clone() - } - - /// Enregistrer le cache audio - pub fn set_audio_cache(&mut self, cache: Arc) { - self.audio_cache = Some(cache); - } - - /// Récupérer le cache audio - pub fn audio_cache(&self) -> Option> { - self.audio_cache.clone() - } - - /// Construit l'URL complète pour une couverture - /// - /// # Arguments - /// - /// * `pk` - Clé primaire de la couverture - /// * `size` - Taille optionnelle de l'image - /// - /// # Returns - /// - /// URL complète (ex: "http://localhost:8080/covers/images/abc123/300") - pub fn build_cover_url(&self, pk: &str, size: Option) -> anyhow::Result { - let base_url = self - .base_url - .as_ref() - .ok_or_else(|| anyhow::anyhow!("Base URL not set in CacheRegistry"))?; - let cache = get_cover_cache().ok_or_else(|| anyhow::anyhow!("No registred cover cache"))?; - let param = match size { - Some(size_) => Some(size_.to_string()), - None => None, - }; - let route = cache.route_for(pk, param.as_deref()); - Ok(format!("{}{}", base_url, route)) - } - - /// Construit l'URL complète pour une piste audio - /// - /// # Arguments - /// - /// * `pk` - Clé primaire de la piste - /// * `param` - Paramètre optionnel (ex: "orig", "128k") - /// - /// # Returns - /// - /// URL complète (ex: "http://localhost:8080/audio/tracks/abc123/orig") - pub fn build_audio_url(&self, pk: &str, param: Option<&str>) -> anyhow::Result { - let base_url = self - .base_url - .as_ref() - .ok_or_else(|| anyhow::anyhow!("Base URL not set in CacheRegistry"))?; - let cache = get_audio_cache().ok_or_else(|| anyhow::anyhow!("No registred audio cache"))?; - let route = cache.route_for(pk, param); - Ok(format!("{}{}", base_url, route)) - } -} - -impl Default for CacheRegistry { - fn default() -> Self { - Self::new() - } -} - -/// Registre global thread-safe -/// -/// Utilise Lazy pour une initialisation paresseuse et RwLock pour le partage entre threads. -/// Permet aux handlers et aux sources d'accéder aux caches depuis n'importe où. -pub(crate) static CACHE_REGISTRY: Lazy> = - Lazy::new(|| RwLock::new(CacheRegistry::new())); - -/// Accès global au cache de couvertures -/// -/// # Examples -/// -/// ```rust,ignore -/// use pmoupnp::cache_registry::get_cover_cache; -/// -/// if let Some(cache) = get_cover_cache() { -/// let pk = cache.add_from_url("http://example.com/cover.jpg").await?; -/// } -/// ``` -pub fn get_cover_cache() -> Option> { - CACHE_REGISTRY.read().unwrap().cover_cache() -} - -/// Accès global au cache audio -/// -/// # Examples -/// -/// ```rust,ignore -/// use pmoupnp::cache_registry::get_audio_cache; -/// -/// if let Some(cache) = get_audio_cache() { -/// let (pk, _) = cache.add_from_url("http://example.com/track.flac", None).await?; -/// } -/// ``` -pub fn get_audio_cache() -> Option> { - CACHE_REGISTRY.read().unwrap().audio_cache() -} - -/// Enregistre le cache audio global -/// -/// Cette fonction doit être appelée au démarrage de l'application -/// pour rendre le cache audio disponible globalement. -/// -/// # Examples -/// -/// ```rust,ignore -/// use pmoupnp::cache_registry::register_audio_cache; -/// use pmoaudiocache::Cache as AudioCache; -/// use std::sync::Arc; -/// -/// let audio_cache = Arc::new(AudioCache::new("./cache", 1000)?); -/// register_audio_cache(audio_cache); -/// ``` -pub fn register_audio_cache(cache: Arc) { - CACHE_REGISTRY.write().unwrap().set_audio_cache(cache); -} - -/// Enregistre le cache de couvertures global -/// -/// Cette fonction doit être appelée au démarrage de l'application -/// pour rendre le cache de couvertures disponible globalement. -/// -/// # Examples -/// -/// ```rust,ignore -/// use pmoupnp::cache_registry::register_cover_cache; -/// use pmocovers::Cache as CoverCache; -/// use std::sync::Arc; -/// -/// let cover_cache = Arc::new(CoverCache::new("./covers", 100)?); -/// register_cover_cache(cover_cache); -/// ``` -pub fn register_cover_cache(cache: Arc) { - CACHE_REGISTRY.write().unwrap().set_cover_cache(cache); -} - -/// Construit l'URL complète pour une couverture -/// -/// Fonction globale qui utilise le registre de caches pour construire l'URL. -/// -/// # Arguments -/// -/// * `pk` - Clé primaire de la couverture -/// * `size` - Taille optionnelle de l'image -/// -/// # Examples -/// -/// ```rust,ignore -/// use pmoupnp::cache_registry::build_cover_url; -/// -/// let url = build_cover_url("abc123", Some(300))?; -/// // url = "http://localhost:8080/covers/images/abc123/300" -/// ``` -pub fn build_cover_url(pk: &str, size: Option) -> anyhow::Result { - CACHE_REGISTRY.read().unwrap().build_cover_url(pk, size) -} - -/// Construit l'URL complète pour une piste audio -/// -/// Fonction globale qui utilise le registre de caches pour construire l'URL. -/// -/// # Arguments -/// -/// * `pk` - Clé primaire de la piste -/// * `param` - Paramètre optionnel (ex: "orig", "128k") -/// -/// # Examples -/// -/// ```rust,ignore -/// use pmoupnp::cache_registry::build_audio_url; -/// -/// let url = build_audio_url("abc123", Some("orig"))?; -/// // url = "http://localhost:8080/audio/tracks/abc123/orig" -/// ``` -pub fn build_audio_url(pk: &str, param: Option<&str>) -> anyhow::Result { - CACHE_REGISTRY.read().unwrap().build_audio_url(pk, param) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_cache_registry_empty() { - let registry = CacheRegistry::new(); - assert!(registry.cover_cache().is_none()); - assert!(registry.audio_cache().is_none()); - } -} diff --git a/pmoupnp/src/lib.rs b/pmoupnp/src/lib.rs index 4442472a..28e0cb93 100644 --- a/pmoupnp/src/lib.rs +++ b/pmoupnp/src/lib.rs @@ -2,7 +2,6 @@ mod object_set; mod object_trait; pub mod actions; -pub mod cache_registry; pub mod devices; pub mod services; pub mod soap; @@ -16,9 +15,10 @@ pub mod variable_types; use std::sync::RwLock; use std::{collections::HashMap, sync::Arc}; -pub use crate::cache_registry::{ - get_audio_cache, get_cover_cache, register_audio_cache, register_cover_cache, -}; +// Réexports pour compatibilité (seulement get_*, pas register_*) +pub use pmoaudiocache::get_audio_cache; +pub use pmocovers::get_cover_cache; + pub use crate::object_trait::*; pub use crate::upnp_server::UpnpServerExt; diff --git a/pmoupnp/src/upnp_server.rs b/pmoupnp/src/upnp_server.rs index f4538193..881b7e9c 100644 --- a/pmoupnp/src/upnp_server.rs +++ b/pmoupnp/src/upnp_server.rs @@ -26,7 +26,6 @@ use pmoserver::Server; use utoipa::OpenApi; use crate::UpnpModel; -use crate::cache_registry::CACHE_REGISTRY; use crate::devices::errors::DeviceError; use crate::devices::{Device, DeviceInstance, DeviceRegistry}; use crate::ssdp::SsdpServer; @@ -330,12 +329,8 @@ impl UpnpServerExt for Server { let openapi = pmocovers::ApiDoc::openapi(); self.add_openapi(api_router, openapi, "covers").await; - // Enregistrer base_url et cache dans le registre global - { - let mut registry = CACHE_REGISTRY.write().unwrap(); - registry.set_base_url(base_url); - registry.set_cover_cache(cache.clone()); - } + // Enregistrer le cache dans le registre global + pmocovers::register_cover_cache(cache.clone()); Ok(cache) } @@ -360,12 +355,8 @@ impl UpnpServerExt for Server { let openapi = pmoaudiocache::ApiDoc::openapi(); self.add_openapi(api_router, openapi, "audio").await; - // Enregistrer base_url et cache dans le registre global - { - let mut registry = CACHE_REGISTRY.write().unwrap(); - registry.set_base_url(base_url); - registry.set_audio_cache(cache.clone()); - } + // Enregistrer le cache dans le registre global + pmoaudiocache::register_audio_cache(cache.clone()); Ok(cache) } @@ -388,11 +379,11 @@ impl UpnpServerExt for Server { } fn cover_cache(&self) -> Option> { - crate::cache_registry::get_cover_cache() + pmocovers::get_cover_cache() } fn audio_cache(&self) -> Option> { - crate::cache_registry::get_audio_cache() + pmoaudiocache::get_audio_cache() } // ========= SSDP Management Implementation ========= From 4e5b8a9148fbe0305c7539b4eef9601c149719bf Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 5 Nov 2025 20:54:07 +0000 Subject: [PATCH 3/3] =?UTF-8?q?Am=C3=A9liorer=20la=20documentation=20des?= =?UTF-8?q?=20fonctions=20singleton=20de=20cache?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Ajouter sections # Arguments et # Returns - Documenter le comportement thread-safe - Préciser le comportement en cas d'appels multiples - Ajouter liens croisés entre register_* et get_* --- pmoaudiocache/src/lib.rs | 22 ++++++++++++++++++++++ pmocovers/src/lib.rs | 22 ++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/pmoaudiocache/src/lib.rs b/pmoaudiocache/src/lib.rs index 5b65f018..61dfa085 100755 --- a/pmoaudiocache/src/lib.rs +++ b/pmoaudiocache/src/lib.rs @@ -114,6 +114,16 @@ static AUDIO_CACHE: OnceCell> = OnceCell::new(); /// Cette fonction doit être appelée au démarrage de l'application /// pour rendre le cache audio disponible globalement. /// +/// # Arguments +/// +/// * `cache` - Instance partagée du cache audio à enregistrer +/// +/// # Behavior +/// +/// - Si appelée plusieurs fois, seul le premier appel prend effet +/// - Thread-safe: peut être appelée depuis plusieurs threads simultanément +/// - Une fois enregistré, le cache est accessible via [`get_audio_cache`] +/// /// # Examples /// /// ```rust,ignore @@ -129,6 +139,18 @@ pub fn register_audio_cache(cache: Arc) { /// Accès global au cache audio /// +/// Retourne une référence au cache audio enregistré via [`register_audio_cache`], +/// ou `None` si aucun cache n'a été enregistré. +/// +/// # Returns +/// +/// * `Some(Arc)` - Instance partagée du cache audio si enregistré +/// * `None` - Si aucun cache n'a été enregistré +/// +/// # Thread Safety +/// +/// Cette fonction est thread-safe et peut être appelée depuis plusieurs threads. +/// /// # Examples /// /// ```rust,ignore diff --git a/pmocovers/src/lib.rs b/pmocovers/src/lib.rs index a9e2cd5b..bc283057 100644 --- a/pmocovers/src/lib.rs +++ b/pmocovers/src/lib.rs @@ -82,6 +82,16 @@ static COVER_CACHE: OnceCell> = OnceCell::new(); /// Cette fonction doit être appelée au démarrage de l'application /// pour rendre le cache de couvertures disponible globalement. /// +/// # Arguments +/// +/// * `cache` - Instance partagée du cache de couvertures à enregistrer +/// +/// # Behavior +/// +/// - Si appelée plusieurs fois, seul le premier appel prend effet +/// - Thread-safe: peut être appelée depuis plusieurs threads simultanément +/// - Une fois enregistré, le cache est accessible via [`get_cover_cache`] +/// /// # Examples /// /// ```rust,ignore @@ -97,6 +107,18 @@ pub fn register_cover_cache(cache: Arc) { /// Accès global au cache de couvertures /// +/// Retourne une référence au cache de couvertures enregistré via [`register_cover_cache`], +/// ou `None` si aucun cache n'a été enregistré. +/// +/// # Returns +/// +/// * `Some(Arc)` - Instance partagée du cache de couvertures si enregistré +/// * `None` - Si aucun cache n'a été enregistré +/// +/// # Thread Safety +/// +/// Cette fonction est thread-safe et peut être appelée depuis plusieurs threads. +/// /// # Examples /// /// ```rust,ignore