Skip to content

Commit 6d7b074

Browse files
committed
feat: finish Forge Metadata fetch
- parallelize legacy - make loading a dotenv explicit Signed-off-by: Rachel Powers <[email protected]>
1 parent 81b6182 commit 6d7b074

File tree

8 files changed

+547
-220
lines changed

8 files changed

+547
-220
lines changed

libmcmeta/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ serde = { version = "1.0.160", features = ["derive"] }
1414
serde_json = "1.0.95"
1515
serde_valid = "0.15.0"
1616
serde_with = "2.3.2"
17+
time = { version = "0.3.20", features = ["serde-human-readable"] }
1718
tracing = "0.1.37"
1819

1920
[features]

libmcmeta/src/models/forge.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::models::{GradleSpecifier, MojangLibrary};
44
use serde::{Deserialize, Serialize};
55
use serde_valid::Validate;
66
use serde_with::skip_serializing_none;
7-
use std::collections::HashMap;
7+
use std::collections::{BTreeMap, HashMap};
88

99
#[derive(Deserialize, Serialize, Clone, Debug, Validate)]
1010
pub struct ForgeMavenMetadata {
@@ -424,6 +424,8 @@ pub struct ForgeLegacyLibrary {
424424
#[skip_serializing_none]
425425
#[serde(deny_unknown_fields, rename_all = "camelCase")]
426426
pub struct ForgeLegacyVersionInfo {
427+
#[serde(rename = "_comment_")]
428+
pub comment: Option<Vec<String>>,
427429
pub id: String,
428430
pub time: String,
429431
pub release_time: String,
@@ -542,8 +544,8 @@ pub struct ForgeEntry {
542544
pub latest: Option<bool>,
543545
#[merge(strategy = merge::option::overwrite_some)]
544546
pub recommended: Option<bool>,
545-
#[merge(strategy = merge::option_hashmap::recurse_some)]
546-
pub files: Option<HashMap<String, ForgeFile>>,
547+
#[merge(strategy = merge::option_btreemap::recurse_some)]
548+
pub files: Option<BTreeMap<String, ForgeFile>>,
547549
}
548550

549551
#[skip_serializing_none]
@@ -561,11 +563,11 @@ pub struct ForgeMCVersionInfo {
561563
#[derive(Deserialize, Serialize, Clone, Debug, Validate, Merge, Default)]
562564
#[serde(deny_unknown_fields)]
563565
pub struct DerivedForgeIndex {
564-
#[merge(strategy = merge::hashmap::recurse)]
565-
pub versions: HashMap<String, ForgeEntry>,
566+
#[merge(strategy = merge::btreemap::recurse)]
567+
pub versions: BTreeMap<String, ForgeEntry>,
566568
#[serde(rename = "by_mcversion")]
567-
#[merge(strategy = merge::hashmap::recurse)]
568-
pub by_mc_version: HashMap<String, ForgeMCVersionInfo>,
569+
#[merge(strategy = merge::btreemap::recurse)]
570+
pub by_mc_version: BTreeMap<String, ForgeMCVersionInfo>,
569571
}
570572

571573
/// Example content
@@ -700,11 +702,11 @@ pub struct ForgeInstallerProfile {
700702

701703
#[derive(Deserialize, Serialize, Clone, Debug, Validate, Merge, Default)]
702704
pub struct ForgeLegacyInfo {
703-
#[serde(rename = "releaseTime")]
704705
#[merge(strategy = merge::option::overwrite_some)]
705-
pub release_time: Option<String>,
706+
#[serde(rename = "releaseTime", with = "time::serde::iso8601::option")]
707+
pub release_time: Option<time::OffsetDateTime>,
706708
#[merge(strategy = merge::option::overwrite_some)]
707-
pub size: Option<i32>,
709+
pub size: Option<u64>,
708710
#[merge(strategy = merge::option::overwrite_some)]
709711
pub sha256: Option<String>,
710712
#[merge(strategy = merge::option::overwrite_some)]
@@ -787,7 +789,7 @@ pub struct ForgeProcessedVersion {
787789
pub build: i32,
788790
pub raw_version: String,
789791
pub mc_version: String,
790-
pub mv_version_sane: String,
792+
pub mc_version_sane: String,
791793
pub branch: Option<String>,
792794
pub installer_filename: Option<String>,
793795
pub installer_url: Option<String>,
@@ -803,7 +805,7 @@ impl ForgeProcessedVersion {
803805
build: entry.build,
804806
raw_version: entry.version.clone(),
805807
mc_version: entry.mc_version.clone(),
806-
mv_version_sane: entry.mc_version.replacen("_pre", "-pre", 1),
808+
mc_version_sane: entry.mc_version.replacen("_pre", "-pre", 1),
807809
branch: entry.branch.clone(),
808810
installer_filename: None,
809811
installer_url: None,

libmcmeta/src/models/mod.rs

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,8 @@ pub struct MetaVersion {
465465
#[merge(strategy = merge::option::overwrite_some)]
466466
pub minecraft_arguments: Option<String>,
467467
#[merge(strategy = merge::option::overwrite_some)]
468-
pub release_time: Option<String>,
468+
#[serde(with = "time::serde::iso8601::option")]
469+
pub release_time: Option<time::OffsetDateTime>,
469470
#[merge(strategy = merge::option_vec::append_some)]
470471
pub compatible_java_majors: Option<Vec<i32>>,
471472
#[merge(strategy = merge::option_vec::append_some)]
@@ -478,6 +479,14 @@ pub struct MetaVersion {
478479
pub additional_jvm_args: Option<Vec<String>>,
479480
}
480481

482+
#[derive(Deserialize, Serialize, Debug, Clone)]
483+
pub struct MetaMcIndexEntry {
484+
#[serde(with = "time::serde::iso8601")]
485+
pub update_time: time::OffsetDateTime,
486+
pub path: String,
487+
pub hash: String,
488+
}
489+
481490
pub mod validation {
482491
pub fn is_some<T>(obj: Option<T>) -> Result<(), serde_valid::validation::Error> {
483492
if !obj.is_some() {
@@ -549,8 +558,36 @@ pub mod merge {
549558
}
550559

551560
pub fn overwrite_key<K: Eq + Hash, V>(left: &mut HashMap<K, V>, right: HashMap<K, V>) {
552-
use std::collections::hash_map::Entry;
561+
for (k, v) in right {
562+
left.insert(k, v);
563+
}
564+
}
565+
}
566+
567+
pub mod btreemap {
568+
use std::collections::BTreeMap;
569+
use std::hash::Hash;
570+
571+
pub fn recurse<K: Eq + Hash + Ord + PartialOrd, V: merge::Merge>(
572+
left: &mut BTreeMap<K, V>,
573+
right: BTreeMap<K, V>,
574+
) {
575+
use std::collections::btree_map::Entry;
553576

577+
for (k, v) in right {
578+
match left.entry(k) {
579+
Entry::Occupied(mut existing) => existing.get_mut().merge(v),
580+
Entry::Vacant(empty) => {
581+
empty.insert(v);
582+
}
583+
}
584+
}
585+
}
586+
587+
pub fn overwrite_key<K: Eq + Hash + Ord + PartialOrd, V>(
588+
left: &mut BTreeMap<K, V>,
589+
right: BTreeMap<K, V>,
590+
) {
554591
for (k, v) in right {
555592
left.insert(k, v);
556593
}
@@ -580,7 +617,6 @@ pub mod merge {
580617
left: &mut Option<HashMap<K, V>>,
581618
right: Option<HashMap<K, V>>,
582619
) {
583-
use std::collections::hash_map::Entry;
584620
if let Some(new) = right {
585621
if let Some(original) = left {
586622
hashmap::overwrite_key(original, new);
@@ -591,6 +627,38 @@ pub mod merge {
591627
}
592628
}
593629

630+
pub mod option_btreemap {
631+
use super::btreemap;
632+
use std::collections::BTreeMap;
633+
use std::hash::Hash;
634+
635+
pub fn recurse_some<K: Eq + Hash + Ord + PartialOrd, V: merge::Merge>(
636+
left: &mut Option<BTreeMap<K, V>>,
637+
right: Option<BTreeMap<K, V>>,
638+
) {
639+
if let Some(new) = right {
640+
if let Some(original) = left {
641+
btreemap::recurse(original, new);
642+
} else {
643+
*left = Some(new);
644+
}
645+
}
646+
}
647+
648+
pub fn overwrite_key_some<K: Eq + Hash + Ord + PartialOrd, V>(
649+
left: &mut Option<BTreeMap<K, V>>,
650+
right: Option<BTreeMap<K, V>>,
651+
) {
652+
if let Some(new) = right {
653+
if let Some(original) = left {
654+
btreemap::overwrite_key(original, new);
655+
} else {
656+
*left = Some(new);
657+
}
658+
}
659+
}
660+
}
661+
594662
/// Merge strategies for `Option<Vec>`
595663
pub mod option_vec {
596664

libmcmeta/src/models/mojang.rs

Lines changed: 52 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -353,38 +353,55 @@ pub struct OldSnapshotIndex {
353353
pub struct LegacyOverrideEntry {
354354
main_class: Option<String>,
355355
applet_class: Option<String>,
356-
release_time: Option<String>,
356+
#[serde(with = "time::serde::iso8601::option")]
357+
pub release_time: Option<time::OffsetDateTime>,
357358
#[serde(rename = "+traits")]
358359
additional_traits: Option<Vec<String>>,
359360
#[serde(rename = "+jvmArgs")]
360361
additional_jvm_args: Option<Vec<String>>,
361362
}
362363

363364
impl LegacyOverrideEntry {
364-
pub fn apply_onto_meta_version(self, meta_version: &MetaVersion, legacy: bool) {
365+
pub fn apply_onto_meta_version(self, meta_version: &mut MetaVersion, legacy: bool) {
365366
// simply hard override classes
366-
// meta_version.main_class = self.main_class
367-
// meta_version.applet_class = self.applet_class
368-
// # if we have an updated release time (more correct than Mojang), use it
369-
// if self.release_time:
370-
// meta_version.release_time = self.release_time
371-
372-
// # add traits, if any
373-
// if self.additional_traits:
374-
// if not meta_version.additional_traits:
375-
// meta_version.additional_traits = []
376-
// meta_version.additional_traits += self.additional_traits
377-
378-
// if self.additional_jvm_args:
379-
// if not meta_version.additional_jvm_args:
380-
// meta_version.additional_jvm_args = []
381-
// meta_version.additional_jvm_args += self.additional_jvm_args
382-
383-
// if legacy:
384-
// # remove all libraries - they are not needed for legacy
385-
// meta_version.libraries = None
386-
// # remove minecraft arguments - we use our own hardcoded ones
387-
// meta_version.minecraft_arguments = None
367+
368+
meta_version.main_class = self.main_class.clone();
369+
meta_version.applet_class = self.applet_class.clone();
370+
371+
// if we have an updated release time (more correct than Mojang), use it
372+
if let Some(release_time) = &self.release_time {
373+
meta_version.release_time = Some(*release_time);
374+
}
375+
376+
// add traits, if any
377+
if let Some(mut additional_traits) = self.additional_traits {
378+
if !meta_version.additional_traits.is_some() {
379+
meta_version.additional_traits = Some(vec![]);
380+
}
381+
meta_version
382+
.additional_traits
383+
.as_mut()
384+
.unwrap()
385+
.append(&mut additional_traits);
386+
}
387+
388+
if let Some(mut additional_jvm_args) = self.additional_jvm_args {
389+
if !meta_version.additional_jvm_args.is_some() {
390+
meta_version.additional_jvm_args = Some(vec![]);
391+
}
392+
meta_version
393+
.additional_jvm_args
394+
.as_mut()
395+
.unwrap()
396+
.append(&mut additional_jvm_args);
397+
}
398+
399+
if legacy {
400+
// remove all libraries - they are not needed for legacy
401+
meta_version.libraries = None;
402+
// remove minecraft arguments - we use our own hardcoded ones
403+
meta_version.minecraft_arguments = None;
404+
}
388405
}
389406
}
390407

@@ -394,14 +411,15 @@ pub struct LegacyOverrideIndex {
394411
}
395412

396413
#[derive(Deserialize, Serialize, Debug, Clone, Validate)]
414+
#[serde(rename_all = "camelCase", deny_unknown_fields)]
397415
pub struct LibraryPatch {
398416
#[serde(rename = "match")]
399417
pub patch_match: Vec<GradleSpecifier>,
400418
#[serde(rename = "override")]
401419
pub patch_override: Option<Library>,
402-
pub additionalLibraries: Option<Vec<Library>>,
420+
pub additional_libraries: Option<Vec<Library>>,
403421
#[serde(default = "default_library_patch_patch_additional_libraries")]
404-
pub patchAdditionalLibraries: bool,
422+
pub patch_additional_libraries: bool,
405423
}
406424

407425
fn default_library_patch_patch_additional_libraries() -> bool {
@@ -435,6 +453,7 @@ impl Deref for LibraryPatches {
435453
pub struct MojangArgumentObject {}
436454

437455
#[derive(Deserialize, Serialize, Debug, Clone, Validate)]
456+
#[serde(untagged)]
438457
pub enum MojangArgument {
439458
String(String),
440459
Object(MojangArgumentObject),
@@ -477,6 +496,8 @@ fn mojang_logging_validate_type(
477496
#[derive(Deserialize, Serialize, Debug, Clone, Validate)]
478497
#[serde(rename_all = "camelCase", deny_unknown_fields)]
479498
pub struct MojangVersion {
499+
#[serde(rename = "_comment_")]
500+
pub comment: Option<Vec<String>>,
480501
pub id: String, // TODO: optional?
481502
pub arguments: Option<MojangArguments>,
482503
pub asset_index: Option<MojangAssets>,
@@ -489,8 +510,10 @@ pub struct MojangVersion {
489510
pub minecraft_arguments: Option<String>,
490511
#[validate(custom(mojang_version_validate_minimum_launcher_version))]
491512
pub minimum_launcher_version: Option<i32>,
492-
pub release_time: Option<String>,
493-
pub time: Option<String>,
513+
#[serde(with = "time::serde::iso8601::option")]
514+
pub release_time: Option<time::OffsetDateTime>,
515+
#[serde(with = "time::serde::iso8601::option")]
516+
pub time: Option<time::OffsetDateTime>,
494517
#[serde(rename = "type")]
495518
pub version_type: Option<String>,
496519
pub inherits_from: Option<String>,
@@ -533,7 +556,7 @@ impl MojangVersion {
533556
let mut main_jar = None;
534557
let mut addn_traits = None;
535558
let mut new_type = self.version_type.clone();
536-
let mut compatible_java_majors = None;
559+
let mut compatible_java_majors;
537560
if !self.id.is_empty() {
538561
let downloads = self.downloads.clone().expect("Missing downloads");
539562
let client_download = downloads

mcmeta/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ edition = "2021"
66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

88
[dependencies]
9-
anyhow = "1.0.70"
9+
anyhow = { version = "1.0.70", features = ["backtrace"] }
1010
argparse = "0.2.2"
1111
axum = "0.6.15"
1212
clap = "4.2.1"
@@ -28,6 +28,7 @@ sha1 = "0.10.5"
2828
sha2 = "0.10.6"
2929
tempdir = "0.3.7"
3030
thiserror = "1.0.40"
31+
time = "0.3.20"
3132
tokio = { version = "1.27.0", features = ["full"] }
3233
tracing = "0.1.37"
3334
tracing-appender = "0.2.2"

mcmeta/src/main.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use axum::{routing::get, Extension, Router};
66
use tracing::{debug, info};
77

88
use anyhow::Result;
9-
use argparse::{ArgumentParser, Store};
9+
use argparse::{ArgumentParser, Store, StoreTrue};
1010
use dotenv::dotenv;
1111
use tracing_subscriber::{filter, prelude::*};
1212

@@ -22,9 +22,8 @@ extern crate lazy_static;
2222

2323
#[tokio::main]
2424
async fn main() -> Result<()> {
25-
dotenv().ok(); // This line loads the environment variables from the ".env" file.
26-
2725
let mut config_path = "".to_string();
26+
let mut use_dotenv = false;
2827
{
2928
// limit scope of argparse borrows
3029
let mut ap = ArgumentParser::new();
@@ -34,9 +33,18 @@ async fn main() -> Result<()> {
3433
Store,
3534
"Path to a json config file.",
3635
);
36+
ap.refer(&mut use_dotenv).add_option(
37+
&["--use-dotenv"],
38+
StoreTrue,
39+
"Load environment variables from a local .env",
40+
);
3741
ap.parse_args_or_exit();
3842
}
3943

44+
if use_dotenv {
45+
dotenv().ok();
46+
}
47+
4048
let config = Arc::new(ServerConfig::from_config(&config_path)?);
4149

4250
let file_appender =

0 commit comments

Comments
 (0)