fix: Loader metadata fetching + Fetch metadata when previous attemps in cache failed
This commit is contained in:
parent
7d507067df
commit
cf85f478f0
6 changed files with 146 additions and 73 deletions
|
|
@ -226,7 +226,7 @@ pub(crate) async fn get_loader_version(
|
|||
_ => return Err(CreateClusterError::MissingManifest(loader.to_string()).into()),
|
||||
};
|
||||
|
||||
let loader_meta = loader_meta.to_owned();
|
||||
let loader_meta = loader_meta.to_owned().ok_or(anyhow::anyhow!("couldn't get game versions"))?;
|
||||
|
||||
let loaders = &loader_meta
|
||||
.game_versions
|
||||
|
|
|
|||
|
|
@ -313,7 +313,7 @@ pub async fn get_optimal_java_version(path: &ClusterPath) -> crate::Result<Optio
|
|||
let state = State::get().await?;
|
||||
if let Some(cluster) = get(path, None).await? {
|
||||
let metadata = state.metadata.read().await;
|
||||
let minecraft_metadata = metadata.minecraft.to_owned();
|
||||
let minecraft_metadata = metadata.minecraft.to_owned().ok_or(anyhow::anyhow!("couldn't get minecraft metadata"))?;
|
||||
|
||||
let version = minecraft_metadata
|
||||
.versions
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ pub use interpulse::api::modded::Manifest;
|
|||
#[tracing::instrument]
|
||||
pub async fn get_minecraft_versions() -> crate::Result<VersionManifest> {
|
||||
let state = State::get().await?;
|
||||
let meta = state.metadata.read().await.minecraft.clone();
|
||||
let meta = state.metadata.read().await.minecraft.clone().ok_or(anyhow::anyhow!("couldn't get minecraft metadata"))?;
|
||||
|
||||
Ok(meta)
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ pub async fn get_minecraft_versions() -> crate::Result<VersionManifest> {
|
|||
#[tracing::instrument]
|
||||
pub async fn get_fabric_versions() -> crate::Result<Manifest> {
|
||||
let state = State::get().await?;
|
||||
let meta = state.metadata.read().await.fabric.clone();
|
||||
let meta = state.metadata.read().await.fabric.clone().ok_or(anyhow::anyhow!("couldn't get fabric metadata"))?;
|
||||
|
||||
Ok(meta)
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@ pub async fn get_fabric_versions() -> crate::Result<Manifest> {
|
|||
#[tracing::instrument]
|
||||
pub async fn get_quilt_versions() -> crate::Result<Manifest> {
|
||||
let state = State::get().await?;
|
||||
let meta = state.metadata.read().await.quilt.clone();
|
||||
let meta = state.metadata.read().await.quilt.clone().ok_or(anyhow::anyhow!("couldn't get quilt metadata"))?;
|
||||
|
||||
Ok(meta)
|
||||
}
|
||||
|
|
@ -35,7 +35,7 @@ pub async fn get_quilt_versions() -> crate::Result<Manifest> {
|
|||
#[tracing::instrument]
|
||||
pub async fn get_forge_versions() -> crate::Result<Manifest> {
|
||||
let state = State::get().await?;
|
||||
let meta = state.metadata.read().await.forge.clone();
|
||||
let meta = state.metadata.read().await.forge.clone().ok_or(anyhow::anyhow!("couldn't get forge metadata"))?;
|
||||
|
||||
Ok(meta)
|
||||
}
|
||||
|
|
@ -44,7 +44,7 @@ pub async fn get_forge_versions() -> crate::Result<Manifest> {
|
|||
#[tracing::instrument]
|
||||
pub async fn get_neoforge_versions() -> crate::Result<Manifest> {
|
||||
let state = State::get().await?;
|
||||
let meta = state.metadata.read().await.neoforge.clone();
|
||||
let meta = state.metadata.read().await.neoforge.clone().ok_or(anyhow::anyhow!("couldn't get neoforge metadata"))?;
|
||||
|
||||
Ok(meta)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,9 +72,13 @@ pub async fn install_minecraft(
|
|||
let metadata = state.metadata.read().await;
|
||||
|
||||
let version_manifest = metadata.minecraft.to_owned();
|
||||
let versions = version_manifest
|
||||
.ok_or(anyhow::anyhow!(
|
||||
"couldn't get minecraft manifest"
|
||||
))?
|
||||
.versions;
|
||||
|
||||
let version_idx = version_manifest
|
||||
.versions
|
||||
let version_idx = versions
|
||||
.iter()
|
||||
.position(|g| g.id == cluster.meta.mc_version)
|
||||
.ok_or(anyhow::anyhow!(
|
||||
|
|
@ -82,10 +86,9 @@ pub async fn install_minecraft(
|
|||
cluster.meta.mc_version
|
||||
))?;
|
||||
|
||||
let version = &version_manifest.versions[version_idx];
|
||||
let version = &versions[version_idx];
|
||||
let updated = version_idx
|
||||
<= version_manifest
|
||||
.versions
|
||||
<= versions
|
||||
.iter()
|
||||
.position(|g| g.id == "22w16a")
|
||||
.unwrap_or(0); // LWJGL patching
|
||||
|
|
@ -274,19 +277,21 @@ pub async fn launch_minecraft(
|
|||
let instance_path = &io::canonicalize(instance_path)?;
|
||||
|
||||
let version_manifest = metadata.minecraft.to_owned();
|
||||
let versions = version_manifest
|
||||
.ok_or(anyhow::anyhow!("couldn't get minecraft manifest"))?
|
||||
.versions;
|
||||
|
||||
let version_index = version_manifest
|
||||
.versions
|
||||
let version_index = versions
|
||||
.iter()
|
||||
.position(|it| it.id == cluster.meta.mc_version)
|
||||
.ok_or(anyhow::anyhow!(
|
||||
"invalid game version {}",
|
||||
cluster.meta.mc_version
|
||||
))?;
|
||||
let version = &version_manifest.versions[version_index];
|
||||
|
||||
let version = &versions[version_index];
|
||||
let updated = version_index
|
||||
<= version_manifest
|
||||
.versions
|
||||
<= versions
|
||||
.iter()
|
||||
.position(|x| x.id == "22w16a")
|
||||
.unwrap_or(0);
|
||||
|
|
|
|||
|
|
@ -17,15 +17,15 @@ const METADATA_URL: &str = "https://meta.polyfrost.org";
|
|||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct Metadata {
|
||||
/// The [`MinecraftManifest`] associated with core Minecraft versions.
|
||||
pub minecraft: MinecraftManifest,
|
||||
pub minecraft: Option<MinecraftManifest>,
|
||||
/// The [`ModdedManifest`] associated with core Fabric versions.
|
||||
pub fabric: ModdedManifest,
|
||||
pub fabric: Option<ModdedManifest>,
|
||||
/// The [`ModdedManifest`] associated with core Quilt versions.
|
||||
pub quilt: ModdedManifest,
|
||||
pub quilt: Option<ModdedManifest>,
|
||||
/// The [`ModdedManifest`] associated with core NeoForge versions.
|
||||
pub neoforge: ModdedManifest,
|
||||
pub neoforge: Option<ModdedManifest>,
|
||||
/// The [`ModdedManifest`] associated with core Forge versions.
|
||||
pub forge: ModdedManifest,
|
||||
pub forge: Option<ModdedManifest>,
|
||||
// /// The [`ModdedManifest`] associated with core Legacy Fabric versions.
|
||||
// pub legacy_fabric: Option<ModdedManifest>,
|
||||
}
|
||||
|
|
@ -33,34 +33,65 @@ pub struct Metadata {
|
|||
impl Metadata {
|
||||
/// Get the formatted manifest for a specific [`Metadata`] type.
|
||||
fn get_manifest(name: &str, version: usize) -> String {
|
||||
format!("{METADATA_URL}/{name}/{version}/manifest.json")
|
||||
format!("{METADATA_URL}/{name}/v{version}/manifest.json")
|
||||
}
|
||||
|
||||
/// Fetch all available metadata types that are currently [`None`] and get a new [`Metadata`] structure.
|
||||
/// Useful for when reading from cache and a certain object not existing
|
||||
pub async fn fetch_errored(&mut self, semaphore: &FetchSemaphore) -> crate::Result<bool> {
|
||||
let mut did_change = false;
|
||||
if self.minecraft.is_none() {
|
||||
self.minecraft = Self::fetch_minecraft(semaphore).await;
|
||||
|
||||
if self.minecraft.is_some() {
|
||||
did_change = true;
|
||||
}
|
||||
}
|
||||
|
||||
if self.fabric.is_none() {
|
||||
self.fabric = Self::fetch_fabric(semaphore).await;
|
||||
|
||||
if self.fabric.is_some() {
|
||||
did_change = true;
|
||||
}
|
||||
}
|
||||
|
||||
if self.quilt.is_none() {
|
||||
self.quilt = Self::fetch_quilt(semaphore).await;
|
||||
|
||||
if self.quilt.is_some() {
|
||||
did_change = true;
|
||||
}
|
||||
}
|
||||
|
||||
if self.neoforge.is_none() {
|
||||
self.neoforge = Self::fetch_neoforge(semaphore).await;
|
||||
|
||||
if self.neoforge.is_some() {
|
||||
did_change = true;
|
||||
}
|
||||
}
|
||||
|
||||
if self.forge.is_none() {
|
||||
self.forge = Self::fetch_forge(semaphore).await;
|
||||
|
||||
if self.forge.is_some() {
|
||||
did_change = true;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(did_change)
|
||||
}
|
||||
|
||||
/// Fetch all available metadata types and get a new [`Metadata`] structure.
|
||||
pub async fn fetch() -> crate::Result<Self> {
|
||||
let semaphore = &State::get().await?.fetch_semaphore;
|
||||
let (minecraft, fabric, quilt, neoforge, forge) = tokio::try_join! {
|
||||
async {
|
||||
let url = Self::get_manifest("minecraft", interpulse::api::minecraft::CURRENT_FORMAT_VERSION);
|
||||
fetch_version_manifest(Some(&url), semaphore).await
|
||||
},
|
||||
async {
|
||||
let url = Self::get_manifest("fabric", interpulse::api::modded::CURRENT_FABRIC_FORMAT_VERSION);
|
||||
fetch_modded_manifest(&url, semaphore).await
|
||||
},
|
||||
async {
|
||||
let url = Self::get_manifest("quilt", interpulse::api::modded::CURRENT_QUILT_FORMAT_VERSION);
|
||||
fetch_modded_manifest(&url, semaphore).await
|
||||
},
|
||||
async {
|
||||
let url = Self::get_manifest("neo", interpulse::api::modded::CURRENT_NEOFORGE_FORMAT_VERSION);
|
||||
fetch_modded_manifest(&url, semaphore).await
|
||||
},
|
||||
async {
|
||||
let url = Self::get_manifest("forge", interpulse::api::modded::CURRENT_FORGE_FORMAT_VERSION);
|
||||
fetch_modded_manifest(&url, semaphore).await
|
||||
},
|
||||
}?;
|
||||
pub async fn fetch(semaphore: &FetchSemaphore) -> crate::Result<Self> {
|
||||
let (minecraft, fabric, quilt, neoforge, forge) = tokio::join! {
|
||||
Self::fetch_minecraft(semaphore),
|
||||
Self::fetch_fabric(semaphore),
|
||||
Self::fetch_quilt(semaphore),
|
||||
Self::fetch_neoforge(semaphore),
|
||||
Self::fetch_forge(semaphore)
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
minecraft,
|
||||
|
|
@ -71,36 +102,53 @@ impl Metadata {
|
|||
})
|
||||
}
|
||||
|
||||
async fn fetch_minecraft(semaphore: &FetchSemaphore) -> Option<MinecraftManifest> {
|
||||
let url = Self::get_manifest("minecraft", interpulse::api::minecraft::CURRENT_FORMAT_VERSION);
|
||||
fetch_version_manifest(Some(&url), semaphore).await.ok()
|
||||
}
|
||||
|
||||
async fn fetch_fabric(semaphore: &FetchSemaphore) -> Option<ModdedManifest> {
|
||||
let url = Self::get_manifest("fabric", interpulse::api::modded::CURRENT_FABRIC_FORMAT_VERSION);
|
||||
fetch_modded_manifest(&url, semaphore).await.ok()
|
||||
}
|
||||
|
||||
async fn fetch_quilt(semaphore: &FetchSemaphore) -> Option<ModdedManifest> {
|
||||
let url = Self::get_manifest("quilt", interpulse::api::modded::CURRENT_QUILT_FORMAT_VERSION);
|
||||
fetch_modded_manifest(&url, semaphore).await.ok()
|
||||
}
|
||||
|
||||
async fn fetch_neoforge(semaphore: &FetchSemaphore) -> Option<ModdedManifest> {
|
||||
let url = Self::get_manifest("neoforge", interpulse::api::modded::CURRENT_NEOFORGE_FORMAT_VERSION);
|
||||
fetch_modded_manifest(&url, semaphore).await.ok()
|
||||
}
|
||||
|
||||
async fn fetch_forge(semaphore: &FetchSemaphore) -> Option<ModdedManifest> {
|
||||
let url = Self::get_manifest("forge", interpulse::api::modded::CURRENT_FORGE_FORMAT_VERSION);
|
||||
fetch_modded_manifest(&url, semaphore).await.ok()
|
||||
}
|
||||
|
||||
/// Initialize the core Metadata manager.
|
||||
#[tracing::instrument(skip(io_semaphore))]
|
||||
#[tracing::instrument(skip(io_semaphore, fetch_semaphore))]
|
||||
#[onelauncher_debug::debugger]
|
||||
pub async fn initialize(
|
||||
dirs: &Directories,
|
||||
online: bool,
|
||||
io_semaphore: &IoSemaphore,
|
||||
fetch_semaphore: &FetchSemaphore,
|
||||
) -> crate::Result<Self> {
|
||||
let mut metadata = None;
|
||||
let path = dirs.caches_dir().await.join("metadata.json");
|
||||
let backup = dirs.caches_dir().await.join("metadata.json.bak");
|
||||
let mut should_write = false;
|
||||
|
||||
if let Ok(mut metadata_json) = read_json::<Metadata>(&path, io_semaphore).await {
|
||||
should_write = metadata_json.fetch_errored(fetch_semaphore).await?;
|
||||
|
||||
if let Ok(metadata_json) = read_json::<Metadata>(&path, io_semaphore).await {
|
||||
metadata = Some(metadata_json);
|
||||
} else if online {
|
||||
let res = async {
|
||||
let fetch_data = Self::fetch().await?;
|
||||
|
||||
write(
|
||||
&path,
|
||||
&serde_json::to_vec(&fetch_data).unwrap_or_default(),
|
||||
io_semaphore,
|
||||
)
|
||||
.await?;
|
||||
write(
|
||||
&backup,
|
||||
&serde_json::to_vec(&fetch_data).unwrap_or_default(),
|
||||
io_semaphore,
|
||||
)
|
||||
.await?;
|
||||
let fetch_data = Self::fetch(fetch_semaphore).await?;
|
||||
should_write = true;
|
||||
|
||||
metadata = Some(fetch_data);
|
||||
Ok::<(), crate::Error>(())
|
||||
|
|
@ -118,6 +166,19 @@ impl Metadata {
|
|||
copy(&backup, &path).await?;
|
||||
}
|
||||
|
||||
if should_write {
|
||||
write(
|
||||
&path,
|
||||
&serde_json::to_vec(&metadata).unwrap_or_default(),
|
||||
io_semaphore,
|
||||
).await?;
|
||||
write(
|
||||
&backup,
|
||||
&serde_json::to_vec(&metadata).unwrap_or_default(),
|
||||
io_semaphore,
|
||||
).await?;
|
||||
}
|
||||
|
||||
if let Some(meta) = metadata {
|
||||
Ok(meta)
|
||||
} else {
|
||||
|
|
@ -128,8 +189,8 @@ impl Metadata {
|
|||
/// Update and backup all available metadata.
|
||||
pub async fn update() {
|
||||
let res = async {
|
||||
let fetch_data = Metadata::fetch().await?;
|
||||
let state = State::get().await?;
|
||||
let state = State::get().await?;
|
||||
let fetch_data = Metadata::fetch(&state.fetch_semaphore).await?;
|
||||
|
||||
let path = state.directories.caches_dir().await.join("metadata.json");
|
||||
let backup = state
|
||||
|
|
@ -169,13 +230,13 @@ async fn fetch_version_manifest(
|
|||
url: Option<&str>,
|
||||
semaphore: &FetchSemaphore,
|
||||
) -> crate::Result<MinecraftManifest> {
|
||||
let url = url.unwrap_or(interpulse::api::minecraft::VERSION_MANIFEST_URL);
|
||||
Ok(serde_json::from_slice(
|
||||
&fetch(
|
||||
url.unwrap_or(interpulse::api::minecraft::VERSION_MANIFEST_URL),
|
||||
None,
|
||||
semaphore,
|
||||
)
|
||||
.await?,
|
||||
&fetch(url, None, semaphore).await
|
||||
.map_err(|err| {
|
||||
tracing::error!("couldn't fetch version manifest at '{}'", url);
|
||||
err
|
||||
})?,
|
||||
)?)
|
||||
}
|
||||
|
||||
|
|
@ -183,5 +244,11 @@ async fn fetch_modded_manifest(
|
|||
url: &str,
|
||||
semaphore: &FetchSemaphore,
|
||||
) -> crate::Result<ModdedManifest> {
|
||||
Ok(serde_json::from_slice(&fetch(url, None, semaphore).await?)?)
|
||||
Ok(serde_json::from_slice(
|
||||
&fetch(url, None, semaphore).await
|
||||
.map_err(|err| {
|
||||
tracing::error!("couldn't fetch modded manifest at '{}'", url);
|
||||
err
|
||||
})?
|
||||
)?)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,7 +131,8 @@ impl State {
|
|||
|
||||
let is_offline = !http::check_internet_connection(3).await;
|
||||
|
||||
let metadata_in = Metadata::initialize(&directories, !is_offline, &io_semaphore);
|
||||
// TODO: Make this run in the background, this delays launcher startup by a couple seconds
|
||||
let metadata_in = Metadata::initialize(&directories, !is_offline, &io_semaphore, &fetch_semaphore);
|
||||
let clusters_in = Clusters::initialize(&directories, &mut watcher);
|
||||
let users_in = MinecraftState::initialize(&directories, &io_semaphore);
|
||||
let (metadata, clusters, users) = crate::ingress_join! {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue