Compare commits
2 Commits
6829440c31
...
355cb36025
| Author | SHA1 | Date | |
|---|---|---|---|
| 355cb36025 | |||
| 03b6afade2 |
@ -11,7 +11,7 @@ crate-type = ["rlib", "cdylib"]
|
||||
common = { path = "../common" }
|
||||
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_json = { workspace = true }
|
||||
reqwest = { workspace = true, features = ["json"] }
|
||||
|
||||
@ -102,17 +102,10 @@ pub struct EventCard {
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct CurrentVersion {
|
||||
#[serde(rename = "appHash")]
|
||||
pub app_hash: String,
|
||||
#[serde(rename = "systemProfile")]
|
||||
pub system_profile: String,
|
||||
#[serde(rename = "appVersion")]
|
||||
pub app_version: String,
|
||||
#[serde(rename = "assetVersion")]
|
||||
pub asset_version: String,
|
||||
#[serde(rename = "dataVersion")]
|
||||
pub data_version: String,
|
||||
#[serde(rename = "assetHash")]
|
||||
pub asset_hash: String,
|
||||
}
|
||||
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
use crate::data::CurrentVersion;
|
||||
use crate::{OPT_CONFIG, STORE, UA};
|
||||
use crate::{ending_point, OPT_CONFIG, STORE, UA};
|
||||
use anyhow::anyhow;
|
||||
use reqwest::Client;
|
||||
use serde::Deserialize;
|
||||
|
||||
const COMMIT_URL: &str = "https://api.github.com/repos/Team-Haruki/haruki-sekai-master/commits?path=master/events.json&per_page=1";
|
||||
const COMMIT_URL: &str = "https://api.github.com/repos/kotori8823/sekai-master-db/commits?path=events.json&per_page=1";
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct CommitResponse {
|
||||
@ -40,26 +40,28 @@ pub async fn fetch_last_hash() -> anyhow::Result<String> {
|
||||
}
|
||||
|
||||
pub fn raw_url(path: &str) -> String {
|
||||
"https://raw.githubusercontent.com/Team-Haruki/haruki-sekai-master/refs/heads/main/".to_owned()
|
||||
"https://raw.githubusercontent.com/kotori8823/sekai-master-db/refs/heads/master/".to_owned()
|
||||
+ path
|
||||
}
|
||||
|
||||
pub async fn sync_data() -> anyhow::Result<()> {
|
||||
let client = http_client()?;
|
||||
let events_cards = &client
|
||||
.get(raw_url("master/eventCards.json"))
|
||||
.get(raw_url("eventCards.json"))
|
||||
.send()
|
||||
.await?
|
||||
.text()
|
||||
.await?;
|
||||
ending_point!(ok);
|
||||
let event_stories = &client
|
||||
.get(raw_url("master/eventStories.json"))
|
||||
.get(raw_url("eventStories.json"))
|
||||
.send()
|
||||
.await?
|
||||
.text()
|
||||
.await?;
|
||||
ending_point!(ok);
|
||||
let card_episodes = &client
|
||||
.get(raw_url("master/cardEpisodes.json"))
|
||||
.get(raw_url("cardEpisodes.json"))
|
||||
.send()
|
||||
.await?
|
||||
.text()
|
||||
@ -75,7 +77,7 @@ pub async fn sync_data() -> anyhow::Result<()> {
|
||||
pub async fn get_master_data() -> anyhow::Result<CurrentVersion> {
|
||||
let client = http_client()?;
|
||||
let text = client
|
||||
.get(raw_url("versions/current_version.json"))
|
||||
.get(raw_url("versions.json"))
|
||||
.send()
|
||||
.await?
|
||||
.text()
|
||||
|
||||
@ -7,19 +7,44 @@ mod store;
|
||||
use crate::data::{Config, FetchResult, OptConfig, State};
|
||||
use crate::main_loop::main;
|
||||
use crate::store::Store;
|
||||
use log::{LevelFilter, debug};
|
||||
use log::{LevelFilter, debug, error};
|
||||
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::thread;
|
||||
use std::time::Duration;
|
||||
use tokio::runtime::Runtime;
|
||||
use tokio::sync::Notify;
|
||||
|
||||
pub static CONFIG: OnceLock<Config> = OnceLock::new();
|
||||
pub static OPT_CONFIG: RwLock<OptConfig> = RwLock::new(OptConfig::new());
|
||||
pub static PROVIDE: RwLock<Option<FetchResult>> = RwLock::new(None);
|
||||
pub static STORE: RwLock<Store> = RwLock::new(Store::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";
|
||||
|
||||
@ -55,7 +80,7 @@ pub unsafe extern "C" fn boot(
|
||||
cwd: *const c_char,
|
||||
name: *const c_char,
|
||||
as_path: *const c_char,
|
||||
) -> i32 {
|
||||
) -> c_int {
|
||||
unsafe {
|
||||
CONFIG
|
||||
.set(Config {
|
||||
@ -78,13 +103,35 @@ pub unsafe extern "C" fn boot(
|
||||
// ColorChoice::Auto,
|
||||
// )
|
||||
// .unwrap();
|
||||
thread::spawn(|| {
|
||||
let rt = Runtime::new().expect("Failed to create Tokio runtime");
|
||||
let handle = thread::Builder::new()
|
||||
.name("sekai-sync-lib".to_string())
|
||||
.spawn(|| {
|
||||
let rt = Runtime::new().expect("Failed to create Tokio runtime");
|
||||
|
||||
rt.block_on(keep_loop());
|
||||
});
|
||||
rt.block_on(keep_loop());
|
||||
});
|
||||
|
||||
0
|
||||
match handle {
|
||||
Ok(thread) => {
|
||||
THREAD.write().unwrap().replace(thread);
|
||||
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
|
||||
@ -95,7 +142,6 @@ pub unsafe extern "C" fn fetch_data() -> *mut c_char {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
let result = provide.take().unwrap();
|
||||
*provide = None;
|
||||
|
||||
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() {
|
||||
loop {
|
||||
ending_point!();
|
||||
debug!("loop_start");
|
||||
if let Err(err) = main().await {
|
||||
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::download::Downloader;
|
||||
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 assets_updater::core::export_pipeline::find_files;
|
||||
use std::fs;
|
||||
use log::debug;
|
||||
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() {
|
||||
@ -33,7 +34,9 @@ pub async fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
// 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
|
||||
@ -54,16 +57,28 @@ pub async fn main() -> anyhow::Result<()> {
|
||||
|
||||
let cards = store.find_cards_by_event(event.event_id);
|
||||
drop(store);
|
||||
ending_point!(ok);
|
||||
let downloader = Downloader::new().await?;
|
||||
ending_point!(ok);
|
||||
let mut images = Vec::new();
|
||||
let cache_dir = CONFIG.get().unwrap().cache_dir();
|
||||
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
|
||||
.pull(&format!("character/member/{}", card.assetbundle_name))
|
||||
.await?;
|
||||
ending_point!(ok_with {
|
||||
fs::remove_dir_all(dir.0)?;
|
||||
});
|
||||
let files = find_files(&dir.0)?;
|
||||
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!(
|
||||
"{}_{}",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user