You've already forked AstralRinth
forked from didirus/AstralRinth
Refactor Library
The launcher code was in a position ripe for sphagetti, so this rewrites it in a more robust way. In addition to cleaner code, this provides the following changes: - Removal of obsolete Mojang authentication - The rebasing of some internal state into a Sled database - Tweaks which make some internal mechanisms more robust (e.g. profiles which fail to load can be removed) - Additional tooling integration such as direnv - Distinct public API to avoid messing with too much internal code - Unified error handling in the form of `theseus::Error` and `theseus::Result`
This commit is contained in:
90
theseus/src/state/metadata.rs
Normal file
90
theseus/src/state/metadata.rs
Normal file
@@ -0,0 +1,90 @@
|
||||
//! Theseus metadata
|
||||
use crate::config::BINCODE_CONFIG;
|
||||
use bincode::{Decode, Encode};
|
||||
use daedalus::{
|
||||
minecraft::{fetch_version_manifest, VersionManifest as MinecraftManifest},
|
||||
modded::{
|
||||
fetch_manifest as fetch_loader_manifest, Manifest as LoaderManifest,
|
||||
},
|
||||
};
|
||||
use futures::prelude::*;
|
||||
use std::collections::LinkedList;
|
||||
|
||||
const METADATA_URL: &str = "https://meta.modrinth.com/gamedata";
|
||||
const METADATA_DB_FIELD: &[u8] = b"metadata";
|
||||
|
||||
#[derive(Encode, Decode, Debug)]
|
||||
pub struct Metadata {
|
||||
pub minecraft: MinecraftManifest,
|
||||
pub forge: LoaderManifest,
|
||||
pub fabric: LoaderManifest,
|
||||
}
|
||||
|
||||
impl Metadata {
|
||||
fn get_manifest(name: &str) -> String {
|
||||
format!("{METADATA_URL}/{name}/v0/manifest.json")
|
||||
}
|
||||
|
||||
async fn fetch() -> crate::Result<Self> {
|
||||
let (minecraft, forge, fabric) = tokio::try_join! {
|
||||
async {
|
||||
let url = Self::get_manifest("minecraft");
|
||||
fetch_version_manifest(Some(&url)).await
|
||||
},
|
||||
async {
|
||||
let url = Self::get_manifest("forge");
|
||||
fetch_loader_manifest(&url).await
|
||||
},
|
||||
async {
|
||||
let url = Self::get_manifest("fabric");
|
||||
fetch_loader_manifest(&url).await
|
||||
}
|
||||
}?;
|
||||
|
||||
Ok(Self {
|
||||
minecraft,
|
||||
forge,
|
||||
fabric,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn init(db: &sled::Db) -> crate::Result<Self> {
|
||||
let mut metadata = None;
|
||||
|
||||
if let Some(ref meta_bin) = db.get(METADATA_DB_FIELD)? {
|
||||
match bincode::decode_from_slice::<Self, _>(
|
||||
&meta_bin,
|
||||
*BINCODE_CONFIG,
|
||||
) {
|
||||
Ok((meta, _)) => metadata = Some(meta),
|
||||
Err(err) => {
|
||||
log::warn!("Could not read launcher metadata: {err}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut fetch_futures = LinkedList::new();
|
||||
for _ in 0..3 {
|
||||
fetch_futures.push_back(Self::fetch().boxed());
|
||||
}
|
||||
|
||||
match future::select_ok(fetch_futures).await {
|
||||
Ok(meta) => metadata = Some(meta.0),
|
||||
Err(err) => log::warn!("Unable to fetch launcher metadata: {err}"),
|
||||
}
|
||||
|
||||
if let Some(meta) = metadata {
|
||||
db.insert(
|
||||
METADATA_DB_FIELD,
|
||||
sled::IVec::from(bincode::encode_to_vec(
|
||||
&meta,
|
||||
*BINCODE_CONFIG,
|
||||
)?),
|
||||
)?;
|
||||
db.flush_async().await?;
|
||||
Ok(meta)
|
||||
} else {
|
||||
Err(crate::Error::NoValueFor(String::from("launcher metadata")))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user