174 lines
8.0 KiB
Rust
174 lines
8.0 KiB
Rust
// file: crates/ksp-app-config-desk/src/tw_splash.rs
|
|
// version: 6
|
|
|
|
//! Tauri-window lifecycle for the Config Desk splash window.
|
|
|
|
use tauri::Emitter; // rust-rules: trait-import
|
|
use tauri::Manager; // rust-rules: trait-import
|
|
|
|
/// Crate-internal splash window label.
|
|
pub(crate) const WINDOW_LABEL_SPLASH: &str = "splash";
|
|
|
|
const SPLASH_EVENT_NAME: &str = "ksp-splash-order";
|
|
|
|
/// Resolves the required splash window or returns a typed error.
|
|
pub(crate) fn require_splash_window(manager: &impl Manager<tauri::Wry>) -> ksp_core_lib::Result<tauri::WebviewWindow> {
|
|
let window = manager.get_webview_window(WINDOW_LABEL_SPLASH);
|
|
return match window {
|
|
std::option::Option::Some(value) => std::result::Result::Ok(value),
|
|
std::option::Option::None => std::result::Result::Err(
|
|
ksp_core_lib::Error::new(crate::ERROR_CODE_TAURI_WINDOW_MISSING, "Config Desk splash window is missing")
|
|
.with_context("window_label", WINDOW_LABEL_SPLASH),
|
|
),
|
|
};
|
|
}
|
|
|
|
/// Starts the one-shot splash lifecycle after the splash frontend reports readiness.
|
|
pub(crate) async fn splash_frontend_ready_service(
|
|
app: tauri::AppHandle,
|
|
invoking_window: tauri::WebviewWindow,
|
|
state: &crate::AppState,
|
|
) -> ksp_core_lib::Result<()> {
|
|
if invoking_window.label() != WINDOW_LABEL_SPLASH {
|
|
return std::result::Result::Err(
|
|
ksp_core_lib::Error::new(crate::ERROR_CODE_SPLASH_ORIGIN_INVALID, "Splash readiness may only originate from the splash window")
|
|
.with_context("window_label", invoking_window.label()),
|
|
);
|
|
}
|
|
if !state.begin_splash_sequence() {
|
|
ksp_logging_lib::trace!(target: crate::TRACING_TARGET, domain = crate::TRACING_DOMAIN_WINDOWS, window_label = WINDOW_LABEL_SPLASH, "duplicate splash frontend readiness ignored");
|
|
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,
|
|
fade_in_ms = settings.fade_in_ms(),
|
|
fade_in_source = settings.fade_in_source(),
|
|
minimum_ms = settings.minimum_ms(),
|
|
minimum_source = settings.minimum_source(),
|
|
fade_out_ms = settings.fade_out_ms(),
|
|
fade_out_source = settings.fade_out_source(),
|
|
expected_backend_lifecycle_ms = settings.expected_backend_lifecycle_ms(),
|
|
"splash frontend readiness accepted; starting splash to main lifecycle"
|
|
);
|
|
let emitted = emit_order(
|
|
&invoking_window,
|
|
crate::SplashOrderDto::new("fade_in", std::option::Option::None, std::option::Option::None, std::option::Option::Some(settings.fade_in_ms())),
|
|
);
|
|
if let std::result::Result::Err(error) = emitted {
|
|
return std::result::Result::Err(error);
|
|
}
|
|
let emitted = emit_message(&invoking_window, "Initialisation de Config Desk...", "info");
|
|
if let std::result::Result::Err(error) = emitted {
|
|
return std::result::Result::Err(error);
|
|
}
|
|
let emitted = emit_debug(&invoking_window, "Listener frontend prêt; fade-in piloté par Rust.");
|
|
if let std::result::Result::Err(error) = emitted {
|
|
return std::result::Result::Err(error);
|
|
}
|
|
sleep_and_log(&invoking_window, "fade-in", u64::from(settings.fade_in_ms()), lifecycle_started).await;
|
|
let emitted = emit_message(&invoking_window, "Configuration KSP chargée.", "success");
|
|
if let std::result::Result::Err(error) = emitted {
|
|
return std::result::Result::Err(error);
|
|
}
|
|
let emitted = emit_debug(&invoking_window, "Configuration et provenance des timings résolues via ksp-config-lib.");
|
|
if let std::result::Result::Err(error) = emitted {
|
|
return std::result::Result::Err(error);
|
|
}
|
|
let emitted = emit_message(&invoking_window, "Runtime Logging initialisé.", "success");
|
|
if let std::result::Result::Err(error) = emitted {
|
|
return std::result::Result::Err(error);
|
|
}
|
|
let emitted = emit_message(&invoking_window, "Gestion Config prête.", "success");
|
|
if let std::result::Result::Err(error) = emitted {
|
|
return std::result::Result::Err(error);
|
|
}
|
|
sleep_and_log(&invoking_window, "minimum", settings.minimum_ms(), lifecycle_started).await;
|
|
let emitted = emit_message(&invoking_window, "Initialisation terminée.", "success");
|
|
if let std::result::Result::Err(error) = emitted {
|
|
return std::result::Result::Err(error);
|
|
}
|
|
let emitted = emit_order(
|
|
&invoking_window,
|
|
crate::SplashOrderDto::new("fade_out", std::option::Option::None, std::option::Option::None, std::option::Option::Some(settings.fade_out_ms())),
|
|
);
|
|
if let std::result::Result::Err(error) = emitted {
|
|
return std::result::Result::Err(error);
|
|
}
|
|
sleep_and_log(&invoking_window, "fade-out", u64::from(settings.fade_out_ms()), lifecycle_started).await;
|
|
let show_main = crate::show_main_window(&app);
|
|
if let std::result::Result::Err(error) = show_main {
|
|
return std::result::Result::Err(error);
|
|
}
|
|
let destroyed = invoking_window.destroy();
|
|
if let std::result::Result::Err(error) = destroyed {
|
|
return std::result::Result::Err(
|
|
ksp_core_lib::Error::new(crate::ERROR_CODE_TAURI_WINDOW_OPERATION_FAILED, "Cannot destroy Config Desk splash window")
|
|
.with_context("window_label", WINDOW_LABEL_SPLASH)
|
|
.with_source(error),
|
|
);
|
|
}
|
|
ksp_logging_lib::debug!(
|
|
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(());
|
|
}
|
|
|
|
fn emit_message(window: &tauri::WebviewWindow, message: &str, status: &str) -> ksp_core_lib::Result<()> {
|
|
return emit_order(
|
|
window,
|
|
crate::SplashOrderDto::new("add_message", std::option::Option::Some(message), std::option::Option::Some(status), std::option::Option::None),
|
|
);
|
|
}
|
|
|
|
fn emit_debug(window: &tauri::WebviewWindow, message: &str) -> ksp_core_lib::Result<()> {
|
|
if !cfg!(debug_assertions) {
|
|
return std::result::Result::Ok(());
|
|
}
|
|
return emit_order(
|
|
window,
|
|
crate::SplashOrderDto::new("add_debug", std::option::Option::Some(message), std::option::Option::None, std::option::Option::None),
|
|
);
|
|
}
|
|
|
|
async fn sleep_and_log(window: &tauri::WebviewWindow, phase: &str, duration_ms: u64, lifecycle_started: std::time::Instant) {
|
|
let wait_started = std::time::Instant::now();
|
|
tokio::time::sleep(std::time::Duration::from_millis(duration_ms)).await;
|
|
ksp_logging_lib::debug!(
|
|
target: crate::TRACING_TARGET,
|
|
domain = crate::TRACING_DOMAIN_WINDOWS,
|
|
window_label = window.label(),
|
|
phase,
|
|
configured_wait_ms = duration_ms,
|
|
actual_wait_ms = wait_started.elapsed().as_secs_f64() * 1000.0,
|
|
lifecycle_elapsed_ms = lifecycle_started.elapsed().as_secs_f64() * 1000.0,
|
|
"splash lifecycle wait completed"
|
|
);
|
|
return;
|
|
}
|
|
|
|
fn emit_order(window: &tauri::WebviewWindow, order: crate::SplashOrderDto) -> ksp_core_lib::Result<()> {
|
|
let action = order.action.clone();
|
|
let emitted = window.emit(SPLASH_EVENT_NAME, order);
|
|
return match emitted {
|
|
std::result::Result::Ok(()) => {
|
|
ksp_logging_lib::trace!(target: crate::TRACING_TARGET, domain = crate::TRACING_DOMAIN_WINDOWS, window_label = WINDOW_LABEL_SPLASH, action = action.as_str(), "splash order emitted");
|
|
std::result::Result::Ok(())
|
|
},
|
|
std::result::Result::Err(error) => std::result::Result::Err(
|
|
ksp_core_lib::Error::new(crate::ERROR_CODE_TAURI_WINDOW_OPERATION_FAILED, "Cannot emit Config Desk splash order")
|
|
.with_context("window_label", WINDOW_LABEL_SPLASH)
|
|
.with_context("action", action)
|
|
.with_source(error),
|
|
),
|
|
};
|
|
}
|