You've already forked AstralRinth
forked from didirus/AstralRinth
Migrate to SQLite for Internal Launcher Data (#1300)
* initial migration * barebones profiles * Finish profiles * Add back file watcher * UI support progress * Finish most of cache * Fix options page * Fix forge, finish modrinth auth * Accounts, process cache * Run SQLX prepare * Finish * Run lint + actions * Fix version to be compat with windows * fix lint * actually fix lint * actually fix lint again
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
use crate::config::MODRINTH_API_URL;
|
||||
use crate::event::emit::{
|
||||
emit_loading, init_or_edit_loading, loading_try_for_each_concurrent,
|
||||
};
|
||||
@@ -6,16 +5,14 @@ use crate::event::LoadingBarType;
|
||||
use crate::pack::install_from::{
|
||||
set_profile_information, EnvType, PackFile, PackFileHash,
|
||||
};
|
||||
use crate::prelude::{ModrinthVersion, ProfilePathId, ProjectMetadata};
|
||||
use crate::state::{ProfileInstallStage, Profiles, SideType};
|
||||
use crate::util::fetch::{fetch_json, fetch_mirrors, write};
|
||||
use crate::state::{
|
||||
cache_file_hash, CacheBehaviour, CachedEntry, ProfileInstallStage, SideType,
|
||||
};
|
||||
use crate::util::fetch::{fetch_mirrors, write};
|
||||
use crate::util::io;
|
||||
use crate::{profile, State};
|
||||
use async_zip::base::read::seek::ZipFileReader;
|
||||
use reqwest::Method;
|
||||
use serde_json::json;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::io::Cursor;
|
||||
use std::path::{Component, PathBuf};
|
||||
|
||||
@@ -28,11 +25,11 @@ use super::install_from::{
|
||||
/// Wrapper around install_pack_files that generates a pack creation description, and
|
||||
/// attempts to install the pack files. If it fails, it will remove the profile (fail safely)
|
||||
/// Install a modpack from a mrpack file (a modrinth .zip format)
|
||||
#[theseus_macros::debug_pin]
|
||||
|
||||
pub async fn install_zipped_mrpack(
|
||||
location: CreatePackLocation,
|
||||
profile_path: ProfilePathId,
|
||||
) -> crate::Result<ProfilePathId> {
|
||||
profile_path: String,
|
||||
) -> crate::Result<String> {
|
||||
// Get file from description
|
||||
let create_pack: CreatePack = match location {
|
||||
CreatePackLocation::FromVersionId {
|
||||
@@ -59,9 +56,6 @@ pub async fn install_zipped_mrpack(
|
||||
// Install pack files, and if it fails, fail safely by removing the profile
|
||||
let result = install_zipped_mrpack_files(create_pack, false).await;
|
||||
|
||||
// Check existing managed packs for potential updates
|
||||
tokio::task::spawn(Profiles::update_modrinth_versions());
|
||||
|
||||
match result {
|
||||
Ok(profile) => Ok(profile),
|
||||
Err(err) => {
|
||||
@@ -74,11 +68,11 @@ pub async fn install_zipped_mrpack(
|
||||
|
||||
/// Install all pack files from a description
|
||||
/// Does not remove the profile if it fails
|
||||
#[theseus_macros::debug_pin]
|
||||
|
||||
pub async fn install_zipped_mrpack_files(
|
||||
create_pack: CreatePack,
|
||||
ignore_lock: bool,
|
||||
) -> crate::Result<ProfilePathId> {
|
||||
) -> crate::Result<String> {
|
||||
let state = &State::get().await?;
|
||||
|
||||
let file = create_pack.file;
|
||||
@@ -132,7 +126,7 @@ pub async fn install_zipped_mrpack_files(
|
||||
let loading_bar = init_or_edit_loading(
|
||||
existing_loading_bar,
|
||||
LoadingBarType::PackDownload {
|
||||
profile_path: profile_path.get_full_path().await?.clone(),
|
||||
profile_path: profile_path.clone(),
|
||||
pack_name: pack.name.clone(),
|
||||
icon,
|
||||
pack_id: project_id,
|
||||
@@ -167,7 +161,6 @@ pub async fn install_zipped_mrpack_files(
|
||||
}
|
||||
}
|
||||
|
||||
let creds = state.credentials.read().await;
|
||||
let file = fetch_mirrors(
|
||||
&project
|
||||
.downloads
|
||||
@@ -176,10 +169,9 @@ pub async fn install_zipped_mrpack_files(
|
||||
.collect::<Vec<&str>>(),
|
||||
project.hashes.get(&PackFileHash::Sha1).map(|x| &**x),
|
||||
&state.fetch_semaphore,
|
||||
&creds,
|
||||
&state.pool,
|
||||
)
|
||||
.await?;
|
||||
drop(creds);
|
||||
|
||||
let project_path = project.path.to_string();
|
||||
|
||||
@@ -188,10 +180,23 @@ pub async fn install_zipped_mrpack_files(
|
||||
if let Some(path) = path {
|
||||
match path {
|
||||
Component::CurDir | Component::Normal(_) => {
|
||||
let path = profile_path
|
||||
.get_full_path()
|
||||
.await?
|
||||
.join(&project_path);
|
||||
let path =
|
||||
profile::get_full_path(&profile_path)
|
||||
.await?
|
||||
.join(&project_path);
|
||||
|
||||
cache_file_hash(
|
||||
file.clone(),
|
||||
&profile_path,
|
||||
&project_path,
|
||||
project
|
||||
.hashes
|
||||
.get(&PackFileHash::Sha1)
|
||||
.map(|x| &**x),
|
||||
&state.pool,
|
||||
)
|
||||
.await?;
|
||||
|
||||
write(&path, &file, &state.io_semaphore)
|
||||
.await?;
|
||||
}
|
||||
@@ -243,9 +248,22 @@ pub async fn install_zipped_mrpack_files(
|
||||
}
|
||||
|
||||
if new_path.file_name().is_some() {
|
||||
let bytes = bytes::Bytes::from(content);
|
||||
|
||||
cache_file_hash(
|
||||
bytes.clone(),
|
||||
&profile_path,
|
||||
&new_path.to_string_lossy(),
|
||||
None,
|
||||
&state.pool,
|
||||
)
|
||||
.await?;
|
||||
|
||||
write(
|
||||
&profile_path.get_full_path().await?.join(new_path),
|
||||
&content,
|
||||
&profile::get_full_path(&profile_path)
|
||||
.await?
|
||||
.join(new_path),
|
||||
&bytes,
|
||||
&state.io_semaphore,
|
||||
)
|
||||
.await?;
|
||||
@@ -265,24 +283,23 @@ pub async fn install_zipped_mrpack_files(
|
||||
|
||||
// If the icon doesn't exist, we expect icon.png to be a potential icon.
|
||||
// If it doesn't exist, and an override to icon.png exists, cache and use that
|
||||
let potential_icon =
|
||||
profile_path.get_full_path().await?.join("icon.png");
|
||||
let potential_icon = profile::get_full_path(&profile_path)
|
||||
.await?
|
||||
.join("icon.png");
|
||||
if !icon_exists && potential_icon.exists() {
|
||||
profile::edit_icon(&profile_path, Some(&potential_icon)).await?;
|
||||
}
|
||||
|
||||
if let Some(profile_val) = profile::get(&profile_path, None).await? {
|
||||
if let Some(profile_val) = profile::get(&profile_path).await? {
|
||||
crate::launcher::install_minecraft(
|
||||
&profile_val,
|
||||
Some(loading_bar),
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
|
||||
State::sync().await?;
|
||||
}
|
||||
|
||||
Ok::<ProfilePathId, crate::Error>(profile_path.clone())
|
||||
Ok::<String, crate::Error>(profile_path.clone())
|
||||
} else {
|
||||
Err(crate::Error::from(crate::ErrorKind::InputError(
|
||||
"No pack manifest found in mrpack".to_string(),
|
||||
@@ -291,9 +308,9 @@ pub async fn install_zipped_mrpack_files(
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(mrpack_file))]
|
||||
#[theseus_macros::debug_pin]
|
||||
|
||||
pub async fn remove_all_related_files(
|
||||
profile_path: ProfilePathId,
|
||||
profile_path: String,
|
||||
mrpack_file: bytes::Bytes,
|
||||
) -> crate::Result<()> {
|
||||
let reader: Cursor<&bytes::Bytes> = Cursor::new(&mrpack_file);
|
||||
@@ -339,43 +356,39 @@ pub async fn remove_all_related_files(
|
||||
let all_hashes = pack
|
||||
.files
|
||||
.iter()
|
||||
.filter_map(|f| Some(f.hashes.get(&PackFileHash::Sha512)?.clone()))
|
||||
.filter_map(|f| Some(f.hashes.get(&PackFileHash::Sha1)?.clone()))
|
||||
.collect::<Vec<_>>();
|
||||
let creds = state.credentials.read().await;
|
||||
|
||||
// First, get project info by hash
|
||||
let files_url = format!("{}version_files", MODRINTH_API_URL);
|
||||
|
||||
let hash_projects = fetch_json::<HashMap<String, ModrinthVersion>>(
|
||||
Method::POST,
|
||||
&files_url,
|
||||
let file_infos = CachedEntry::get_file_many(
|
||||
&all_hashes.iter().map(|x| &**x).collect::<Vec<_>>(),
|
||||
None,
|
||||
Some(json!({
|
||||
"hashes": all_hashes,
|
||||
"algorithm": "sha512",
|
||||
})),
|
||||
&state.fetch_semaphore,
|
||||
&creds,
|
||||
&state.pool,
|
||||
&state.api_semaphore,
|
||||
)
|
||||
.await?;
|
||||
let to_remove = hash_projects
|
||||
.into_values()
|
||||
|
||||
let to_remove = file_infos
|
||||
.into_iter()
|
||||
.map(|p| p.project_id)
|
||||
.collect::<Vec<_>>();
|
||||
let profile =
|
||||
profile::get(&profile_path, None).await?.ok_or_else(|| {
|
||||
crate::ErrorKind::UnmanagedProfileError(
|
||||
profile_path.to_string(),
|
||||
)
|
||||
})?;
|
||||
for (project_id, project) in &profile.projects {
|
||||
if let ProjectMetadata::Modrinth { project, .. } = &project.metadata
|
||||
{
|
||||
if to_remove.contains(&project.id) {
|
||||
let path = profile
|
||||
.get_profile_full_path()
|
||||
.await?
|
||||
.join(project_id.0.clone());
|
||||
|
||||
let profile = profile::get(&profile_path).await?.ok_or_else(|| {
|
||||
crate::ErrorKind::UnmanagedProfileError(profile_path.to_string())
|
||||
})?;
|
||||
let profile_full_path = profile::get_full_path(&profile_path).await?;
|
||||
|
||||
for (file_path, project) in profile
|
||||
.get_projects(
|
||||
Some(CacheBehaviour::MustRevalidate),
|
||||
&state.pool,
|
||||
&state.api_semaphore,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
if let Some(metadata) = &project.metadata {
|
||||
if to_remove.contains(&metadata.project_id) {
|
||||
let path = profile_full_path.join(file_path);
|
||||
if path.exists() {
|
||||
io::remove_file(&path).await?;
|
||||
}
|
||||
@@ -386,10 +399,7 @@ pub async fn remove_all_related_files(
|
||||
// Iterate over all Modrinth project file paths in the json, and remove them
|
||||
// (There should be few, but this removes any files the .mrpack intended as Modrinth projects but were unrecognized)
|
||||
for file in pack.files {
|
||||
let path: PathBuf = profile_path
|
||||
.get_full_path()
|
||||
.await?
|
||||
.join(file.path.to_string());
|
||||
let path: PathBuf = profile_full_path.join(file.path);
|
||||
if path.exists() {
|
||||
io::remove_file(&path).await?;
|
||||
}
|
||||
@@ -414,8 +424,9 @@ pub async fn remove_all_related_files(
|
||||
}
|
||||
|
||||
// Remove this file if a corresponding one exists in the filesystem
|
||||
let existing_file =
|
||||
profile_path.get_full_path().await?.join(&new_path);
|
||||
let existing_file = profile::get_full_path(&profile_path)
|
||||
.await?
|
||||
.join(&new_path);
|
||||
if existing_file.exists() {
|
||||
io::remove_file(&existing_file).await?;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user