From 24be870e4a0c0bb96c6baeded9c7336da815ac96 Mon Sep 17 00:00:00 2001 From: Eric Coissac Date: Tue, 7 Oct 2025 13:12:44 +0200 Subject: [PATCH] Debuggage --- pmoapp/webapp/src/services/coverCache.ts | 12 ++++----- pmocovers/src/pmoserver_impl.rs | 21 ++++++++++----- pmoserver/src/server.rs | 33 +++++++++++++++++++++--- 3 files changed, 50 insertions(+), 16 deletions(-) diff --git a/pmoapp/webapp/src/services/coverCache.ts b/pmoapp/webapp/src/services/coverCache.ts index 96c36d0d..a277c097 100644 --- a/pmoapp/webapp/src/services/coverCache.ts +++ b/pmoapp/webapp/src/services/coverCache.ts @@ -28,7 +28,7 @@ export interface ApiError { * Liste toutes les images en cache */ export async function listImages(): Promise { - const response = await fetch("/api/covers/images"); + const response = await fetch("/api/covers"); if (!response.ok) { const error: ApiError = await response.json(); throw new Error(error.message || "Failed to fetch images"); @@ -40,7 +40,7 @@ export async function listImages(): Promise { * Récupère les informations d'une image spécifique */ export async function getImageInfo(pk: string): Promise { - const response = await fetch(`/api/covers/images/${pk}`); + const response = await fetch(`/api/covers/${pk}`); if (!response.ok) { const error: ApiError = await response.json(); throw new Error(error.message || "Failed to fetch image info"); @@ -52,7 +52,7 @@ export async function getImageInfo(pk: string): Promise { * Ajoute une nouvelle image au cache depuis une URL */ export async function addImage(url: string): Promise { - const response = await fetch("/api/covers/images", { + const response = await fetch("/api/covers", { method: "POST", headers: { "Content-Type": "application/json", @@ -71,7 +71,7 @@ export async function addImage(url: string): Promise { * Supprime une image du cache */ export async function deleteImage(pk: string): Promise { - const response = await fetch(`/api/covers/images/${pk}`, { + const response = await fetch(`/api/covers/${pk}`, { method: "DELETE", }); @@ -85,7 +85,7 @@ export async function deleteImage(pk: string): Promise { * Purge complètement le cache */ export async function purgeCache(): Promise { - const response = await fetch("/api/covers/images", { + const response = await fetch("/api/covers", { method: "DELETE", }); @@ -99,7 +99,7 @@ export async function purgeCache(): Promise { * Consolide le cache (re-télécharge les images manquantes) */ export async function consolidateCache(): Promise { - const response = await fetch("/api/covers/images/consolidate", { + const response = await fetch("/api/covers/consolidate", { method: "POST", }); diff --git a/pmocovers/src/pmoserver_impl.rs b/pmocovers/src/pmoserver_impl.rs index 18743e5b..c36029ab 100644 --- a/pmocovers/src/pmoserver_impl.rs +++ b/pmocovers/src/pmoserver_impl.rs @@ -116,29 +116,34 @@ impl CoverCacheExt for Server { async fn init_cover_cache(&mut self, cache_dir: &str, limit: usize) -> anyhow::Result> { let cache = Arc::new(Cache::new(cache_dir, limit)?); - // Enregistrer les routes HTTP classiques - self.add_handler_with_state("/covers/images", get_cover_image, cache.clone()).await; + // Enregistrer les routes HTTP classiques pour servir les images + let image_router = Router::new() + .route("/{pk}", get(get_cover_image)) + .route("/{pk}/{size}", get(get_cover_variant)) + .with_state(cache.clone()); + + self.add_router("/covers/images", image_router).await; self.add_handler_with_state("/covers/stats", get_cover_stats, cache.clone()).await; // Router API RESTful - // Router API RESTful monté sur /api/covers + // Router API RESTful qui sera nesté sous /api/covers par add_openapi let api_router = Router::new() // Liste et ajout .route( - "/images/", + "/", get(api::list_images) // GET /api/covers .post(api::add_image) // POST /api/covers .delete(api::purge_cache), // DELETE /api/covers ) // Ressource unique .route( - "/images/{pk}", + "/{pk}", get(api::get_image_info) // GET /api/covers/{pk} .delete(api::delete_image), // DELETE /api/covers/{pk} ) // Action spécifique .route( - "/images/consolidate", + "/consolidate", post(api::consolidate_cache), // POST /api/covers/consolidate ) .with_state(cache.clone()); @@ -147,7 +152,9 @@ impl CoverCacheExt for Server { let openapi = crate::ApiDoc::openapi(); // Enregistrer l'API avec Swagger UI - // /api/covers/images... et /swagger-ui/covers + // Le router sera nesté automatiquement sous /api/covers par add_openapi + // Routes finales: /api/covers, /api/covers/{pk}, /api/covers/consolidate + // Swagger UI sera disponible à /swagger-ui/covers self.add_openapi(api_router, openapi, "covers").await; Ok(cache) diff --git a/pmoserver/src/server.rs b/pmoserver/src/server.rs index d22de2a0..665ada30 100644 --- a/pmoserver/src/server.rs +++ b/pmoserver/src/server.rs @@ -131,6 +131,29 @@ impl Server { *r = std::mem::take(&mut *r).nest(path, route); } + /// Add a new router safely: + /// - If `path` starts with '/', it is merged at root level. + /// - Otherwise, it is nested under the given subpath. + pub async fn add_router(&mut self, path: &str, route: Router) { + let mut r = self.router.write().await; + + // Take current router without losing content + let current = std::mem::take(&mut *r); + + let combined = if path.starts_with('/') { + // Absolute path => merge directly at root + tracing::debug!("Merging router at root path: {}", path); + current.merge(route) + } else { + // Relative path => nest under the given path + let normalized = format!("/{}", path.trim_start_matches('/')); + tracing::debug!("Nesting router under: {}", normalized); + current.nest(&normalized, route) + }; + + *r = combined; + } + /// Ajoute un répertoire de fichiers statiques /// /// Sert des fichiers embarqués via `RustEmbed`. Les fichiers sont compilés @@ -455,7 +478,7 @@ impl Server { /// /// Résultat : /// - /// - `/users` et `/products` sont accessibles via Axum. + /// - `/api/api1/users` et `/api/api2/products` sont accessibles via Axum. /// - `/swagger-ui/api1` et `/swagger-ui/api2` affichent la documentation Swagger correspondante. /// - `/api-docs/api1.json` et `/api-docs/api2.json` fournissent les spécifications OpenAPI respectives. @@ -480,11 +503,15 @@ impl Server { let openapi_json_path_static: &'static str = Box::leak(openapi_json_path.into_boxed_str()); let swagger = SwaggerUi::new(swagger_path_static).url(openapi_json_path_static, openapi); - + + // Nester le router API sous /api/{name} + let base_path = format!("/api/{}", name); + let nested_router = Router::new().nest(&base_path, api_router); + // Fusionner avec le router principal let mut r = self.router.write().await; let mut combined = std::mem::take(&mut *r); - combined = combined.merge(api_router).merge(swagger); + combined = combined.merge(nested_router).merge(swagger); *r = combined; } /// Démarre le serveur HTTP