fix: synchronisation dédoublonnage entre upload web et watcher

- Ajout de dedup_db_path dans AppState (partagé avec le watcher)
- upload_image() calcule le SHA-256 avant upload et marque le hash
  dans la DB de dédoublonnage après succès
- Le watcher voit maintenant les fichiers uploadés via le dashboard
  comme 'déjà vus' → plus de doublons watcher/drag-and-drop
- Correction compilation: indentation du match upload_image
This commit is contained in:
2026-06-25 13:18:08 -04:00
parent ed3ef23d2f
commit e867dadb1f
2 changed files with 33 additions and 9 deletions
+11
View File
@@ -32,12 +32,23 @@ pub async fn serve_with_config(host: &str, port: u16, config: &Config) -> anyhow
// Hub WebSocket // Hub WebSocket
let ws_hub = ws::WsHub::new(); let ws_hub = ws::WsHub::new();
// Base de données de dédoublonnage (partagée avec le watcher)
let data_dir = if cfg!(target_os = "windows") {
let appdata = std::env::var("APPDATA").unwrap_or_else(|_| ".".into());
std::path::PathBuf::from(appdata)
} else {
let home = std::env::var("HOME").unwrap_or_else(|_| "/tmp".into());
std::path::PathBuf::from(home).join(".config")
};
let dedup_db_path = data_dir.join("imagod-web").join("imagod.db");
// État partagé // État partagé
let state = routes::AppState { let state = routes::AppState {
imago, imago,
base_url: config.imago.url.clone(), base_url: config.imago.url.clone(),
api_key: config.imago.api_key.clone(), api_key: config.imago.api_key.clone(),
ws_hub: ws_hub.clone(), ws_hub: ws_hub.clone(),
dedup_db_path,
}; };
// Router principal // Router principal
+22 -9
View File
@@ -9,6 +9,7 @@ use axum::{
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::sync::Arc; use std::sync::Arc;
use std::path::PathBuf;
use crate::imago_client::{ImagoClient, ImageSummary}; use crate::imago_client::{ImagoClient, ImageSummary};
/// État partagé de l'application /// État partagé de l'application
@@ -17,6 +18,8 @@ pub struct AppState {
pub base_url: String, pub base_url: String,
pub api_key: String, pub api_key: String,
pub ws_hub: crate::server::ws::WsHub, pub ws_hub: crate::server::ws::WsHub,
/// Chemin vers la DB de dédoublonnage (partagée avec le watcher)
pub dedup_db_path: PathBuf,
} }
/// Crée un ImagoClient — utilise la clé fournie par l'utilisateur si présente, /// Crée un ImagoClient — utilise la clé fournie par l'utilisateur si présente,
@@ -217,16 +220,26 @@ async fn upload_image(
Err(e) => return error_response(500, &format!("Erreur client : {}", e)), Err(e) => return error_response(500, &format!("Erreur client : {}", e)),
}; };
// Calculer le hash AVANT de consommer `data` (upload_image prend ownership)
let file_hash = crate::dedup::Dedup::hash_bytes(&data);
match client.upload_image(data, &filename, None).await { match client.upload_image(data, &filename, None).await {
Ok(response) => ( Ok(response) => {
axum::http::StatusCode::CREATED, // Marquer le hash dans la DB de dédoublonnage pour que le watcher
Json(serde_json::json!({ // ne ré-upload pas ce fichier
"id": response.id, if let Ok(dedup) = crate::dedup::Dedup::open(&state.dedup_db_path, 1000) {
"uuid": response.uuid, let _ = dedup.mark_seen(&file_hash, &response.id.to_string());
"filename": response.original_name, }
"status": response.status, (
})), axum::http::StatusCode::CREATED,
), Json(serde_json::json!({
"id": response.id,
"uuid": response.uuid,
"filename": response.original_name,
"status": response.status,
})),
)
}
Err(e) => { Err(e) => {
tracing::error!("Upload vers Imago échoué : {:#}", e); tracing::error!("Upload vers Imago échoué : {:#}", e);
( (