use std::fs; use serde::{Deserialize, Serialize}; use thirtyfour::{DesiredCapabilities, WebDriver, By}; use toml::Table; use tracing::{info, debug}; use crate::errors::CliError; #[derive(Deserialize, Serialize)] pub struct PackConfig { pub pack: Pack, pub mods: Table, } #[derive(Deserialize, Serialize)] pub struct Pack { pub name: String, pub pack_base_url: String, pub forge_url: String, pub game_version: String, pub java_args: String, } #[derive(Deserialize, Serialize)] pub struct PackLock { pub global: LockGlobal, pub mod_versions: Table, } #[derive(Deserialize, Serialize)] pub struct LockGlobal { pub pack_version: u16, } pub fn read_pack_config() -> Result { let contents = fs::read_to_string("./pack.toml")?; let res: PackConfig = toml::from_str(&contents)?; Ok(res) } pub fn read_pack_lock() -> Result { let contents = fs::read_to_string("./pack.lock")?; let res = toml::from_str(&contents)?; Ok(res) } pub async fn find_updated_urls(urls: toml::map::Values<'_>, game_version: String) -> Result, CliError> { let res: Vec = Vec::new(); debug!("Attempting to find updated URLs"); debug!("Attempting to open webdriver"); let caps = DesiredCapabilities::firefox(); let driver = WebDriver::new("http://localhost:9515", caps).await?; driver.close_window().await?; debug!("Closed test window"); for url in urls { find_url(url.to_string(), &game_version).await?; } Ok(res) } async fn find_url(homepage_url: String, game_version: &String) -> Result { if homepage_url.contains("curseforge") { let caps = DesiredCapabilities::firefox(); let driver = WebDriver::new("http://localhost:9515", caps).await?; find_cdn(&driver, homepage_url, game_version).await?; driver.close_window().await?; } else { } Ok(String::new()) } #[derive(Debug)] struct RowInfo { pub release_type: String, pub filename: String, pub cdn_id: String, pub game_version: (u16, u16, u16) } /** * Ugh... */ async fn find_cdn(driver: &WebDriver, homepage_url: String, game_version: &String) -> Result { let mut page_index = 0; let best_row: RowInfo; loop { let mut url = homepage_url.clone(); url.push_str(&format!("/files/all?page={}", page_index)); driver.goto(&url).await?; let mod_vers = driver.find(By::ClassName("listing")).await?.find_all(By::XPath("tbody/tr")).await?; let mut rows: Vec = Vec::new(); for entry in mod_vers { let entry_cells = entry.find_all(By::Tag("td")).await?; let release_type = entry_cells[0].text().await?; let tmp0 = &entry_cells[1].find_all(By::Tag("a")).await?[0].text().await?; let initial_filename = urlencoding::encode(tmp0); let tmp = entry_cells[4].find(By::ClassName("mr-2")).await?.text().await?; let tmp2: Vec<&str> = tmp.split(".").collect(); let version = (tmp2[0].clone().parse::()?, tmp2[1].clone().parse::()?, tmp2[2].parse::()?); let tmp3 = entry_cells[1].find(By::Tag("a")).await?.prop("href").await?.unwrap(); let tmp4: Vec<&str> = tmp3.split("/").collect(); let cdn_id = *tmp4.last().unwrap(); if !(initial_filename.to_lowercase().contains("fabric")) || (initial_filename.to_lowercase().contains("forge")) { rows.push(RowInfo { release_type, cdn_id: cdn_id.to_string(), game_version: version, filename: initial_filename.to_string() }) } } rows.sort_by_key(|k| k.game_version); let tuple_game_version_tmp: Vec<&str> = game_version.split(".").collect(); let tuple_game_version = (tuple_game_version_tmp[0].parse::()?, tuple_game_version_tmp[1].parse::()?, tuple_game_version_tmp[2].parse::()?); let best_rows: Vec<&RowInfo> = rows.iter().filter(|x| x.game_version > tuple_game_version).collect(); info!("{:?}", best_rows); } }