diff --git a/Cargo.lock b/Cargo.lock index 38cb4b2..7c5d40e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3652,6 +3652,7 @@ dependencies = [ "serde_json", "thiserror 2.0.11", "tokio", + "toml", "tracing", "tracing-subscriber", "trigger-cryptography", diff --git a/crates/dispatch-server/Cargo.toml b/crates/dispatch-server/Cargo.toml index 7483404..ecd5a43 100644 --- a/crates/dispatch-server/Cargo.toml +++ b/crates/dispatch-server/Cargo.toml @@ -9,6 +9,7 @@ axum.workspace = true serde.workspace = true serde_json.workspace = true +toml.workspace = true base64.workspace = true tracing.workspace = true diff --git a/crates/dispatch-server/src/config.rs b/crates/dispatch-server/src/config.rs index d281ed1..a047425 100644 --- a/crates/dispatch-server/src/config.rs +++ b/crates/dispatch-server/src/config.rs @@ -1,7 +1,7 @@ -use std::net::SocketAddr; +use std::{collections::HashMap, net::SocketAddr}; use serde::Deserialize; -use trigger_sv::config::TomlConfig; +use trigger_sv::config::{ConfigurationLoadError, TomlConfig}; #[derive(Deserialize)] pub struct NetworkSetting { @@ -37,6 +37,29 @@ pub struct DispatchConfig { pub bound_server: BoundRegionSetting, } +#[derive(Deserialize)] +pub struct ResVersionConfig { + pub design_data_url: String, + pub design_data_revision: String, + pub design_data_files: String, + pub game_res_url: String, + pub game_res_branch: String, + pub game_audio_revision: String, + pub game_res_revision: String, + pub game_res_files: String, + pub silence_url: String, + pub silence_revision: String, + pub silence_files: String, +} + +impl ResVersionConfig { + pub fn load_version_map_from_file( + path: &str, + ) -> Result, ConfigurationLoadError> { + Ok(toml::from_str(&std::fs::read_to_string(path)?)?) + } +} + impl TomlConfig for DispatchConfig { const DEFAULT_TOML: &str = include_str!("../dispatch.default.toml"); } diff --git a/crates/dispatch-server/src/main.rs b/crates/dispatch-server/src/main.rs index 3e5e847..163aa98 100644 --- a/crates/dispatch-server/src/main.rs +++ b/crates/dispatch-server/src/main.rs @@ -1,10 +1,11 @@ use std::{ + collections::HashMap, process::ExitCode, sync::{LazyLock, OnceLock}, }; use axum::{routing::get, Router}; -use config::DispatchConfig; +use config::{DispatchConfig, ResVersionConfig}; use tokio::net::TcpListener; use tracing::error; use trigger_sv::{ @@ -19,11 +20,12 @@ mod query_dispatch; mod query_gateway; const CONFIG_FILE: &str = "dispatch.toml"; +const RES_CONFIG_FILE: &str = "res_versions.toml"; -#[derive(Clone)] struct AppState { pub config: &'static DispatchConfig, pub environment: &'static ServerEnvironmentConfiguration, + pub res_versions: HashMap, } #[tokio::main] @@ -41,9 +43,16 @@ async fn main() -> ExitCode { print_banner(); logging::init_tracing(tracing::Level::DEBUG); + let res_versions = ResVersionConfig::load_version_map_from_file(RES_CONFIG_FILE) + .unwrap_or_else(|err| { + error!("failed to load {RES_CONFIG_FILE}: {err}"); + die(); + }); + let state = APP_STATE.get_or_init(|| AppState { config: &CONFIG, environment: &ENVIRONMENT, + res_versions, }); let app = Router::new() @@ -52,11 +61,10 @@ async fn main() -> ExitCode { .route(query_gateway::ROUTE_ENDPOINT, get(query_gateway::process)) .with_state(state); - let Ok(listener) = TcpListener::bind(CONFIG.network.http_addr).await.inspect_err(|err| { + let listener = TcpListener::bind(CONFIG.network.http_addr).await.unwrap_or_else(|err| { error!("TcpListener::bind failed. Is another instance of the server already running? Error: {err}"); - }) else { die(); - }; + }); axum::serve(listener, app).await.unwrap_or_else(|err| { error!("axum::serve failed: {err}"); diff --git a/crates/dispatch-server/src/query_gateway.rs b/crates/dispatch-server/src/query_gateway.rs index 905d5b0..3be55ad 100644 --- a/crates/dispatch-server/src/query_gateway.rs +++ b/crates/dispatch-server/src/query_gateway.rs @@ -30,13 +30,15 @@ pub enum QueryGatewayError { InvalidRsaVer(u32), #[error("invalid dispatch seed, expected: {0}, got: {1}")] InvalidDispatchSeed(&'static str, String), + #[error("ResVersionConfig for {0} is not defined")] + MissingResVersionConfig(String), } impl QueryGatewayError { pub fn retcode(&self) -> i32 { match self { Self::InvalidRsaVer(_) => 74, - Self::InvalidDispatchSeed(_, _) => 75, + Self::InvalidDispatchSeed(_, _) | Self::MissingResVersionConfig(_) => 75, } } @@ -71,6 +73,7 @@ impl IntoResponse for Response { #[derive(Deserialize)] pub struct QueryGatewayParam { + pub version: String, pub rsa_ver: u32, pub seed: String, } @@ -118,6 +121,13 @@ fn internal_process( QueryGatewayError::InvalidDispatchSeed(&state.config.bound_server.seed, param.seed), ))?; + let res_version = state.res_versions.get(¶m.version).ok_or_else(|| { + ( + rsa, + QueryGatewayError::MissingResVersionConfig(param.version), + ) + })?; + let server = &state.config.bound_server; Ok(Response { @@ -127,7 +137,10 @@ fn internal_process( msg: String::with_capacity(0), region_name: Borrowed(&server.name), title: Borrowed(&server.title), - client_secret_key: Owned(base64::engine::general_purpose::STANDARD.encode(&state.environment.security.static_key.seed_buf)), + client_secret_key: Owned( + base64::engine::general_purpose::STANDARD + .encode(&state.environment.security.static_key.seed_buf), + ), cdn_check_url: String::with_capacity(0), gateway: Some(ServerGateway { ip: Borrowed(&server.addr), @@ -137,23 +150,22 @@ fn internal_process( force_update_url: String::new(), stop_jump_url: String::new(), cdn_conf_ext: Some(CdnConfExt { - // TODO: unhardcode this design_data: CdnDesignData { - base_url: Borrowed("https://autopatchos.zenlesszonezero.com/design_data/1.6_live/output_6898738_6ffe812558/client/"), - data_revision: Borrowed("6898738"), - md5_files: Borrowed(r#"[{"fileName": "data_version", "fileSize": 2065, "fileMD5": "16970197844668905690"}]"#), + base_url: Borrowed(&res_version.design_data_url), + data_revision: Borrowed(&res_version.design_data_revision), + md5_files: Borrowed(&res_version.design_data_files), }, game_res: CdnGameRes { - audio_revision: Borrowed("6898738"), - base_url: Borrowed("https://autopatchos.zenlesszonezero.com/game_res/1.6_live/output_6898738_6ffe812558/client/"), - branch: Borrowed("beta_live"), - md5_files: Borrowed(r#"[{"fileName": "res_version", "fileSize": 1167660, "fileMD5": "8072678507435758384"}, {"fileName": "audio_version", "fileSize": 15447, "fileMD5": "5401804085122358755"}, {"fileName": "base_revision", "fileSize": 4, "fileMD5": "4524394692449115962"}]"#), - res_revision: Borrowed("6898738"), + audio_revision: Borrowed(&res_version.game_audio_revision), + base_url: Borrowed(&res_version.game_res_url), + branch: Borrowed(&res_version.game_res_branch), + md5_files: Borrowed(&res_version.game_res_files), + res_revision: Borrowed(&res_version.game_res_revision), }, silence_data: CdnSilenceData { - base_url: Borrowed("https://autopatchos.zenlesszonezero.com/design_data/1.6_live/output_6898738_6ffe812558/client_silence/"), - md5_files: Borrowed(r#"[{"fileName": "silence_version", "fileSize": 130, "fileMD5": "2077712550601860122"}]"#), - silence_revision: Borrowed("6898738"), + base_url: Borrowed(&res_version.silence_url), + md5_files: Borrowed(&res_version.silence_files), + silence_revision: Borrowed(&res_version.silence_revision), }, pre_download: None, }), @@ -174,7 +186,7 @@ fn internal_process( url_check_nap: String::new(), url_check_sdk: String::new(), }), - } + }, }) } diff --git a/res_versions.toml b/res_versions.toml new file mode 100644 index 0000000..fddb51c --- /dev/null +++ b/res_versions.toml @@ -0,0 +1,13 @@ +["OSPRODWin1.6.0"] +design_data_url = "https://autopatchos.zenlesszonezero.com/design_data/1.6_live/output_7108077_40d564da66/client/" +design_data_revision = "7108077" +design_data_files = '[{"fileName":"data_version","fileSize":4304,"fileMD5":"941245265336071363"}]' +game_res_url = "https://autopatchos.zenlesszonezero.com/game_res/1.6_live/output_7108077_40d564da66/client/" +game_res_branch = "1.6_live" +game_audio_revision = "7036823" +game_res_revision = "7108077" +game_res_files = '[{"fileName":"res_version","fileSize":2487933,"fileMD5":"16738022146290696861"},{"fileName":"audio_version","fileSize":32246,"fileMD5":"718221674779072830"},{"fileName":"base_revision","fileSize":18,"fileMD5":"3467029748880207404"}]' +silence_url = "https://autopatchos.zenlesszonezero.com/design_data/1.6_live/output_7108077_40d564da66/client_silence/" +silence_revision = "7036823" +silence_files = '[{"fileName":"silence_version","fileSize":467,"fileMD5":"2392489994088458280"}]' +