feat:移除了弹窗,服务器添加sls
This commit is contained in:
405
apps/app/src/api/install.rs
Normal file
405
apps/app/src/api/install.rs
Normal file
@ -0,0 +1,405 @@
|
||||
use crate::api::Result;
|
||||
use crate::api::instance::InstanceLink;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
use theseus::data::ModLoader;
|
||||
use theseus::install::{
|
||||
ImportPlanRequest, InstallJobSnapshot, InstallModpackPreview,
|
||||
InstallPostInstallEdit,
|
||||
};
|
||||
use theseus::pack::import::ImportLauncherType;
|
||||
use theseus::pack::install_from::CreatePackLocation;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub fn init<R: tauri::Runtime>() -> tauri::plugin::TauriPlugin<R> {
|
||||
tauri::plugin::Builder::new("install")
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
install_get_modpack_preview,
|
||||
install_create_instance,
|
||||
install_create_modpack_instance,
|
||||
install_import_instance,
|
||||
install_start_import_plan,
|
||||
install_cancel_import_plan,
|
||||
install_duplicate_instance,
|
||||
install_existing_instance,
|
||||
install_pack_to_existing_instance,
|
||||
install_job_list,
|
||||
install_job_get,
|
||||
install_job_retry,
|
||||
install_job_repair_cache_and_retry,
|
||||
install_job_resume,
|
||||
install_job_skip_missing_content,
|
||||
install_job_missing_files,
|
||||
install_job_scan_missing_files,
|
||||
install_job_retry_missing_file,
|
||||
install_job_import_missing_file,
|
||||
install_job_cancel,
|
||||
install_job_dismiss,
|
||||
install_job_support_details,
|
||||
download_job_list,
|
||||
download_job_get,
|
||||
download_job_retry,
|
||||
download_job_resume,
|
||||
download_job_cancel,
|
||||
download_job_delete,
|
||||
download_history_clear,
|
||||
download_job_support_details,
|
||||
])
|
||||
.build()
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InstallCreateInstanceRequest {
|
||||
pub name: String,
|
||||
pub game_version: String,
|
||||
pub loader: ModLoader,
|
||||
pub loader_version: Option<String>,
|
||||
#[serde(default)]
|
||||
pub adjuncts: Vec<theseus::data::LoaderComponent>,
|
||||
pub icon_path: Option<String>,
|
||||
pub link: Option<InstanceLink>,
|
||||
#[serde(default)]
|
||||
pub game_dir_override: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct InstallPostInstallEditRequest {
|
||||
pub name: Option<String>,
|
||||
#[serde(
|
||||
default,
|
||||
skip_serializing_if = "Option::is_none",
|
||||
with = "serde_with::rust::double_option"
|
||||
)]
|
||||
pub icon_path: Option<Option<String>>,
|
||||
pub link: Option<InstanceLink>,
|
||||
}
|
||||
|
||||
impl InstallPostInstallEditRequest {
|
||||
fn into_core(self) -> Result<InstallPostInstallEdit> {
|
||||
Ok(InstallPostInstallEdit {
|
||||
name: self.name,
|
||||
icon_path: self.icon_path,
|
||||
link: self.link.map(|link| link.into_core()).transpose()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_get_modpack_preview(
|
||||
location: CreatePackLocation,
|
||||
) -> Result<InstallModpackPreview> {
|
||||
Ok(theseus::pack::install_from::get_instance_from_pack(location).await?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_create_instance(
|
||||
request: InstallCreateInstanceRequest,
|
||||
) -> Result<InstallJobSnapshot> {
|
||||
Ok(theseus::install::create_instance_with_adjuncts(
|
||||
request.name.trim().to_string(),
|
||||
request.game_version,
|
||||
request.loader,
|
||||
request.loader_version,
|
||||
request.adjuncts,
|
||||
request.icon_path,
|
||||
match request.link {
|
||||
Some(link) => link.into_core()?,
|
||||
None => theseus::data::InstanceLink::Unmanaged,
|
||||
},
|
||||
request.game_dir_override,
|
||||
)
|
||||
.await?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_create_modpack_instance(
|
||||
location: CreatePackLocation,
|
||||
post_install_edit: Option<InstallPostInstallEditRequest>,
|
||||
) -> Result<InstallJobSnapshot> {
|
||||
Ok(theseus::install::create_modpack_instance(
|
||||
location,
|
||||
post_install_edit.map(|edit| edit.into_core()).transpose()?,
|
||||
)
|
||||
.await?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_import_instance(
|
||||
launcher_type: ImportLauncherType,
|
||||
base_path: PathBuf,
|
||||
instance_folder: String,
|
||||
instance_path: Option<String>,
|
||||
symlink: bool,
|
||||
game_version: Option<String>,
|
||||
loader: Option<ModLoader>,
|
||||
loader_version: Option<String>,
|
||||
game_dir_override: Option<String>,
|
||||
) -> Result<InstallJobSnapshot> {
|
||||
tracing::debug!(
|
||||
"install_import_instance called: launcher_type={launcher_type:?} base_path={} instance_folder={} instance_path={:?} symlink={symlink} game_version={game_version:?} loader={loader:?} loader_version={loader_version:?} game_dir_override={game_dir_override:?}",
|
||||
base_path.display(),
|
||||
instance_folder,
|
||||
instance_path,
|
||||
);
|
||||
// Extracted launcher archives live in a temporary folder that is removed
|
||||
// after the import; a symlink into it would dangle immediately.
|
||||
if symlink
|
||||
&& base_path
|
||||
.starts_with(std::env::temp_dir().join("axolotl-launcher-import"))
|
||||
{
|
||||
return Err(theseus::Error::from(theseus::ErrorKind::InputError(
|
||||
"Symbolic-link import is unavailable for extracted archives: \
|
||||
the temporary folder is deleted after the import completes. \
|
||||
Choose copy instead."
|
||||
.to_string(),
|
||||
))
|
||||
.into());
|
||||
}
|
||||
Ok(theseus::install::import_instance_with_plan(
|
||||
launcher_type,
|
||||
base_path,
|
||||
instance_folder,
|
||||
instance_path,
|
||||
symlink,
|
||||
game_version,
|
||||
loader,
|
||||
loader_version,
|
||||
game_dir_override,
|
||||
)
|
||||
.await?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_start_import_plan(
|
||||
request: ImportPlanRequest,
|
||||
) -> Result<String> {
|
||||
Ok(theseus::install::start_import_plan(request)?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_cancel_import_plan(request_id: String) -> Result<()> {
|
||||
Ok(theseus::install::cancel_import_plan(&request_id).await?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_duplicate_instance(
|
||||
source_instance_id: String,
|
||||
) -> Result<InstallJobSnapshot> {
|
||||
Ok(theseus::install::duplicate_instance(source_instance_id).await?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_existing_instance(
|
||||
instance_id: String,
|
||||
force: bool,
|
||||
) -> Result<InstallJobSnapshot> {
|
||||
Ok(theseus::install::install_existing_instance(instance_id, force).await?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_pack_to_existing_instance(
|
||||
instance_id: String,
|
||||
location: CreatePackLocation,
|
||||
post_install_edit: Option<InstallPostInstallEditRequest>,
|
||||
) -> Result<InstallJobSnapshot> {
|
||||
Ok(theseus::install::install_pack_to_existing_instance(
|
||||
instance_id,
|
||||
location,
|
||||
post_install_edit.map(|edit| edit.into_core()).transpose()?,
|
||||
)
|
||||
.await?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_job_list(
|
||||
include_finished: bool,
|
||||
) -> Result<Vec<InstallJobSnapshot>> {
|
||||
Ok(theseus::install::list_jobs(include_finished).await?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_job_get(job_id: Uuid) -> Result<InstallJobSnapshot> {
|
||||
Ok(theseus::install::get_job(job_id).await?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_job_retry(job_id: Uuid) -> Result<InstallJobSnapshot> {
|
||||
Ok(theseus::install::retry_job(job_id).await?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_job_repair_cache_and_retry(
|
||||
job_id: Uuid,
|
||||
) -> Result<InstallJobSnapshot> {
|
||||
Ok(theseus::install::repair_cache_and_retry_job(job_id).await?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_job_resume(job_id: Uuid) -> Result<InstallJobSnapshot> {
|
||||
Ok(theseus::install::resume_job(job_id).await?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_job_skip_missing_content(
|
||||
job_id: Uuid,
|
||||
) -> Result<InstallJobSnapshot> {
|
||||
Ok(theseus::install::skip_missing_content_and_resume_job(job_id).await?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_job_missing_files(
|
||||
job_id: Uuid,
|
||||
) -> Result<theseus::install::MissingModpackContentView> {
|
||||
Ok(theseus::install::list_missing_modpack_files(job_id).await?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_job_scan_missing_files(
|
||||
job_id: Uuid,
|
||||
scan_directory: Option<PathBuf>,
|
||||
) -> Result<theseus::install::MissingModpackScanResult> {
|
||||
Ok(
|
||||
theseus::install::scan_missing_modpack_files(job_id, scan_directory)
|
||||
.await?,
|
||||
)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_job_retry_missing_file(
|
||||
job_id: Uuid,
|
||||
item_id: String,
|
||||
) -> Result<InstallJobSnapshot> {
|
||||
Ok(theseus::install::retry_missing_modpack_file(job_id, item_id).await?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_job_import_missing_file(
|
||||
job_id: Uuid,
|
||||
item_id: String,
|
||||
selected_file_path: PathBuf,
|
||||
) -> Result<InstallJobSnapshot> {
|
||||
Ok(theseus::install::import_missing_modpack_file(
|
||||
job_id,
|
||||
item_id,
|
||||
selected_file_path,
|
||||
)
|
||||
.await?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_job_cancel(job_id: Uuid) -> Result<InstallJobSnapshot> {
|
||||
Ok(theseus::install::cancel_job(job_id).await?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_job_dismiss(job_id: Uuid) -> Result<()> {
|
||||
Ok(theseus::install::dismiss_job(job_id).await?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_job_support_details(job_id: String) -> Result<String> {
|
||||
let Ok(uuid) = Uuid::parse_str(&job_id) else {
|
||||
// Synthetic, frontend-tracked jobs (e.g. server downloads) use non-UUID
|
||||
// identifiers and do not expose backend diagnostic details.
|
||||
return Ok(String::new());
|
||||
};
|
||||
Ok(theseus::install::job_support_details(uuid).await?)
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DownloadJobListRequest {
|
||||
pub status: Option<String>,
|
||||
pub provider: Option<String>,
|
||||
pub query: Option<String>,
|
||||
pub cursor: Option<String>,
|
||||
pub limit: Option<usize>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DownloadJobPage {
|
||||
pub jobs: Vec<InstallJobSnapshot>,
|
||||
pub next_cursor: Option<String>,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn download_job_list(
|
||||
request: Option<DownloadJobListRequest>,
|
||||
) -> Result<DownloadJobPage> {
|
||||
let request = request.unwrap_or_default();
|
||||
let mut jobs = theseus::install::list_jobs(true).await?;
|
||||
if let Some(status) = request.status.as_deref() {
|
||||
jobs.retain(|job| job.status.as_str() == status);
|
||||
}
|
||||
if let Some(provider) = request.provider.as_deref() {
|
||||
jobs.retain(|job| {
|
||||
format!("{:?}", job.provider)
|
||||
.to_ascii_lowercase()
|
||||
.replace('_', "")
|
||||
== provider.to_ascii_lowercase().replace('_', "")
|
||||
});
|
||||
}
|
||||
if let Some(query) = request.query.as_deref() {
|
||||
let query = query.trim().to_ascii_lowercase();
|
||||
if !query.is_empty() {
|
||||
jobs.retain(|job| {
|
||||
job.display.as_ref().is_some_and(|display| {
|
||||
display.title.to_ascii_lowercase().contains(&query)
|
||||
}) || job.job_id.to_string().contains(&query)
|
||||
});
|
||||
}
|
||||
}
|
||||
jobs.sort_by(|a, b| b.created.cmp(&a.created));
|
||||
let offset = request
|
||||
.cursor
|
||||
.as_deref()
|
||||
.and_then(|cursor| cursor.parse::<usize>().ok())
|
||||
.unwrap_or(0);
|
||||
let limit = request.limit.unwrap_or(100).clamp(1, 250);
|
||||
let jobs = jobs
|
||||
.into_iter()
|
||||
.skip(offset)
|
||||
.take(limit)
|
||||
.collect::<Vec<_>>();
|
||||
let next_cursor =
|
||||
(jobs.len() == limit).then(|| (offset + limit).to_string());
|
||||
Ok(DownloadJobPage { jobs, next_cursor })
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn download_job_get(job_id: Uuid) -> Result<InstallJobSnapshot> {
|
||||
install_job_get(job_id).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn download_job_retry(job_id: Uuid) -> Result<InstallJobSnapshot> {
|
||||
Ok(theseus::install::retry_job_as_new(job_id).await?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn download_job_resume(job_id: Uuid) -> Result<InstallJobSnapshot> {
|
||||
install_job_resume(job_id).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn download_job_cancel(job_id: Uuid) -> Result<InstallJobSnapshot> {
|
||||
install_job_cancel(job_id).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn download_job_delete(job_id: Uuid) -> Result<()> {
|
||||
install_job_dismiss(job_id).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn download_history_clear() -> Result<u64> {
|
||||
Ok(theseus::install::clear_job_history().await?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn download_job_support_details(job_id: String) -> Result<String> {
|
||||
install_job_support_details(job_id).await
|
||||
}
|
||||
Reference in New Issue
Block a user