Updating + Profile Repairs + Performance Improvements (#97)

* repairing

* Main framework for updating

* add jsconfig

* more work

* Improve performance

* Finish updating

* run lint
This commit is contained in:
Geometrically
2023-04-26 10:28:08 -07:00
committed by GitHub
parent c53104c28e
commit f0b8a708a3
48 changed files with 1217 additions and 894 deletions

View File

@@ -1,10 +1,8 @@
use super::settings::{Hooks, MemorySettings, WindowSize};
use crate::config::MODRINTH_API_URL;
use crate::data::DirectoryInfo;
use crate::event::emit::{
emit_profile, init_loading, loading_try_for_each_concurrent,
};
use crate::event::{LoadingBarType, ProfilePayloadType};
use crate::event::emit::emit_profile;
use crate::event::ProfilePayloadType;
use crate::state::projects::Project;
use crate::state::{ModrinthVersion, ProjectType};
use crate::util::fetch::{fetch, fetch_json, write, write_cached_icon};
@@ -34,6 +32,8 @@ pub const CURRENT_FORMAT_VERSION: u32 = 1;
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Profile {
pub uuid: Uuid, // todo: will be used in restructure to refer to profiles
#[serde(default)]
pub installed: bool,
pub path: PathBuf,
pub metadata: ProfileMetadata,
#[serde(skip_serializing_if = "Option::is_none")]
@@ -58,10 +58,15 @@ pub struct ProfileMetadata {
#[serde(skip_serializing_if = "Option::is_none")]
pub loader_version: Option<LoaderVersion>,
pub format_version: u32,
pub linked_project_id: Option<String>,
pub linked_data: Option<LinkedData>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct LinkedData {
pub project_id: Option<String>,
pub version_id: Option<String>,
}
// TODO: Quilt?
#[derive(
Debug, Eq, PartialEq, Clone, Copy, Deserialize, Serialize, Default,
)]
@@ -85,6 +90,17 @@ impl std::fmt::Display for ModLoader {
}
}
impl ModLoader {
pub(crate) fn as_api_str(&self) -> &'static str {
match *self {
Self::Vanilla => "vanilla",
Self::Forge => "forge",
Self::Fabric => "fabric",
Self::Quilt => "quilt",
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct JavaSettings {
#[serde(skip_serializing_if = "Option::is_none")]
@@ -110,6 +126,7 @@ impl Profile {
Ok(Self {
uuid,
installed: false,
path: canonicalize(path)?,
metadata: ProfileMetadata {
name,
@@ -118,7 +135,7 @@ impl Profile {
loader: ModLoader::Vanilla,
loader_version: None,
format_version: CURRENT_FORMAT_VERSION,
linked_project_id: None,
linked_data: None,
},
projects: HashMap::new(),
java: None,
@@ -147,7 +164,7 @@ impl Profile {
let paths = self.get_profile_project_paths()?;
let projects = crate::state::infer_data_from_files(
paths,
&[(self.clone(), paths)],
state.directories.caches_dir(),
&state.io_semaphore,
)
@@ -155,6 +172,14 @@ impl Profile {
self.projects = projects;
emit_profile(
self.uuid,
self.path.clone(),
&self.metadata.name,
ProfilePayloadType::Synced,
)
.await?;
Ok(())
}
@@ -266,8 +291,6 @@ impl Profile {
let path = self.path.join(project_type.get_folder()).join(file_name);
write(&path, &bytes, &state.io_semaphore).await?;
self.sync().await?;
Ok(path)
}
@@ -345,36 +368,62 @@ impl Profiles {
}
}
// project path, parent profile path
let mut files: HashMap<PathBuf, PathBuf> = HashMap::new();
{
for (profile_path, profile) in profiles.iter() {
let paths = profile.get_profile_project_paths()?;
for path in paths {
files.insert(path, profile_path.clone());
}
}
}
let inferred = super::projects::infer_data_from_files(
files.keys().cloned().collect(),
dirs.caches_dir(),
io_sempahore,
)
.await?;
for (key, value) in inferred {
if let Some(profile_path) = files.get(&key) {
if let Some(profile) = profiles.get_mut(profile_path) {
profile.projects.insert(key, value);
}
}
}
Ok(Self(profiles))
}
pub async fn update_projects() {
let res = async {
let state = State::get().await?;
// profile, child paths
let mut files: Vec<(Profile, Vec<PathBuf>)> = Vec::new();
{
let profiles = state.profiles.read().await;
for (_profile_path, profile) in profiles.0.iter() {
let paths = profile.get_profile_project_paths()?;
files.push((profile.clone(), paths));
}
}
if !files.is_empty() {
let inferred = super::projects::infer_data_from_files(
&files,
state.directories.caches_dir(),
&state.io_semaphore,
)
.await?;
let mut wipe_profiles = Vec::new();
for (key, value) in inferred {
if let Some((profile, _)) =
files.iter().find(|(_, files)| files.contains(&key))
{
let mut new_profiles = state.profiles.write().await;
if let Some(profile) =
new_profiles.0.get_mut(&profile.path)
{
if !wipe_profiles.contains(&profile.path) {
profile.projects = HashMap::new();
wipe_profiles.push(profile.path.clone());
}
profile.projects.insert(key, value);
}
}
}
}
Ok::<(), crate::Error>(())
}
.await;
match res {
Ok(()) => {}
Err(err) => {
log::warn!("Unable to fetch profile projects: {err}")
}
};
}
#[tracing::instrument(skip(self))]
pub async fn insert(&mut self, profile: Profile) -> crate::Result<&Self> {
emit_profile(
@@ -406,35 +455,26 @@ impl Profiles {
}
#[tracing::instrument(skip(self))]
pub async fn remove(&mut self, path: &Path) -> crate::Result<&Self> {
pub async fn remove(
&mut self,
path: &Path,
) -> crate::Result<Option<Profile>> {
let path =
PathBuf::from(&canonicalize(path)?.to_string_lossy().to_string());
self.0.remove(&path);
let profile = self.0.remove(&path);
if path.exists() {
fs::remove_dir_all(path).await?;
}
Ok(self)
Ok(profile)
}
#[tracing::instrument(skip_all)]
pub async fn sync(&self) -> crate::Result<&Self> {
let loading_bar = init_loading(
LoadingBarType::ProfileSync,
100.0,
"Syncing profiles...",
)
.await?;
let num_futs = self.0.len();
loading_try_for_each_concurrent(
stream::iter(self.0.iter()).map(Ok::<_, crate::Error>),
None,
Some(&loading_bar),
100.0,
num_futs,
None,
|(path, profile)| async move {
stream::iter(self.0.iter())
.map(Ok::<_, crate::Error>)
.try_for_each_concurrent(None, |(path, profile)| async move {
let json = serde_json::to_vec(&profile)?;
let json_path = Path::new(&path.to_string_lossy().to_string())
@@ -442,9 +482,8 @@ impl Profiles {
fs::write(json_path, json).await?;
Ok::<_, crate::Error>(())
},
)
.await?;
})
.await?;
Ok(self)
}