- ProcessManager 新增 has_instance_process(备份启动守卫依赖) - 删除/启动/编辑/迁移目录时接入备份维护钩子(lock_instance_maintenance + begin_instance_deletion + delete_instance_backups),remove_instance 拆出 remove_instance_files_and_state - run 启动前检查活跃备份操作并加维护锁 - 目录迁移时搬移默认备份仓库并入队清理 - 更新 settings SELECT 的 SQLX 离线缓存(补 ui_font/backup_repository_path/mono_font) - create_recorded_symlink 非 Windows 未用参数加 cfg_attr 豁免
This commit is contained in:
1 parent
4674f31dd3
commit
996044bdc2
7 files changed
+94
-3
No files matched your search
+21
-3
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT\n max_concurrent_writes, max_concurrent_downloads,\n auto_concurrent_downloads, minecraft_metadata_source,\n minecraft_file_source, modrinth_source, curseforge_source, mojang_auth_source,\n theme, locale, default_page, collapsed_navigation, hide_nametag_skins_page, advanced_rendering, native_decorations,\n\t\t\t\tdiscord_rpc, developer_mode, telemetry, telemetry_consent_version, personalized_ads,\n onboarded, onboarding_version, onboarding_instance_tour_completed,\n json(extra_launch_args) extra_launch_args, json(custom_env_vars) custom_env_vars,\n mc_memory_max, mc_memory_auto, mc_force_fullscreen, mc_maximize_window, mc_game_resolution_x, mc_game_resolution_y, hide_on_process_start, enter_lightweight_mode_on_game_launch,\n auto_set_java_high_performance_mode,\n hook_pre_launch, hook_wrapper, hook_post_exit,\n custom_dir, prev_custom_dir, migrated, json(feature_flags) feature_flags, toggle_sidebar,\n skipped_update, pending_update_toast_for_version, auto_download_updates, accent_color,\n custom_background_path, custom_background_blur, custom_background_opacity,\n transparent_background, transparent_background_opacity, transparent_background_blur,\n sidebar_instance_count, home_layout, minimal_home_instance_id,\n json(home_widgets) as \"home_widgets?: String\", auto_hide_downloads_button,\n json(terracotta_public_nodes) terracotta_public_nodes,\n ui_scale,\n version\n FROM settings\n ",
|
||||
"query": "\n SELECT\n max_concurrent_writes, max_concurrent_downloads,\n auto_concurrent_downloads, minecraft_metadata_source,\n minecraft_file_source, modrinth_source, curseforge_source, mojang_auth_source,\n theme, locale, default_page, collapsed_navigation, hide_nametag_skins_page, advanced_rendering, native_decorations,\n\t\t\t\tdiscord_rpc, developer_mode, telemetry, telemetry_consent_version, personalized_ads,\n onboarded, onboarding_version, onboarding_instance_tour_completed,\n json(extra_launch_args) extra_launch_args, json(custom_env_vars) custom_env_vars,\n mc_memory_max, mc_memory_auto, mc_force_fullscreen, mc_maximize_window, mc_game_resolution_x, mc_game_resolution_y, hide_on_process_start, enter_lightweight_mode_on_game_launch,\n auto_set_java_high_performance_mode,\n hook_pre_launch, hook_wrapper, hook_post_exit,\n custom_dir, prev_custom_dir, migrated, json(feature_flags) feature_flags, toggle_sidebar,\n skipped_update, pending_update_toast_for_version, auto_download_updates, accent_color,\n custom_background_path, custom_background_blur, custom_background_opacity,\n transparent_background, transparent_background_opacity, transparent_background_blur,\n sidebar_instance_count, home_layout, minimal_home_instance_id,\n json(home_widgets) as \"home_widgets?: String\", auto_hide_downloads_button,\n json(terracotta_public_nodes) terracotta_public_nodes,\n ui_scale,\n ui_font,\n backup_repository_path,\n mono_font,\n version\n FROM settings\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -299,8 +299,23 @@
|
||||
"type_info": "Float"
|
||||
},
|
||||
{
|
||||
"name": "version",
|
||||
"name": "ui_font",
|
||||
"ordinal": 59,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "backup_repository_path",
|
||||
"ordinal": 60,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "mono_font",
|
||||
"ordinal": 61,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "version",
|
||||
"ordinal": 62,
|
||||
"type_info": "Integer"
|
||||
}
|
||||
],
|
||||
@@ -367,8 +382,11 @@
|
||||
false,
|
||||
null,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "a00177609aec1a056ec47d46d4acd6d1a6244434991d3624b70c7734a2ab85c3"
|
||||
"hash": "52d2d61ed9239875d6188417f74bbde439c49582e1e81f5acb7b52d769a1bc18"
|
||||
}
|
||||
@@ -3632,6 +3632,7 @@ async fn verify_object(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg_attr(not(windows), allow(unused_variables))]
|
||||
async fn create_recorded_symlink(
|
||||
target: PathBuf,
|
||||
link: PathBuf,
|
||||
|
||||
@@ -103,6 +103,7 @@ pub async fn edit(
|
||||
patch: EditInstance,
|
||||
) -> crate::Result<InstanceMetadata> {
|
||||
let state = State::get().await?;
|
||||
super::ensure_backup_eligible_edit(instance_id, &patch).await?;
|
||||
crate::state::edit_instance(instance_id, patch, &state.pool).await?;
|
||||
|
||||
let instance = crate::state::get_instance(instance_id, &state.pool)
|
||||
|
||||
@@ -75,6 +75,15 @@ async fn run_with_extra_launch_args_inner(
|
||||
extra_launch_args: Option<Vec<String>>,
|
||||
gc_intent: Option<GcLaunchIntent>,
|
||||
) -> crate::Result<(ProcessMetadata, Option<GcLaunchReport>)> {
|
||||
if crate::api::instance::has_active_instance_operation(instance_id) {
|
||||
return Err(crate::ErrorKind::InputError(
|
||||
"Wait for the active backup operation to finish before launching this instance"
|
||||
.to_string(),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
let _maintenance_guard =
|
||||
crate::api::instance::lock_instance_maintenance(instance_id).await;
|
||||
let _hosted_guard =
|
||||
crate::pack::hosted::prepare_launch(instance_id, offline_mode).await?;
|
||||
let state = State::get().await?;
|
||||
|
||||
@@ -363,6 +363,32 @@ impl DirectoryInfo {
|
||||
return Err(crate::ErrorKind::DirectoryMoveError(format!("Cannot move directory to {}: directory is not writable", move_dir.display())).into());
|
||||
}
|
||||
|
||||
// If the user hasn't chosen a custom backup repository, the
|
||||
// default one lives next to the launcher data. Move it along
|
||||
// with the rest of the directory and queue a cleanup of the
|
||||
// old copy on next startup.
|
||||
if settings.backup_repository_path.is_none() {
|
||||
let old_repository =
|
||||
prev_dir.join("Backups").join("instances");
|
||||
let new_repository =
|
||||
move_dir.join("Backups").join("instances");
|
||||
if let Some(path) = crate::api::instance::move_default_repository_for_launcher_directory(
|
||||
&old_repository,
|
||||
&new_repository,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
sqlx::query(
|
||||
"INSERT INTO pending_backup_repository_cleanups (path, created_at)
|
||||
VALUES (?, unixepoch('subsec') * 1000)
|
||||
ON CONFLICT(path) DO UPDATE SET created_at = excluded.created_at",
|
||||
)
|
||||
.bind(path.to_string_lossy().to_string())
|
||||
.execute(exec)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
const MOVE_DIRS: &[&str] = &[
|
||||
CACHES_FOLDER_NAME,
|
||||
INSTANCES_FOLDER_NAME,
|
||||
|
||||
@@ -9,7 +9,36 @@ pub(crate) async fn remove_instance(
|
||||
state: &State,
|
||||
) -> crate::Result<()> {
|
||||
let _instance_lock = state.lock_instance_content(instance_id).await;
|
||||
let _maintenance_guard =
|
||||
crate::api::instance::lock_instance_maintenance(instance_id).await;
|
||||
crate::api::instance::begin_instance_deletion(instance_id).await?;
|
||||
|
||||
let result = remove_instance_files_and_state(instance_id, state).await;
|
||||
|
||||
match result {
|
||||
Ok(()) => {
|
||||
crate::api::instance::delete_instance_backups(instance_id).await
|
||||
}
|
||||
Err(error) => {
|
||||
if let Err(cancel_error) =
|
||||
crate::api::instance::cancel_instance_deletion(instance_id)
|
||||
.await
|
||||
{
|
||||
tracing::warn!(
|
||||
instance_id,
|
||||
%cancel_error,
|
||||
"Failed to clear pending backup deletion marker"
|
||||
);
|
||||
}
|
||||
Err(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn remove_instance_files_and_state(
|
||||
instance_id: &str,
|
||||
state: &State,
|
||||
) -> crate::Result<()> {
|
||||
let instance = instance_rows::get_instance_by_id(instance_id, &state.pool)
|
||||
.await?
|
||||
.ok_or_else(|| {
|
||||
|
||||
@@ -533,6 +533,13 @@ impl ProcessManager {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Whether any tracked process belongs to the given instance.
|
||||
pub fn has_instance_process(&self, instance_id: &str) -> bool {
|
||||
self.processes
|
||||
.iter()
|
||||
.any(|entry| entry.value().metadata.instance_id == instance_id)
|
||||
}
|
||||
|
||||
pub fn try_wait(
|
||||
&self,
|
||||
id: Uuid,
|
||||
|
||||
Reference in new issue
Block a user