0.8.0 beta fixes (#2154)

* initial fixes

* 0.8.0 beta fixes

* run actions

* run fmt

* Fix windows build

* Add purge cache opt

* add must revalidate to project req

* lint + clippy

* fix processes, open folder

* Update migrator to use old launcher cache for perf

* fix empty dirs not moving

* fix lint + create natives dir if not exist

* fix large request batches

* finish

* Fix deep linking on mac

* fix comp err

* fix comp err (2)

---------

Signed-off-by: Geometrically <18202329+Geometrically@users.noreply.github.com>
This commit is contained in:
Geometrically
2024-08-16 23:20:11 -07:00
committed by GitHub
parent 3a4843fb46
commit 910e219c0e
66 changed files with 1961 additions and 1896 deletions

View File

@@ -1,11 +1,13 @@
use crate::data::DirectoryInfo;
use crate::data::{Dependency, User, Version};
use crate::jre::check_jre;
use crate::prelude::ModLoader;
use crate::state;
use crate::state::{
Credentials, DefaultPage, DeviceToken, DeviceTokenKey, DeviceTokenPair,
Hooks, LinkedData, MemorySettings, ModrinthCredentials, Profile,
ProfileInstallStage, Theme, WindowSize,
CacheValue, CachedEntry, CachedFile, CachedFileHash, CachedFileUpdate,
Credentials, DefaultPage, DependencyType, DeviceToken, DeviceTokenKey,
DeviceTokenPair, FileType, Hooks, LinkedData, MemorySettings,
ModrinthCredentials, Profile, ProfileInstallStage, TeamMember, Theme,
VersionFile, WindowSize,
};
use crate::util::fetch::{read_json, IoSemaphore};
use chrono::{DateTime, Utc};
@@ -34,18 +36,6 @@ where
};
let old_launcher_root_str = old_launcher_root.to_string_lossy().to_string();
let new_launcher_root = DirectoryInfo::get_initial_settings_dir().ok_or(
crate::ErrorKind::FSError(
"Could not find valid config dir".to_string(),
),
)?;
let new_launcher_root_str = new_launcher_root
.to_string_lossy()
.to_string()
.trim_end_matches('/')
.trim_end_matches('\\')
.to_string();
let io_semaphore = IoSemaphore(Semaphore::new(10));
let settings_path = old_launcher_root.join("settings.json");
@@ -95,13 +85,9 @@ where
settings.prev_custom_dir = Some(old_launcher_root_str.clone());
for (_, legacy_version) in legacy_settings.java_globals.0 {
if let Ok(Some(mut java_version)) =
if let Ok(Some(java_version)) =
check_jre(PathBuf::from(legacy_version.path)).await
{
java_version.path = java_version
.path
.replace(&old_launcher_root_str, &new_launcher_root_str);
java_version.upsert(exec).await?;
}
}
@@ -175,127 +161,239 @@ where
}
}
let mut cached_entries = vec![];
if let Ok(profiles_dir) = std::fs::read_dir(
&legacy_settings
legacy_settings
.loaded_config_dir
.unwrap_or(old_launcher_root)
.clone()
.unwrap_or_else(|| old_launcher_root.clone())
.join("profiles"),
) {
for entry in profiles_dir.flatten() {
if entry.path().is_dir() {
let profile_path = entry.path().join("profile.json");
if !entry.path().is_dir() {
continue;
}
if let Ok(profile) =
read_json::<LegacyProfile>(&profile_path, &io_semaphore)
.await
let profile_path = entry.path().join("profile.json");
let profile = if let Ok(profile) =
read_json::<LegacyProfile>(&profile_path, &io_semaphore)
.await
{
profile
} else {
continue;
};
for (path, project) in profile.projects {
let full_path = legacy_settings
.loaded_config_dir
.clone()
.unwrap_or_else(|| old_launcher_root.clone())
.join("profiles")
.join(&profile.path)
.join(&path);
if !full_path.exists() || !full_path.is_file() {
continue;
}
let sha512 = project.sha512;
if let LegacyProjectMetadata::Modrinth {
version,
members,
update_version,
..
} = project.metadata
{
Profile {
path: profile.path,
install_stage: match profile.install_stage {
LegacyProfileInstallStage::Installed => {
ProfileInstallStage::Installed
}
LegacyProfileInstallStage::Installing => {
ProfileInstallStage::Installing
}
LegacyProfileInstallStage::PackInstalling => {
ProfileInstallStage::PackInstalling
}
LegacyProfileInstallStage::NotInstalled => {
ProfileInstallStage::NotInstalled
}
},
name: profile.metadata.name,
icon_path: profile.metadata.icon.map(|x| {
x.replace(
&old_launcher_root_str,
&new_launcher_root_str,
)
}),
game_version: profile.metadata.game_version,
loader: match profile.metadata.loader {
LegacyModLoader::Vanilla => ModLoader::Vanilla,
LegacyModLoader::Forge => ModLoader::Forge,
LegacyModLoader::Fabric => ModLoader::Fabric,
LegacyModLoader::Quilt => ModLoader::Quilt,
LegacyModLoader::NeoForge => {
ModLoader::NeoForge
}
},
loader_version: profile
.metadata
.loader_version
.map(|x| x.id),
groups: profile.metadata.groups,
linked_data: profile.metadata.linked_data.and_then(
|x| {
if let Some(project_id) = x.project_id {
if let Some(version_id) = x.version_id {
if let Some(locked) = x.locked {
return Some(LinkedData {
project_id,
version_id,
locked,
});
}
}
}
if let Some(file) = version
.files
.iter()
.find(|x| x.hashes.get("sha512") == Some(&sha512))
{
if let Some(sha1) = file.hashes.get("sha1") {
if let Ok(metadata) = full_path.metadata() {
let file_name = format!(
"{}/{}",
profile.path,
path.replace("\\", "/")
.replace(".disabled", "")
);
None
},
),
created: profile.metadata.date_created,
modified: profile.metadata.date_modified,
last_played: profile.metadata.last_played,
submitted_time_played: profile
.metadata
.submitted_time_played,
recent_time_played: profile
.metadata
.recent_time_played,
java_path: profile.java.as_ref().and_then(|x| {
x.override_version.clone().map(|x| {
x.path.replace(
&old_launcher_root_str,
&new_launcher_root_str,
)
})
}),
extra_launch_args: profile
.java
.as_ref()
.and_then(|x| x.extra_arguments.clone()),
custom_env_vars: profile
.java
.and_then(|x| x.custom_env_args),
memory: profile
.memory
.map(|x| MemorySettings { maximum: x.maximum }),
force_fullscreen: profile.fullscreen,
game_resolution: profile
.resolution
.map(|x| WindowSize(x.0, x.1)),
hooks: Hooks {
pre_launch: profile
.hooks
.as_ref()
.and_then(|x| x.pre_launch.clone()),
wrapper: profile
.hooks
.as_ref()
.and_then(|x| x.wrapper.clone()),
post_exit: profile
.hooks
.and_then(|x| x.post_exit),
},
cached_entries.push(CacheValue::FileHash(
CachedFileHash {
path: file_name,
size: metadata.len(),
hash: sha1.clone(),
},
));
}
cached_entries.push(CacheValue::File(
CachedFile {
hash: sha1.clone(),
project_id: version.project_id.clone(),
version_id: version.id.clone(),
},
));
if let Some(update_version) = update_version {
let mod_loader: ModLoader =
profile.metadata.loader.into();
cached_entries.push(
CacheValue::FileUpdate(
CachedFileUpdate {
hash: sha1.clone(),
game_version: profile
.metadata
.game_version
.clone(),
loader: mod_loader
.as_str()
.to_string(),
update_version_id:
update_version.id.clone(),
},
),
);
cached_entries.push(CacheValue::Version(
(*update_version).into(),
));
}
let members = members
.into_iter()
.map(|x| {
let user = User {
id: x.user.id,
username: x.user.username,
avatar_url: x.user.avatar_url,
bio: x.user.bio,
created: x.user.created,
role: x.user.role,
};
cached_entries.push(CacheValue::User(
user.clone(),
));
TeamMember {
team_id: x.team_id,
user: user.clone(),
is_owner: x.role == "Owner",
role: x.role,
ordering: x.ordering,
}
})
.collect::<Vec<_>>();
cached_entries.push(CacheValue::Team(members));
cached_entries.push(CacheValue::Version(
(*version).into(),
));
}
}
.upsert(exec)
.await?;
}
}
Profile {
path: profile.path,
install_stage: match profile.install_stage {
LegacyProfileInstallStage::Installed => {
ProfileInstallStage::Installed
}
LegacyProfileInstallStage::Installing => {
ProfileInstallStage::Installing
}
LegacyProfileInstallStage::PackInstalling => {
ProfileInstallStage::PackInstalling
}
LegacyProfileInstallStage::NotInstalled => {
ProfileInstallStage::NotInstalled
}
},
name: profile.metadata.name,
icon_path: profile.metadata.icon,
game_version: profile.metadata.game_version,
loader: profile.metadata.loader.into(),
loader_version: profile
.metadata
.loader_version
.map(|x| x.id),
groups: profile.metadata.groups,
linked_data: profile.metadata.linked_data.and_then(|x| {
if let Some(project_id) = x.project_id {
if let Some(version_id) = x.version_id {
if let Some(locked) = x.locked {
return Some(LinkedData {
project_id,
version_id,
locked,
});
}
}
}
None
}),
created: profile.metadata.date_created,
modified: profile.metadata.date_modified,
last_played: profile.metadata.last_played,
submitted_time_played: profile
.metadata
.submitted_time_played,
recent_time_played: profile.metadata.recent_time_played,
java_path: profile.java.as_ref().and_then(|x| {
x.override_version.clone().map(|x| x.path)
}),
extra_launch_args: profile
.java
.as_ref()
.and_then(|x| x.extra_arguments.clone()),
custom_env_vars: profile
.java
.and_then(|x| x.custom_env_args),
memory: profile
.memory
.map(|x| MemorySettings { maximum: x.maximum }),
force_fullscreen: profile.fullscreen,
game_resolution: profile
.resolution
.map(|x| WindowSize(x.0, x.1)),
hooks: Hooks {
pre_launch: profile
.hooks
.as_ref()
.and_then(|x| x.pre_launch.clone()),
wrapper: profile
.hooks
.as_ref()
.and_then(|x| x.wrapper.clone()),
post_exit: profile.hooks.and_then(|x| x.post_exit),
},
}
.upsert(exec)
.await?;
}
}
CachedEntry::upsert_many(
&cached_entries
.into_iter()
.map(|x| {
let mut entry = x.get_entry();
entry.expires =
Utc::now().timestamp() - entry.type_.expiry();
entry
})
.collect::<Vec<_>>(),
exec,
)
.await?;
settings.migrated = true;
settings.update(exec).await?;
}
@@ -384,6 +482,12 @@ struct LegacyJavaVersion {
#[derive(Deserialize, Clone, Debug)]
struct LegacyModrinthUser {
pub id: String,
pub username: String,
// pub name: Option<String>,
pub avatar_url: Option<String>,
pub bio: Option<String>,
pub created: DateTime<Utc>,
pub role: String,
}
#[derive(Deserialize, Clone, Debug)]
@@ -439,6 +543,195 @@ struct LegacyProfile {
pub resolution: Option<LegacyWindowSize>,
pub fullscreen: Option<bool>,
pub hooks: Option<LegacyHooks>,
pub projects: HashMap<String, LegacyProject>,
}
#[derive(Deserialize, Clone, Debug)]
struct LegacyProject {
pub sha512: String,
// pub disabled: bool,
pub metadata: LegacyProjectMetadata,
// pub file_name: String,
}
#[derive(Deserialize, Clone, Debug)]
#[serde(tag = "type", rename_all = "snake_case")]
enum LegacyProjectMetadata {
Modrinth {
// project: Box<LegacyModrinthProject>,
version: Box<LegacyModrinthVersion>,
members: Vec<LegacyModrinthTeamMember>,
update_version: Option<Box<LegacyModrinthVersion>>,
},
Inferred,
Unknown,
}
// #[derive(Deserialize, Clone, Debug)]
// struct LegacyModrinthProject {
// pub id: String,
// pub slug: Option<String>,
// pub project_type: String,
// pub team: String,
// pub title: String,
// pub description: String,
// pub body: String,
//
// pub published: DateTime<Utc>,
// pub updated: DateTime<Utc>,
//
// pub client_side: LegacySideType,
// pub server_side: LegacySideType,
//
// pub downloads: u32,
// pub followers: u32,
//
// pub categories: Vec<String>,
// pub additional_categories: Vec<String>,
// pub game_versions: Vec<String>,
// pub loaders: Vec<String>,
//
// pub versions: Vec<String>,
//
// pub icon_url: Option<String>,
// }
#[derive(Deserialize, Clone, Debug)]
struct LegacyModrinthVersion {
pub id: String,
pub project_id: String,
pub author_id: String,
pub featured: bool,
pub name: String,
pub version_number: String,
pub changelog: String,
pub changelog_url: Option<String>,
pub date_published: DateTime<Utc>,
pub downloads: u32,
pub version_type: String,
pub files: Vec<LegacyModrinthVersionFile>,
pub dependencies: Vec<LegacyDependency>,
pub game_versions: Vec<String>,
pub loaders: Vec<String>,
}
impl From<LegacyModrinthVersion> for Version {
fn from(value: LegacyModrinthVersion) -> Self {
Version {
id: value.id,
project_id: value.project_id,
author_id: value.author_id,
featured: value.featured,
name: value.name,
version_number: value.version_number,
changelog: value.changelog,
changelog_url: value.changelog_url,
date_published: value.date_published,
downloads: value.downloads,
version_type: value.version_type,
files: value
.files
.into_iter()
.map(|x| VersionFile {
hashes: x.hashes,
url: x.url,
filename: x.filename,
primary: x.primary,
size: x.size,
file_type: x.file_type.map(|x| match x {
LegacyFileType::RequiredResourcePack => {
FileType::RequiredResourcePack
}
LegacyFileType::OptionalResourcePack => {
FileType::OptionalResourcePack
}
LegacyFileType::Unknown => FileType::Unknown,
}),
})
.collect::<Vec<_>>(),
dependencies: value
.dependencies
.into_iter()
.map(|x| Dependency {
version_id: x.version_id,
project_id: x.project_id,
file_name: x.file_name,
dependency_type: match x.dependency_type {
LegacyDependencyType::Required => {
DependencyType::Required
}
LegacyDependencyType::Optional => {
DependencyType::Optional
}
LegacyDependencyType::Incompatible => {
DependencyType::Incompatible
}
LegacyDependencyType::Embedded => {
DependencyType::Embedded
}
},
})
.collect::<Vec<_>>(),
game_versions: value.game_versions,
loaders: value.loaders,
}
}
}
#[derive(Deserialize, Clone, Debug)]
struct LegacyModrinthVersionFile {
pub hashes: HashMap<String, String>,
pub url: String,
pub filename: String,
pub primary: bool,
pub size: u32,
pub file_type: Option<LegacyFileType>,
}
#[derive(Deserialize, Clone, Debug)]
struct LegacyDependency {
pub version_id: Option<String>,
pub project_id: Option<String>,
pub file_name: Option<String>,
pub dependency_type: LegacyDependencyType,
}
#[derive(Deserialize, Clone, Debug)]
struct LegacyModrinthTeamMember {
pub team_id: String,
pub user: LegacyModrinthUser,
pub role: String,
pub ordering: i64,
}
#[derive(Deserialize, Copy, Clone, Debug)]
#[serde(rename_all = "lowercase")]
enum LegacyDependencyType {
Required,
Optional,
Incompatible,
Embedded,
}
// #[derive(Deserialize, Clone, Debug, Eq, PartialEq)]
// #[serde(rename_all = "kebab-case")]
// enum LegacySideType {
// Required,
// Optional,
// Unsupported,
// Unknown,
// }
#[derive(Deserialize, Copy, Clone, Debug)]
#[serde(rename_all = "kebab-case")]
enum LegacyFileType {
RequiredResourcePack,
OptionalResourcePack,
Unknown,
}
#[derive(Deserialize, Clone, Debug)]
@@ -477,6 +770,18 @@ enum LegacyModLoader {
NeoForge,
}
impl From<LegacyModLoader> for ModLoader {
fn from(value: LegacyModLoader) -> Self {
match value {
LegacyModLoader::Vanilla => ModLoader::Vanilla,
LegacyModLoader::Forge => ModLoader::Forge,
LegacyModLoader::Fabric => ModLoader::Fabric,
LegacyModLoader::Quilt => ModLoader::Quilt,
LegacyModLoader::NeoForge => ModLoader::NeoForge,
}
}
}
#[derive(Deserialize, Clone, Debug)]
struct LegacyLinkedData {
pub project_id: Option<String>,