1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-04-29 09:57:46 +00:00

Serve a launcher page under launcher.ffxiv.localhost

This can eventually be put into a retail launcher, but it doesn't do
much yet.
This commit is contained in:
Joshua Goins 2025-04-22 16:00:10 -04:00
parent ef58358756
commit 28b27866db
7 changed files with 152 additions and 1 deletions

View file

@ -74,6 +74,7 @@ jobs:
target/release/kawari-patch* target/release/kawari-patch*
target/release/kawari-web* target/release/kawari-web*
target/release/kawari-world* target/release/kawari-world*
target/release/kawari-launcher*
!target/release/*.d !target/release/*.d
resources/ resources/
!resources/tests !resources/tests

View file

@ -31,6 +31,9 @@ name = "kawari-lobby"
name = "kawari-world" name = "kawari-world"
required-features = ["oodle"] required-features = ["oodle"]
[[bin]]
name = "kawari-launcher"
[profile.release] [profile.release]
lto = true lto = true
strip = true strip = true

View file

@ -10,6 +10,10 @@ ffxiv.localhost:80 {
reverse_proxy :5801 reverse_proxy :5801
} }
launcher.ffxiv.localhost:80 {
reverse_proxy :5802
}
frontier.ffxiv.localhost:80 { frontier.ffxiv.localhost:80 {
reverse_proxy :5857 reverse_proxy :5857
} }
@ -24,4 +28,4 @@ patch-gamever.ffxiv.localhost:80 {
ffxiv-login.square.localhost:80 { ffxiv-login.square.localhost:80 {
reverse_proxy :6700 reverse_proxy :6700
} }

View file

@ -9,4 +9,5 @@ cargo run -q --package kawari --features oodle --bin kawari-patch &
cargo run -q --package kawari --features oodle --bin kawari-web & cargo run -q --package kawari --features oodle --bin kawari-web &
cargo run -q --package kawari --features oodle --bin kawari-lobby & cargo run -q --package kawari --features oodle --bin kawari-lobby &
cargo run -q --package kawari --features oodle --bin kawari-world & cargo run -q --package kawari --features oodle --bin kawari-world &
cargo run -q --package kawari --features oodle --bin kawari-launcher &
wait wait

View file

@ -0,0 +1,42 @@
use axum::response::Html;
use axum::{Router, routing::get};
use kawari::config::get_config;
use minijinja::Environment;
use minijinja::context;
fn setup_default_environment() -> Environment<'static> {
let mut env = Environment::new();
env.add_template(
"launcher.html",
include_str!("../../templates/launcher.html"),
)
.unwrap();
env
}
async fn root() -> Html<String> {
let config = get_config();
let environment = setup_default_environment();
let template = environment.get_template("launcher.html").unwrap();
Html(
template
.render(context! { login_server => config.login.server_name })
.unwrap(),
)
}
#[tokio::main]
async fn main() {
tracing_subscriber::fmt::init();
let app = Router::new().route("/v700", get(root));
let config = get_config();
let addr = config.launcher.get_socketaddr();
tracing::info!("Server started on {addr}");
let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
axum::serve(listener, app).await.unwrap();
}

View file

@ -263,6 +263,32 @@ impl WorldConfig {
} }
} }
/// Configuration for the launcher server.
#[derive(Serialize, Deserialize)]
pub struct LauncherConfig {
pub port: u16,
pub listen_address: String,
}
impl Default for LauncherConfig {
fn default() -> Self {
Self {
port: 5802,
listen_address: "127.0.0.1".to_string(),
}
}
}
impl LauncherConfig {
/// Returns the configured IP address & port as a `SocketAddr`.
pub fn get_socketaddr(&self) -> SocketAddr {
SocketAddr::from((
IpAddr::from_str(&self.listen_address).expect("Invalid IP address format in config!"),
self.port,
))
}
}
/// Global and all-encompassing config. /// Global and all-encompassing config.
/// Settings that affect all servers belong here. /// Settings that affect all servers belong here.
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -294,6 +320,9 @@ pub struct Config {
#[serde(default)] #[serde(default)]
pub world: WorldConfig, pub world: WorldConfig,
#[serde(default)]
pub launcher: LauncherConfig,
/// Enable various packet debug functions. This will clutter your working directory! /// Enable various packet debug functions. This will clutter your working directory!
#[serde(default)] #[serde(default)]
pub packet_debugging: bool, pub packet_debugging: bool,
@ -311,6 +340,7 @@ impl Default for Config {
patch: PatchConfig::default(), patch: PatchConfig::default(),
web: WebConfig::default(), web: WebConfig::default(),
world: WorldConfig::default(), world: WorldConfig::default(),
launcher: LauncherConfig::default(),
packet_debugging: false, packet_debugging: false,
} }
} }

70
templates/launcher.html Normal file
View file

@ -0,0 +1,70 @@
<!DOCTYPE html>
<html lang=en>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge;">
<title>Kawari Launcher</title>
</head>
<body>
<p>Welcome to Kawari!</p>
<input type="button" value="System Info" onclick="window.external.user('systemInfo');" />
<input type="button" value="Play" onclick="window.external.user('startPlay');" />
<input type="button" value="Exit" onclick="window.external.user('requestExit');" />
<input type="button" value="Reboot" onclick="window.external.user('requestReboot');" />
<input type="button" value="Open Google" onclick="window.external.user('link=https://google.com/');" />
<input type="button" value="Accept EULA" onclick="window.external.user('eulaOk');" />
<input type="button" value="Disable DX11" onclick="window.external.user('config=dx11enabled=0');" />
<input type="button" value="Enable DX11" onclick="window.external.user('config=dx11enabled=1');" />
<input type="button" value="Request Config" onclick="window.external.user('requestConfig');" />
<input type="button" value="Request Login Url" onclick="window.external.user('requestLoginUrl');" />
<input type="button" value="Request Platform" onclick="window.external.user('requestDP');" />
<p id="replace-me">meh</p>
<script type="text/javascript">
function checkHandlerType(e) {
if ('function' != typeof e) throw new Error('Protocol Callback is not function.');
return e
}
function fromAppConfig(thing) {
document.getElementById('replace-me').innerText += "config: " + JSON.stringify(thing);
}
window.fromAppConfig = this.checkHandlerType(fromAppConfig);
function fromAppWarn(thing) {
document.getElementById('replace-me').innerText += "warn: " + JSON.stringify(thing);
}
window.fromAppWarn = this.checkHandlerType(fromAppWarn);
function fromAppStartVersionCheck(thing) {
document.getElementById('replace-me').innerText += "version: " + JSON.stringify(thing);
}
window.fromAppStartVersionCheck = this.checkHandlerType(fromAppStartVersionCheck);
function fromAppDP(thing) {
document.getElementById('replace-me').innerText += "dp: " + JSON.stringify(thing);
}
window.fromAppDP = this.checkHandlerType(fromAppDP);
function fromAppDisplaySettings(thing) {
document.getElementById('replace-me').innerText += "display settings: " + JSON.stringify(thing);
}
window.fromAppDisplaySettings = this.checkHandlerType(fromAppDisplaySettings);
function fromAppResumeInfo(thing) {
document.getElementById('replace-me').innerText += "resume info: " + JSON.stringify(thing);
}
window.fromAppResumeInfo = this.checkHandlerType(fromAppResumeInfo);
// this is what the retail launcher does
window.external.user('permissionFromApp=1');
window.external.user('requestDP');
window.external.user('requestConfig');
window.external.user('requestDisplaySettings');
window.external.user('requestResumeInfo');
</script>
</body>
</html>