1
Fork 0
mirror of https://github.com/redstrate/Auracite.git synced 2025-04-22 20:57:46 +00:00

Make the Dalamud plugin work with the WebAssembly version

This commit is contained in:
Joshua Goins 2024-10-31 23:11:26 -04:00
parent 66f641b7ca
commit acb42a7cb6
6 changed files with 109 additions and 39 deletions

81
Cargo.lock generated
View file

@ -199,14 +199,14 @@ checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
[[package]]
name = "cssparser"
version = "0.34.0"
version = "0.31.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7c66d1cd8ed61bf80b38432613a7a2f09401ab8d0501110655f8b341484a3e3"
checksum = "5b3df4f93e5fbbe73ec01ec8d3f68bba73107993a5b1e7519273c32db9b0d5be"
dependencies = [
"cssparser-macros",
"dtoa-short",
"itoa",
"phf",
"phf 0.11.2",
"smallvec",
]
@ -397,9 +397,9 @@ dependencies = [
[[package]]
name = "ego-tree"
version = "0.9.0"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c6ba7d4eec39eaa9ab24d44a0e73a7949a1095a8b3f3abb11eddf27dbb56a53"
checksum = "12a0bb14ac04a9fcf170d0bbbef949b44cc492f4452bd20c095636956f653642"
[[package]]
name = "either"
@ -526,6 +526,15 @@ dependencies = [
"byteorder",
]
[[package]]
name = "getopts"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
dependencies = [
"unicode-width",
]
[[package]]
name = "getrandom"
version = "0.2.15"
@ -578,9 +587,9 @@ checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]]
name = "html5ever"
version = "0.29.0"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e15626aaf9c351bc696217cbe29cb9b5e86c43f8a46b5e2f5c6c5cf7cb904ce"
checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4"
dependencies = [
"log",
"mac",
@ -812,13 +821,13 @@ checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
[[package]]
name = "markup5ever"
version = "0.14.0"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82c88c6129bd24319e62a0359cb6b958fa7e8be6e19bb1663bc396b90883aca5"
checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45"
dependencies = [
"log",
"phf",
"phf_codegen",
"phf 0.11.2",
"phf_codegen 0.11.2",
"string_cache",
"string_cache_codegen",
"tendril",
@ -993,6 +1002,15 @@ version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "phf"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
dependencies = [
"phf_shared 0.10.0",
]
[[package]]
name = "phf"
version = "0.11.2"
@ -1003,6 +1021,16 @@ dependencies = [
"phf_shared 0.11.2",
]
[[package]]
name = "phf_codegen"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd"
dependencies = [
"phf_generator 0.10.0",
"phf_shared 0.10.0",
]
[[package]]
name = "phf_codegen"
version = "0.11.2"
@ -1328,15 +1356,16 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "scraper"
version = "0.21.0"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0e749d29b2064585327af5038a5a8eb73aeebad4a3472e83531a436563f7208"
checksum = "b90460b31bfe1fc07be8262e42c665ad97118d4585869de9345a84d501a9eaf0"
dependencies = [
"ahash",
"cssparser",
"ego-tree",
"getopts",
"html5ever",
"precomputed-hash",
"once_cell",
"selectors",
"tendril",
]
@ -1366,9 +1395,9 @@ dependencies = [
[[package]]
name = "selectors"
version = "0.26.0"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd568a4c9bb598e291a08244a5c1f5a8a6650bee243b5b0f8dbb3d9cc1d87fe8"
checksum = "4eb30575f3638fc8f6815f448d50cb1a2e255b0897985c8c59f4d37b72a07b06"
dependencies = [
"bitflags",
"cssparser",
@ -1376,8 +1405,8 @@ dependencies = [
"fxhash",
"log",
"new_debug_unreachable",
"phf",
"phf_codegen",
"phf 0.10.1",
"phf_codegen 0.10.0",
"precomputed-hash",
"servo_arc",
"smallvec",
@ -1429,9 +1458,9 @@ dependencies = [
[[package]]
name = "servo_arc"
version = "0.4.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae65c4249478a2647db249fb43e23cec56a2c8974a427e7bd8cb5a1d0964921a"
checksum = "d036d71a959e00c77a63538b90a6c2390969f9772b096ea837205c6bd0491a44"
dependencies = [
"stable_deref_trait",
]
@ -1525,9 +1554,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "2.0.85"
version = "2.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56"
checksum = "e89275301d38033efb81a6e60e3497e734dfcc62571f2854bf4b16690398824c"
dependencies = [
"proc-macro2",
"quote",
@ -1599,18 +1628,18 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.65"
version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5"
checksum = "5d171f59dbaa811dbbb1aee1e73db92ec2b122911a48e1390dfe327a821ddede"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.65"
version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602"
checksum = "b08be0f17bd307950653ce45db00cd31200d82b624b36e181337d9c7d92765b5"
dependencies = [
"proc-macro2",
"quote",

View file

@ -12,7 +12,8 @@ cxx-qt-build = { git = "https://github.com/KDAB/cxx-qt", branch = "main", featur
[dependencies]
# Used to scrape the Lodestone HTML pages
scraper = { version ="0.21", default-features = false }
# NOTE: Do not upgrade to 0.21, as it crashes in WebAssembly for some reason. Report this upstream.
scraper = { version ="0.20" }
# Used to serialize the JSON data we export
serde = { version = "1.0", features = ["derive"], default-features = false }

View file

@ -44,10 +44,17 @@ public class EndStep : IStep
[Route(HttpVerbs.Get, "/package")]
public void GetPackage()
{
Response.Headers.Set(HttpHeaderNames.AccessControlAllowOrigin, "*");
Response.ContentType = MimeType.Json;
using var writer = HttpContext.OpenResponseText(Encoding.UTF8, true);
writer.Write(JsonConvert.SerializeObject(Plugin.package));
}
// TODO: Make this a POST request?
// This is needed since we don't know when the CORS handshake really stops. This really shouldn't be needed though.
[Route(HttpVerbs.Get, "/stop")]
public void Stop()
{
_endStep.End();
}
}
@ -61,7 +68,6 @@ public class EndStep : IStep
_server = new WebServer(o => o
.WithUrlPrefix("http://localhost:42072/")
.WithMode(HttpListenerMode.EmbedIO))
.WithCors("http://localhost:42072/")
.WithWebApi("/", m => m.WithController(() => new Controller(this)));
_server.RunAsync();
}

View file

@ -10,7 +10,7 @@
function archive() {
init().then(() => {
archive_character_base64(document.getElementById("name").value, false).then((uri) => {
archive_character_base64(document.getElementById("name").value, document.getElementById("scales").checked).then((uri) => {
// Download character archive
window.location.replace(uri);
document.getElementById("statusMessage").innerText = "Archive complete!";

View file

@ -1,9 +1,14 @@
use reqwest::Url;
pub async fn download(url: &Url) -> Result<Vec<u8>, reqwest::Error> {
let client = reqwest::Client::builder()
.no_proxy() // This fixes localhost connections... for some reason (https://github.com/seanmonstar/reqwest/issues/913)
.build()?;
let mut client = reqwest::Client::builder();
#[cfg(not(target_family = "wasm"))]
{
client = client.no_proxy(); // This fixes localhost connections... for some reason (https://github.com/seanmonstar/reqwest/issues/913)
}
let client = client.build()?;
let body = client.get(url.to_string())
.send()

View file

@ -21,8 +21,18 @@ use wasm_bindgen::prelude::wasm_bindgen;
#[cfg(target_family = "wasm")]
use wasm_bindgen::JsValue;
/// The main Lodestone domain
const LODESTONE_HOST: &str = "https://na.finalfantasyxiv.com";
/// The Lodestone proxy used in WebAssembly builds. Needed for CORS and cookie injection.
const LODESTONE_TUNNEL_HOST: &str = "https://lodestone-tunnel.ryne.moe";
/// The image domain.
const IMAGE_HOST: &str = "img2.finalfantasyxiv.com";
/// The image proxy used in WebAssembly builds. Needed for CORS.
const IMAGE_TUNNEL_HOST: &str = "img-tunnel.ryne.moe";
#[derive(Default, Deserialize, Clone)]
struct Package {
playtime: String,
@ -66,13 +76,20 @@ impl From<ArchiveError> for JsValue {
ArchiveError::CharacterNotFound => { JsValue::from_str(&"character_not_found".to_string()) }
ArchiveError::ParsingError => { JsValue::from_str(&"parsing_error".to_string())}
ArchiveError::UnknownError => { JsValue::from_str(&"unknown_error".to_string()) }
ArchiveError::CouldNotConnectToDalamud => { JsValue::from_str(&"could_not_connect_to_dalamud".to_string()) }
}
}
}
/// Archives the character named `character_name` and gives a ZIP file as bytes that can be written to disk.
pub async fn archive_character(character_name: &str, use_dalamud: bool) -> Result<Vec<u8>, ArchiveError> {
let search_url = Url::parse_with_params(&format!("{LODESTONE_HOST}/lodestone/character?"), &[("q", character_name)]).map_err(|_| ArchiveError::UnknownError)?;
let lodestone_host = if cfg!(target_family = "wasm") {
LODESTONE_TUNNEL_HOST
} else {
LODESTONE_HOST
};
let search_url = Url::parse_with_params(&format!("{lodestone_host}/lodestone/character?"), &[("q", character_name)]).map_err(|_| ArchiveError::UnknownError)?;
let search_page = download(&search_url)
.await
.map_err(|_| ArchiveError::DownloadFailed(search_url.to_string()))?;
@ -83,7 +100,7 @@ pub async fn archive_character(character_name: &str, use_dalamud: bool) -> Resul
return Err(ArchiveError::CharacterNotFound);
}
let char_page_url = Url::parse(&format!("{LODESTONE_HOST}{}", href)).map_err(|_| ArchiveError::UnknownError)?;
let char_page_url = Url::parse(&format!("{lodestone_host}{}", href)).map_err(|_| ArchiveError::UnknownError)?;
let char_page = download(&char_page_url)
.await
.map_err(|_| ArchiveError::DownloadFailed(char_page_url.to_string()))?;
@ -92,13 +109,17 @@ pub async fn archive_character(character_name: &str, use_dalamud: bool) -> Resul
let mut char_data = parser::parse_lodestone(&char_page);
// 2 MiB, for one JSON and two images
let mut buf = vec![0; 2097152];
let mut zip = ZipWriter::new(std::io::Cursor::new(&mut buf[..]));
let mut buf = Vec::new();
let mut zip = ZipWriter::new(std::io::Cursor::new(&mut buf));
let options = SimpleFileOptions::default().compression_method(zip::CompressionMethod::Stored);
if !char_data.portrait_url.is_empty() {
let portrait_url = char_data.portrait_url.replace("img2.finalfantasyxiv.com", "img-tunnel.ryne.moe");
let portrait_url = if cfg!(target_family = "wasm") {
&char_data.portrait_url.replace(IMAGE_HOST, IMAGE_TUNNEL_HOST)
} else {
&char_data.portrait_url
};
let portrait_url = Url::parse(&portrait_url).map_err(|_| ArchiveError::UnknownError)?;
let portrait = download(&portrait_url)
@ -109,7 +130,11 @@ pub async fn archive_character(character_name: &str, use_dalamud: bool) -> Resul
zip.write_all(&*portrait)?;
}
if !char_data.face_url.is_empty() {
let face_url = char_data.face_url.replace("img2.finalfantasyxiv.com", "img-tunnel.ryne.moe");
let face_url = if cfg!(target_family = "wasm") {
&char_data.face_url.replace(IMAGE_HOST, IMAGE_TUNNEL_HOST)
} else {
&char_data.face_url
};
let face_url = Url::parse(&face_url).map_err(|_| ArchiveError::UnknownError)?;
let face = download(&face_url)
@ -137,6 +162,10 @@ pub async fn archive_character(character_name: &str, use_dalamud: bool) -> Resul
char_data.is_novice = package.is_novice;
char_data.is_returner = package.is_returner;
char_data.player_commendations = package.player_commendations; // TODO: fetch from the lodestone?
// Stop the HTTP server
let stop_url = Url::parse(&"http://localhost:42072/stop").map_err(|_| ArchiveError::UnknownError)?;
download(&stop_url).await;
}
zip.start_file("character.json", options)?;