use crate::data::{FetchResult, FetchResultCard, State}; use crate::download::Downloader; use crate::github::{fetch_last_hash, sync_data}; use crate::{CONFIG, PROVIDE, STATE, STORE, ending_point}; use anyhow::anyhow; use assets_updater::core::export_pipeline::find_files; use futures::StreamExt; use futures::stream::FuturesUnordered; use log::{debug, info}; use std::fs; pub async fn main() -> anyhow::Result<()> { let current_hash = fetch_last_hash().await?; ending_point!(ok); let old_state = { let mut l = STATE.read(); if l.is_err() { STATE.clear_poison(); drop(l); let mut s = STATE.write().map_err(|e| anyhow!("{}", e))?; *s = State::new(); let _ = s.init(); drop(s); l = STATE.read(); } if let Ok(state) = l { state.clone() } else { State::new() } }; if let Some(old_hash) = &old_state.git_hash && old_hash == ¤t_hash { return Ok(()); } // hash updated ending_point!(ok); sync_data().await?; ending_point!(ok); let store = STORE.read().map_err(|e| anyhow!("{}", e))?; let event = store.find_last_event(); if event .as_ref() .zip(old_state.event_id.as_ref()) .is_none_or(|(e, id)| &e.event_id == id) { let mut state = STATE.write().map_err(|e| anyhow!("{}", e))?; state.git_hash = Some(current_hash); if let Some(event) = event { state.event_id = Some(event.event_id); } state.save(); return Ok(()); } let event = event.unwrap(); // event updated info!("Event updated to {}", event.event_id); let cards = store.find_cards_by_event(event.event_id); drop(store); ending_point!(ok); let downloader = Downloader::new().await?; ending_point!(ok); let cache_dir = CONFIG.get().unwrap().cache_dir(); let mut futures = FuturesUnordered::new(); for card in &cards { futures.push(async { ending_point!(ok); debug!( "Pulling card {} from bundle {}", card.id, card.assetbundle_name ); let dir = downloader .pull(&format!("character/member/{}", card.assetbundle_name)) .await?; ending_point!(ok_with { fs::remove_dir_all(dir.0)?; }); let files = find_files(&dir.0)?; let mut local_images = Vec::new(); for file in files { ending_point!(ok_with { fs::remove_dir_all(dir.0)?; }); if file.is_file() && file.extension().map(|ext| ext == "png").unwrap_or(false) { let new_filename = format!( "{}_{}", card.assetbundle_name, file.file_name().unwrap().to_str().unwrap() ); let new_file = cache_dir.join(new_filename); fs::copy(&file, &new_file)?; fs::remove_file(&file)?; local_images.push(new_file); } } fs::remove_dir_all(dir.0)?; Ok::<_, anyhow::Error>((card.clone(), local_images)) }); } let mut images = Vec::new(); while let Some(res) = futures.next().await { images.push(res?); } images.sort_by(|a, b| a.0.id.cmp(&b.0.id)); // 小在前 let images: Vec<_> = images .into_iter() .map(|(card, path)| FetchResultCard { text: format!( "#{id} {attr}{rarity} {skill} [{prefix}]{name}", id = card.id, attr = card.attr_short_text(), rarity = card.rarity_short_text(), skill = card .skill_id_short().map(|s| format!("({})", s)) .unwrap_or_default(), prefix = card.prefix, name = card.character_name() ), path, }) .collect(); info!( "In event {} collected {} cards", event.event_id, images.len() ); let result = FetchResult { event_id: event.event_id, cards: images, }; debug!("Providing result: {:?}", result); *PROVIDE.write().map_err(|e| anyhow!("{}", e))? = Some(result); let mut state = STATE.write().map_err(|e| anyhow!("{}", e))?; state.git_hash = Some(current_hash); state.event_id = Some(event.event_id); state.save(); Ok(()) }