feat: sync Aeronautics from launcher v2

This commit is contained in:
emil28092005
2026-09-06 01:06:29 +03:00
parent f4cfe601fd
commit ad98fb701d
4 changed files with 126 additions and 6 deletions
+27
View File
@@ -1,6 +1,7 @@
mod java;
mod manifest;
mod profile;
mod remote;
mod settings;
use serde::Serialize;
@@ -76,6 +77,30 @@ async fn sync_profile(app: AppHandle, manifest_json: String) -> Result<profile::
.map_err(|error| error.to_string())
}
/// Loads and validates the published ShaCraft manifest before inspecting a profile.
#[tauri::command]
async fn inspect_remote_profile(app: AppHandle, profile_id: String) -> Result<profile::ProfileInspection, String> {
let data_dir = app.path().app_data_dir()
.map_err(|error| format!("Cannot resolve launcher data directory: {error}"))?;
tauri::async_runtime::spawn_blocking(move || {
let manifest = remote::fetch_manifest(&profile_id).map_err(|error| error.to_string())?;
profile::inspect(&data_dir.join("profiles").join(&manifest.id), &manifest)
.map_err(|error| error.to_string())
}).await.map_err(|error| format!("Profile inspection task failed: {error}"))?
}
/// Downloads missing or changed ShaCraft-managed files from the fixed v2 endpoint.
#[tauri::command]
async fn sync_remote_profile(app: AppHandle, profile_id: String) -> Result<profile::SyncResult, String> {
let data_dir = app.path().app_data_dir()
.map_err(|error| format!("Cannot resolve launcher data directory: {error}"))?;
tauri::async_runtime::spawn_blocking(move || {
let manifest = remote::fetch_manifest(&profile_id).map_err(|error| error.to_string())?;
profile::sync(&data_dir.join("profiles").join(&manifest.id), &manifest)
.map_err(|error| error.to_string())
}).await.map_err(|error| format!("Profile synchronization task failed: {error}"))?
}
#[tauri::command]
async fn load_settings(app: AppHandle) -> Result<settings::LauncherSettings, String> {
let data_dir = app
@@ -108,6 +133,8 @@ pub fn run() {
validate_manifest,
inspect_profile,
sync_profile,
inspect_remote_profile,
sync_remote_profile,
load_settings,
save_settings
])
+48
View File
@@ -0,0 +1,48 @@
use crate::manifest::{self, Manifest};
use reqwest::{blocking::Client, redirect::Policy};
use std::{fmt, time::Duration};
const AERONAUTICS_MANIFEST: &str =
"https://shacraft.ru/api/launcher/v2/profiles/aeronautics/manifest";
#[derive(Debug)]
pub enum RemoteError {
UnknownProfile,
Network(reqwest::Error),
Status(reqwest::StatusCode),
TooLarge,
InvalidManifest(manifest::ManifestError),
}
impl fmt::Display for RemoteError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::UnknownProfile => formatter.write_str("Unknown ShaCraft profile"),
Self::Network(error) => write!(formatter, "Cannot load ShaCraft manifest: {error}"),
Self::Status(status) => write!(formatter, "ShaCraft manifest request failed: {status}"),
Self::TooLarge => formatter.write_str("ShaCraft manifest is too large"),
Self::InvalidManifest(error) => write!(formatter, "ShaCraft manifest is invalid: {error}"),
}
}
}
pub fn fetch_manifest(profile_id: &str) -> Result<Manifest, RemoteError> {
let url = match profile_id {
"aeronautics" => AERONAUTICS_MANIFEST,
_ => return Err(RemoteError::UnknownProfile),
};
let client = Client::builder()
.timeout(Duration::from_secs(30))
.redirect(Policy::none())
.build()
.map_err(RemoteError::Network)?;
let response = client.get(url).send().map_err(RemoteError::Network)?;
if !response.status().is_success() {
return Err(RemoteError::Status(response.status()));
}
if response.content_length().is_some_and(|size| size > 2 * 1024 * 1024) {
return Err(RemoteError::TooLarge);
}
let source = response.text().map_err(RemoteError::Network)?;
manifest::validate_json(&source).map_err(RemoteError::InvalidManifest)
}