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:
Danielle
2022-06-27 15:53:25 -07:00
committed by GitHub
parent 179dcdcd04
commit 10610e157f
37 changed files with 2730 additions and 4117 deletions

View 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")))
}
}
}