Fix forever installing (#3135)

* Rough draft for fix for Mojang servers being down causing infinite installation

* Add "pack installed" install step

* Allow repairing an instance from Library to recover pack contents

* Allow repair from instance page

* Deduplicate repair code

* Fix lint

* Fix lint (for real this time)

---------

Co-authored-by: Jai Agrawal <18202329+Geometrically@users.noreply.github.com>
This commit is contained in:
Josiah Glosson
2025-01-11 17:27:47 -06:00
committed by GitHub
parent abd679d716
commit 227386bb0d
14 changed files with 170 additions and 74 deletions

View File

@@ -9,7 +9,7 @@ use crate::pack::install_from::{
};
use crate::state::{
CacheBehaviour, CachedEntry, Credentials, JavaVersion, ProcessMetadata,
ProfileFile, ProjectType, SideType,
ProfileFile, ProfileInstallStage, ProjectType, SideType,
};
use crate::event::{emit::emit_profile, ProfilePayloadType};
@@ -225,7 +225,18 @@ pub async fn list() -> crate::Result<Vec<Profile>> {
#[tracing::instrument]
pub async fn install(path: &str, force: bool) -> crate::Result<()> {
if let Some(profile) = get(path).await? {
crate::launcher::install_minecraft(&profile, None, force).await?;
let result =
crate::launcher::install_minecraft(&profile, None, force).await;
if result.is_err()
&& profile.install_stage != ProfileInstallStage::Installed
{
edit(path, |prof| {
prof.install_stage = ProfileInstallStage::NotInstalled;
async { Ok(()) }
})
.await?;
}
result?;
} else {
return Err(crate::ErrorKind::UnmanagedProfileError(path.to_string())
.as_error());

View File

@@ -111,7 +111,7 @@ async fn replace_managed_modrinth(
ignore_lock: bool,
) -> crate::Result<()> {
crate::profile::edit(profile_path, |profile| {
profile.install_stage = ProfileInstallStage::Installing;
profile.install_stage = ProfileInstallStage::MinecraftInstalling;
async { Ok(()) }
})
.await?;

View File

@@ -7,11 +7,7 @@ use crate::state::{
Credentials, JavaVersion, ProcessMetadata, ProfileInstallStage,
};
use crate::util::io;
use crate::{
process,
state::{self as st},
State,
};
use crate::{process, state as st, State};
use chrono::Utc;
use daedalus as d;
use daedalus::minecraft::{RuleAction, VersionInfo};
@@ -199,7 +195,7 @@ pub async fn install_minecraft(
.await?;
crate::api::profile::edit(&profile.path, |prof| {
prof.install_stage = ProfileInstallStage::Installing;
prof.install_stage = ProfileInstallStage::MinecraftInstalling;
async { Ok(()) }
})
@@ -431,7 +427,7 @@ pub async fn launch_minecraft(
profile: &Profile,
) -> crate::Result<ProcessMetadata> {
if profile.install_stage == ProfileInstallStage::PackInstalling
|| profile.install_stage == ProfileInstallStage::Installing
|| profile.install_stage == ProfileInstallStage::MinecraftInstalling
{
return Err(crate::ErrorKind::LauncherError(
"Profile is still installing".to_string(),

View File

@@ -308,7 +308,7 @@ where
ProfileInstallStage::Installed
}
LegacyProfileInstallStage::Installing => {
ProfileInstallStage::Installing
ProfileInstallStage::MinecraftInstalling
}
LegacyProfileInstallStage::PackInstalling => {
ProfileInstallStage::PackInstalling

View File

@@ -53,7 +53,9 @@ pub enum ProfileInstallStage {
/// Profile is installed
Installed,
/// Profile's minecraft game is still installing
Installing,
MinecraftInstalling,
/// Pack is installed, but Minecraft installation has not begun
PackInstalled,
/// Profile created for pack, but the pack hasn't been fully installed yet
PackInstalling,
/// Profile is not installed
@@ -64,7 +66,8 @@ impl ProfileInstallStage {
pub fn as_str(&self) -> &'static str {
match *self {
Self::Installed => "installed",
Self::Installing => "installing",
Self::MinecraftInstalling => "minecraft_installing",
Self::PackInstalled => "pack_installed",
Self::PackInstalling => "pack_installing",
Self::NotInstalled => "not_installed",
}
@@ -73,7 +76,9 @@ impl ProfileInstallStage {
pub fn from_str(val: &str) -> Self {
match val {
"installed" => Self::Installed,
"installing" => Self::Installing,
"minecraft_installing" => Self::MinecraftInstalling,
"installing" => Self::MinecraftInstalling, // Backwards compatibility
"pack_installed" => Self::PackInstalled,
"pack_installing" => Self::PackInstalling,
"not_installed" => Self::NotInstalled,
_ => Self::NotInstalled,
@@ -549,11 +554,11 @@ impl Profile {
pub(crate) async fn refresh_all() -> crate::Result<()> {
let state = crate::State::get().await?;
let all = Self::get_all(&state.pool).await?;
let mut all = Self::get_all(&state.pool).await?;
let mut keys = vec![];
for profile in &all {
for profile in &mut all {
let path =
crate::api::profile::get_full_path(&profile.path).await?;
@@ -586,6 +591,17 @@ impl Profile {
}
}
}
if profile.install_stage == ProfileInstallStage::MinecraftInstalling
{
profile.install_stage = ProfileInstallStage::PackInstalled;
profile.upsert(&state.pool).await?;
} else if profile.install_stage
== ProfileInstallStage::PackInstalling
{
profile.install_stage = ProfileInstallStage::NotInstalled;
profile.upsert(&state.pool).await?;
}
}
let file_hashes = CachedEntry::get_file_hash_many(