Fix syncing, repairing, add edit method (#111)

* Fix syncing, repairing, add edit method

* comp err

* temp push up

* fixes

* fix more

* add frontend
This commit is contained in:
Geometrically
2023-05-11 10:26:00 -07:00
committed by GitHub
parent 71cf2c53f5
commit 7a0798d9d0
24 changed files with 501 additions and 352 deletions

View File

@@ -4,11 +4,12 @@ use crate::data::DirectoryInfo;
use crate::event::emit::emit_profile;
use crate::event::ProfilePayloadType;
use crate::state::projects::Project;
use crate::state::{ModrinthVersion, ProjectType};
use crate::state::{ModrinthVersion, ProjectMetadata, ProjectType};
use crate::util::fetch::{
fetch, fetch_json, write, write_cached_icon, IoSemaphore,
};
use crate::State;
use daedalus::get_hash;
use daedalus::modded::LoaderVersion;
use dunce::canonicalize;
use futures::prelude::*;
@@ -29,12 +30,28 @@ pub(crate) struct Profiles(pub HashMap<PathBuf, Profile>);
// TODO: possibly add defaults to some of these values
pub const CURRENT_FORMAT_VERSION: u32 = 1;
#[derive(
Serialize, Deserialize, Clone, Copy, Debug, Default, Eq, PartialEq,
)]
#[serde(rename_all = "snake_case")]
pub enum ProfileInstallStage {
/// Profile is installed
Installed,
/// Profile's minecraft game is still installing
Installing,
/// Profile created for pack, but the pack hasn't been fully installed yet
PackInstalling,
/// Profile is not installed
#[default]
NotInstalled,
}
// Represent a Minecraft instance.
#[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 install_stage: ProfileInstallStage,
pub path: PathBuf,
pub metadata: ProfileMetadata,
#[serde(skip_serializing_if = "Option::is_none")]
@@ -53,6 +70,8 @@ pub struct ProfileMetadata {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<PathBuf>,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon_url: Option<String>,
pub game_version: String,
#[serde(default)]
pub loader: ModLoader,
@@ -127,11 +146,12 @@ impl Profile {
Ok(Self {
uuid,
installed: false,
install_stage: ProfileInstallStage::NotInstalled,
path: canonicalize(path)?,
metadata: ProfileMetadata {
name,
icon: None,
icon_url: None,
game_version: version,
loader: ModLoader::Vanilla,
loader_version: None,
@@ -160,7 +180,7 @@ impl Profile {
Ok(self)
}
pub async fn sync(&mut self) -> crate::Result<()> {
pub async fn sync_projects(&mut self) -> crate::Result<()> {
let state = State::get().await?;
let paths = self.get_profile_project_paths()?;
@@ -186,6 +206,45 @@ impl Profile {
Ok(())
}
pub fn sync_projects_task(path: PathBuf) {
tokio::task::spawn(async move {
let res = async {
let state = State::get().await?;
let profile = crate::api::profile::get(&path).await?;
if let Some(profile) = profile {
let paths = profile.get_profile_project_paths()?;
let projects = crate::state::infer_data_from_files(
profile,
paths,
state.directories.caches_dir(),
&state.io_semaphore,
&state.fetch_semaphore,
)
.await?;
let mut new_profiles = state.profiles.write().await;
if let Some(profile) = new_profiles.0.get_mut(&path) {
profile.projects = projects;
}
}
Ok::<(), crate::Error>(())
}
.await;
match res {
Ok(()) => {}
Err(err) => {
tracing::warn!(
"Unable to fetch single profile projects: {err}"
)
}
};
});
}
pub fn get_profile_project_paths(&self) -> crate::Result<Vec<PathBuf>> {
let mut files = Vec::new();
let mut read_paths = |path: &str| {
@@ -212,7 +271,7 @@ impl Profile {
pub async fn add_project_version(
&mut self,
version_id: String,
) -> crate::Result<PathBuf> {
) -> crate::Result<(PathBuf, ModrinthVersion)> {
let state = State::get().await?;
let version = fetch_json::<ModrinthVersion>(
@@ -247,11 +306,11 @@ impl Profile {
.add_project_bytes(
&file.filename,
bytes,
ProjectType::get_from_loaders(version.loaders),
ProjectType::get_from_loaders(version.loaders.clone()),
)
.await?;
Ok(path)
Ok((path, version))
}
pub async fn add_project_bytes(
@@ -294,6 +353,25 @@ impl Profile {
let path = self.path.join(project_type.get_folder()).join(file_name);
write(&path, &bytes, &state.io_semaphore).await?;
let hash = get_hash(bytes).await?;
self.projects.insert(
path.clone(),
Project {
sha512: hash,
disabled: false,
metadata: ProjectMetadata::Unknown,
file_name: file_name.to_string(),
},
);
emit_profile(
self.uuid,
self.path.clone(),
&self.metadata.name,
ProfilePayloadType::Synced,
)
.await?;
Ok(path)
}
@@ -329,10 +407,16 @@ impl Profile {
Ok(())
}
pub async fn remove_project(&mut self, path: &Path) -> crate::Result<()> {
pub async fn remove_project(
&mut self,
path: &Path,
dont_remove_arr: Option<bool>,
) -> crate::Result<()> {
if self.projects.contains_key(path) {
fs::remove_file(path).await?;
self.projects.remove(path);
if !dont_remove_arr.unwrap_or(false) {
self.projects.remove(path);
}
} else {
return Err(crate::ErrorKind::InputError(format!(
"Project path does not exist: {:?}",