v0.1.4-pre.008-fix.002

This commit is contained in:
2026-08-16 13:35:12 +02:00
parent 73d05862af
commit 60d3cb5606
15 changed files with 420 additions and 39 deletions

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-config-desk/src/app_state.rs
// version: 2
// version: 3
//! Shared backend state owned by the Tauri application.
@@ -50,7 +50,10 @@ impl AppState {
target: crate::TRACING_TARGET,
domain = crate::TRACING_DOMAIN_WINDOWS,
minimum_ms = splash_settings.minimum_ms(),
minimum_source = splash_settings.minimum_source(),
fade_ms = splash_settings.fade_ms(),
fade_source = splash_settings.fade_source(),
expected_backend_lifecycle_ms = splash_settings.expected_backend_lifecycle_ms(),
"resolved Config Desk splash timings"
);
return std::result::Result::Ok(Self {

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-config-desk/src/main.rs
// version: 2
// version: 3
//! Binary entry point for the KSP configuration desktop application.
@@ -11,6 +11,11 @@
use fs2::FileExt; // rust-rules: trait-import
fn main() -> std::process::ExitCode {
let working_directory = configure_runtime_working_directory();
if let std::result::Result::Err(error) = working_directory {
eprintln!("cannot configure Config Desk runtime working directory: {error}");
return std::process::ExitCode::FAILURE;
}
let mut lock_path = std::env::temp_dir();
lock_path.push("com_sasedev_ksp_app_config_desk.lock");
let lock_file = match std::fs::OpenOptions::new().read(true).write(true).create(true).truncate(false).open(&lock_path) {
@@ -39,3 +44,15 @@ fn main() -> std::process::ExitCode {
},
};
}
fn configure_runtime_working_directory() -> std::io::Result<()> {
#[cfg(debug_assertions)]
{
let workspace_root = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../..");
return std::env::set_current_dir(workspace_root);
}
#[cfg(not(debug_assertions))]
{
return std::result::Result::Ok(());
}
}

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-config-desk/src/splash.rs
// version: 2
// version: 3
//! Common splash settings and frontend event contracts for Config Desk.
@@ -17,6 +17,8 @@ const MAX_SPLASH_FADE_MS: u32 = 10_000;
pub(crate) struct SplashSettings {
minimum_ms: u64,
fade_ms: u32,
minimum_source: ksp_config_lib::ConfigEnvironmentSource,
fade_source: ksp_config_lib::ConfigEnvironmentSource,
}
impl SplashSettings {
@@ -47,13 +49,18 @@ impl SplashSettings {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
return std::result::Result::Ok(Self { minimum_ms, fade_ms });
return std::result::Result::Ok(Self { minimum_ms, fade_ms, minimum_source: minimum.source(), fade_source: fade.source() });
}
/// Returns safe in-memory timings used when the managed environment cannot be resolved.
#[must_use]
pub(crate) const fn fallback() -> Self {
return Self { minimum_ms: DEFAULT_SPLASH_MINIMUM_MS, fade_ms: DEFAULT_SPLASH_FADE_MS };
return Self {
minimum_ms: DEFAULT_SPLASH_MINIMUM_MS,
fade_ms: DEFAULT_SPLASH_FADE_MS,
minimum_source: ksp_config_lib::ConfigEnvironmentSource::Fallback,
fade_source: ksp_config_lib::ConfigEnvironmentSource::Fallback,
};
}
/// Returns the minimum visible duration after splash frontend readiness.
@@ -67,6 +74,32 @@ impl SplashSettings {
pub(crate) const fn fade_ms(self) -> u32 {
return self.fade_ms;
}
/// Returns the safe provenance code for the minimum duration.
#[must_use]
pub(crate) const fn minimum_source(self) -> &'static str {
return environment_source_code(self.minimum_source);
}
/// Returns the safe provenance code for the fade duration.
#[must_use]
pub(crate) const fn fade_source(self) -> &'static str {
return environment_source_code(self.fade_source);
}
/// Returns the minimum backend lifecycle duration from readiness until main activation.
#[must_use]
pub(crate) fn expected_backend_lifecycle_ms(self) -> u64 {
return self.minimum_ms + u64::from(self.fade_ms);
}
}
const fn environment_source_code(source: ksp_config_lib::ConfigEnvironmentSource) -> &'static str {
return match source {
ksp_config_lib::ConfigEnvironmentSource::Process => "process",
ksp_config_lib::ConfigEnvironmentSource::DotEnv => "dotenv",
ksp_config_lib::ConfigEnvironmentSource::Fallback => "fallback",
};
}
/// Command emitted by Rust to the splash frontend.

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-config-desk/src/tauri.rs
// version: 5
// version: 6
//! Tauri runtime assembly for the KSP configuration desktop application.
@@ -35,7 +35,7 @@ fn configure_plugins(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<taur
return builder.plugin(tracing_plugin);
}
#[allow(clippy::question_mark_used)]
#[allow(clippy::question_mark_used)] // Tauri generates the question-mark operator internally for async command dispatch.
fn configure_commands(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri::Wry> {
return builder.invoke_handler(tauri::generate_handler![get_app_snapshot, emit_frontend_log, splash_frontend_ready]);
}

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-config-desk/src/tw_splash.rs
// version: 1
// version: 2
//! Tauri-window lifecycle for the Config Desk splash window.
@@ -37,12 +37,17 @@ pub(crate) async fn frontend_ready(app: tauri::AppHandle, invoking_window: tauri
return std::result::Result::Ok(());
}
let settings = state.splash_settings();
let lifecycle_started = std::time::Instant::now();
ksp_logging_lib::debug!(
target: crate::TRACING_TARGET,
domain = crate::TRACING_DOMAIN_WINDOWS,
window_label = WINDOW_LABEL_SPLASH,
minimum_ms = settings.minimum_ms(),
minimum_source = settings.minimum_source(),
fade_ms = settings.fade_ms(),
"starting splash to main lifecycle"
fade_source = settings.fade_source(),
expected_backend_lifecycle_ms = settings.expected_backend_lifecycle_ms(),
"splash frontend readiness accepted; starting splash to main lifecycle"
);
let fade_in = emit_order(
&invoking_window,
@@ -51,7 +56,17 @@ pub(crate) async fn frontend_ready(app: tauri::AppHandle, invoking_window: tauri
if let std::result::Result::Err(error) = fade_in {
return std::result::Result::Err(error);
}
let minimum_wait_started = std::time::Instant::now();
tokio::time::sleep(std::time::Duration::from_millis(settings.minimum_ms())).await;
ksp_logging_lib::debug!(
target: crate::TRACING_TARGET,
domain = crate::TRACING_DOMAIN_WINDOWS,
window_label = WINDOW_LABEL_SPLASH,
configured_wait_ms = settings.minimum_ms(),
actual_wait_ms = minimum_wait_started.elapsed().as_secs_f64() * 1000.0,
lifecycle_elapsed_ms = lifecycle_started.elapsed().as_secs_f64() * 1000.0,
"splash minimum wait completed"
);
let fade_out = emit_order(
&invoking_window,
crate::SplashOrderDto::new("fade_out", std::option::Option::Some("Initialisation terminée."), std::option::Option::Some(settings.fade_ms())),
@@ -59,7 +74,17 @@ pub(crate) async fn frontend_ready(app: tauri::AppHandle, invoking_window: tauri
if let std::result::Result::Err(error) = fade_out {
return std::result::Result::Err(error);
}
let fade_wait_started = std::time::Instant::now();
tokio::time::sleep(std::time::Duration::from_millis(u64::from(settings.fade_ms()))).await;
ksp_logging_lib::debug!(
target: crate::TRACING_TARGET,
domain = crate::TRACING_DOMAIN_WINDOWS,
window_label = WINDOW_LABEL_SPLASH,
configured_wait_ms = settings.fade_ms(),
actual_wait_ms = fade_wait_started.elapsed().as_secs_f64() * 1000.0,
lifecycle_elapsed_ms = lifecycle_started.elapsed().as_secs_f64() * 1000.0,
"splash fade-out wait completed"
);
let show_main = crate::show_main_window(&app);
if let std::result::Result::Err(error) = show_main {
return std::result::Result::Err(error);
@@ -76,6 +101,8 @@ pub(crate) async fn frontend_ready(app: tauri::AppHandle, invoking_window: tauri
target: crate::TRACING_TARGET,
domain = crate::TRACING_DOMAIN_WINDOWS,
window_label = WINDOW_LABEL_SPLASH,
expected_backend_lifecycle_ms = settings.expected_backend_lifecycle_ms(),
actual_backend_lifecycle_ms = lifecycle_started.elapsed().as_secs_f64() * 1000.0,
"splash window destroyed after main activation"
);
return std::result::Result::Ok(());