You've already forked AstralRinth
forked from didirus/AstralRinth
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:
@@ -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>,
|
||||
|
||||
Reference in New Issue
Block a user