forked from ObolSquad/trigger-rs
dispatch-server: unhardcode cdn_conf_ext and load res versions from configuration file
This commit is contained in:
parent
de4bf109ed
commit
f89b49f903
6 changed files with 80 additions and 22 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -3652,6 +3652,7 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror 2.0.11",
|
"thiserror 2.0.11",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"toml",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"trigger-cryptography",
|
"trigger-cryptography",
|
||||||
|
|
|
@ -9,6 +9,7 @@ axum.workspace = true
|
||||||
|
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
|
toml.workspace = true
|
||||||
base64.workspace = true
|
base64.workspace = true
|
||||||
|
|
||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::net::SocketAddr;
|
use std::{collections::HashMap, net::SocketAddr};
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use trigger_sv::config::TomlConfig;
|
use trigger_sv::config::{ConfigurationLoadError, TomlConfig};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct NetworkSetting {
|
pub struct NetworkSetting {
|
||||||
|
@ -37,6 +37,29 @@ pub struct DispatchConfig {
|
||||||
pub bound_server: BoundRegionSetting,
|
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<HashMap<String, Self>, ConfigurationLoadError> {
|
||||||
|
Ok(toml::from_str(&std::fs::read_to_string(path)?)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TomlConfig for DispatchConfig {
|
impl TomlConfig for DispatchConfig {
|
||||||
const DEFAULT_TOML: &str = include_str!("../dispatch.default.toml");
|
const DEFAULT_TOML: &str = include_str!("../dispatch.default.toml");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
use std::{
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
process::ExitCode,
|
process::ExitCode,
|
||||||
sync::{LazyLock, OnceLock},
|
sync::{LazyLock, OnceLock},
|
||||||
};
|
};
|
||||||
|
|
||||||
use axum::{routing::get, Router};
|
use axum::{routing::get, Router};
|
||||||
use config::DispatchConfig;
|
use config::{DispatchConfig, ResVersionConfig};
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
use trigger_sv::{
|
use trigger_sv::{
|
||||||
|
@ -19,11 +20,12 @@ mod query_dispatch;
|
||||||
mod query_gateway;
|
mod query_gateway;
|
||||||
|
|
||||||
const CONFIG_FILE: &str = "dispatch.toml";
|
const CONFIG_FILE: &str = "dispatch.toml";
|
||||||
|
const RES_CONFIG_FILE: &str = "res_versions.toml";
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct AppState {
|
struct AppState {
|
||||||
pub config: &'static DispatchConfig,
|
pub config: &'static DispatchConfig,
|
||||||
pub environment: &'static ServerEnvironmentConfiguration,
|
pub environment: &'static ServerEnvironmentConfiguration,
|
||||||
|
pub res_versions: HashMap<String, ResVersionConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
|
@ -41,9 +43,16 @@ async fn main() -> ExitCode {
|
||||||
print_banner();
|
print_banner();
|
||||||
logging::init_tracing(tracing::Level::DEBUG);
|
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 {
|
let state = APP_STATE.get_or_init(|| AppState {
|
||||||
config: &CONFIG,
|
config: &CONFIG,
|
||||||
environment: &ENVIRONMENT,
|
environment: &ENVIRONMENT,
|
||||||
|
res_versions,
|
||||||
});
|
});
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
|
@ -52,11 +61,10 @@ async fn main() -> ExitCode {
|
||||||
.route(query_gateway::ROUTE_ENDPOINT, get(query_gateway::process))
|
.route(query_gateway::ROUTE_ENDPOINT, get(query_gateway::process))
|
||||||
.with_state(state);
|
.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}");
|
error!("TcpListener::bind failed. Is another instance of the server already running? Error: {err}");
|
||||||
}) else {
|
|
||||||
die();
|
die();
|
||||||
};
|
});
|
||||||
|
|
||||||
axum::serve(listener, app).await.unwrap_or_else(|err| {
|
axum::serve(listener, app).await.unwrap_or_else(|err| {
|
||||||
error!("axum::serve failed: {err}");
|
error!("axum::serve failed: {err}");
|
||||||
|
|
|
@ -30,13 +30,15 @@ pub enum QueryGatewayError {
|
||||||
InvalidRsaVer(u32),
|
InvalidRsaVer(u32),
|
||||||
#[error("invalid dispatch seed, expected: {0}, got: {1}")]
|
#[error("invalid dispatch seed, expected: {0}, got: {1}")]
|
||||||
InvalidDispatchSeed(&'static str, String),
|
InvalidDispatchSeed(&'static str, String),
|
||||||
|
#[error("ResVersionConfig for {0} is not defined")]
|
||||||
|
MissingResVersionConfig(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QueryGatewayError {
|
impl QueryGatewayError {
|
||||||
pub fn retcode(&self) -> i32 {
|
pub fn retcode(&self) -> i32 {
|
||||||
match self {
|
match self {
|
||||||
Self::InvalidRsaVer(_) => 74,
|
Self::InvalidRsaVer(_) => 74,
|
||||||
Self::InvalidDispatchSeed(_, _) => 75,
|
Self::InvalidDispatchSeed(_, _) | Self::MissingResVersionConfig(_) => 75,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +73,7 @@ impl IntoResponse for Response {
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct QueryGatewayParam {
|
pub struct QueryGatewayParam {
|
||||||
|
pub version: String,
|
||||||
pub rsa_ver: u32,
|
pub rsa_ver: u32,
|
||||||
pub seed: String,
|
pub seed: String,
|
||||||
}
|
}
|
||||||
|
@ -118,6 +121,13 @@ fn internal_process(
|
||||||
QueryGatewayError::InvalidDispatchSeed(&state.config.bound_server.seed, param.seed),
|
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;
|
let server = &state.config.bound_server;
|
||||||
|
|
||||||
Ok(Response {
|
Ok(Response {
|
||||||
|
@ -127,7 +137,10 @@ fn internal_process(
|
||||||
msg: String::with_capacity(0),
|
msg: String::with_capacity(0),
|
||||||
region_name: Borrowed(&server.name),
|
region_name: Borrowed(&server.name),
|
||||||
title: Borrowed(&server.title),
|
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),
|
cdn_check_url: String::with_capacity(0),
|
||||||
gateway: Some(ServerGateway {
|
gateway: Some(ServerGateway {
|
||||||
ip: Borrowed(&server.addr),
|
ip: Borrowed(&server.addr),
|
||||||
|
@ -137,23 +150,22 @@ fn internal_process(
|
||||||
force_update_url: String::new(),
|
force_update_url: String::new(),
|
||||||
stop_jump_url: String::new(),
|
stop_jump_url: String::new(),
|
||||||
cdn_conf_ext: Some(CdnConfExt {
|
cdn_conf_ext: Some(CdnConfExt {
|
||||||
// TODO: unhardcode this
|
|
||||||
design_data: CdnDesignData {
|
design_data: CdnDesignData {
|
||||||
base_url: Borrowed("https://autopatchos.zenlesszonezero.com/design_data/1.6_live/output_6898738_6ffe812558/client/"),
|
base_url: Borrowed(&res_version.design_data_url),
|
||||||
data_revision: Borrowed("6898738"),
|
data_revision: Borrowed(&res_version.design_data_revision),
|
||||||
md5_files: Borrowed(r#"[{"fileName": "data_version", "fileSize": 2065, "fileMD5": "16970197844668905690"}]"#),
|
md5_files: Borrowed(&res_version.design_data_files),
|
||||||
},
|
},
|
||||||
game_res: CdnGameRes {
|
game_res: CdnGameRes {
|
||||||
audio_revision: Borrowed("6898738"),
|
audio_revision: Borrowed(&res_version.game_audio_revision),
|
||||||
base_url: Borrowed("https://autopatchos.zenlesszonezero.com/game_res/1.6_live/output_6898738_6ffe812558/client/"),
|
base_url: Borrowed(&res_version.game_res_url),
|
||||||
branch: Borrowed("beta_live"),
|
branch: Borrowed(&res_version.game_res_branch),
|
||||||
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"}]"#),
|
md5_files: Borrowed(&res_version.game_res_files),
|
||||||
res_revision: Borrowed("6898738"),
|
res_revision: Borrowed(&res_version.game_res_revision),
|
||||||
},
|
},
|
||||||
silence_data: CdnSilenceData {
|
silence_data: CdnSilenceData {
|
||||||
base_url: Borrowed("https://autopatchos.zenlesszonezero.com/design_data/1.6_live/output_6898738_6ffe812558/client_silence/"),
|
base_url: Borrowed(&res_version.silence_url),
|
||||||
md5_files: Borrowed(r#"[{"fileName": "silence_version", "fileSize": 130, "fileMD5": "2077712550601860122"}]"#),
|
md5_files: Borrowed(&res_version.silence_files),
|
||||||
silence_revision: Borrowed("6898738"),
|
silence_revision: Borrowed(&res_version.silence_revision),
|
||||||
},
|
},
|
||||||
pre_download: None,
|
pre_download: None,
|
||||||
}),
|
}),
|
||||||
|
@ -174,7 +186,7 @@ fn internal_process(
|
||||||
url_check_nap: String::new(),
|
url_check_nap: String::new(),
|
||||||
url_check_sdk: String::new(),
|
url_check_sdk: String::new(),
|
||||||
}),
|
}),
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
13
res_versions.toml
Normal file
13
res_versions.toml
Normal file
|
@ -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"}]'
|
||||||
|
|
Loading…
Reference in a new issue