conduit_cli/core/api/minecraftforge/
mod.rs1pub mod models;
2
3use crate::errors::{ConduitError, ConduitResult};
4
5use self::models::ForgeMetadata;
6use quick_xml::de::from_str;
7use reqwest::Client;
8
9pub struct ForgeClient {
10 client: Client,
11}
12
13impl Default for ForgeClient {
14 fn default() -> Self {
15 Self {
16 client: Client::new(),
17 }
18 }
19}
20
21impl ForgeClient {
22 pub async fn get_metadata(&self) -> ConduitResult<ForgeMetadata> {
23 let url = "https://maven.minecraftforge.net/net/minecraftforge/forge/maven-metadata.xml";
24 let response = self.client.get(url).send().await?.text().await?;
25
26 let metadata: ForgeMetadata = from_str(&response)
27 .map_err(|e| ConduitError::Deserialize(format!("failed to parse forge xml: {e}")))?;
28
29 Ok(metadata)
30 }
31
32 pub async fn get_latest_version(&self, input_version: &str) -> ConduitResult<String> {
33 let meta = self.get_metadata().await?;
34
35 if meta
36 .versioning
37 .versions
38 .list
39 .iter()
40 .any(|v| v == input_version)
41 {
42 return Ok(input_version.to_string());
43 }
44
45 let prefix = format!("{input_version}-");
46
47 meta.versioning
48 .versions
49 .list
50 .into_iter()
51 .rev()
52 .find(|v| v.starts_with(&prefix))
53 .ok_or_else(|| {
54 ConduitError::NotFound(format!("no forge version found for {input_version}"))
55 })
56 }
57 pub fn build_bin_url(&self, version: &str, classifier: &str) -> String {
58 let base = "https://maven.minecraftforge.net/net/minecraftforge/forge";
59 format!("{base}/{version}/forge-{version}-{classifier}.jar")
60 }
61}