mirror of
https://github.com/redstrate/Kawari.git
synced 2025-04-24 08:07:45 +00:00
Run cargo fmt
This commit is contained in:
parent
f7a5940f20
commit
40ef6b8193
8 changed files with 171 additions and 146 deletions
|
@ -1,16 +1,12 @@
|
|||
use std::net::SocketAddr;
|
||||
|
||||
use axum::{
|
||||
Json,
|
||||
Router, routing::get,
|
||||
extract::Form
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use axum::response::{Html, Redirect};
|
||||
use axum::routing::post;
|
||||
use axum::{Json, Router, extract::Form, routing::get};
|
||||
use kawari::config::{Config, get_config};
|
||||
use minijinja::{Environment, context};
|
||||
use kawari::setup_default_environment;
|
||||
use minijinja::{Environment, context};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct GateStatus {
|
||||
|
@ -56,10 +52,7 @@ async fn apply(Form(input): Form<Input>) -> Redirect {
|
|||
config.boot_patches_location = boot_patch_location;
|
||||
}
|
||||
|
||||
serde_json::to_writer(
|
||||
&std::fs::File::create("config.json").unwrap(),
|
||||
&config,
|
||||
)
|
||||
serde_json::to_writer(&std::fs::File::create("config.json").unwrap(), &config)
|
||||
.expect("TODO: panic message");
|
||||
|
||||
Redirect::to("/")
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
use std::net::SocketAddr;
|
||||
|
||||
use axum::{
|
||||
Json,
|
||||
Router, routing::get,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use axum::{Json, Router, routing::get};
|
||||
use kawari::config::{Config, get_config};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct GateStatus {
|
||||
|
@ -17,7 +14,7 @@ async fn get_login_status() -> Json<GateStatus> {
|
|||
|
||||
let config = get_config();
|
||||
Json(GateStatus {
|
||||
status: config.login_open.into()
|
||||
status: config.login_open.into(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -26,14 +23,14 @@ async fn get_world_status() -> Json<GateStatus> {
|
|||
|
||||
let config = get_config();
|
||||
Json(GateStatus {
|
||||
status: config.login_open.into()
|
||||
status: config.login_open.into(),
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct Banner {
|
||||
link: String,
|
||||
lsb_banner: String
|
||||
lsb_banner: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
|
@ -42,7 +39,7 @@ struct NewsItem {
|
|||
id: String,
|
||||
tag: String,
|
||||
title: String,
|
||||
url: String
|
||||
url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
use std::net::SocketAddr;
|
||||
|
||||
use axum::{Form, Router, routing::get};
|
||||
use axum::extract::Query;
|
||||
use axum::response::Html;
|
||||
use axum::routing::post;
|
||||
use rand::distributions::Alphanumeric;
|
||||
use rand::Rng;
|
||||
use serde::Deserialize;
|
||||
use axum::{Form, Router, routing::get};
|
||||
use kawari::generate_sid;
|
||||
use rand::Rng;
|
||||
use rand::distributions::Alphanumeric;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[allow(dead_code)]
|
||||
|
@ -17,11 +17,13 @@ struct Params {
|
|||
isft: String,
|
||||
cssmode: String,
|
||||
isnew: String,
|
||||
launchver: String
|
||||
launchver: String,
|
||||
}
|
||||
|
||||
async fn top(Query(params): Query<Params>) -> Html<&'static str> {
|
||||
Html("\r\n<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\r\n<html lang=en-GB id=gb>\r\n<head>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /></head><form action=\"login.send\" method=\"post\" name=\"mainForm\">\r\n\t\r\n\t\t\r\n\t\t<input type=\"hidden\" name=\"_STORED_\" value=\"42f06e5f4194001a9ad61c8481f435e8b9eac79242f9221d463aa492ab2b3373655adadff3e72dd16a798ee8a222c519848743c97084f1af71854f06050a1f2813e5c3aaf66e5f0ef24dc18588a8cf06758992e42035f7e4f99f85c8b6082200dcabc6a37c7f76ce542eefc1f1798da5e23fd4b46ed17489de5eb8e8a222c5198487433bff5f3433c061ded661b3f33b5f2d2807f5db74747f4dfe8f1fe89f9388f717347bbea9e9ec2931bb6fdc4b11648dfa9e726cdf690d74970a36f7482c12593a5ad7b966c4cf14655e11641f0bb67b8e807377edfa81055480da52031e0ba86ec52f991eb3cb8913c8f807287f3cb5ac4143326f33a4503cf31e021c8f41a5eec01870e0004acc0d0bf2bed65da5eeae3703ae878c20bd7f1167745e96770979146463fa40235e6bba8bdac1273dcbc1256cda0caacbdaad\">\n\r\n\t\t\r\n\t\t<div class=\"form-item type-id\">\r\n\t\t\t<label class=\"item-label\" for=\"sqexid\"><span class=\"label-image-text\" title=\"Square Enix ID\"></span></label>\r\n\t\t\t<input class=\"item-input\" name=\"sqexid\" id=\"sqexid\" type=\"text\" value=\"\" tabindex=\"1\" placeholder=\"ID (Required)\" maxLength=\"16\"\r\n\t\t\t\r\n\t\t\t\t />\r\n\t\t\t\r\n\t\t</div>\r\n\r\n\t\t <div class=\"form-item type-pw\">\r\n\t\t\t<label class=\"item-label\" for=\"password\"><span class=\"label-image-text\" title=\"Square Enix Password\"></span></label>\r\n\t\t\t<input class=\"item-password\" name=\"password\" id=\"password\" type=\"password\" value=\"\" tabindex=\"2\" placeholder=\"Password (Required)\" maxLength=\"32\" autocomplete=\"off\"/>\r\n\t\t</div>\r\n\t\r\n\t\t<div class=\"form-item type-otpw\">\r\n\t\t\t<label class=\"item-label\" for=\"otppw\"><span class=\"label-image-text\" title=\"One-Time Password\"></span></label>\r\n\t\t\t<input class=\"item-otpw\" name=\"otppw\" id=\"otppw\" type=\"text\" value=\"\" tabindex=\"3\" autocomplete=\"off\" maxLength=\"6\" placeholder=\"Password (Optional)\" />\r\n\t\t</div>\r\n\r\n\t\t\r\n\t\t<div class=\"form-item type-remember-id\">\r\n\t\t\t<input name=\"saveid\" id=\"saveid\" type=\"checkbox\" value=\"1\" class=\"item-checkbox\" tabindex=\"4\" />\r\n\t\t\t<label class=\"item-checkbox-label\" for=\"saveid\"><span class=\"label-checkbox-image-text\" title=\"Remember Square Enix ID\"></span></label>\r\n\t\t</div>\r\n\t\t\r\n\r\n\t\t<div class=\"form-item type-submit\">\r\n\t\t\t<button class=\"item-button\" type=\"submit\" tabindex=\"5\" onClick=\"ctrEvent('mainForm')\" id=\"btLogin\"><span class=\"button-image-text\" title=\"Login\"></span></button>\r\n\t\t</div>\r\n\r\n\t</form>\r\n</div>\r\n</body>\r\n</html>\r\n\r\n</html>")
|
||||
Html(
|
||||
"\r\n<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\r\n<html lang=en-GB id=gb>\r\n<head>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /></head><form action=\"login.send\" method=\"post\" name=\"mainForm\">\r\n\t\r\n\t\t\r\n\t\t<input type=\"hidden\" name=\"_STORED_\" value=\"42f06e5f4194001a9ad61c8481f435e8b9eac79242f9221d463aa492ab2b3373655adadff3e72dd16a798ee8a222c519848743c97084f1af71854f06050a1f2813e5c3aaf66e5f0ef24dc18588a8cf06758992e42035f7e4f99f85c8b6082200dcabc6a37c7f76ce542eefc1f1798da5e23fd4b46ed17489de5eb8e8a222c5198487433bff5f3433c061ded661b3f33b5f2d2807f5db74747f4dfe8f1fe89f9388f717347bbea9e9ec2931bb6fdc4b11648dfa9e726cdf690d74970a36f7482c12593a5ad7b966c4cf14655e11641f0bb67b8e807377edfa81055480da52031e0ba86ec52f991eb3cb8913c8f807287f3cb5ac4143326f33a4503cf31e021c8f41a5eec01870e0004acc0d0bf2bed65da5eeae3703ae878c20bd7f1167745e96770979146463fa40235e6bba8bdac1273dcbc1256cda0caacbdaad\">\n\r\n\t\t\r\n\t\t<div class=\"form-item type-id\">\r\n\t\t\t<label class=\"item-label\" for=\"sqexid\"><span class=\"label-image-text\" title=\"Square Enix ID\"></span></label>\r\n\t\t\t<input class=\"item-input\" name=\"sqexid\" id=\"sqexid\" type=\"text\" value=\"\" tabindex=\"1\" placeholder=\"ID (Required)\" maxLength=\"16\"\r\n\t\t\t\r\n\t\t\t\t />\r\n\t\t\t\r\n\t\t</div>\r\n\r\n\t\t <div class=\"form-item type-pw\">\r\n\t\t\t<label class=\"item-label\" for=\"password\"><span class=\"label-image-text\" title=\"Square Enix Password\"></span></label>\r\n\t\t\t<input class=\"item-password\" name=\"password\" id=\"password\" type=\"password\" value=\"\" tabindex=\"2\" placeholder=\"Password (Required)\" maxLength=\"32\" autocomplete=\"off\"/>\r\n\t\t</div>\r\n\t\r\n\t\t<div class=\"form-item type-otpw\">\r\n\t\t\t<label class=\"item-label\" for=\"otppw\"><span class=\"label-image-text\" title=\"One-Time Password\"></span></label>\r\n\t\t\t<input class=\"item-otpw\" name=\"otppw\" id=\"otppw\" type=\"text\" value=\"\" tabindex=\"3\" autocomplete=\"off\" maxLength=\"6\" placeholder=\"Password (Optional)\" />\r\n\t\t</div>\r\n\r\n\t\t\r\n\t\t<div class=\"form-item type-remember-id\">\r\n\t\t\t<input name=\"saveid\" id=\"saveid\" type=\"checkbox\" value=\"1\" class=\"item-checkbox\" tabindex=\"4\" />\r\n\t\t\t<label class=\"item-checkbox-label\" for=\"saveid\"><span class=\"label-checkbox-image-text\" title=\"Remember Square Enix ID\"></span></label>\r\n\t\t</div>\r\n\t\t\r\n\r\n\t\t<div class=\"form-item type-submit\">\r\n\t\t\t<button class=\"item-button\" type=\"submit\" tabindex=\"5\" onClick=\"ctrEvent('mainForm')\" id=\"btLogin\"><span class=\"button-image-text\" title=\"Login\"></span></button>\r\n\t\t</div>\r\n\r\n\t</form>\r\n</div>\r\n</body>\r\n</html>\r\n\r\n</html>",
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
|
@ -30,12 +32,14 @@ struct Input {
|
|||
_STORED_: String,
|
||||
sqexid: String,
|
||||
password: String,
|
||||
otppw: String
|
||||
otppw: String,
|
||||
}
|
||||
|
||||
async fn login_send(Form(input): Form<Input>) -> Html<String> {
|
||||
let sid = generate_sid();
|
||||
Html(format!("window.external.user(\"login=auth,ok,sid,{sid},terms,1,region,2,etmadd,0,playable,1,ps3pkg,0,maxex,4,product,1\");"))
|
||||
Html(format!(
|
||||
"window.external.user(\"login=auth,ok,sid,{sid},terms,1,region,2,etmadd,0,playable,1,ps3pkg,0,maxex,4,product,1\");"
|
||||
))
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
|
|
|
@ -2,22 +2,22 @@ use std::cmp::Ordering;
|
|||
use std::fs::read_dir;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use axum::{Form, Json, Router, routing::get};
|
||||
use axum::extract::Query;
|
||||
use axum::response::Html;
|
||||
use axum::routing::post;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use kawari::config::{Config, get_config};
|
||||
use axum::extract::Path;
|
||||
use axum::response::IntoResponse;
|
||||
use axum::extract::Query;
|
||||
use axum::http::{HeaderMap, StatusCode};
|
||||
use minijinja::filters::list;
|
||||
use axum::response::Html;
|
||||
use axum::response::IntoResponse;
|
||||
use axum::routing::post;
|
||||
use axum::{Form, Json, Router, routing::get};
|
||||
use kawari::config::{Config, get_config};
|
||||
use kawari::patchlist::{PatchEntry, PatchList, PatchType};
|
||||
use minijinja::filters::list;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
fn list_patch_files(dir_path: &str) -> Vec<String> {
|
||||
// If the dir doesn't exist, pretend there is no patch files
|
||||
let Ok(dir) = read_dir(dir_path) else {
|
||||
return Vec::new()
|
||||
return Vec::new();
|
||||
};
|
||||
let mut entries: Vec<_> = dir.flatten().collect();
|
||||
entries.sort_by_key(|dir| dir.path());
|
||||
|
@ -38,20 +38,37 @@ fn list_patch_files(dir_path: &str) -> Vec<String> {
|
|||
.collect();
|
||||
game_patches.sort_by(|a, b| {
|
||||
// Ignore H/D in front of filenames
|
||||
let mut a_path = a.as_path().file_name().unwrap().to_str().unwrap().to_string();
|
||||
let mut a_path = a
|
||||
.as_path()
|
||||
.file_name()
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string();
|
||||
if a_path.starts_with("H") {
|
||||
return Ordering::Less;
|
||||
}
|
||||
let mut b_path = b.as_path().file_name().unwrap().to_str().unwrap().to_string();
|
||||
let mut b_path = b
|
||||
.as_path()
|
||||
.file_name()
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string();
|
||||
/*if b_path.starts_with("H") {
|
||||
return Ordering::Greater;
|
||||
}*/
|
||||
a_path.partial_cmp(&b_path).unwrap()
|
||||
}); // ensure we're actually installing them in the correct order
|
||||
game_patches.iter().map(|x| x.file_stem().unwrap().to_str().unwrap().to_string() ).collect()
|
||||
game_patches
|
||||
.iter()
|
||||
.map(|x| x.file_stem().unwrap().to_str().unwrap().to_string())
|
||||
.collect()
|
||||
}
|
||||
|
||||
async fn verify_session(Path((platform, game_version, sid)): Path<(String, String, String)>) -> impl IntoResponse {
|
||||
async fn verify_session(
|
||||
Path((platform, game_version, sid)): Path<(String, String, String)>,
|
||||
) -> impl IntoResponse {
|
||||
let config = get_config();
|
||||
if !config.supports_platform(&platform) {
|
||||
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
||||
|
@ -63,7 +80,6 @@ async fn verify_session(Path((platform, game_version, sid)): Path<(String, Strin
|
|||
(headers).into_response()
|
||||
}
|
||||
|
||||
|
||||
async fn verify_boot(Path((platform, boot_version)): Path<(String, String)>) -> impl IntoResponse {
|
||||
tracing::info!("Verifying boot components...");
|
||||
|
||||
|
@ -85,8 +101,7 @@ async fn verify_boot(Path((platform, boot_version)): Path<(String, String)>) ->
|
|||
id: "477D80B1_38BC_41d4_8B48_5273ADB89CAC".to_string(),
|
||||
patch_type: PatchType::Boot,
|
||||
requested_version: boot_version.clone(),
|
||||
patches: vec![
|
||||
PatchEntry {
|
||||
patches: vec![PatchEntry {
|
||||
url: format!("http://{}", patch).to_string(),
|
||||
version: "2023.09.15.0000.0000".to_string(),
|
||||
hash_block_size: 50000000,
|
||||
|
@ -95,8 +110,7 @@ async fn verify_boot(Path((platform, boot_version)): Path<(String, String)>) ->
|
|||
hashes: vec![],
|
||||
unknown_a: 0,
|
||||
unknown_b: 0,
|
||||
}
|
||||
]
|
||||
}],
|
||||
};
|
||||
let patch_list_str = patch_list.to_string();
|
||||
return patch_list_str.into_response();
|
||||
|
@ -112,8 +126,14 @@ async fn main() {
|
|||
tracing_subscriber::fmt::init();
|
||||
|
||||
let app = Router::new()
|
||||
.route("/http/:platform/ffxivneo_release_game/:game_version/:sid", post(verify_session))
|
||||
.route("/http/:platform/ffxivneo_release_boot/*boot_version", get(verify_boot)); // NOTE: for future programmers, this is a wildcard because axum hates the /version/?time=blah format.
|
||||
.route(
|
||||
"/http/:platform/ffxivneo_release_game/:game_version/:sid",
|
||||
post(verify_session),
|
||||
)
|
||||
.route(
|
||||
"/http/:platform/ffxivneo_release_boot/*boot_version",
|
||||
get(verify_boot),
|
||||
); // NOTE: for future programmers, this is a wildcard because axum hates the /version/?time=blah format.
|
||||
|
||||
let addr = SocketAddr::from(([127, 0, 0, 1], 6900));
|
||||
tracing::info!("Patch server started on {}", addr);
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
use std::net::SocketAddr;
|
||||
|
||||
use axum::{
|
||||
Json,
|
||||
Router, routing::get,
|
||||
extract::Form
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use axum::response::{Html, Redirect};
|
||||
use axum::routing::post;
|
||||
use axum::{Json, Router, extract::Form, routing::get};
|
||||
use kawari::config::{Config, get_config};
|
||||
use minijinja::{Environment, context};
|
||||
use kawari::setup_default_environment;
|
||||
use minijinja::{Environment, context};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct GateStatus {
|
||||
|
@ -22,7 +18,7 @@ async fn root() -> Html<String> {
|
|||
|
||||
let environment = setup_default_environment();
|
||||
let template = environment.get_template("web.html").unwrap();
|
||||
Html(template.render(context! { }).unwrap())
|
||||
Html(template.render(context! {}).unwrap())
|
||||
}
|
||||
|
||||
async fn login() -> Html<String> {
|
||||
|
@ -30,7 +26,7 @@ async fn login() -> Html<String> {
|
|||
|
||||
let environment = setup_default_environment();
|
||||
let template = environment.get_template("login.html").unwrap();
|
||||
Html(template.render(context! { }).unwrap())
|
||||
Html(template.render(context! {}).unwrap())
|
||||
}
|
||||
|
||||
async fn register() -> Html<String> {
|
||||
|
@ -38,7 +34,7 @@ async fn register() -> Html<String> {
|
|||
|
||||
let environment = setup_default_environment();
|
||||
let template = environment.get_template("register.html").unwrap();
|
||||
Html(template.render(context! { }).unwrap())
|
||||
Html(template.render(context! {}).unwrap())
|
||||
}
|
||||
|
||||
async fn world_status() -> Html<String> {
|
||||
|
@ -46,7 +42,11 @@ async fn world_status() -> Html<String> {
|
|||
|
||||
let environment = setup_default_environment();
|
||||
let template = environment.get_template("worldstatus.html").unwrap();
|
||||
Html(template.render(context! { login_open => config.login_open, worlds_open => config.worlds_open }).unwrap())
|
||||
Html(
|
||||
template
|
||||
.render(context! { login_open => config.login_open, worlds_open => config.worlds_open })
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
|
@ -60,10 +60,7 @@ async fn apply(Form(input): Form<Input>) -> Redirect {
|
|||
|
||||
let mut config = get_config();
|
||||
|
||||
serde_json::to_writer(
|
||||
&std::fs::File::create("config.json").unwrap(),
|
||||
&config,
|
||||
)
|
||||
serde_json::to_writer(&std::fs::File::create("config.json").unwrap(), &config)
|
||||
.expect("TODO: panic message");
|
||||
|
||||
Redirect::to("/")
|
||||
|
|
|
@ -12,7 +12,7 @@ pub struct Config {
|
|||
pub supported_platforms: Vec<String>,
|
||||
|
||||
#[serde(default)]
|
||||
pub boot_patches_location: String
|
||||
pub boot_patches_location: String,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
|
@ -21,7 +21,7 @@ impl Default for Config {
|
|||
worlds_open: false,
|
||||
login_open: false,
|
||||
boot_patches_location: String::new(),
|
||||
supported_platforms: default_supported_platforms()
|
||||
supported_platforms: default_supported_platforms(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
20
src/lib.rs
20
src/lib.rs
|
@ -1,6 +1,6 @@
|
|||
use minijinja::Environment;
|
||||
use rand::distributions::Alphanumeric;
|
||||
use rand::Rng;
|
||||
use rand::distributions::Alphanumeric;
|
||||
|
||||
pub mod config;
|
||||
pub mod patchlist;
|
||||
|
@ -16,11 +16,19 @@ pub fn generate_sid() -> String {
|
|||
|
||||
pub fn setup_default_environment() -> Environment<'static> {
|
||||
let mut env = Environment::new();
|
||||
env.add_template("admin.html", include_str!("../templates/admin.html")).unwrap();
|
||||
env.add_template("web.html", include_str!("../templates/web.html")).unwrap();
|
||||
env.add_template("login.html", include_str!("../templates/login.html")).unwrap();
|
||||
env.add_template("register.html", include_str!("../templates/register.html")).unwrap();
|
||||
env.add_template("worldstatus.html", include_str!("../templates/worldstatus.html")).unwrap();
|
||||
env.add_template("admin.html", include_str!("../templates/admin.html"))
|
||||
.unwrap();
|
||||
env.add_template("web.html", include_str!("../templates/web.html"))
|
||||
.unwrap();
|
||||
env.add_template("login.html", include_str!("../templates/login.html"))
|
||||
.unwrap();
|
||||
env.add_template("register.html", include_str!("../templates/register.html"))
|
||||
.unwrap();
|
||||
env.add_template(
|
||||
"worldstatus.html",
|
||||
include_str!("../templates/worldstatus.html"),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
env
|
||||
}
|
|
@ -14,7 +14,7 @@ pub enum PatchType {
|
|||
/// Corresponds to 4e9a232b
|
||||
Boot,
|
||||
/// Corresponds to 2b5cbc63
|
||||
Game
|
||||
Game,
|
||||
}
|
||||
|
||||
pub struct PatchList {
|
||||
|
@ -22,7 +22,7 @@ pub struct PatchList {
|
|||
pub id: String,
|
||||
pub patch_type: PatchType,
|
||||
pub requested_version: String,
|
||||
pub patches: Vec<PatchEntry>
|
||||
pub patches: Vec<PatchEntry>,
|
||||
}
|
||||
|
||||
impl PatchList {
|
||||
|
@ -34,7 +34,15 @@ impl PatchList {
|
|||
str.push_str(&self.id);
|
||||
str.push_str("\r\n");
|
||||
str.push_str("Content-Type: application/octet-stream\r\n");
|
||||
str.push_str(&format!("Content-Location: ffxivpatch/{}/metainfo/{}.http\r\n", if self.patch_type == PatchType::Boot { "2b5cbc63" } else { "4e9a232b" }, self.requested_version));
|
||||
str.push_str(&format!(
|
||||
"Content-Location: ffxivpatch/{}/metainfo/{}.http\r\n",
|
||||
if self.patch_type == PatchType::Boot {
|
||||
"2b5cbc63"
|
||||
} else {
|
||||
"4e9a232b"
|
||||
},
|
||||
self.requested_version
|
||||
));
|
||||
|
||||
let mut total_patch_size = 0;
|
||||
for patch in &self.patches {
|
||||
|
@ -115,18 +123,17 @@ mod tests {
|
|||
id: "477D80B1_38BC_41d4_8B48_5273ADB89CAC".to_string(),
|
||||
requested_version: "D2023.04.28.0000.0001".to_string(),
|
||||
patch_type: PatchType::Boot,
|
||||
patches: vec![
|
||||
PatchEntry {
|
||||
url: "http://patch-dl.ffxiv.com/boot/2b5cbc63/D2023.09.14.0000.0001.patch".to_string(),
|
||||
patches: vec![PatchEntry {
|
||||
url: "http://patch-dl.ffxiv.com/boot/2b5cbc63/D2023.09.14.0000.0001.patch"
|
||||
.to_string(),
|
||||
version: "2023.09.14.0000.0001".to_string(),
|
||||
hash_block_size: 0,
|
||||
length: 22221335,
|
||||
size_on_disk: 69674819,
|
||||
hashes: vec![],
|
||||
unknown_a: 19,
|
||||
unknown_b: 18
|
||||
}
|
||||
]
|
||||
unknown_b: 18,
|
||||
}],
|
||||
};
|
||||
|
||||
assert_eq!(patch_list.to_string(), test_case);
|
||||
|
@ -153,9 +160,9 @@ mod tests {
|
|||
id: "477D80B1_38BC_41d4_8B48_5273ADB89CAC".to_string(),
|
||||
requested_version: "2023.07.26.0000.0000".to_string(),
|
||||
patch_type: PatchType::Game,
|
||||
patches: vec![
|
||||
PatchEntry {
|
||||
url: "http://patch-dl.ffxiv.com/game/4e9a232b/D2023.09.15.0000.0000.patch".to_string(),
|
||||
patches: vec![PatchEntry {
|
||||
url: "http://patch-dl.ffxiv.com/game/4e9a232b/D2023.09.15.0000.0000.patch"
|
||||
.to_string(),
|
||||
version: "2023.09.15.0000.0000".to_string(),
|
||||
hash_block_size: 50000000,
|
||||
length: 1479062470,
|
||||
|
@ -192,10 +199,9 @@ mod tests {
|
|||
"4561eb6f954d80cdb1ece3cc4d58cbd864bf2b50".to_string(),
|
||||
"de94175c4db39a11d5334aefc7a99434eea8e4f9".to_string(),
|
||||
"55dd7215f24441d6e47d1f9b32cebdb041f2157f".to_string(),
|
||||
"2ca09db645cfeefa41a04251dfcb13587418347a".to_string()
|
||||
"2ca09db645cfeefa41a04251dfcb13587418347a".to_string(),
|
||||
],
|
||||
}
|
||||
]
|
||||
}],
|
||||
};
|
||||
|
||||
assert_eq!(patch_list.to_string(), test_case);
|
||||
|
|
Loading…
Add table
Reference in a new issue