Make the update checker work for non-mods (#3088)
* Fix https://github.com/modrinth/code/issues/1057 * Make sure mods use the installed loader * Switch &PathBuf to &Path * Clippy fix * Deduplicate some code --------- Co-authored-by: Jai Agrawal <18202329+Geometrically@users.noreply.github.com>
This commit is contained in:
parent
8b7547ae38
commit
01fe08f079
@ -13,13 +13,13 @@ use crate::util::io;
|
|||||||
use crate::{profile, State};
|
use crate::{profile, State};
|
||||||
use async_zip::base::read::seek::ZipFileReader;
|
use async_zip::base::read::seek::ZipFileReader;
|
||||||
|
|
||||||
use std::io::Cursor;
|
|
||||||
use std::path::{Component, PathBuf};
|
|
||||||
|
|
||||||
use super::install_from::{
|
use super::install_from::{
|
||||||
generate_pack_from_file, generate_pack_from_version_id, CreatePack,
|
generate_pack_from_file, generate_pack_from_version_id, CreatePack,
|
||||||
CreatePackLocation, PackFormat,
|
CreatePackLocation, PackFormat,
|
||||||
};
|
};
|
||||||
|
use crate::data::ProjectType;
|
||||||
|
use std::io::Cursor;
|
||||||
|
use std::path::{Component, PathBuf};
|
||||||
|
|
||||||
/// Install a pack
|
/// Install a pack
|
||||||
/// Wrapper around install_pack_files that generates a pack creation description, and
|
/// Wrapper around install_pack_files that generates a pack creation description, and
|
||||||
@ -189,6 +189,7 @@ pub async fn install_zipped_mrpack_files(
|
|||||||
.hashes
|
.hashes
|
||||||
.get(&PackFileHash::Sha1)
|
.get(&PackFileHash::Sha1)
|
||||||
.map(|x| &**x),
|
.map(|x| &**x),
|
||||||
|
ProjectType::get_from_parent_folder(&path),
|
||||||
&state.pool,
|
&state.pool,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
@ -247,6 +248,7 @@ pub async fn install_zipped_mrpack_files(
|
|||||||
&profile_path,
|
&profile_path,
|
||||||
&new_path.to_string_lossy(),
|
&new_path.to_string_lossy(),
|
||||||
None,
|
None,
|
||||||
|
ProjectType::get_from_parent_folder(&new_path),
|
||||||
&state.pool,
|
&state.pool,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use crate::config::{META_URL, MODRINTH_API_URL, MODRINTH_API_URL_V3};
|
use crate::config::{META_URL, MODRINTH_API_URL, MODRINTH_API_URL_V3};
|
||||||
|
use crate::state::ProjectType;
|
||||||
use crate::util::fetch::{fetch_json, sha1_async, FetchSemaphore};
|
use crate::util::fetch::{fetch_json, sha1_async, FetchSemaphore};
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use dashmap::DashSet;
|
use dashmap::DashSet;
|
||||||
@ -194,7 +195,7 @@ pub struct SearchEntry {
|
|||||||
pub struct CachedFileUpdate {
|
pub struct CachedFileUpdate {
|
||||||
pub hash: String,
|
pub hash: String,
|
||||||
pub game_version: String,
|
pub game_version: String,
|
||||||
pub loader: String,
|
pub loaders: Vec<String>,
|
||||||
pub update_version_id: String,
|
pub update_version_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,6 +204,7 @@ pub struct CachedFileHash {
|
|||||||
pub path: String,
|
pub path: String,
|
||||||
pub size: u64,
|
pub size: u64,
|
||||||
pub hash: String,
|
pub hash: String,
|
||||||
|
pub project_type: Option<ProjectType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
@ -481,7 +483,12 @@ impl CacheValue {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
CacheValue::FileUpdate(hash) => {
|
CacheValue::FileUpdate(hash) => {
|
||||||
format!("{}-{}-{}", hash.hash, hash.loader, hash.game_version)
|
format!(
|
||||||
|
"{}-{}-{}",
|
||||||
|
hash.hash,
|
||||||
|
hash.loaders.join("+"),
|
||||||
|
hash.game_version
|
||||||
|
)
|
||||||
}
|
}
|
||||||
CacheValue::SearchResults(search) => search.search.clone(),
|
CacheValue::SearchResults(search) => search.search.clone(),
|
||||||
}
|
}
|
||||||
@ -1240,6 +1247,9 @@ impl CachedEntry {
|
|||||||
path: path.to_string(),
|
path: path.to_string(),
|
||||||
size,
|
size,
|
||||||
hash,
|
hash,
|
||||||
|
project_type: ProjectType::get_from_parent_folder(
|
||||||
|
&full_path,
|
||||||
|
),
|
||||||
})
|
})
|
||||||
.get_entry(),
|
.get_entry(),
|
||||||
true,
|
true,
|
||||||
@ -1270,18 +1280,21 @@ impl CachedEntry {
|
|||||||
|
|
||||||
if key.len() == 3 {
|
if key.len() == 3 {
|
||||||
let hash = key[0];
|
let hash = key[0];
|
||||||
let loader = key[1];
|
let loaders_key = key[1];
|
||||||
let game_version = key[2];
|
let game_version = key[2];
|
||||||
|
|
||||||
if let Some(values) =
|
if let Some(values) =
|
||||||
filtered_keys.iter_mut().find(|x| {
|
filtered_keys.iter_mut().find(|x| {
|
||||||
x.0 .0 == loader && x.0 .1 == game_version
|
x.0 .0 == loaders_key && x.0 .1 == game_version
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
values.1.push(hash.to_string());
|
values.1.push(hash.to_string());
|
||||||
} else {
|
} else {
|
||||||
filtered_keys.push((
|
filtered_keys.push((
|
||||||
(loader.to_string(), game_version.to_string()),
|
(
|
||||||
|
loaders_key.to_string(),
|
||||||
|
game_version.to_string(),
|
||||||
|
),
|
||||||
vec![hash.to_string()],
|
vec![hash.to_string()],
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -1297,7 +1310,7 @@ impl CachedEntry {
|
|||||||
format!("{}version_files/update", MODRINTH_API_URL);
|
format!("{}version_files/update", MODRINTH_API_URL);
|
||||||
let variations =
|
let variations =
|
||||||
futures::future::try_join_all(filtered_keys.iter().map(
|
futures::future::try_join_all(filtered_keys.iter().map(
|
||||||
|((loader, game_version), hashes)| {
|
|((loaders_key, game_version), hashes)| {
|
||||||
fetch_json::<HashMap<String, Version>>(
|
fetch_json::<HashMap<String, Version>>(
|
||||||
Method::POST,
|
Method::POST,
|
||||||
&version_update_url,
|
&version_update_url,
|
||||||
@ -1305,7 +1318,7 @@ impl CachedEntry {
|
|||||||
Some(serde_json::json!({
|
Some(serde_json::json!({
|
||||||
"algorithm": "sha1",
|
"algorithm": "sha1",
|
||||||
"hashes": hashes,
|
"hashes": hashes,
|
||||||
"loaders": [loader],
|
"loaders": loaders_key.split('+').collect::<Vec<_>>(),
|
||||||
"game_versions": [game_version]
|
"game_versions": [game_version]
|
||||||
})),
|
})),
|
||||||
fetch_semaphore,
|
fetch_semaphore,
|
||||||
@ -1317,7 +1330,7 @@ impl CachedEntry {
|
|||||||
|
|
||||||
for (index, mut variation) in variations.into_iter().enumerate()
|
for (index, mut variation) in variations.into_iter().enumerate()
|
||||||
{
|
{
|
||||||
let ((loader, game_version), hashes) =
|
let ((loaders_key, game_version), hashes) =
|
||||||
&filtered_keys[index];
|
&filtered_keys[index];
|
||||||
|
|
||||||
for hash in hashes {
|
for hash in hashes {
|
||||||
@ -1334,7 +1347,10 @@ impl CachedEntry {
|
|||||||
CacheValue::FileUpdate(CachedFileUpdate {
|
CacheValue::FileUpdate(CachedFileUpdate {
|
||||||
hash: hash.clone(),
|
hash: hash.clone(),
|
||||||
game_version: game_version.clone(),
|
game_version: game_version.clone(),
|
||||||
loader: loader.clone(),
|
loaders: loaders_key
|
||||||
|
.split('+')
|
||||||
|
.map(|x| x.to_string())
|
||||||
|
.collect(),
|
||||||
update_version_id: version_id,
|
update_version_id: version_id,
|
||||||
})
|
})
|
||||||
.get_entry(),
|
.get_entry(),
|
||||||
@ -1343,7 +1359,9 @@ impl CachedEntry {
|
|||||||
} else {
|
} else {
|
||||||
vals.push((
|
vals.push((
|
||||||
CacheValueType::FileUpdate.get_empty_entry(
|
CacheValueType::FileUpdate.get_empty_entry(
|
||||||
format!("{hash}-{loader}-{game_version}"),
|
format!(
|
||||||
|
"{hash}-{loaders_key}-{game_version}"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
true,
|
true,
|
||||||
))
|
))
|
||||||
@ -1450,6 +1468,7 @@ pub async fn cache_file_hash(
|
|||||||
profile_path: &str,
|
profile_path: &str,
|
||||||
path: &str,
|
path: &str,
|
||||||
known_hash: Option<&str>,
|
known_hash: Option<&str>,
|
||||||
|
project_type: Option<ProjectType>,
|
||||||
exec: impl sqlx::Executor<'_, Database = sqlx::Sqlite>,
|
exec: impl sqlx::Executor<'_, Database = sqlx::Sqlite>,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
let size = bytes.len();
|
let size = bytes.len();
|
||||||
@ -1465,6 +1484,7 @@ pub async fn cache_file_hash(
|
|||||||
path: format!("{}/{}", profile_path, path),
|
path: format!("{}/{}", profile_path, path),
|
||||||
size: size as u64,
|
size: size as u64,
|
||||||
hash,
|
hash,
|
||||||
|
project_type,
|
||||||
})
|
})
|
||||||
.get_entry()],
|
.get_entry()],
|
||||||
exec,
|
exec,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use crate::data::{Dependency, User, Version};
|
use crate::data::{Dependency, ProjectType, User, Version};
|
||||||
use crate::jre::check_jre;
|
use crate::jre::check_jre;
|
||||||
use crate::prelude::ModLoader;
|
use crate::prelude::ModLoader;
|
||||||
use crate::state;
|
use crate::state;
|
||||||
@ -226,6 +226,7 @@ where
|
|||||||
path: file_name,
|
path: file_name,
|
||||||
size: metadata.len(),
|
size: metadata.len(),
|
||||||
hash: sha1.clone(),
|
hash: sha1.clone(),
|
||||||
|
project_type: ProjectType::get_from_parent_folder(&full_path),
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -249,9 +250,9 @@ where
|
|||||||
.metadata
|
.metadata
|
||||||
.game_version
|
.game_version
|
||||||
.clone(),
|
.clone(),
|
||||||
loader: mod_loader
|
loaders: vec![mod_loader
|
||||||
.as_str()
|
.as_str()
|
||||||
.to_string(),
|
.to_string()],
|
||||||
update_version_id:
|
update_version_id:
|
||||||
update_version.id.clone(),
|
update_version.id.clone(),
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
use super::settings::{Hooks, MemorySettings, WindowSize};
|
use super::settings::{Hooks, MemorySettings, WindowSize};
|
||||||
use crate::state::{cache_file_hash, CacheBehaviour, CachedEntry};
|
use crate::state::{
|
||||||
|
cache_file_hash, CacheBehaviour, CachedEntry, CachedFileHash,
|
||||||
|
};
|
||||||
use crate::util;
|
use crate::util;
|
||||||
use crate::util::fetch::{write_cached_icon, FetchSemaphore, IoSemaphore};
|
use crate::util::fetch::{write_cached_icon, FetchSemaphore, IoSemaphore};
|
||||||
use crate::util::io::{self};
|
use crate::util::io::{self};
|
||||||
@ -9,7 +11,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::Path;
|
||||||
|
|
||||||
// Represent a Minecraft instance.
|
// Represent a Minecraft instance.
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
@ -146,7 +148,7 @@ pub struct FileMetadata {
|
|||||||
pub version_id: String,
|
pub version_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Copy)]
|
#[derive(Serialize, Deserialize, Clone, Debug, Copy, PartialEq, Eq)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
pub enum ProjectType {
|
pub enum ProjectType {
|
||||||
Mod,
|
Mod,
|
||||||
@ -176,7 +178,7 @@ impl ProjectType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_from_parent_folder(path: PathBuf) -> Option<Self> {
|
pub fn get_from_parent_folder(path: &Path) -> Option<Self> {
|
||||||
// Get parent folder
|
// Get parent folder
|
||||||
let path = path.parent()?.file_name()?;
|
let path = path.parent()?.file_name()?;
|
||||||
match path.to_str()? {
|
match path.to_str()? {
|
||||||
@ -206,6 +208,15 @@ impl ProjectType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_loaders(&self) -> &'static [&'static str] {
|
||||||
|
match self {
|
||||||
|
ProjectType::Mod => &["fabric", "forge", "quilt", "neoforge"],
|
||||||
|
ProjectType::DataPack => &["datapack"],
|
||||||
|
ProjectType::ResourcePack => &["vanilla", "canvas", "minecraft"],
|
||||||
|
ProjectType::ShaderPack => &["iris", "optifine"],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn iterator() -> impl Iterator<Item = ProjectType> {
|
pub fn iterator() -> impl Iterator<Item = ProjectType> {
|
||||||
[
|
[
|
||||||
ProjectType::Mod,
|
ProjectType::Mod,
|
||||||
@ -587,17 +598,10 @@ impl Profile {
|
|||||||
|
|
||||||
let file_updates = file_hashes
|
let file_updates = file_hashes
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|x| {
|
.filter_map(|file| {
|
||||||
all.iter().find(|prof| x.path.contains(&prof.path)).map(
|
all.iter()
|
||||||
|profile| {
|
.find(|prof| file.path.contains(&prof.path))
|
||||||
format!(
|
.map(|profile| Self::get_cache_key(file, profile))
|
||||||
"{}-{}-{}",
|
|
||||||
x.hash,
|
|
||||||
profile.loader.as_str(),
|
|
||||||
profile.game_version
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
@ -690,14 +694,7 @@ impl Profile {
|
|||||||
|
|
||||||
let file_updates = file_hashes
|
let file_updates = file_hashes
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| {
|
.map(|x| Self::get_cache_key(x, self))
|
||||||
format!(
|
|
||||||
"{}-{}-{}",
|
|
||||||
x.hash,
|
|
||||||
self.loader.as_str(),
|
|
||||||
self.game_version
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let file_hashes_ref =
|
let file_hashes_ref =
|
||||||
@ -773,6 +770,18 @@ impl Profile {
|
|||||||
Ok(files)
|
Ok(files)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_cache_key(file: &CachedFileHash, profile: &Profile) -> String {
|
||||||
|
format!(
|
||||||
|
"{}-{}-{}",
|
||||||
|
file.hash,
|
||||||
|
file.project_type
|
||||||
|
.filter(|x| *x != ProjectType::Mod)
|
||||||
|
.map(|x| x.get_loaders().join("+"))
|
||||||
|
.unwrap_or_else(|| profile.loader.as_str().to_string()),
|
||||||
|
profile.game_version
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(pool))]
|
#[tracing::instrument(skip(pool))]
|
||||||
pub async fn add_project_version(
|
pub async fn add_project_version(
|
||||||
profile_path: &str,
|
profile_path: &str,
|
||||||
@ -873,8 +882,15 @@ impl Profile {
|
|||||||
let project_path =
|
let project_path =
|
||||||
format!("{}/{}", project_type.get_folder(), file_name);
|
format!("{}/{}", project_type.get_folder(), file_name);
|
||||||
|
|
||||||
cache_file_hash(bytes.clone(), profile_path, &project_path, hash, exec)
|
cache_file_hash(
|
||||||
.await?;
|
bytes.clone(),
|
||||||
|
profile_path,
|
||||||
|
&project_path,
|
||||||
|
hash,
|
||||||
|
Some(project_type),
|
||||||
|
exec,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
util::fetch::write(&path.join(&project_path), &bytes, io_semaphore)
|
util::fetch::write(&path.join(&project_path), &bytes, io_semaphore)
|
||||||
.await?;
|
.await?;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user