清理线程
This commit is contained in:
parent
6829440c31
commit
03b6afade2
@ -11,7 +11,7 @@ crate-type = ["rlib", "cdylib"]
|
|||||||
common = { path = "../common" }
|
common = { path = "../common" }
|
||||||
assets-updater = { path = "../assets-updater" }
|
assets-updater = { path = "../assets-updater" }
|
||||||
|
|
||||||
tokio = { workspace = true, features = ["macros", "rt", "rt-multi-thread"] }
|
tokio = { workspace = true, features = ["macros", "rt", "rt-multi-thread", "sync"] }
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
reqwest = { workspace = true, features = ["json"] }
|
reqwest = { workspace = true, features = ["json"] }
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use crate::data::CurrentVersion;
|
use crate::data::CurrentVersion;
|
||||||
use crate::{OPT_CONFIG, STORE, UA};
|
use crate::{ending_point, OPT_CONFIG, STORE, UA};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
@ -52,12 +52,14 @@ pub async fn sync_data() -> anyhow::Result<()> {
|
|||||||
.await?
|
.await?
|
||||||
.text()
|
.text()
|
||||||
.await?;
|
.await?;
|
||||||
|
ending_point!(ok);
|
||||||
let event_stories = &client
|
let event_stories = &client
|
||||||
.get(raw_url("master/eventStories.json"))
|
.get(raw_url("master/eventStories.json"))
|
||||||
.send()
|
.send()
|
||||||
.await?
|
.await?
|
||||||
.text()
|
.text()
|
||||||
.await?;
|
.await?;
|
||||||
|
ending_point!(ok);
|
||||||
let card_episodes = &client
|
let card_episodes = &client
|
||||||
.get(raw_url("master/cardEpisodes.json"))
|
.get(raw_url("master/cardEpisodes.json"))
|
||||||
.send()
|
.send()
|
||||||
|
|||||||
@ -7,19 +7,44 @@ mod store;
|
|||||||
use crate::data::{Config, FetchResult, OptConfig, State};
|
use crate::data::{Config, FetchResult, OptConfig, State};
|
||||||
use crate::main_loop::main;
|
use crate::main_loop::main;
|
||||||
use crate::store::Store;
|
use crate::store::Store;
|
||||||
use log::{LevelFilter, debug};
|
use log::{LevelFilter, debug, error};
|
||||||
use simplelog::{ColorChoice, TermLogger, TerminalMode};
|
use simplelog::{ColorChoice, TermLogger, TerminalMode};
|
||||||
use std::ffi::{CStr, CString, c_char};
|
use std::ffi::{CStr, CString, c_char, c_int};
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::{OnceLock, RwLock};
|
use std::sync::{OnceLock, RwLock};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
|
use tokio::sync::Notify;
|
||||||
|
|
||||||
pub static CONFIG: OnceLock<Config> = OnceLock::new();
|
pub static CONFIG: OnceLock<Config> = OnceLock::new();
|
||||||
pub static OPT_CONFIG: RwLock<OptConfig> = RwLock::new(OptConfig::new());
|
pub static OPT_CONFIG: RwLock<OptConfig> = RwLock::new(OptConfig::new());
|
||||||
pub static PROVIDE: RwLock<Option<FetchResult>> = RwLock::new(None);
|
pub static PROVIDE: RwLock<Option<FetchResult>> = RwLock::new(None);
|
||||||
pub static STORE: RwLock<Store> = RwLock::new(Store::new());
|
pub static STORE: RwLock<Store> = RwLock::new(Store::new());
|
||||||
pub static STATE: RwLock<State> = RwLock::new(State::new());
|
pub static STATE: RwLock<State> = RwLock::new(State::new());
|
||||||
|
pub static THREAD: RwLock<Option<thread::JoinHandle<()>>> = RwLock::new(None);
|
||||||
|
pub static KILLING: AtomicBool = AtomicBool::new(false);
|
||||||
|
pub static NOTIFY: Notify = Notify::const_new();
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! ending_point {
|
||||||
|
(ok)=>{
|
||||||
|
ending_point!(Err(anyhow!("Killed")))
|
||||||
|
};
|
||||||
|
(ok_with $b:block)=>{
|
||||||
|
if $crate::KILLING.load(::std::sync::atomic::Ordering::SeqCst){
|
||||||
|
$b;
|
||||||
|
return Err(anyhow!("Killed"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($ret: expr) => {
|
||||||
|
if $crate::KILLING.load(::std::sync::atomic::Ordering::SeqCst){
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
() => {
|
||||||
|
ending_point!(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub const UA: &str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36";
|
pub const UA: &str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36";
|
||||||
|
|
||||||
@ -55,7 +80,7 @@ pub unsafe extern "C" fn boot(
|
|||||||
cwd: *const c_char,
|
cwd: *const c_char,
|
||||||
name: *const c_char,
|
name: *const c_char,
|
||||||
as_path: *const c_char,
|
as_path: *const c_char,
|
||||||
) -> i32 {
|
) -> c_int {
|
||||||
unsafe {
|
unsafe {
|
||||||
CONFIG
|
CONFIG
|
||||||
.set(Config {
|
.set(Config {
|
||||||
@ -78,14 +103,36 @@ pub unsafe extern "C" fn boot(
|
|||||||
// ColorChoice::Auto,
|
// ColorChoice::Auto,
|
||||||
// )
|
// )
|
||||||
// .unwrap();
|
// .unwrap();
|
||||||
thread::spawn(|| {
|
let handle = thread::Builder::new()
|
||||||
|
.name("sekai-sync-lib".to_string())
|
||||||
|
.spawn(|| {
|
||||||
let rt = Runtime::new().expect("Failed to create Tokio runtime");
|
let rt = Runtime::new().expect("Failed to create Tokio runtime");
|
||||||
|
|
||||||
rt.block_on(keep_loop());
|
rt.block_on(keep_loop());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
match handle {
|
||||||
|
Ok(thread) => {
|
||||||
|
THREAD.write().unwrap().replace(thread);
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
Err(error) => {
|
||||||
|
error!("{}", error);
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
pub unsafe extern "C" fn stop() -> c_int {
|
||||||
|
if let Some(thread) = THREAD.write().unwrap().take() {
|
||||||
|
KILLING.store(true, Ordering::SeqCst);
|
||||||
|
NOTIFY.notify_waiters();
|
||||||
|
thread.join().expect("Failed to join thread");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
|
||||||
/// # Safety
|
/// # Safety
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
@ -95,7 +142,6 @@ pub unsafe extern "C" fn fetch_data() -> *mut c_char {
|
|||||||
return std::ptr::null_mut();
|
return std::ptr::null_mut();
|
||||||
}
|
}
|
||||||
let result = provide.take().unwrap();
|
let result = provide.take().unwrap();
|
||||||
*provide = None;
|
|
||||||
|
|
||||||
let json_string = serde_json::to_string(&result).unwrap();
|
let json_string = serde_json::to_string(&result).unwrap();
|
||||||
|
|
||||||
@ -116,10 +162,14 @@ pub unsafe extern "C" fn free_string(s: *mut c_char) {
|
|||||||
|
|
||||||
async fn keep_loop() {
|
async fn keep_loop() {
|
||||||
loop {
|
loop {
|
||||||
|
ending_point!();
|
||||||
debug!("loop_start");
|
debug!("loop_start");
|
||||||
if let Err(err) = main().await {
|
if let Err(err) = main().await {
|
||||||
println!("Error: {}", err);
|
println!("Error: {}", err);
|
||||||
}
|
}
|
||||||
tokio::time::sleep(Duration::from_secs(60)).await;
|
tokio::select! {
|
||||||
|
_ = tokio::time::sleep(Duration::from_secs(60)) => {},
|
||||||
|
_ = NOTIFY.notified() => {},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,15 @@
|
|||||||
use crate::data::{FetchResult, State};
|
use crate::data::{FetchResult, State};
|
||||||
use crate::download::Downloader;
|
use crate::download::Downloader;
|
||||||
use crate::github::{fetch_last_hash, sync_data};
|
use crate::github::{fetch_last_hash, sync_data};
|
||||||
use crate::{CONFIG, PROVIDE, STATE, STORE};
|
use crate::{CONFIG, PROVIDE, STATE, STORE, ending_point};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use assets_updater::core::export_pipeline::find_files;
|
use assets_updater::core::export_pipeline::find_files;
|
||||||
use std::fs;
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
pub async fn main() -> anyhow::Result<()> {
|
pub async fn main() -> anyhow::Result<()> {
|
||||||
let current_hash = fetch_last_hash().await?;
|
let current_hash = fetch_last_hash().await?;
|
||||||
|
ending_point!(ok);
|
||||||
let old_state = {
|
let old_state = {
|
||||||
let mut l = STATE.read();
|
let mut l = STATE.read();
|
||||||
if l.is_err() {
|
if l.is_err() {
|
||||||
@ -33,7 +34,9 @@ pub async fn main() -> anyhow::Result<()> {
|
|||||||
}
|
}
|
||||||
// hash updated
|
// hash updated
|
||||||
|
|
||||||
|
ending_point!(ok);
|
||||||
sync_data().await?;
|
sync_data().await?;
|
||||||
|
ending_point!(ok);
|
||||||
let store = STORE.read().map_err(|e| anyhow!("{}", e))?;
|
let store = STORE.read().map_err(|e| anyhow!("{}", e))?;
|
||||||
let event = store.find_last_event();
|
let event = store.find_last_event();
|
||||||
if event
|
if event
|
||||||
@ -54,16 +57,28 @@ pub async fn main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
let cards = store.find_cards_by_event(event.event_id);
|
let cards = store.find_cards_by_event(event.event_id);
|
||||||
drop(store);
|
drop(store);
|
||||||
|
ending_point!(ok);
|
||||||
let downloader = Downloader::new().await?;
|
let downloader = Downloader::new().await?;
|
||||||
|
ending_point!(ok);
|
||||||
let mut images = Vec::new();
|
let mut images = Vec::new();
|
||||||
let cache_dir = CONFIG.get().unwrap().cache_dir();
|
let cache_dir = CONFIG.get().unwrap().cache_dir();
|
||||||
for card in cards {
|
for card in cards {
|
||||||
debug!("Pulling card {} from bundle {}", card.card_id, card.assetbundle_name);
|
ending_point!(ok);
|
||||||
|
debug!(
|
||||||
|
"Pulling card {} from bundle {}",
|
||||||
|
card.card_id, card.assetbundle_name
|
||||||
|
);
|
||||||
let dir = downloader
|
let dir = downloader
|
||||||
.pull(&format!("character/member/{}", card.assetbundle_name))
|
.pull(&format!("character/member/{}", card.assetbundle_name))
|
||||||
.await?;
|
.await?;
|
||||||
|
ending_point!(ok_with {
|
||||||
|
fs::remove_dir_all(dir.0)?;
|
||||||
|
});
|
||||||
let files = find_files(&dir.0)?;
|
let files = find_files(&dir.0)?;
|
||||||
for file in files {
|
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) {
|
if file.is_file() && file.extension().map(|ext| ext == "png").unwrap_or(false) {
|
||||||
let new_filename = format!(
|
let new_filename = format!(
|
||||||
"{}_{}",
|
"{}_{}",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user