From f5f48e349f2c7bdefb39b4d59e08b5e0e1c84803 Mon Sep 17 00:00:00 2001 From: LynithDev <61880709+LynithDev@users.noreply.github.com> Date: Wed, 31 Jul 2024 17:48:35 +0200 Subject: [PATCH] feat: Screenshots + refactor: Commands --- apps/desktop/src/api/commands.rs | 371 ------------------ apps/desktop/src/api/commands/cluster.rs | 143 +++++++ apps/desktop/src/api/commands/mod.rs | 78 ++++ apps/desktop/src/api/commands/package.rs | 37 ++ apps/desktop/src/api/commands/processor.rs | 21 + apps/desktop/src/api/commands/users.rs | 100 +++++ .../src/api/{ => cluster/content}/logger.rs | 0 packages/core/src/api/cluster/content/mod.rs | 2 + .../src/api/cluster/content/screenshots.rs | 30 ++ packages/core/src/api/cluster/mod.rs | 8 +- packages/core/src/api/mod.rs | 1 - packages/core/src/store/clusters.rs | 6 +- packages/core/src/utils/io.rs | 15 + 13 files changed, 430 insertions(+), 382 deletions(-) delete mode 100644 apps/desktop/src/api/commands.rs create mode 100644 apps/desktop/src/api/commands/cluster.rs create mode 100644 apps/desktop/src/api/commands/mod.rs create mode 100644 apps/desktop/src/api/commands/package.rs create mode 100644 apps/desktop/src/api/commands/processor.rs create mode 100644 apps/desktop/src/api/commands/users.rs rename packages/core/src/api/{ => cluster/content}/logger.rs (100%) create mode 100644 packages/core/src/api/cluster/content/mod.rs create mode 100644 packages/core/src/api/cluster/content/screenshots.rs diff --git a/apps/desktop/src/api/commands.rs b/apps/desktop/src/api/commands.rs deleted file mode 100644 index 9cfafd37..00000000 --- a/apps/desktop/src/api/commands.rs +++ /dev/null @@ -1,371 +0,0 @@ -use std::path::PathBuf; -use std::str::FromStr; - -use interpulse::api::minecraft::Version; -use onelauncher::api::logger; -use onelauncher::data::{Loader, ManagedPackage, MinecraftCredentials, PackageData, Settings}; -use onelauncher::package::content; -use onelauncher::store::{Cluster, ClusterPath}; -use onelauncher::{cluster, minecraft, processor, settings, State}; -use serde::{Deserialize, Serialize}; -use specta::Type; -use tauri::{AppHandle, Manager}; -use uuid::Uuid; - -#[macro_export] -macro_rules! collect_commands { - () => {{ - use $crate::api::commands::*; - use $crate::ext::updater::*; - tauri_specta::collect_commands![ - // User - auth_login, - get_users, - get_user, - get_default_user, - set_default_user, - remove_user, - // Cluster - create_cluster, - edit_cluster, - remove_cluster, - get_cluster, - get_clusters, - run_cluster, - get_cluster_logs, - get_cluster_log, - upload_log, - // Processor - get_running_clusters, - get_processes_by_path, - kill_process, - // Settings - get_settings, - set_settings, - // Metadata - get_minecraft_versions, - // Package - random_mods, - get_mod, - download_mod, - // Updater - check_for_update, - install_update, - ] - }}; -} - -#[derive(Serialize, Deserialize, Type)] -pub struct CreateCluster { - name: String, - mc_version: String, - mod_loader: Loader, - loader_version: Option, - icon: Option, - icon_url: Option, - package_data: Option, - skip: Option, - skip_watch: Option, -} - -#[specta::specta] -#[tauri::command] -pub async fn create_cluster(props: CreateCluster) -> Result { - let path = cluster::create::create_cluster( - props.name, - props.mc_version, - props.mod_loader, - props.loader_version, - props.icon, - props.icon_url, - props.package_data, - props.skip, - props.skip_watch, - ) - .await?; - - if let Some(cluster) = cluster::get(&path, None).await? { - Ok(cluster.uuid) - } else { - Err("Cluster does not exist".to_string()) - } -} - -#[specta::specta] -#[tauri::command] -pub async fn edit_cluster( - uuid: Uuid, - name: Option, - icon_path: Option, -) -> Result<(), String> { - let cluster = cluster::get_by_uuid(uuid, None) - .await? - .ok_or("cluster does not exist")?; - - cluster::edit(&cluster.cluster_path(), move |cluster| { - if let Some(name) = name.clone() { - cluster.meta.name = name; - } - - async move { Ok(()) } - }) - .await?; - - let icon_path = icon_path.and_then(|x| PathBuf::from_str(x.as_str()).ok()); - cluster::edit_icon(&cluster.cluster_path(), icon_path.as_deref()).await?; - - State::sync().await?; - - Ok(()) -} - -#[specta::specta] -#[tauri::command] -pub async fn remove_cluster(uuid: Uuid) -> Result<(), String> { - let path = ClusterPath::find_by_uuid(uuid).await?; - Ok(cluster::remove(&path).await?) -} - -#[specta::specta] -#[tauri::command] -pub async fn run_cluster(uuid: Uuid) -> Result<(Uuid, u32), String> { - let path = ClusterPath::find_by_uuid(uuid).await?; - let c_lock = cluster::run(&path).await?; - - let p_uuid = c_lock.read().await.uuid; - let p_pid = c_lock - .read() - .await - .current_child - .read() - .await - .id() - .unwrap_or(0); - - Ok((p_uuid, p_pid)) -} - -#[specta::specta] -#[tauri::command] -pub async fn get_running_clusters() -> Result, String> { - Ok(processor::get_running_clusters().await?) -} - -#[specta::specta] -#[tauri::command] -pub async fn get_processes_by_path(path: ClusterPath) -> Result, String> { - Ok(processor::get_uuids_by_cluster_path(path).await?) -} - -#[specta::specta] -#[tauri::command] -pub async fn kill_process(uuid: Uuid) -> Result<(), String> { - processor::kill_by_uuid(uuid).await?; - Ok(()) -} - -// #[specta::specta] -// #[tauri::command] -// pub fn update_cluster(cluster: Cluster) -> Result<(), String> { - -// } - -#[specta::specta] -#[tauri::command] -pub async fn get_cluster(uuid: Uuid) -> Result { - match cluster::get_by_uuid(uuid, None).await? { - Some(cluster) => Ok(cluster), - None => Err("Cluster does not exist".into()), - } -} - - -#[specta::specta] -#[tauri::command] -pub async fn get_cluster_logs(uuid: Uuid) -> Result, String> { - let cluster = cluster::get_by_uuid(uuid, None).await?.ok_or("cluster not found")?; - let logs = logger::get_logs(&cluster.cluster_path(), None) - .await? - .iter() - .map(|x| x.log_file.clone()) - .collect(); - Ok(logs) -} - -#[specta::specta] -#[tauri::command] -pub async fn get_cluster_log(uuid: Uuid, log_name: String) -> Result { - let cluster = cluster::get_by_uuid(uuid, None).await?.ok_or("cluster not found")?; - let log = logger::get_output_by_file(&cluster.cluster_path(), logger::LogType::Info, &log_name) - .await?; - Ok(log.0) -} - -#[specta::specta] -#[tauri::command] -pub async fn upload_log(uuid: Uuid, log_name: String) -> Result { - let cluster = cluster::get_by_uuid(uuid, None).await?.ok_or("cluster not found")?; - let log = logger::get_output_by_file(&cluster.cluster_path(), logger::LogType::Info, &log_name) - .await?; - - let id = logger::upload_log(&cluster.cluster_path(), log).await?; - Ok(id) -} - -#[specta::specta] -#[tauri::command] -pub async fn get_clusters() -> Result, String> { - Ok(cluster::list(None).await?) -} - -#[specta::specta] -#[tauri::command] -pub async fn get_minecraft_versions() -> Result, String> { - Ok(onelauncher::api::metadata::get_minecraft_versions() - .await? - .versions) -} - -#[specta::specta] -#[tauri::command] -pub async fn get_settings() -> Result { - Ok(settings::get().await?) -} - -#[specta::specta] -#[tauri::command] -pub async fn set_settings(settings: Settings) -> Result<(), String> { - Ok(settings::set(settings).await?) -} - -#[specta::specta] -#[tauri::command] -pub async fn get_users() -> Result, String> { - Ok(minecraft::users().await?) -} - -#[specta::specta] -#[tauri::command] -pub async fn get_user(uuid: Uuid) -> Result { - Ok(minecraft::get_user(uuid).await?) -} - -#[specta::specta] -#[tauri::command] -pub async fn get_default_user() -> Result, String> { - let uuid = minecraft::get_default_user().await?; - - match uuid { - Some(uuid) => Ok(Some(minecraft::get_user(uuid).await?)), - None => Ok(None), - } -} - -#[specta::specta] -#[tauri::command] -pub async fn set_default_user(uuid: Uuid) -> Result<(), String> { - minecraft::set_default_user(uuid).await?; - Ok(()) -} - -#[specta::specta] -#[tauri::command] -pub async fn auth_login(handle: AppHandle) -> Result, String> { - let flow = minecraft::begin().await?; - let now = chrono::Utc::now(); - - if let Some(win) = handle.get_webview_window("login") { - win.close().map_err(|err| err.to_string())?; - } - - let win = tauri::WebviewWindowBuilder::new( - &handle, - "login", - tauri::WebviewUrl::External( - flow.redirect_uri - .parse() - .map_err(|_| anyhow::anyhow!("failed to parse auth redirect url")) - .map_err(|err| err.to_string())?, - ), - ) - .title("Log into OneLauncher") - .always_on_top(true) - .center() - .build() - .map_err(|err| err.to_string())?; - - win.request_user_attention(Some(tauri::UserAttentionType::Critical)) - .map_err(|err| err.to_string())?; - - while (chrono::Utc::now() - now) < chrono::Duration::minutes(10) { - if win.title().is_err() { - return Ok(None); - } - - if win - .url() - .map_err(|err| err.to_string())? - .as_str() - .starts_with("https://login.live.com/oauth20_desktop.srf") - { - if let Some((_, code)) = win - .url() - .map_err(|err| err.to_string())? - .query_pairs() - .find(|x| x.0 == "code") - { - win.close().map_err(|err| err.to_string())?; - let value = minecraft::finish(&code.clone(), flow).await?; - - return Ok(Some(value)); - } - } - - tokio::time::sleep(std::time::Duration::from_millis(50)).await; - } - - win.close().map_err(|err| err.to_string())?; - - Ok(None) -} - -#[specta::specta] -#[tauri::command] -pub async fn remove_user(uuid: Uuid) -> Result<(), String> { - Ok(minecraft::remove_user(uuid).await?) -} - -#[specta::specta] -#[tauri::command] -pub async fn random_mods() -> Result, String> { - let provider = content::Providers::Modrinth; - Ok(provider.list().await?) -} - -#[specta::specta] -#[tauri::command] -pub async fn get_mod(project_id: String) -> Result { - let provider = content::Providers::Modrinth; - Ok(provider.get(&project_id).await?) -} - -#[specta::specta] -#[tauri::command] -pub async fn download_mod(cluster_id: Uuid, version_id: String) -> Result<(), String> { - let cluster = cluster::get_by_uuid(cluster_id, None) - .await? - .ok_or("cluster not found")?; - let provider = content::Providers::Modrinth; - let game_version = cluster.meta.mc_version.clone(); - - provider - .get_version_for_game_version(&version_id, &game_version) - .await? - .files - .first() - .ok_or("no files found")? - .download_to_cluster(&cluster) - .await?; - - Ok(()) -} diff --git a/apps/desktop/src/api/commands/cluster.rs b/apps/desktop/src/api/commands/cluster.rs new file mode 100644 index 00000000..d93f16cc --- /dev/null +++ b/apps/desktop/src/api/commands/cluster.rs @@ -0,0 +1,143 @@ +use std::{path::PathBuf, str::FromStr}; + +use onelauncher::{cluster::{self, content::logger}, data::{Loader, PackageData}, store::{Cluster, ClusterPath}, State}; +use serde::{Deserialize, Serialize}; +use specta::Type; +use uuid::Uuid; + +#[specta::specta] +#[tauri::command] +pub async fn get_cluster(uuid: Uuid) -> Result { + match onelauncher::cluster::get_by_uuid(uuid, None).await? { + Some(cluster) => Ok(cluster), + None => Err("Cluster does not exist".into()), + } +} + +#[specta::specta] +#[tauri::command] +pub async fn get_clusters() -> Result, String> { + Ok(onelauncher::cluster::list(None).await?) +} + +#[derive(Serialize, Deserialize, Type)] +pub struct CreateCluster { + name: String, + mc_version: String, + mod_loader: Loader, + loader_version: Option, + icon: Option, + icon_url: Option, + package_data: Option, + skip: Option, + skip_watch: Option, +} + +#[specta::specta] +#[tauri::command] +pub async fn create_cluster(props: CreateCluster) -> Result { + let path = cluster::create::create_cluster( + props.name, + props.mc_version, + props.mod_loader, + props.loader_version, + props.icon, + props.icon_url, + props.package_data, + props.skip, + props.skip_watch, + ) + .await?; + + if let Some(cluster) = cluster::get(&path, None).await? { + Ok(cluster.uuid) + } else { + Err("Cluster does not exist".to_string()) + } +} + +#[specta::specta] +#[tauri::command] +pub async fn edit_cluster( + uuid: Uuid, + name: Option, + icon_path: Option, +) -> Result<(), String> { + let cluster = cluster::get_by_uuid(uuid, None) + .await? + .ok_or("cluster does not exist")?; + + cluster::edit(&cluster.cluster_path(), move |cluster| { + if let Some(name) = name.clone() { + cluster.meta.name = name; + } + + async move { Ok(()) } + }) + .await?; + + let icon_path = icon_path.and_then(|x| PathBuf::from_str(x.as_str()).ok()); + cluster::edit_icon(&cluster.cluster_path(), icon_path.as_deref()).await?; + + State::sync().await?; + + Ok(()) +} + +#[specta::specta] +#[tauri::command] +pub async fn remove_cluster(uuid: Uuid) -> Result<(), String> { + let path = ClusterPath::find_by_uuid(uuid).await?; + Ok(cluster::remove(&path).await?) +} + +#[specta::specta] +#[tauri::command] +pub async fn run_cluster(uuid: Uuid) -> Result<(Uuid, u32), String> { + let path = ClusterPath::find_by_uuid(uuid).await?; + let c_lock = cluster::run(&path).await?; + + let p_uuid = c_lock.read().await.uuid; + let p_pid = c_lock + .read() + .await + .current_child + .read() + .await + .id() + .unwrap_or(0); + + Ok((p_uuid, p_pid)) +} + +#[specta::specta] +#[tauri::command] +pub async fn get_cluster_logs(uuid: Uuid) -> Result, String> { + let cluster = onelauncher::cluster::get_by_uuid(uuid, None).await?.ok_or("cluster not found")?; + let logs = logger::get_logs(&cluster.cluster_path(), None) + .await? + .iter() + .map(|x| x.log_file.clone()) + .collect(); + Ok(logs) +} + +#[specta::specta] +#[tauri::command] +pub async fn get_cluster_log(uuid: Uuid, log_name: String) -> Result { + let cluster = onelauncher::cluster::get_by_uuid(uuid, None).await?.ok_or("cluster not found")?; + let log = logger::get_output_by_file(&cluster.cluster_path(), logger::LogType::Info, &log_name) + .await?; + Ok(log.0) +} + +#[specta::specta] +#[tauri::command] +pub async fn upload_log(uuid: Uuid, log_name: String) -> Result { + let cluster = onelauncher::cluster::get_by_uuid(uuid, None).await?.ok_or("cluster not found")?; + let log = logger::get_output_by_file(&cluster.cluster_path(), logger::LogType::Info, &log_name) + .await?; + + let id = logger::upload_log(&cluster.cluster_path(), log).await?; + Ok(id) +} \ No newline at end of file diff --git a/apps/desktop/src/api/commands/mod.rs b/apps/desktop/src/api/commands/mod.rs new file mode 100644 index 00000000..57d74881 --- /dev/null +++ b/apps/desktop/src/api/commands/mod.rs @@ -0,0 +1,78 @@ +use interpulse::api::minecraft::Version; +use onelauncher::data::Settings; +use onelauncher::settings; + +mod cluster; +pub use crate::api::commands::cluster::*; + +mod users; +pub use crate::api::commands::users::*; + +mod processor; +pub use crate::api::commands::processor::*; + +mod package; +pub use crate::api::commands::package::*; + +#[macro_export] +macro_rules! collect_commands { + () => {{ + use $crate::api::commands::*; + use $crate::ext::updater::*; + tauri_specta::collect_commands![ + // User + auth_login, + get_users, + get_user, + get_default_user, + set_default_user, + remove_user, + // Cluster + create_cluster, + edit_cluster, + remove_cluster, + get_cluster, + get_clusters, + run_cluster, + get_cluster_logs, + get_cluster_log, + upload_log, + // Processor + get_running_clusters, + get_processes_by_path, + kill_process, + // Settings + get_settings, + set_settings, + // Metadata + get_minecraft_versions, + // Package + random_mods, + get_mod, + download_mod, + // Updater + check_for_update, + install_update, + ] + }}; +} + +#[specta::specta] +#[tauri::command] +pub async fn get_minecraft_versions() -> Result, String> { + Ok(onelauncher::api::metadata::get_minecraft_versions() + .await? + .versions) +} + +#[specta::specta] +#[tauri::command] +pub async fn get_settings() -> Result { + Ok(settings::get().await?) +} + +#[specta::specta] +#[tauri::command] +pub async fn set_settings(settings: Settings) -> Result<(), String> { + Ok(settings::set(settings).await?) +} diff --git a/apps/desktop/src/api/commands/package.rs b/apps/desktop/src/api/commands/package.rs new file mode 100644 index 00000000..6e83fc1a --- /dev/null +++ b/apps/desktop/src/api/commands/package.rs @@ -0,0 +1,37 @@ +use onelauncher::{data::ManagedPackage, package::content}; +use uuid::Uuid; + +#[specta::specta] +#[tauri::command] +pub async fn random_mods() -> Result, String> { + let provider = content::Providers::Modrinth; + Ok(provider.list().await?) +} + +#[specta::specta] +#[tauri::command] +pub async fn get_mod(project_id: String) -> Result { + let provider = content::Providers::Modrinth; + Ok(provider.get(&project_id).await?) +} + +#[specta::specta] +#[tauri::command] +pub async fn download_mod(cluster_id: Uuid, version_id: String) -> Result<(), String> { + let cluster = onelauncher::cluster::get_by_uuid(cluster_id, None) + .await? + .ok_or("cluster not found")?; + let provider = content::Providers::Modrinth; + let game_version = cluster.meta.mc_version.clone(); + + provider + .get_version_for_game_version(&version_id, &game_version) + .await? + .files + .first() + .ok_or("no files found")? + .download_to_cluster(&cluster) + .await?; + + Ok(()) +} \ No newline at end of file diff --git a/apps/desktop/src/api/commands/processor.rs b/apps/desktop/src/api/commands/processor.rs new file mode 100644 index 00000000..b440cd59 --- /dev/null +++ b/apps/desktop/src/api/commands/processor.rs @@ -0,0 +1,21 @@ +use onelauncher::{processor, store::{Cluster, ClusterPath}}; +use uuid::Uuid; + +#[specta::specta] +#[tauri::command] +pub async fn get_running_clusters() -> Result, String> { + Ok(processor::get_running_clusters().await?) +} + +#[specta::specta] +#[tauri::command] +pub async fn get_processes_by_path(path: ClusterPath) -> Result, String> { + Ok(processor::get_uuids_by_cluster_path(path).await?) +} + +#[specta::specta] +#[tauri::command] +pub async fn kill_process(uuid: Uuid) -> Result<(), String> { + processor::kill_by_uuid(uuid).await?; + Ok(()) +} \ No newline at end of file diff --git a/apps/desktop/src/api/commands/users.rs b/apps/desktop/src/api/commands/users.rs new file mode 100644 index 00000000..7039f3e4 --- /dev/null +++ b/apps/desktop/src/api/commands/users.rs @@ -0,0 +1,100 @@ +use onelauncher::{data::MinecraftCredentials, minecraft}; +use tauri::{AppHandle, Manager}; +use uuid::Uuid; + +#[specta::specta] +#[tauri::command] +pub async fn get_users() -> Result, String> { + Ok(minecraft::users().await?) +} + +#[specta::specta] +#[tauri::command] +pub async fn get_user(uuid: Uuid) -> Result { + Ok(minecraft::get_user(uuid).await?) +} + +#[specta::specta] +#[tauri::command] +pub async fn remove_user(uuid: Uuid) -> Result<(), String> { + Ok(minecraft::remove_user(uuid).await?) +} + +#[specta::specta] +#[tauri::command] +pub async fn get_default_user() -> Result, String> { + let uuid = minecraft::get_default_user().await?; + + match uuid { + Some(uuid) => Ok(Some(minecraft::get_user(uuid).await?)), + None => Ok(None), + } +} + +#[specta::specta] +#[tauri::command] +pub async fn set_default_user(uuid: Uuid) -> Result<(), String> { + minecraft::set_default_user(uuid).await?; + Ok(()) +} + +#[specta::specta] +#[tauri::command] +pub async fn auth_login(handle: AppHandle) -> Result, String> { + let flow = minecraft::begin().await?; + let now = chrono::Utc::now(); + + if let Some(win) = handle.get_webview_window("login") { + win.close().map_err(|err| err.to_string())?; + } + + let win = tauri::WebviewWindowBuilder::new( + &handle, + "login", + tauri::WebviewUrl::External( + flow.redirect_uri + .parse() + .map_err(|_| anyhow::anyhow!("failed to parse auth redirect url")) + .map_err(|err| err.to_string())?, + ), + ) + .title("Log into OneLauncher") + .always_on_top(true) + .center() + .build() + .map_err(|err| err.to_string())?; + + win.request_user_attention(Some(tauri::UserAttentionType::Critical)) + .map_err(|err| err.to_string())?; + + while (chrono::Utc::now() - now) < chrono::Duration::minutes(10) { + if win.title().is_err() { + return Ok(None); + } + + if win + .url() + .map_err(|err| err.to_string())? + .as_str() + .starts_with("https://login.live.com/oauth20_desktop.srf") + { + if let Some((_, code)) = win + .url() + .map_err(|err| err.to_string())? + .query_pairs() + .find(|x| x.0 == "code") + { + win.close().map_err(|err| err.to_string())?; + let value = minecraft::finish(&code.clone(), flow).await?; + + return Ok(Some(value)); + } + } + + tokio::time::sleep(std::time::Duration::from_millis(50)).await; + } + + win.close().map_err(|err| err.to_string())?; + + Ok(None) +} \ No newline at end of file diff --git a/packages/core/src/api/logger.rs b/packages/core/src/api/cluster/content/logger.rs similarity index 100% rename from packages/core/src/api/logger.rs rename to packages/core/src/api/cluster/content/logger.rs diff --git a/packages/core/src/api/cluster/content/mod.rs b/packages/core/src/api/cluster/content/mod.rs new file mode 100644 index 00000000..5d892bc6 --- /dev/null +++ b/packages/core/src/api/cluster/content/mod.rs @@ -0,0 +1,2 @@ +pub mod screenshots; +pub mod logger; \ No newline at end of file diff --git a/packages/core/src/api/cluster/content/screenshots.rs b/packages/core/src/api/cluster/content/screenshots.rs new file mode 100644 index 00000000..2ff31a62 --- /dev/null +++ b/packages/core/src/api/cluster/content/screenshots.rs @@ -0,0 +1,30 @@ +use std::path::PathBuf; + +use crate::{utils::io, Result}; + +use crate::store::ClusterPath; + +/// Gets a list of screenshot file names from the [`ClusterPath`] +#[tracing::instrument] +pub async fn get_screenshots(cluster: &ClusterPath) -> Result> { + let dir = cluster.full_path().await?.join("screenshots"); + + if !dir.exists() { + io::create_dir(dir).await?; + return Ok(vec![]); + } + + let mut list = vec![]; + let mut files = io::read_dir(dir).await?; + while let Some(file) = files.next_entry().await? { + list.push(file.file_name().to_string_lossy().to_string()); + } + + Ok(list) +} + +#[tracing::instrument] +pub async fn get_screenshot_path(cluster: &ClusterPath, file_name: String) -> Result { + let dir = cluster.full_path().await?.join("screenshots"); + Ok(dir.join(file_name)) +} \ No newline at end of file diff --git a/packages/core/src/api/cluster/mod.rs b/packages/core/src/api/cluster/mod.rs index de49ddf2..0e1cd83d 100644 --- a/packages/core/src/api/cluster/mod.rs +++ b/packages/core/src/api/cluster/mod.rs @@ -25,6 +25,7 @@ use tokio::sync::RwLock; pub mod create; pub mod update; +pub mod content; /// get a cluster by its specified [`ClusterPath`]. #[tracing::instrument] @@ -60,13 +61,6 @@ pub async fn list(clear: Option) -> crate::Result> { .collect()) } -// #[tracing::instrument] -// pub async fn list_grouped(clear: Option) -> crate::Result> { -// let clusters = list(clear).await?; -// let mut map = HashMap::new(); - -// } - /// run a Minecraft [`Cluster`] using the default credentials. #[tracing::instrument] pub async fn run(path: &ClusterPath) -> crate::Result>> { diff --git a/packages/core/src/api/mod.rs b/packages/core/src/api/mod.rs index b21c9937..80706aaf 100644 --- a/packages/core/src/api/mod.rs +++ b/packages/core/src/api/mod.rs @@ -6,7 +6,6 @@ pub mod cluster; pub mod handler; pub mod ingress; pub mod java; -pub mod logger; pub mod metadata; pub mod minecraft; pub mod package; diff --git a/packages/core/src/store/clusters.rs b/packages/core/src/store/clusters.rs index 1e659593..45275f29 100644 --- a/packages/core/src/store/clusters.rs +++ b/packages/core/src/store/clusters.rs @@ -235,8 +235,8 @@ pub struct ClusterMeta { pub name: String, /// The user-facing group of the cluster stored as a string. - #[serde(default)] - pub group: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub group: Option, /// The associated Minecraft version of the cluster as last updated. pub mc_version: String, @@ -355,7 +355,7 @@ impl Cluster { path: PathBuf::new().join(&name), meta: ClusterMeta { name, - group: vec![], + group: None, mc_version: version, loader: Loader::Vanilla, loader_version: None, diff --git a/packages/core/src/utils/io.rs b/packages/core/src/utils/io.rs index f40e9caf..4b0021df 100644 --- a/packages/core/src/utils/io.rs +++ b/packages/core/src/utils/io.rs @@ -64,6 +64,21 @@ pub async fn read_dir(path: impl AsRef) -> Result) -> Result<(), IOError> { + let path = path.as_ref(); + if path.exists() { + return Ok(()); + } + + tokio::fs::create_dir(path) + .await + .map_err(|e| IOError::IOErrorWrapper { + source: e, + path: path.to_string_lossy().to_string(), + }) +} + /// Recursively creates a directory and all of its parent components if they are missing. pub async fn create_dir_all(path: impl AsRef) -> Result<(), IOError> { let path = path.as_ref();