feat: upgrade needed ressources and fight for each quest
This commit is contained in:
@ -2,6 +2,7 @@ use tauri::{AppHandle, Emitter, Manager, State};
|
||||
use tauri::window::Color;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Mutex;
|
||||
use std::collections::HashMap;
|
||||
use rusqlite::Connection;
|
||||
|
||||
use crate::{db, parser};
|
||||
@ -556,6 +557,112 @@ pub async fn open_image_viewer(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Lit le cache SQLite pour une liste d'URLs et retourne les indicateurs déjà stockés.
|
||||
/// Synchrone et instantané — utilisé au chargement de la vue pour afficher les données en cache.
|
||||
#[tauri::command]
|
||||
pub fn get_cached_previews(
|
||||
state: State<DbState>,
|
||||
quest_urls: Vec<String>,
|
||||
) -> Result<HashMap<String, Vec<parser::CombatIndicator>>, String> {
|
||||
let conn = state.0.lock().map_err(|e| e.to_string())?;
|
||||
Ok(db::get_cached_previews(&conn, &quest_urls))
|
||||
}
|
||||
|
||||
/// Scrape toutes les quêtes d'un guide qui ne sont pas encore en cache, stocke les résultats
|
||||
/// en DB et retourne l'ensemble `url → indicateurs` pour le guide demandé.
|
||||
#[tauri::command]
|
||||
pub async fn fetch_guide_previews(
|
||||
state: State<'_, DbState>,
|
||||
gid: String,
|
||||
) -> Result<HashMap<String, Vec<parser::CombatIndicator>>, String> {
|
||||
// 1. Charge le guide depuis la DB (section critique minimale)
|
||||
let guide = {
|
||||
let conn = state.0.lock().map_err(|e| e.to_string())?;
|
||||
db::get_guide(&conn, &gid)
|
||||
.map_err(|e| e.to_string())?
|
||||
.ok_or_else(|| format!("Guide {} introuvable", gid))?
|
||||
};
|
||||
|
||||
// 2. Collecte toutes les URLs des quêtes du guide
|
||||
let all_urls: Vec<String> = collect_quest_urls(&guide);
|
||||
|
||||
// 3. Détermine quelles URLs ne sont pas encore en cache
|
||||
let cached_urls = {
|
||||
let conn = state.0.lock().map_err(|e| e.to_string())?;
|
||||
db::get_cached_urls(&conn, &all_urls)
|
||||
};
|
||||
|
||||
let urls_to_fetch: Vec<String> = all_urls
|
||||
.iter()
|
||||
.filter(|u| !cached_urls.contains(*u))
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
// 4. Scrape les pages manquantes (bloquant → spawn_blocking)
|
||||
for url in urls_to_fetch {
|
||||
let url_clone = url.clone();
|
||||
let result = tokio::task::spawn_blocking(move || -> Result<Vec<parser::CombatIndicator>, String> {
|
||||
let client = reqwest::blocking::Client::builder()
|
||||
.timeout(std::time::Duration::from_secs(20))
|
||||
.user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
|
||||
.build()
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let html = client
|
||||
.get(&url_clone)
|
||||
.send()
|
||||
.map_err(|e| format!("Erreur réseau {} : {}", url_clone, e))?
|
||||
.text()
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(parser::extract_a_prevoir(&html))
|
||||
})
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
// On persiste même si le résultat est vide (évite de re-scraper une page sans section)
|
||||
match result {
|
||||
Ok(indicators) => {
|
||||
let conn = state.0.lock().map_err(|e| e.to_string())?;
|
||||
db::upsert_preview(&conn, &url, &indicators).map_err(|e| e.to_string())?;
|
||||
}
|
||||
Err(e) => {
|
||||
// Erreur réseau non fatale : on log et on continue
|
||||
eprintln!("[fetch_guide_previews] Erreur pour {} : {}", url, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Retourne l'ensemble du cache pour toutes les URLs du guide
|
||||
let conn = state.0.lock().map_err(|e| e.to_string())?;
|
||||
Ok(db::get_cached_previews(&conn, &all_urls))
|
||||
}
|
||||
|
||||
/// Extrait toutes les URLs de quêtes depuis un `GuideData` (Quest + Group.quests).
|
||||
fn collect_quest_urls(data: &parser::GuideData) -> Vec<String> {
|
||||
let mut urls = Vec::new();
|
||||
for section in &data.sections {
|
||||
for item in §ion.items {
|
||||
match item {
|
||||
parser::SectionItem::Quest(q) => {
|
||||
if let Some(url) = &q.url {
|
||||
urls.push(url.clone());
|
||||
}
|
||||
}
|
||||
parser::SectionItem::Group(g) => {
|
||||
for q in &g.quests {
|
||||
if let Some(url) = &q.url {
|
||||
urls.push(url.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
parser::SectionItem::Instruction(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
urls
|
||||
}
|
||||
|
||||
fn collect_quest_names(data: &parser::GuideData) -> Vec<String> {
|
||||
let mut names = Vec::new();
|
||||
for section in &data.sections {
|
||||
|
||||
Reference in New Issue
Block a user