Files
Starlight_Launcher/packages/app-lib/src/api/instance/planet_minecraft.rs
T

135 lines
4.2 KiB
Rust

use crate::api::planet_minecraft::PlanetMinecraftInstallRoute;
use crate::state::instances::commands::add_project_bytes;
use crate::state::{ContentSourceKind, ProjectType, State};
use bytes::Bytes;
use std::path::PathBuf;
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PlanetMinecraftContentInstallRequest {
pub project_id: String,
pub version_id: String,
pub project_type: ProjectType,
}
#[derive(Clone, Debug, serde::Serialize)]
#[serde(tag = "state", rename_all = "snake_case")]
pub enum PlanetMinecraftContentInstallResult {
Installed {
relative_path: String,
},
ManualDownload {
page_url: String,
file_name: Option<String>,
},
}
pub async fn install_planet_minecraft_content(
instance_id: &str,
request: PlanetMinecraftContentInstallRequest,
) -> crate::Result<PlanetMinecraftContentInstallResult> {
let project =
crate::api::planet_minecraft::get_project(&request.project_id).await?;
let version = project
.versions
.iter()
.find(|version| version.id == request.version_id)
.ok_or_else(|| {
crate::ErrorKind::InputError(
"The selected Planet Minecraft release is no longer available"
.to_string(),
)
})?;
match version.download.install_route() {
PlanetMinecraftInstallRoute::Manual {
page_url,
file_name,
} => Ok(PlanetMinecraftContentInstallResult::ManualDownload {
page_url,
file_name,
}),
PlanetMinecraftInstallRoute::Automatic {
direct_url,
sha256,
file_name,
} => {
let bytes = crate::api::planet_minecraft::download_verified_file(
&direct_url,
&sha256,
)
.await?;
let name =
file_name.unwrap_or_else(|| format!("{}.jar", version.name));
let state = State::get().await?;
let relative_path = add_project_bytes(
instance_id,
&name,
Bytes::from(bytes),
None,
Some(request.project_type),
ContentSourceKind::Local,
&state,
)
.await?;
super::emit_content_changed(instance_id).await?;
Ok(
PlanetMinecraftContentInstallResult::Installed {
relative_path,
},
)
}
}
}
pub async fn import_planet_minecraft_content(
instance_id: &str,
request: PlanetMinecraftContentInstallRequest,
source_path: PathBuf,
) -> crate::Result<PlanetMinecraftContentInstallResult> {
let project =
crate::api::planet_minecraft::get_project(&request.project_id).await?;
let version = project
.versions
.iter()
.find(|version| version.id == request.version_id)
.ok_or_else(|| {
crate::ErrorKind::InputError(
"The selected Planet Minecraft release is no longer available"
.to_string(),
)
})?;
let PlanetMinecraftInstallRoute::Manual {
file_name,
page_url: _,
} = version.download.install_route()
else {
return Err(crate::ErrorKind::InputError(
"This Planet Minecraft release has a verified direct download; use automatic installation"
.to_string(),
)
.into());
};
let metadata = tokio::fs::metadata(&source_path).await?;
if !metadata.is_file() {
return Err(crate::ErrorKind::InputError(
"The selected Planet Minecraft import must be a regular file"
.to_string(),
)
.into());
}
let bytes = tokio::fs::read(&source_path).await?;
let state = State::get().await?;
let relative_path = add_project_bytes(
instance_id,
file_name.as_deref().unwrap_or("planet-minecraft.jar"),
Bytes::from(bytes),
None,
Some(request.project_type),
ContentSourceKind::Local,
&state,
)
.await?;
super::emit_content_changed(instance_id).await?;
Ok(PlanetMinecraftContentInstallResult::Installed { relative_path })
}