Compare commits
4
Commits
6829440c31
..
lib
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b56f3fa40a
|
||
|
|
1a645f9177
|
||
|
|
355cb36025
|
||
|
|
03b6afade2
|
@@ -1,2 +1,3 @@
|
|||||||
target/
|
target/
|
||||||
.idea/
|
.idea/
|
||||||
|
/cross-build.bat
|
||||||
Generated
+97
-81
@@ -338,6 +338,16 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colored"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "combine"
|
name = "combine"
|
||||||
version = "4.6.7"
|
version = "4.6.7"
|
||||||
@@ -454,12 +464,6 @@ dependencies = [
|
|||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "deranged"
|
|
||||||
version = "0.5.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "displaydoc"
|
name = "displaydoc"
|
||||||
version = "0.2.6"
|
version = "0.2.6"
|
||||||
@@ -498,12 +502,15 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"assets-updater",
|
"assets-updater",
|
||||||
|
"chrono",
|
||||||
"common",
|
"common",
|
||||||
|
"fern",
|
||||||
|
"futures",
|
||||||
"log",
|
"log",
|
||||||
|
"mimalloc",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"simplelog",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -579,6 +586,16 @@ dependencies = [
|
|||||||
"simd-adler32",
|
"simd-adler32",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fern"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4316185f709b23713e41e3195f90edef7fb00c3ed4adc79769cf09cc762a3b29"
|
||||||
|
dependencies = [
|
||||||
|
"colored",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "find-msvc-tools"
|
name = "find-msvc-tools"
|
||||||
version = "0.1.9"
|
version = "0.1.9"
|
||||||
@@ -616,6 +633,21 @@ version = "1.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
|
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures"
|
||||||
|
version = "0.3.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
|
||||||
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-executor",
|
||||||
|
"futures-io",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-channel"
|
name = "futures-channel"
|
||||||
version = "0.3.32"
|
version = "0.3.32"
|
||||||
@@ -623,6 +655,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
|
checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -631,6 +664,34 @@ version = "0.3.32"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
|
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-executor"
|
||||||
|
version = "0.3.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-io"
|
||||||
|
version = "0.3.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-macro"
|
||||||
|
version = "0.3.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-sink"
|
name = "futures-sink"
|
||||||
version = "0.3.32"
|
version = "0.3.32"
|
||||||
@@ -649,8 +710,13 @@ version = "0.3.32"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
|
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
"futures-io",
|
||||||
|
"futures-macro",
|
||||||
|
"futures-sink",
|
||||||
"futures-task",
|
"futures-task",
|
||||||
|
"memchr",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
@@ -1144,6 +1210,12 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lebe"
|
name = "lebe"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
@@ -1166,6 +1238,15 @@ dependencies = [
|
|||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libmimalloc-sys"
|
||||||
|
version = "0.1.49"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6a45a52f43e1c16f667ccfe4dd8c85b7f7c204fd5e3bf46c5b0db9a5c3c0b8e9"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libyaml-rs"
|
name = "libyaml-rs"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@@ -1221,6 +1302,15 @@ version = "2.8.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
|
checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mimalloc"
|
||||||
|
version = "0.1.52"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2d4139bb28d14ad1facf21d5eb8825051b326e172d216b39f6d31df53cc97862"
|
||||||
|
dependencies = [
|
||||||
|
"libmimalloc-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mime"
|
name = "mime"
|
||||||
version = "0.3.17"
|
version = "0.3.17"
|
||||||
@@ -1298,12 +1388,6 @@ dependencies = [
|
|||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-conv"
|
|
||||||
version = "0.2.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-derive"
|
name = "num-derive"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
@@ -1344,15 +1428,6 @@ dependencies = [
|
|||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num_threads"
|
|
||||||
version = "0.1.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.21.4"
|
version = "1.21.4"
|
||||||
@@ -1411,12 +1486,6 @@ dependencies = [
|
|||||||
"zerovec",
|
"zerovec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "powerfmt"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.21"
|
version = "0.2.21"
|
||||||
@@ -2011,17 +2080,6 @@ version = "0.1.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
|
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "simplelog"
|
|
||||||
version = "0.12.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "16257adbfaef1ee58b1363bdc0664c9b8e1e30aed86049635fb5f147d065a9c0"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
"termcolor",
|
|
||||||
"time",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.12"
|
version = "0.4.12"
|
||||||
@@ -2121,21 +2179,11 @@ dependencies = [
|
|||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "termcolor"
|
|
||||||
version = "1.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "test-main"
|
name = "test-main"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"entry",
|
"entry",
|
||||||
"simplelog",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2172,38 +2220,6 @@ dependencies = [
|
|||||||
"zune-jpeg",
|
"zune-jpeg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "time"
|
|
||||||
version = "0.3.49"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "711a53c2d47bbd818258c498c8dbfe186a2526c631495cfe7e078567f86b8469"
|
|
||||||
dependencies = [
|
|
||||||
"deranged",
|
|
||||||
"libc",
|
|
||||||
"num-conv",
|
|
||||||
"num_threads",
|
|
||||||
"powerfmt",
|
|
||||||
"serde_core",
|
|
||||||
"time-core",
|
|
||||||
"time-macros",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "time-core"
|
|
||||||
version = "0.1.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "time-macros"
|
|
||||||
version = "0.2.29"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "71c652a3727a9cbb9a02f707f530b618ce00d0ccd762009c8c23bd191df3c17d"
|
|
||||||
dependencies = [
|
|
||||||
"num-conv",
|
|
||||||
"time-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinystr"
|
name = "tinystr"
|
||||||
version = "0.8.3"
|
version = "0.8.3"
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ impl AssetExecutionContext {
|
|||||||
.default_headers(headers)
|
.default_headers(headers)
|
||||||
.connect_timeout(Duration::from_secs(10))
|
.connect_timeout(Duration::from_secs(10))
|
||||||
.timeout(Duration::from_secs(180))
|
.timeout(Duration::from_secs(180))
|
||||||
.pool_max_idle_per_host(100)
|
.pool_max_idle_per_host(4)
|
||||||
.tcp_keepalive(Duration::from_secs(30));
|
.tcp_keepalive(Duration::from_secs(30));
|
||||||
|
|
||||||
if let Some(proxy) = &app_config.execution.proxy
|
if let Some(proxy) = &app_config.execution.proxy
|
||||||
|
|||||||
+9
-3
@@ -2,8 +2,12 @@
|
|||||||
resolver = "3"
|
resolver = "3"
|
||||||
members = ["entry", "common", "assets-updater", "test-main"]
|
members = ["entry", "common", "assets-updater", "test-main"]
|
||||||
|
|
||||||
#[profile.dev]
|
[profile.minimum]
|
||||||
#codegen-units = 4
|
inherits = "release"
|
||||||
|
lto = true
|
||||||
|
opt-level = 'z'
|
||||||
|
codegen-units = 1
|
||||||
|
strip = true
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
anyhow = "1.0.102"
|
anyhow = "1.0.102"
|
||||||
@@ -25,4 +29,6 @@ cridecoder = "0.1.1"
|
|||||||
thiserror = "2.0.18"
|
thiserror = "2.0.18"
|
||||||
cipher = "0.4.4"
|
cipher = "0.4.4"
|
||||||
twox-hash = "2.1.2"
|
twox-hash = "2.1.2"
|
||||||
|
fern = "0.7"
|
||||||
|
futures = "0.3.32"
|
||||||
|
mimalloc = { version = "0.1", default-features = false }
|
||||||
|
|||||||
+5
-2
@@ -11,10 +11,13 @@ 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", "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"] }
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
simplelog = "0.12.2"
|
fern = { workspace = true, features = ["colored"] }
|
||||||
|
futures = { workspace = true }
|
||||||
|
mimalloc = { workspace = true, default-features = false }
|
||||||
|
chrono = { workspace = true }
|
||||||
+120
-20
@@ -1,5 +1,6 @@
|
|||||||
use crate::CONFIG;
|
use crate::CONFIG;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::cmp::Ordering;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -19,14 +20,18 @@ impl Config {
|
|||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct OptConfig {
|
pub struct OptConfig {
|
||||||
pub proxy: Option<String>,
|
pub proxy: Option<String>,
|
||||||
|
pub pjsk_proxy: Option<String>,
|
||||||
pub ghp: Option<String>,
|
pub ghp: Option<String>,
|
||||||
|
pub log_level: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OptConfig {
|
impl OptConfig {
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
proxy: None,
|
proxy: None,
|
||||||
|
pjsk_proxy: None,
|
||||||
ghp: None,
|
ghp: None,
|
||||||
|
log_level: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,7 +47,6 @@ impl State {
|
|||||||
serde_json::from_str(x).unwrap()
|
serde_json::from_str(x).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
git_hash: None,
|
git_hash: None,
|
||||||
@@ -80,17 +84,6 @@ pub struct EventStory {
|
|||||||
pub assetbundle_name: String,
|
pub assetbundle_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 用这个找是因为这个文件小一点(((
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
pub struct CardEpisode {
|
|
||||||
pub id: u64,
|
|
||||||
pub seq: u64,
|
|
||||||
#[serde(rename = "cardId")]
|
|
||||||
pub card_id: u64,
|
|
||||||
#[serde(rename = "assetbundleName")]
|
|
||||||
pub assetbundle_name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct EventCard {
|
pub struct EventCard {
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
@@ -100,24 +93,131 @@ pub struct EventCard {
|
|||||||
pub event_id: u64,
|
pub event_id: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Card {
|
||||||
|
pub id: u64,
|
||||||
|
#[serde(rename = "characterId")]
|
||||||
|
pub character_id: u64,
|
||||||
|
#[serde(rename = "cardRarityType")]
|
||||||
|
pub card_rarity_type: String,
|
||||||
|
pub attr: String,
|
||||||
|
#[serde(rename = "skillId")]
|
||||||
|
pub skill_id: u64,
|
||||||
|
pub prefix: String,
|
||||||
|
#[serde(rename = "assetbundleName")]
|
||||||
|
pub assetbundle_name: String,
|
||||||
|
}
|
||||||
|
impl PartialEq for Card {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.id.eq(&other.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for Card {}
|
||||||
|
|
||||||
|
impl PartialOrd for Card {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Ord for Card {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
self.id.cmp(&other.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Card {
|
||||||
|
pub fn rarity_short_text(&self) -> String {
|
||||||
|
match self.card_rarity_type.as_str() {
|
||||||
|
"rarity_1" => "⭐".to_string(),
|
||||||
|
"rarity_2" => "⭐⭐".to_string(),
|
||||||
|
"rarity_3" => "⭐⭐⭐".to_string(),
|
||||||
|
"rarity_4" => "⭐⭐⭐⭐".to_string(),
|
||||||
|
"rarity_birthday" => "🎀".to_string(),
|
||||||
|
_ => self.card_rarity_type.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn attr_short_text(&self) -> String {
|
||||||
|
match self.attr.as_str() {
|
||||||
|
"cute" => "粉花".to_string(),
|
||||||
|
"pure" => "绿草".to_string(),
|
||||||
|
"cool" => "蓝星".to_string(),
|
||||||
|
"mysterious" => "紫月".to_string(),
|
||||||
|
"happy" => "橙心".to_string(),
|
||||||
|
_ => self.attr.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn skill_id_short(&self) -> Option<String> {
|
||||||
|
match self.skill_id {
|
||||||
|
1..=4 => Some("得分提高".to_string()),
|
||||||
|
5..=8 => Some("判定提升".to_string()),
|
||||||
|
9..=10 => Some("回复".to_string()),
|
||||||
|
11 => Some("P分".to_string()),
|
||||||
|
12 => Some("血分".to_string()),
|
||||||
|
13 => Some("P分(特殊)".to_string()),
|
||||||
|
14 => Some("回复P分(特殊)".to_string()),
|
||||||
|
15 => Some("LN团分".to_string()),
|
||||||
|
16 => Some("MMJ团分".to_string()),
|
||||||
|
17 => Some("VBS团分".to_string()),
|
||||||
|
18 => Some("WS团分".to_string()),
|
||||||
|
19 => Some("25团分".to_string()),
|
||||||
|
22 => Some("等级分(bfes)".to_string()),
|
||||||
|
23 => Some("队内抽分(bfes)".to_string()),
|
||||||
|
24 => Some("多团分".to_string()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn character_name(&self) -> String {
|
||||||
|
match self.character_id {
|
||||||
|
1 => "星乃一歌".to_string(),
|
||||||
|
2 => "天馬咲希".to_string(),
|
||||||
|
3 => "望月穂波".to_string(),
|
||||||
|
4 => "日野森志歩".to_string(),
|
||||||
|
5 => "花里みのり".to_string(),
|
||||||
|
6 => "桐谷遥".to_string(),
|
||||||
|
7 => "桃井愛莉".to_string(),
|
||||||
|
8 => "日野森雫".to_string(),
|
||||||
|
9 => "小豆沢こはね".to_string(),
|
||||||
|
10 => "白石杏".to_string(),
|
||||||
|
11 => "東雲彰人".to_string(),
|
||||||
|
12 => "青柳冬弥".to_string(),
|
||||||
|
13 => "天馬司".to_string(),
|
||||||
|
14 => "鳳えむ".to_string(),
|
||||||
|
15 => "草薙寧々".to_string(),
|
||||||
|
16 => "神代類".to_string(),
|
||||||
|
17 => "宵崎奏".to_string(),
|
||||||
|
18 => "朝比奈まふゆ".to_string(),
|
||||||
|
19 => "東雲絵名".to_string(),
|
||||||
|
20 => "暁山瑞希".to_string(),
|
||||||
|
21 => "初音ミク".to_string(),
|
||||||
|
22 => "鏡音リン".to_string(),
|
||||||
|
23 => "鏡音レン".to_string(),
|
||||||
|
24 => "巡音ルカ".to_string(),
|
||||||
|
25 => "MEIKO".to_string(),
|
||||||
|
26 => "KAITO".to_string(),
|
||||||
|
_ => "".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct CurrentVersion {
|
pub struct CurrentVersion {
|
||||||
#[serde(rename = "appHash")]
|
|
||||||
pub app_hash: String,
|
pub app_hash: String,
|
||||||
#[serde(rename = "systemProfile")]
|
|
||||||
pub system_profile: String,
|
|
||||||
#[serde(rename = "appVersion")]
|
|
||||||
pub app_version: String,
|
pub app_version: String,
|
||||||
#[serde(rename = "assetVersion")]
|
|
||||||
pub asset_version: String,
|
pub asset_version: String,
|
||||||
#[serde(rename = "dataVersion")]
|
|
||||||
pub data_version: String,
|
pub data_version: String,
|
||||||
#[serde(rename = "assetHash")]
|
|
||||||
pub asset_hash: String,
|
pub asset_hash: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
pub struct FetchResultCard {
|
||||||
|
pub text: String,
|
||||||
|
pub path: Vec<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct FetchResult {
|
pub struct FetchResult {
|
||||||
pub event_id: u64,
|
pub event_id: u64,
|
||||||
pub card_paths: Vec<PathBuf>,
|
pub cards: Vec<FetchResultCard>,
|
||||||
}
|
}
|
||||||
@@ -14,11 +14,11 @@ impl Downloader {
|
|||||||
pub async fn new() -> anyhow::Result<Downloader> {
|
pub async fn new() -> anyhow::Result<Downloader> {
|
||||||
let master_data = get_master_data().await?;
|
let master_data = get_master_data().await?;
|
||||||
let mut execution = ExecutionConfig::default();
|
let mut execution = ExecutionConfig::default();
|
||||||
// if let Ok(opt_conf) = &OPT_CONFIG.read()
|
if let Ok(opt_conf) = &OPT_CONFIG.read()
|
||||||
// && let Some(proxy) = &opt_conf.proxy
|
&& let Some(proxy) = &opt_conf.pjsk_proxy
|
||||||
// {
|
{
|
||||||
// execution.proxy = Some(proxy.to_string());
|
execution.proxy = Some(proxy.to_string());
|
||||||
// }
|
}
|
||||||
let app_config = AppConfig {
|
let app_config = AppConfig {
|
||||||
execution,
|
execution,
|
||||||
tools: ToolsConfig{
|
tools: ToolsConfig{
|
||||||
|
|||||||
+34
-23
@@ -1,17 +1,21 @@
|
|||||||
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;
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
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)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct CommitResponse {
|
struct CommitResponse {
|
||||||
sha: String,
|
sha: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn http_client() -> anyhow::Result<Client> {
|
static HTTP_CLIENT: OnceLock<Client> = OnceLock::new();
|
||||||
|
|
||||||
|
fn new_http_client() -> anyhow::Result<Client> {
|
||||||
let mut builder = Client::builder();
|
let mut builder = Client::builder();
|
||||||
if let Ok(opt_conf) = &OPT_CONFIG.read() {
|
if let Ok(opt_conf) = &OPT_CONFIG.read() {
|
||||||
if let Some(proxy) = &opt_conf.proxy {
|
if let Some(proxy) = &opt_conf.proxy {
|
||||||
@@ -32,6 +36,17 @@ fn http_client() -> anyhow::Result<Client> {
|
|||||||
Ok(builder.build()?)
|
Ok(builder.build()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn http_client() -> anyhow::Result<&'static Client> {
|
||||||
|
let is_init = { HTTP_CLIENT.get().is_some() };
|
||||||
|
if !is_init {
|
||||||
|
let client = new_http_client()?;
|
||||||
|
HTTP_CLIENT
|
||||||
|
.set(client)
|
||||||
|
.map_err(|_| anyhow!("Failed to set HTTP client"))?;
|
||||||
|
}
|
||||||
|
Ok(HTTP_CLIENT.get().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn fetch_last_hash() -> anyhow::Result<String> {
|
pub async fn fetch_last_hash() -> anyhow::Result<String> {
|
||||||
let resp = http_client()?.get(COMMIT_URL).send().await?;
|
let resp = http_client()?.get(COMMIT_URL).send().await?;
|
||||||
let text = resp.text().await?;
|
let text = resp.text().await?;
|
||||||
@@ -40,34 +55,30 @@ pub async fn fetch_last_hash() -> anyhow::Result<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn raw_url(path: &str) -> 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
|
+ path
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn sync_data() -> anyhow::Result<()> {
|
pub async fn sync_data() -> anyhow::Result<()> {
|
||||||
let client = http_client()?;
|
let client = http_client()?;
|
||||||
let events_cards = &client
|
let (events_cards, event_stories, cards) = tokio::try_join!(
|
||||||
.get(raw_url("master/eventCards.json"))
|
client.get(raw_url("eventCards.json")).send().await?.text(),
|
||||||
|
client
|
||||||
|
.get(raw_url("eventStories.json"))
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.text(),
|
||||||
|
client
|
||||||
|
.get(raw_url("cards.json"))
|
||||||
.send()
|
.send()
|
||||||
.await?
|
.await?
|
||||||
.text()
|
.text()
|
||||||
.await?;
|
)?;
|
||||||
let event_stories = &client
|
ending_point!(ok);
|
||||||
.get(raw_url("master/eventStories.json"))
|
|
||||||
.send()
|
|
||||||
.await?
|
|
||||||
.text()
|
|
||||||
.await?;
|
|
||||||
let card_episodes = &client
|
|
||||||
.get(raw_url("master/cardEpisodes.json"))
|
|
||||||
.send()
|
|
||||||
.await?
|
|
||||||
.text()
|
|
||||||
.await?;
|
|
||||||
let mut store = STORE.write().map_err(|e| anyhow!("{}", e))?;
|
let mut store = STORE.write().map_err(|e| anyhow!("{}", e))?;
|
||||||
store.set_event_cards(serde_json::from_str(events_cards)?);
|
store.set_event_cards(serde_json::from_str(&events_cards)?);
|
||||||
store.set_event_stories(serde_json::from_str(event_stories)?);
|
store.set_event_stories(serde_json::from_str(&event_stories)?);
|
||||||
store.set_card_episodes(serde_json::from_str(card_episodes)?);
|
store.set_cards(serde_json::from_str(&cards)?);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -75,7 +86,7 @@ pub async fn sync_data() -> anyhow::Result<()> {
|
|||||||
pub async fn get_master_data() -> anyhow::Result<CurrentVersion> {
|
pub async fn get_master_data() -> anyhow::Result<CurrentVersion> {
|
||||||
let client = http_client()?;
|
let client = http_client()?;
|
||||||
let text = client
|
let text = client
|
||||||
.get(raw_url("versions/current_version.json"))
|
.get(raw_url("versions.json"))
|
||||||
.send()
|
.send()
|
||||||
.await?
|
.await?
|
||||||
.text()
|
.text()
|
||||||
|
|||||||
+110
-15
@@ -1,3 +1,8 @@
|
|||||||
|
use mimalloc::MiMalloc;
|
||||||
|
|
||||||
|
#[global_allocator]
|
||||||
|
static GLOBAL: MiMalloc = MiMalloc;
|
||||||
|
|
||||||
mod data;
|
mod data;
|
||||||
mod download;
|
mod download;
|
||||||
mod github;
|
mod github;
|
||||||
@@ -7,19 +12,45 @@ 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 chrono::Local;
|
||||||
|
use fern::colors::{Color, ColoredLevelConfig};
|
||||||
use log::{LevelFilter, debug};
|
use log::{LevelFilter, debug};
|
||||||
use simplelog::{ColorChoice, TermLogger, TerminalMode};
|
use std::ffi::{CStr, CString, c_char, c_int};
|
||||||
use std::ffi::{CStr, CString, c_char};
|
use std::str::FromStr;
|
||||||
|
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::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";
|
||||||
|
|
||||||
@@ -47,7 +78,9 @@ macro_rules! def_opt_str_setter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def_opt_str_setter!(proxy);
|
def_opt_str_setter!(proxy);
|
||||||
|
def_opt_str_setter!(pjsk_proxy);
|
||||||
def_opt_str_setter!(ghp);
|
def_opt_str_setter!(ghp);
|
||||||
|
def_opt_str_setter!(log_level);
|
||||||
|
|
||||||
/// # Safety
|
/// # Safety
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
@@ -55,7 +88,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 {
|
||||||
@@ -71,21 +104,80 @@ pub unsafe extern "C" fn boot(
|
|||||||
.init()
|
.init()
|
||||||
.expect("Failed to initialize state");
|
.expect("Failed to initialize state");
|
||||||
*STORE.write().unwrap() = Store::load();
|
*STORE.write().unwrap() = Store::load();
|
||||||
// TermLogger::init(
|
|
||||||
// LevelFilter::Debug,
|
if let Some(log_level) = &OPT_CONFIG.read().unwrap().log_level {
|
||||||
// simplelog::Config::default(),
|
match LevelFilter::from_str(log_level) {
|
||||||
// TerminalMode::Mixed,
|
Ok(level) => {
|
||||||
// ColorChoice::Auto,
|
let name = CONFIG.get().unwrap().name.clone();
|
||||||
// )
|
let colors = ColoredLevelConfig::new()
|
||||||
// .unwrap();
|
.info(Color::BrightWhite)
|
||||||
thread::spawn(|| {
|
.debug(Color::BrightBlue)
|
||||||
let rt = Runtime::new().expect("Failed to create Tokio runtime");
|
.warn(Color::Yellow)
|
||||||
|
.error(Color::Red);
|
||||||
|
const GREEN: &str = "\x1b[32m"; // 绿色
|
||||||
|
const CYAN_UNDERLINE: &str = "\x1b[36;4m"; // 青色 + 下划线
|
||||||
|
const RESET: &str = "\x1b[0m"; // 重置颜色
|
||||||
|
|
||||||
|
let _ = fern::Dispatch::new()
|
||||||
|
.format(move |out, message, record| {
|
||||||
|
out.finish(format_args!(
|
||||||
|
"{green}{time}{reset} [{level}] {cyan_ul}{name}{reset} | {message}",
|
||||||
|
green = GREEN,
|
||||||
|
time = Local::now().format("%m-%d %H:%M:%S"),
|
||||||
|
reset = RESET,
|
||||||
|
level = colors.color(record.level()), // fern 处理等级颜色
|
||||||
|
cyan_ul = CYAN_UNDERLINE,
|
||||||
|
name = name,
|
||||||
|
message = message
|
||||||
|
))
|
||||||
|
})
|
||||||
|
.level(level)
|
||||||
|
.chain(std::io::stdout())
|
||||||
|
.apply()
|
||||||
|
.is_err_and(|e| {
|
||||||
|
eprintln!("Failed to initialize logger: {}", e);
|
||||||
|
true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("Invalid log level: '{}': {}", log_level, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let handle = thread::Builder::new()
|
||||||
|
.name("sekai-sync-lib".to_string())
|
||||||
|
.spawn(|| {
|
||||||
|
let rt = tokio::runtime::Builder::new_current_thread()
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.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) => {
|
||||||
|
eprintln!("{}", error);
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
#[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 +187,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 +207,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() => {},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+63
-12
@@ -1,14 +1,17 @@
|
|||||||
use crate::data::{FetchResult, State};
|
use crate::data::{FetchResult, FetchResultCard, 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 futures::StreamExt;
|
||||||
|
use futures::stream::FuturesUnordered;
|
||||||
|
use log::{debug, info};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use log::debug;
|
|
||||||
|
|
||||||
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 +36,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
|
||||||
@@ -52,18 +57,33 @@ pub async fn main() -> anyhow::Result<()> {
|
|||||||
let event = event.unwrap();
|
let event = event.unwrap();
|
||||||
// event updated
|
// event updated
|
||||||
|
|
||||||
|
info!("Event updated to {}", event.event_id);
|
||||||
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?;
|
||||||
let mut images = Vec::new();
|
ending_point!(ok);
|
||||||
let cache_dir = CONFIG.get().unwrap().cache_dir();
|
let cache_dir = CONFIG.get().unwrap().cache_dir();
|
||||||
for card in cards {
|
let mut futures = FuturesUnordered::new();
|
||||||
debug!("Pulling card {} from bundle {}", card.card_id, card.assetbundle_name);
|
for card in &cards {
|
||||||
|
futures.push(async {
|
||||||
|
ending_point!(ok);
|
||||||
|
debug!(
|
||||||
|
"Pulling card {} from bundle {}",
|
||||||
|
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)?;
|
||||||
|
let mut local_images = Vec::new();
|
||||||
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!(
|
||||||
"{}_{}",
|
"{}_{}",
|
||||||
@@ -73,16 +93,47 @@ pub async fn main() -> anyhow::Result<()> {
|
|||||||
let new_file = cache_dir.join(new_filename);
|
let new_file = cache_dir.join(new_filename);
|
||||||
fs::copy(&file, &new_file)?;
|
fs::copy(&file, &new_file)?;
|
||||||
fs::remove_file(&file)?;
|
fs::remove_file(&file)?;
|
||||||
images.push(new_file);
|
local_images.push(new_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fs::remove_dir_all(dir.0)?;
|
fs::remove_dir_all(dir.0)?;
|
||||||
}
|
Ok::<_, anyhow::Error>((card.clone(), local_images))
|
||||||
|
|
||||||
*PROVIDE.write().map_err(|e| anyhow!("{}", e))? = Some(FetchResult {
|
|
||||||
event_id: event.event_id,
|
|
||||||
card_paths: 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))?;
|
let mut state = STATE.write().map_err(|e| anyhow!("{}", e))?;
|
||||||
state.git_hash = Some(current_hash);
|
state.git_hash = Some(current_hash);
|
||||||
state.event_id = Some(event.event_id);
|
state.event_id = Some(event.event_id);
|
||||||
|
|||||||
+14
-14
@@ -1,5 +1,5 @@
|
|||||||
use crate::CONFIG;
|
use crate::CONFIG;
|
||||||
use crate::data::{CardEpisode, EventCard, EventStory};
|
use crate::data::{Card, EventCard, EventStory};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
@@ -8,16 +8,16 @@ use std::path::PathBuf;
|
|||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Store {
|
pub struct Store {
|
||||||
pub event_stories: Vec<EventStory>,
|
pub event_stories: Vec<EventStory>,
|
||||||
pub card_episodes: Vec<CardEpisode>,
|
|
||||||
pub event_cards: Vec<EventCard>,
|
pub event_cards: Vec<EventCard>,
|
||||||
|
pub cards: Vec<Card>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Store {
|
impl Store {
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
event_cards: Vec::new(),
|
event_cards: Vec::new(),
|
||||||
card_episodes: Vec::new(),
|
|
||||||
event_stories: Vec::new(),
|
event_stories: Vec::new(),
|
||||||
|
cards: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,8 +31,8 @@ impl Store {
|
|||||||
|
|
||||||
Self {
|
Self {
|
||||||
event_stories: Self::load_file(&cache_dir.join("event_stories.json")),
|
event_stories: Self::load_file(&cache_dir.join("event_stories.json")),
|
||||||
card_episodes: Self::load_file(&cache_dir.join("card_episodes.json")),
|
|
||||||
event_cards: Self::load_file(&cache_dir.join("event_cards.json")),
|
event_cards: Self::load_file(&cache_dir.join("event_cards.json")),
|
||||||
|
cards: Self::load_file(&cache_dir.join("cards.json")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,23 +55,23 @@ impl Store {
|
|||||||
Self::save_file(&path, &self.event_stories);
|
Self::save_file(&path, &self.event_stories);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_card_episodes(&mut self, data: Vec<CardEpisode>) {
|
|
||||||
self.card_episodes = data;
|
|
||||||
let path = CONFIG.get().unwrap().cache_dir().join("card_episodes.json");
|
|
||||||
Self::save_file(&path, &self.card_episodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_event_cards(&mut self, data: Vec<EventCard>) {
|
pub fn set_event_cards(&mut self, data: Vec<EventCard>) {
|
||||||
self.event_cards = data;
|
self.event_cards = data;
|
||||||
let path = CONFIG.get().unwrap().cache_dir().join("event_cards.json");
|
let path = CONFIG.get().unwrap().cache_dir().join("event_cards.json");
|
||||||
Self::save_file(&path, &self.event_cards);
|
Self::save_file(&path, &self.event_cards);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_cards(&mut self, data: Vec<Card>) {
|
||||||
|
self.cards = data;
|
||||||
|
let path = CONFIG.get().unwrap().cache_dir().join("cards.json");
|
||||||
|
Self::save_file(&path, &self.cards);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn save_all(&self) {
|
pub fn save_all(&self) {
|
||||||
let cache_dir = CONFIG.get().unwrap().cache_dir();
|
let cache_dir = CONFIG.get().unwrap().cache_dir();
|
||||||
Self::save_file(&cache_dir.join("event_stories.json"), &self.event_stories);
|
Self::save_file(&cache_dir.join("event_stories.json"), &self.event_stories);
|
||||||
Self::save_file(&cache_dir.join("card_episodes.json"), &self.card_episodes);
|
|
||||||
Self::save_file(&cache_dir.join("event_cards.json"), &self.event_cards);
|
Self::save_file(&cache_dir.join("event_cards.json"), &self.event_cards);
|
||||||
|
Self::save_file(&cache_dir.join("cards.json"), &self.cards);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_last_event(&self) -> Option<EventStory> {
|
pub fn find_last_event(&self) -> Option<EventStory> {
|
||||||
@@ -81,15 +81,15 @@ impl Store {
|
|||||||
.cloned()
|
.cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_cards_by_event(&self, event_id: u64) -> Vec<CardEpisode> {
|
pub fn find_cards_by_event(&self, event_id: u64) -> Vec<Card> {
|
||||||
self.event_cards
|
self.event_cards
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|e| e.event_id == event_id)
|
.filter(|e| e.event_id == event_id)
|
||||||
.filter_map(|c| {
|
.filter_map(|c| {
|
||||||
self.card_episodes
|
self.cards
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.find(|e| e.card_id == c.card_id)
|
.find(|e| e.id == c.card_id)
|
||||||
})
|
})
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect()
|
.collect()
|
||||||
|
|||||||
@@ -5,5 +5,3 @@ edition = "2024"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
entry = { path = "../entry" }
|
entry = { path = "../entry" }
|
||||||
|
|
||||||
simplelog = "0.12.2"
|
|
||||||
+5
-10
@@ -1,19 +1,13 @@
|
|||||||
use simplelog::{ColorChoice, Config, LevelFilter, TermLogger, TerminalMode};
|
use sekai_sync_lib::{boot, ghp, log_level, proxy};
|
||||||
use sekai_sync_lib::{boot, ghp, proxy};
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let _proxy = "http://127.0.0.1:7890";
|
let _proxy = "http://127.0.0.1:7890";
|
||||||
let _cwd = "D:\\Workspace\\sekai-sync-lib\\target";
|
let _cwd = "D:\\Workspace\\sekai-sync-lib\\target";
|
||||||
let _name = "sekai-sync-lib";
|
let _name = "sekai-sync-lib";
|
||||||
let _as_path = "D:\\Workspace\\AssetStudio\\AssetStudioCLI\\bin\\Release\\net9.0\\AssetStudioModCLI.exe";
|
let _as_path =
|
||||||
|
"D:\\Workspace\\AssetStudio\\AssetStudioCLI\\bin\\Release\\net9.0\\AssetStudioModCLI.exe";
|
||||||
let _ghp = "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";
|
let _ghp = "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";
|
||||||
//
|
let _log_level = "debug";
|
||||||
// TermLogger::init(
|
|
||||||
// LevelFilter::Debug,
|
|
||||||
// Config::default(),
|
|
||||||
// TerminalMode::Mixed,
|
|
||||||
// ColorChoice::Auto,
|
|
||||||
// ).unwrap();
|
|
||||||
|
|
||||||
macro_rules! cstr {
|
macro_rules! cstr {
|
||||||
($v:expr) => {
|
($v:expr) => {
|
||||||
@@ -21,6 +15,7 @@ fn main() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
|
log_level(cstr!(_log_level));
|
||||||
proxy(cstr!(_proxy));
|
proxy(cstr!(_proxy));
|
||||||
ghp(cstr!(_ghp));
|
ghp(cstr!(_ghp));
|
||||||
boot(cstr!(_cwd), cstr!(_name), cstr!(_as_path));
|
boot(cstr!(_cwd), cstr!(_name), cstr!(_as_path));
|
||||||
|
|||||||
Reference in New Issue
Block a user