Files
nonebot_sekai_update_notify/entry/src/main_loop.rs
T
2026-08-08 00:48:05 +08:00

144 lines
4.5 KiB
Rust

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 == &current_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(())
}