Debuggage
This commit is contained in:
@@ -28,7 +28,7 @@ export interface ApiError {
|
|||||||
* Liste toutes les images en cache
|
* Liste toutes les images en cache
|
||||||
*/
|
*/
|
||||||
export async function listImages(): Promise<CacheEntry[]> {
|
export async function listImages(): Promise<CacheEntry[]> {
|
||||||
const response = await fetch("/api/covers/images");
|
const response = await fetch("/api/covers");
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const error: ApiError = await response.json();
|
const error: ApiError = await response.json();
|
||||||
throw new Error(error.message || "Failed to fetch images");
|
throw new Error(error.message || "Failed to fetch images");
|
||||||
@@ -40,7 +40,7 @@ export async function listImages(): Promise<CacheEntry[]> {
|
|||||||
* Récupère les informations d'une image spécifique
|
* Récupère les informations d'une image spécifique
|
||||||
*/
|
*/
|
||||||
export async function getImageInfo(pk: string): Promise<CacheEntry> {
|
export async function getImageInfo(pk: string): Promise<CacheEntry> {
|
||||||
const response = await fetch(`/api/covers/images/${pk}`);
|
const response = await fetch(`/api/covers/${pk}`);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const error: ApiError = await response.json();
|
const error: ApiError = await response.json();
|
||||||
throw new Error(error.message || "Failed to fetch image info");
|
throw new Error(error.message || "Failed to fetch image info");
|
||||||
@@ -52,7 +52,7 @@ export async function getImageInfo(pk: string): Promise<CacheEntry> {
|
|||||||
* Ajoute une nouvelle image au cache depuis une URL
|
* Ajoute une nouvelle image au cache depuis une URL
|
||||||
*/
|
*/
|
||||||
export async function addImage(url: string): Promise<AddImageResponse> {
|
export async function addImage(url: string): Promise<AddImageResponse> {
|
||||||
const response = await fetch("/api/covers/images", {
|
const response = await fetch("/api/covers", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -71,7 +71,7 @@ export async function addImage(url: string): Promise<AddImageResponse> {
|
|||||||
* Supprime une image du cache
|
* Supprime une image du cache
|
||||||
*/
|
*/
|
||||||
export async function deleteImage(pk: string): Promise<void> {
|
export async function deleteImage(pk: string): Promise<void> {
|
||||||
const response = await fetch(`/api/covers/images/${pk}`, {
|
const response = await fetch(`/api/covers/${pk}`, {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ export async function deleteImage(pk: string): Promise<void> {
|
|||||||
* Purge complètement le cache
|
* Purge complètement le cache
|
||||||
*/
|
*/
|
||||||
export async function purgeCache(): Promise<void> {
|
export async function purgeCache(): Promise<void> {
|
||||||
const response = await fetch("/api/covers/images", {
|
const response = await fetch("/api/covers", {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ export async function purgeCache(): Promise<void> {
|
|||||||
* Consolide le cache (re-télécharge les images manquantes)
|
* Consolide le cache (re-télécharge les images manquantes)
|
||||||
*/
|
*/
|
||||||
export async function consolidateCache(): Promise<void> {
|
export async function consolidateCache(): Promise<void> {
|
||||||
const response = await fetch("/api/covers/images/consolidate", {
|
const response = await fetch("/api/covers/consolidate", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -116,29 +116,34 @@ impl CoverCacheExt for Server {
|
|||||||
async fn init_cover_cache(&mut self, cache_dir: &str, limit: usize) -> anyhow::Result<Arc<Cache>> {
|
async fn init_cover_cache(&mut self, cache_dir: &str, limit: usize) -> anyhow::Result<Arc<Cache>> {
|
||||||
let cache = Arc::new(Cache::new(cache_dir, limit)?);
|
let cache = Arc::new(Cache::new(cache_dir, limit)?);
|
||||||
|
|
||||||
// Enregistrer les routes HTTP classiques
|
// Enregistrer les routes HTTP classiques pour servir les images
|
||||||
self.add_handler_with_state("/covers/images", get_cover_image, cache.clone()).await;
|
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;
|
self.add_handler_with_state("/covers/stats", get_cover_stats, cache.clone()).await;
|
||||||
|
|
||||||
// Router API RESTful
|
// 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()
|
let api_router = Router::new()
|
||||||
// Liste et ajout
|
// Liste et ajout
|
||||||
.route(
|
.route(
|
||||||
"/images/",
|
"/",
|
||||||
get(api::list_images) // GET /api/covers
|
get(api::list_images) // GET /api/covers
|
||||||
.post(api::add_image) // POST /api/covers
|
.post(api::add_image) // POST /api/covers
|
||||||
.delete(api::purge_cache), // DELETE /api/covers
|
.delete(api::purge_cache), // DELETE /api/covers
|
||||||
)
|
)
|
||||||
// Ressource unique
|
// Ressource unique
|
||||||
.route(
|
.route(
|
||||||
"/images/{pk}",
|
"/{pk}",
|
||||||
get(api::get_image_info) // GET /api/covers/{pk}
|
get(api::get_image_info) // GET /api/covers/{pk}
|
||||||
.delete(api::delete_image), // DELETE /api/covers/{pk}
|
.delete(api::delete_image), // DELETE /api/covers/{pk}
|
||||||
)
|
)
|
||||||
// Action spécifique
|
// Action spécifique
|
||||||
.route(
|
.route(
|
||||||
"/images/consolidate",
|
"/consolidate",
|
||||||
post(api::consolidate_cache), // POST /api/covers/consolidate
|
post(api::consolidate_cache), // POST /api/covers/consolidate
|
||||||
)
|
)
|
||||||
.with_state(cache.clone());
|
.with_state(cache.clone());
|
||||||
@@ -147,7 +152,9 @@ impl CoverCacheExt for Server {
|
|||||||
let openapi = crate::ApiDoc::openapi();
|
let openapi = crate::ApiDoc::openapi();
|
||||||
|
|
||||||
// Enregistrer l'API avec Swagger UI
|
// 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;
|
self.add_openapi(api_router, openapi, "covers").await;
|
||||||
|
|
||||||
Ok(cache)
|
Ok(cache)
|
||||||
|
|||||||
@@ -131,6 +131,29 @@ impl Server {
|
|||||||
*r = std::mem::take(&mut *r).nest(path, route);
|
*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
|
/// Ajoute un répertoire de fichiers statiques
|
||||||
///
|
///
|
||||||
/// Sert des fichiers embarqués via `RustEmbed`. Les fichiers sont compilés
|
/// Sert des fichiers embarqués via `RustEmbed`. Les fichiers sont compilés
|
||||||
@@ -455,7 +478,7 @@ impl Server {
|
|||||||
///
|
///
|
||||||
/// Résultat :
|
/// 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.
|
/// - `/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.
|
/// - `/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 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);
|
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
|
// Fusionner avec le router principal
|
||||||
let mut r = self.router.write().await;
|
let mut r = self.router.write().await;
|
||||||
let mut combined = std::mem::take(&mut *r);
|
let mut combined = std::mem::take(&mut *r);
|
||||||
combined = combined.merge(api_router).merge(swagger);
|
combined = combined.merge(nested_router).merge(swagger);
|
||||||
*r = combined;
|
*r = combined;
|
||||||
}
|
}
|
||||||
/// Démarre le serveur HTTP
|
/// Démarre le serveur HTTP
|
||||||
|
|||||||
Reference in New Issue
Block a user