From 0acea2646ebe220f362b7524131788be57a2324d Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Wed, 30 Oct 2024 16:32:50 -0400 Subject: [PATCH] Move character archiving to the library So this can eventually be called by JavaScript. --- Cargo.lock | 21 ++++---- Cargo.toml | 3 ++ src/lib.rs | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++- src/main.rs | 77 ++---------------------------- 4 files changed, 150 insertions(+), 85 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 10451e9..8b8ffb5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,6 +103,7 @@ dependencies = [ "serde", "serde_json", "touche", + "wasm-bindgen", ] [[package]] @@ -1688,9 +1689,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", "once_cell", @@ -1699,9 +1700,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", @@ -1726,9 +1727,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1736,9 +1737,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", @@ -1749,9 +1750,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "web-sys" diff --git a/Cargo.toml b/Cargo.toml index 6276632..975e2bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,9 @@ minijinja = "2.0" # TODO: upstream this or poke upstream to add this touche = { git = "https://github.com/redstrate/touche" } +# Used to generate the WebAssembly version +wasm-bindgen = "0.2.95" + # Not used directly by us, but to disable the "std" feature and is used by the scraper crate. ahash = { version = "0.8.0", default-features = false } diff --git a/src/lib.rs b/src/lib.rs index 8f00a4e..84fdc94 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,136 @@ pub mod data; pub mod downloader; pub mod html; -pub mod parser; \ No newline at end of file +pub mod parser; + +use clap::Parser; +use serde::Deserialize; +use std::convert::Infallible; +use std::fs::{read, write}; +use std::path::Path; +use std::sync::{Arc, Mutex}; +use touche::server::Service; +use touche::{Body, HttpBody, Request, Response, Server, StatusCode}; +use wasm_bindgen::prelude::wasm_bindgen; +use crate::downloader::download; +use crate::html::write_html; +use crate::parser::parse_search; + +const LODESTONE_HOST: &str = "https://na.finalfantasyxiv.com"; + +#[derive(Default, Deserialize, Clone)] +struct Package { + playtime: String, + height: i32, + bust_size: i32, + gil: u32, + is_battle_mentor: bool, + is_trade_mentor: bool, + is_novice: bool, + is_returner: bool, + player_commendations: i32, +} + +#[derive(Clone)] +struct PackageService<'a> { + wants_stop: Arc>, // TODO: THIS IS TERRIBLE STOP STOP STOP + package: &'a Arc>, +} + +impl Service for PackageService<'_> { + type Body = &'static str; + type Error = Infallible; + + fn call(&self, req: Request) -> Result, Self::Error> { + *self.package.lock().unwrap() = serde_json::from_str(&String::from_utf8(req.into_body().into_bytes().unwrap()).unwrap()).unwrap(); + + *self.wants_stop.lock().unwrap() = true; + + Ok(Response::builder() + .status(StatusCode::OK) + .body("") + .unwrap()) + } + + // TODO: NO NO NO NO + fn wants_stop(&self) -> bool { + *self.wants_stop.lock().unwrap() + } +} + +#[wasm_bindgen] +pub extern fn archive_character(character_name: &str, use_dalamud: bool) { + let search_page_path = Path::new("/tmp/search.html"); + download( + &format!("{LODESTONE_HOST}/lodestone/character/?q={}", character_name), + search_page_path, + ) + .expect("Failed to download the search page from the Lodestone."); + + let href = parse_search(&String::from_utf8(read(search_page_path).unwrap()).unwrap()); + if href.is_empty() { + println!("Unable to find character!"); + } + + let char_page_path = Path::new("/tmp/character.html"); + download(&format!("{LODESTONE_HOST}{}", href), char_page_path) + .expect("Failed to download the character page from the Lodestone."); + + let mut char_data = crate::parser::parse_lodestone(&String::from_utf8(read(char_page_path).unwrap()).unwrap()); + + let character_folder = Path::new(&character_name); + if !character_folder.exists() { + std::fs::create_dir(character_folder).unwrap(); + } + + if !char_data.portrait_url.is_empty() { + download( + &char_data.portrait_url, + &character_folder.join("portrait.jpg"), + ) + .expect("Failed to download the character portrait image."); + } + if !char_data.face_url.is_empty() { + download(&char_data.face_url, &character_folder.join("face.jpg")) + .expect("Failed to download the character face image."); + } + + if use_dalamud { + println!("Now waiting for the Dalamud plugin. Type /auracite begin in chat."); + + let package = Arc::new(Mutex::new(Package::default())); + + Server::bind("0.0.0.0:8000").serve_single_thread(PackageService { wants_stop: Arc::new(Mutex::new(false)), package: &package }).unwrap(); + + let package = &*package.lock().unwrap(); + + char_data.playtime = package.playtime.parse().unwrap(); + char_data.appearance.height = package.height; + char_data.appearance.bust_size = package.bust_size; + char_data.currencies.gil = package.gil; // TODO: also fetch from the lodestone + char_data.is_battle_mentor = package.is_battle_mentor; + char_data.is_trade_mentor = package.is_trade_mentor; + 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? + } + + let serialized = serde_json::to_string(&char_data).unwrap(); + write(character_folder.join("character.json"), serialized) + .expect("Failed to write the character JSON file."); + + println!( + "Download complete! The archive is located at: {}", + character_folder.file_name().unwrap().to_str().unwrap() + ); + + write_html( + &char_data, + &character_folder + .join("character.html") + .into_os_string() + .into_string() + .unwrap(), + ) + .expect("Failed to write the character HTML file."); +} diff --git a/src/main.rs b/src/main.rs index 6b11464..360d4e2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ use std::path::Path; use std::sync::{Arc, Mutex}; use touche::server::Service; use touche::{Body, HttpBody, Request, Response, Server, StatusCode}; +use auracite::archive_character; const LODESTONE_HOST: &str = "https://na.finalfantasyxiv.com"; @@ -66,78 +67,6 @@ fn main() { let args = Args::parse(); println!("Downloading character data for {}...", args.name); - - let search_page_path = Path::new("/tmp/search.html"); - download( - &format!("{LODESTONE_HOST}/lodestone/character/?q={}", args.name), - search_page_path, - ) - .expect("Failed to download the search page from the Lodestone."); - - let href = parse_search(&String::from_utf8(read(search_page_path).unwrap()).unwrap()); - if href.is_empty() { - println!("Unable to find character!"); - } - - let char_page_path = Path::new("/tmp/character.html"); - download(&format!("{LODESTONE_HOST}{}", href), char_page_path) - .expect("Failed to download the character page from the Lodestone."); - - let mut char_data = parse_lodestone(&String::from_utf8(read(char_page_path).unwrap()).unwrap()); - - let character_folder = Path::new(&args.name); - if !character_folder.exists() { - std::fs::create_dir(character_folder).unwrap(); - } - - if !char_data.portrait_url.is_empty() { - download( - &char_data.portrait_url, - &character_folder.join("portrait.jpg"), - ) - .expect("Failed to download the character portrait image."); - } - if !char_data.face_url.is_empty() { - download(&char_data.face_url, &character_folder.join("face.jpg")) - .expect("Failed to download the character face image."); - } - - if args.dalamud { - println!("Now waiting for the Dalamud plugin. Type /auracite begin in chat."); - - let package = Arc::new(Mutex::new(Package::default())); - - Server::bind("0.0.0.0:8000").serve_single_thread(PackageService { wants_stop: Arc::new(Mutex::new(false)), package: &package }).unwrap(); - - let package = &*package.lock().unwrap(); - - char_data.playtime = package.playtime.parse().unwrap(); - char_data.appearance.height = package.height; - char_data.appearance.bust_size = package.bust_size; - char_data.currencies.gil = package.gil; // TODO: also fetch from the lodestone - char_data.is_battle_mentor = package.is_battle_mentor; - char_data.is_trade_mentor = package.is_trade_mentor; - 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? - } - - let serialized = serde_json::to_string(&char_data).unwrap(); - write(character_folder.join("character.json"), serialized) - .expect("Failed to write the character JSON file."); - - println!( - "Download complete! The archive is located at: {}", - character_folder.file_name().unwrap().to_str().unwrap() - ); - - write_html( - &char_data, - &character_folder - .join("character.html") - .into_os_string() - .into_string() - .unwrap(), - ) - .expect("Failed to write the character HTML file."); + + archive_character(&args.name, args.dalamud); }