diff --git a/apps/oneclient/desktop/src/oneclient/bundles.rs b/apps/oneclient/desktop/src/oneclient/bundles.rs index f5d32859..10430565 100644 --- a/apps/oneclient/desktop/src/oneclient/bundles.rs +++ b/apps/oneclient/desktop/src/oneclient/bundles.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; use std::path::PathBuf; -use std::sync::Arc; use onelauncher_core::api::packages::modpack::data::ModpackArchive; use onelauncher_core::api::packages::modpack::{InstallableModpackFormatExt, ModpackFormat}; @@ -216,7 +215,7 @@ async fn download_and_load_bundle( tracing::debug!("downloading bundle from remote: {url}"); // if we are at this point, it means we either need to update or download - let bytes = http::download(Method::GET, &url, disk_path, None, None).await?; + http::download(Method::GET, &url, disk_path, None, None).await?; - Ok(ModpackFormat::from_bytes(Arc::new(bytes.to_vec())).await?) + Ok(ModpackFormat::from_file(disk_path).await?) } diff --git a/apps/oneclient/desktop/src/oneclient/mod.rs b/apps/oneclient/desktop/src/oneclient/mod.rs index 5e5558ff..e344e9b9 100644 --- a/apps/oneclient/desktop/src/oneclient/mod.rs +++ b/apps/oneclient/desktop/src/oneclient/mod.rs @@ -5,4 +5,8 @@ pub async fn initialize_oneclient() { if let Err(err) = clusters::init_clusters().await { tracing::error!("failed to initialize clusters: {err}"); } + + tokio::spawn(async { + bundles::BundlesManager::get().await; + }); } diff --git a/apps/oneclient/frontend/src/bindings.gen.ts b/apps/oneclient/frontend/src/bindings.gen.ts index 99379545..998b373b 100644 --- a/apps/oneclient/frontend/src/bindings.gen.ts +++ b/apps/oneclient/frontend/src/bindings.gen.ts @@ -189,7 +189,7 @@ export type SettingProfileModel = { name: string; java_id: number | null; res: R export type Settings = { global_game_settings: SettingProfileModel; allow_parallel_running_clusters: boolean; enable_gamemode: boolean; discord_enabled: boolean; max_concurrent_requests: number; settings_version: number; native_window_frame: boolean } -export type SettingsOsExtra = Record +export type SettingsOsExtra = { enable_gamemode: boolean | null } export type SkinVariant = "classic" | "slim" @@ -254,8 +254,13 @@ export type VersionType = */ "old_beta" -const ARGS_MAP = { 'core':'{"getDefaultUser":["fallback"],"fetchLoggedInProfile":["access_token"],"changeSkin":["access_token","skin_url","skin_variant"],"getClusterById":["id"],"launchCluster":["id","uuid"],"getUsers":[],"updateClusterProfile":["name","profile"],"getWorlds":["id"],"getPackageVersions":["provider","slug","mc_version","loader","offset","limit"],"getClusters":[],"getLogByName":["id","name"],"setDefaultUser":["uuid"],"open":["input"],"openMsaLogin":[],"removeCluster":["id"],"searchPackages":["provider","query"],"getGlobalProfile":[],"updateClusterById":["id","request"],"isClusterRunning":["cluster_id"],"downloadPackage":["provider","package_id","version_id","cluster_id","skip_compatibility"],"installModpack":["modpack","cluster_id"],"fetchMinecraftProfile":["uuid"],"getRunningProcesses":[],"getUser":["uuid"],"killProcess":["pid"],"removeUser":["uuid"],"getRunningProcessesByClusterId":["cluster_id"],"convertUsernameUUID":["username_uuid"],"uploadSkinBytes":["access_token","skin_data","image_format","skin_variant"],"getScreenshots":["id"],"getPackageBody":["provider","body"],"changeCape":["access_token","cape_uuid"],"removeCape":["access_token"],"getMultiplePackages":["provider","slugs"],"getLoadersForVersion":["mc_version"],"getPackage":["provider","slug"],"getUsersFromAuthor":["provider","author"],"readSettings":[],"createCluster":["options"],"createSettingsProfile":["name"],"writeSettings":["setting"],"getLogs":["id"],"getGameVersions":[],"getProfileOrDefault":["name"]}', 'events':'{"message":["event"],"process":["event"],"ingress":["event"]}', 'oneclient':'{"openDevTools":[],"getClustersGroupedByMajor":[],"getBundlesFor":["cluster_id"]}', 'folders':'{"fromCluster":["folder_name"],"openCluster":["folder_name"]}' } -export type Router = { 'core': { getClusters: () => Promise, +const ARGS_MAP = { 'events':'{"message":["event"],"process":["event"],"ingress":["event"]}', 'folders':'{"openCluster":["folder_name"],"fromCluster":["folder_name"]}', 'oneclient':'{"getClustersGroupedByMajor":[],"getBundlesFor":["cluster_id"],"openDevTools":[]}', 'core':'{"getLogByName":["id","name"],"getGlobalProfile":[],"getUsers":[],"getPackageVersions":["provider","slug","mc_version","loader","offset","limit"],"updateClusterProfile":["name","profile"],"searchPackages":["provider","query"],"getPackage":["provider","slug"],"launchCluster":["id","uuid"],"installModpack":["modpack","cluster_id"],"writeSettings":["setting"],"convertUsernameUUID":["username_uuid"],"getUsersFromAuthor":["provider","author"],"openMsaLogin":[],"open":["input"],"getClusters":[],"isClusterRunning":["cluster_id"],"getLoadersForVersion":["mc_version"],"getPackageBody":["provider","body"],"fetchMinecraftProfile":["uuid"],"changeSkin":["access_token","skin_url","skin_variant"],"getUser":["uuid"],"createCluster":["options"],"createSettingsProfile":["name"],"getClusterById":["id"],"setDefaultUser":["uuid"],"killProcess":["pid"],"fetchLoggedInProfile":["access_token"],"getRunningProcesses":[],"removeCluster":["id"],"getGameVersions":[],"getWorlds":["id"],"removeUser":["uuid"],"getRunningProcessesByClusterId":["cluster_id"],"updateClusterById":["id","request"],"readSettings":[],"changeCape":["access_token","cape_uuid"],"downloadPackage":["provider","package_id","version_id","cluster_id","skip_compatibility"],"getLogs":["id"],"uploadSkinBytes":["access_token","skin_data","image_format","skin_variant"],"getScreenshots":["id"],"getProfileOrDefault":["name"],"getMultiplePackages":["provider","slugs"],"getDefaultUser":["fallback"],"removeCape":["access_token"]}' } +export type Router = { 'folders': { fromCluster: (folderName: string) => Promise, +openCluster: (folderName: string) => Promise }, +'oneclient': { openDevTools: () => Promise, +getClustersGroupedByMajor: () => Promise>, +getBundlesFor: (clusterId: number) => Promise }, +'core': { getClusters: () => Promise, getClusterById: (id: number) => Promise, removeCluster: (id: number) => Promise, createCluster: (options: CreateCluster) => Promise, @@ -301,12 +306,7 @@ convertUsernameUUID: (usernameUuid: string) => Promise, open: (input: string) => Promise }, 'events': { ingress: (event: IngressPayload) => Promise, message: (event: MessagePayload) => Promise, -process: (event: ProcessPayload) => Promise }, -'folders': { fromCluster: (folderName: string) => Promise, -openCluster: (folderName: string) => Promise }, -'oneclient': { openDevTools: () => Promise, -getClustersGroupedByMajor: () => Promise>, -getBundlesFor: (clusterId: number) => Promise } }; +process: (event: ProcessPayload) => Promise } }; export type { InferCommandOutput } diff --git a/apps/oneclient/frontend/src/routes/app/cluster/overview.tsx b/apps/oneclient/frontend/src/routes/app/cluster/overview.tsx index 8c9c8192..dd09a1a1 100644 --- a/apps/oneclient/frontend/src/routes/app/cluster/overview.tsx +++ b/apps/oneclient/frontend/src/routes/app/cluster/overview.tsx @@ -1,4 +1,6 @@ import { SheetPage } from '@/components/SheetPage'; +import { bindings } from '@/main'; +import { useCommandSuspense } from '@onelauncher/common'; import { createFileRoute } from '@tanstack/react-router'; export const Route = createFileRoute('/app/cluster/overview')({ @@ -14,7 +16,11 @@ function RouteComponent() {

Cluster Overview

Welcome to the cluster overview page. Here you can find information about your clusters.

- Cluster Name: {cluster.name} + Cluster Name: + {' '} + {cluster.name} + +

test

{/* Additional content can be added here */} @@ -22,3 +28,24 @@ function RouteComponent() { ); } + +function TestBundles() { + const { cluster } = Route.useRouteContext(); + + const { data: bundles } = useCommandSuspense(['getBundlesFor', cluster.id], () => bindings.oneclient.getBundlesFor(cluster.id)); + + return ( +
+

Bundles

+
    + {bundles.map(bundle => ( +
  • + + {JSON.stringify(bundle, null, 4)} + +
  • + ))} +
+
+ ); +} diff --git a/packages/core/src/api/packages/modpack/mod.rs b/packages/core/src/api/packages/modpack/mod.rs index 1ce37c86..b2e345ba 100644 --- a/packages/core/src/api/packages/modpack/mod.rs +++ b/packages/core/src/api/packages/modpack/mod.rs @@ -30,13 +30,13 @@ pub enum ModpackFormat { } const FORMAT_PIPELINE_PATH: &[LoaderFn] = &[ - PolyMrPackFormatImpl::from_file, // has to be first because of it being a **VALID** mrpack with extra stuff - MrPackFormatImpl::from_file, + PolyMrPackFormatImpl::from_path, // has to be first because of it being a **VALID** mrpack with extra stuff + MrPackFormatImpl::from_path, ]; const FORMAT_PIPELINE_BYTES: &[LoaderFn>>] = &[ - PolyMrPackFormatImpl::from_bytes, // has to be first because of it being a **VALID** mrpack with extra stuff - MrPackFormatImpl::from_bytes, + PolyMrPackFormatImpl::from_manifest_bytes, // has to be first because of it being a **VALID** mrpack with extra stuff + MrPackFormatImpl::from_manifest_bytes, ]; type LoaderFn = fn( @@ -47,13 +47,13 @@ type LoaderFn = fn( #[async_trait::async_trait] pub trait ModpackFormatExt { - async fn from_file( + async fn from_path( path: PathBuf, ) -> LauncherResult>> where Self: Sized; - async fn from_bytes( + async fn from_manifest_bytes( bytes: Arc>, ) -> LauncherResult>> where @@ -95,7 +95,7 @@ impl ModpackFormat { Err(PackageError::UnsupportedModpackFormat.into()) } - pub async fn from_bytes( + pub async fn from_manifest_bytes( bytes: Arc>, ) -> LauncherResult> { for stage in FORMAT_PIPELINE_BYTES { diff --git a/packages/core/src/api/packages/modpack/mrpack.rs b/packages/core/src/api/packages/modpack/mrpack.rs index ee559be0..95f4b751 100644 --- a/packages/core/src/api/packages/modpack/mrpack.rs +++ b/packages/core/src/api/packages/modpack/mrpack.rs @@ -35,7 +35,7 @@ pub(super) const MODRINTH_URL_PREFIX: &str = "https://cdn.modrinth.com/"; #[async_trait::async_trait] impl ModpackFormatExt for MrPackFormatImpl { - async fn from_file( + async fn from_path( path: std::path::PathBuf, ) -> LauncherResult>> where @@ -48,7 +48,7 @@ impl ModpackFormatExt for MrPackFormatImpl { let manifest_file = io::try_read_zip_entry_bytes(buf_reader, "modrinth.index.json").await?; - let Some(this) = Self::from_bytes(Arc::new(manifest_file)).await? else { + let Some(this) = Self::from_manifest_bytes(Arc::new(manifest_file)).await? else { return Ok(None); }; @@ -61,7 +61,7 @@ impl ModpackFormatExt for MrPackFormatImpl { Ok(Some(this)) } - async fn from_bytes( + async fn from_manifest_bytes( bytes: Arc>, ) -> LauncherResult>> where diff --git a/packages/core/src/api/packages/modpack/polymrpack.rs b/packages/core/src/api/packages/modpack/polymrpack.rs index 240aff94..d24b8fbe 100644 --- a/packages/core/src/api/packages/modpack/polymrpack.rs +++ b/packages/core/src/api/packages/modpack/polymrpack.rs @@ -31,7 +31,7 @@ pub struct PolyMrPackFormatImpl { #[async_trait::async_trait] impl ModpackFormatExt for PolyMrPackFormatImpl { - async fn from_file( + async fn from_path( path: std::path::PathBuf, ) -> LauncherResult>> where @@ -44,7 +44,7 @@ impl ModpackFormatExt for PolyMrPackFormatImpl { let manifest_file = io::try_read_zip_entry_bytes(buf_reader, "modrinth.index.json").await?; - let Some(this) = Self::from_bytes(Arc::new(manifest_file)).await? else { + let Some(this) = Self::from_manifest_bytes(Arc::new(manifest_file)).await? else { return Ok(None); }; @@ -57,7 +57,7 @@ impl ModpackFormatExt for PolyMrPackFormatImpl { Ok(Some(this)) } - async fn from_bytes( + async fn from_manifest_bytes( bytes: Arc>, ) -> LauncherResult>> where @@ -146,7 +146,9 @@ impl InstallableModpackFormatExt for PolyMrPackFormatImpl { return Ok(manifest); } - let files = to_modpack_files(&self.raw_manifest.files).await?; + let files = to_modpack_files(&self.raw_manifest.files) + .await + .map_err(|e| anyhow::anyhow!("failed to parse polymrpack files: {e}"))?; let manifest = ModpackManifest { name: self.raw_manifest.name.clone(),