Files
khadhroony-solana-project/crates/ksp-app-backfill-desk/src/tauri.rs
2026-09-02 19:50:01 +02:00

344 lines
15 KiB
Rust

// file: crates/ksp-app-backfill-desk/src/tauri.rs
// version: 9
//! Tauri runtime assembly for the KSP Backfill desktop application.
use tauri::Emitter; // rust-rules: trait-import
use tauri::Manager; // rust-rules: trait-import
/// Runs the Backfill desktop application.
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run(arguments: &[std::ffi::OsString]) -> ksp_core_lib::Result<()> {
let context = tauri::generate_context!();
let runtime_layout = configure_packaged_runtime(&context);
if let std::result::Result::Err(error) = runtime_layout {
return std::result::Result::Err(error);
}
let app_state = crate::AppState::initialize(arguments);
let app_state = match app_state {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let mut builder = tauri::Builder::default();
builder = configure_state(builder, app_state);
builder = configure_plugins(builder);
builder = configure_commands(builder);
builder = configure_setup(builder);
builder = configure_window_events(builder);
let run_result = builder.run(context);
return match run_result {
std::result::Result::Ok(()) => std::result::Result::Ok(()),
std::result::Result::Err(error) => std::result::Result::Err(
ksp_core_lib::Error::new(crate::ERROR_CODE_TAURI_RUNTIME_FAILED, "Cannot run KSP Backfill Desk Tauri runtime")
.with_context("tauri_error", error.to_string()),
),
};
}
fn configure_packaged_runtime(context: &tauri::Context<tauri::Wry>) -> ksp_core_lib::Result<()> {
if cfg!(debug_assertions) {
return std::result::Result::Ok(());
}
let resource_root = tauri::utils::platform::resource_dir(context.package_info(), &tauri::Env::default());
let resource_root = match resource_root {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
return std::result::Result::Err(
ksp_core_lib::Error::new(crate::ERROR_CODE_TAURI_RUNTIME_FAILED, "Cannot resolve packaged Tauri resource directory")
.with_context("tauri_error", error.to_string()),
);
},
};
let layout = ksp_config_lib::prepare_packaged_runtime(resource_root.as_path());
let layout = match layout {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let working_directory = std::env::set_current_dir(layout.runtime_root());
return match working_directory {
std::result::Result::Ok(()) => std::result::Result::Ok(()),
std::result::Result::Err(error) => std::result::Result::Err(
ksp_core_lib::Error::new(crate::ERROR_CODE_TAURI_RUNTIME_FAILED, "Cannot activate packaged KSP runtime directory")
.with_context("runtime_root", layout.runtime_root().to_string_lossy().into_owned())
.with_source(error),
),
};
}
fn configure_state(builder: tauri::Builder<tauri::Wry>, app_state: crate::AppState) -> tauri::Builder<tauri::Wry> {
return builder.manage(app_state);
}
fn configure_plugins(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri::Wry> {
let tracing_plugin = tauri_plugin_tracing::Builder::new().build::<tauri::Wry>();
return builder.plugin(tracing_plugin);
}
#[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![
backfill_cancel,
backfill_options,
backfill_resume,
backfill_start,
backfill_status,
backfill_validate_request,
emit_frontend_log,
get_runtime_status,
splash_frontend_ready
]);
}
fn configure_setup(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri::Wry> {
return builder.setup(|app| {
let splash = crate::require_splash_window(app);
if let std::result::Result::Err(error) = splash {
return std::result::Result::Err(std::boxed::Box::new(error));
}
let main = crate::require_main_window(app);
if let std::result::Result::Err(error) = main {
return std::result::Result::Err(std::boxed::Box::new(error));
}
ksp_logging_lib::debug!(target: crate::TRACING_TARGET, domain = crate::TRACING_DOMAIN_SHELL, "Backfill Desk Tauri shell setup completed");
return std::result::Result::Ok(());
});
}
fn configure_window_events(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri::Wry> {
return builder.on_window_event(|window, event| {
if window.label() != "main" {
return;
}
if let tauri::WindowEvent::CloseRequested { api, .. } = event {
api.prevent_close();
let app_handle = window.app_handle().clone();
let state = app_handle.state::<crate::AppState>();
if !state.begin_shutdown() {
return;
}
let cancellation = state.cancel_active_backfill_for_shutdown();
match cancellation {
std::result::Result::Ok(accepted) => {
ksp_logging_lib::debug!(
target: crate::TRACING_TARGET,
domain = crate::TRACING_DOMAIN_WINDOWS,
cancellation_accepted = accepted,
"Backfill Desk main-window close requested; cooperative Backfill cancellation attempted before bounded Store shutdown"
);
},
std::result::Result::Err(error) => {
ksp_logging_lib::warn!(
target: crate::TRACING_TARGET,
domain = crate::TRACING_DOMAIN_WINDOWS,
error_domain = error.code().domain(),
error_code = error.code().code(),
"Backfill Desk could not request cooperative cancellation during shutdown; continuing bounded shutdown"
);
},
}
tauri::async_runtime::spawn(async move {
let state = app_handle.state::<crate::AppState>();
let closed = state.close_store().await;
match closed {
std::result::Result::Ok(()) => {
ksp_logging_lib::debug!(
target: crate::TRACING_TARGET,
domain = crate::TRACING_DOMAIN_WINDOWS,
"Backfill Desk Store shutdown completed; exiting application"
);
},
std::result::Result::Err(error) => {
ksp_logging_lib::warn!(
target: crate::TRACING_TARGET,
domain = crate::TRACING_DOMAIN_WINDOWS,
error_domain = error.code().domain(),
error_code = error.code().code(),
"Backfill Desk Store shutdown failed; exiting application after bounded close attempt"
);
},
}
app_handle.exit(0);
});
}
});
}
fn project_command_error(command: &'static str, domain: &'static str, error: &ksp_core_lib::Error) -> crate::CommandErrorDto {
ksp_logging_lib::warn!(
target: crate::TRACING_TARGET,
domain = domain,
command = command,
error_domain = error.code().domain(),
error_code = error.code().code(),
"Backfill Desk Tauri command failed"
);
return crate::CommandErrorDto::from_error(error);
}
#[tauri::command]
fn backfill_cancel(job_id: String, state: tauri::State<'_, crate::AppState>) -> std::result::Result<crate::BackfillCancelResponseDto, crate::CommandErrorDto> {
let result = state.cancel_backfill(job_id.as_str());
return match result {
std::result::Result::Ok(value) => std::result::Result::Ok(value),
std::result::Result::Err(error) => std::result::Result::Err(project_command_error("backfill_cancel", crate::TRACING_DOMAIN_RUN, &error)),
};
}
#[tauri::command]
fn backfill_options(state: tauri::State<'_, crate::AppState>) -> std::result::Result<crate::BackfillDeskOptionsDto, crate::CommandErrorDto> {
let result = state.backfill_options();
return match result {
std::result::Result::Ok(value) => std::result::Result::Ok(value),
std::result::Result::Err(error) => std::result::Result::Err(project_command_error("backfill_options", crate::TRACING_DOMAIN_TRANSPORT, &error)),
};
}
#[tauri::command]
fn backfill_start(
app: tauri::AppHandle,
request: crate::BackfillStartRequestDto,
state: tauri::State<'_, crate::AppState>,
) -> std::result::Result<crate::BackfillStartResponseDto, crate::CommandErrorDto> {
let launch = state.prepare_backfill_start(request);
let launch = match launch {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
return std::result::Result::Err(project_command_error("backfill_start", crate::TRACING_DOMAIN_RUN, &error));
},
};
let response = launch.response();
spawn_backfill_launch(app, launch);
return std::result::Result::Ok(response);
}
#[tauri::command]
fn backfill_resume(
app: tauri::AppHandle,
state: tauri::State<'_, crate::AppState>,
) -> std::result::Result<crate::BackfillResumeResponseDto, crate::CommandErrorDto> {
let launch = state.prepare_backfill_resume();
let launch = match launch {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
return std::result::Result::Err(project_command_error("backfill_resume", crate::TRACING_DOMAIN_RUN, &error));
},
};
let response = crate::BackfillResumeResponseDto {
accepted: true,
job_id: launch.job_id.as_str().to_owned(),
state: ksp_job_api::JobState::Created.code().to_owned(),
};
spawn_backfill_launch(app, launch);
return std::result::Result::Ok(response);
}
fn spawn_backfill_launch(app: tauri::AppHandle, launch: crate::BackfillRunLaunch) {
let monitor_app = app.clone();
let monitor_source = launch.snapshots.clone();
let _monitor_task = tauri::async_runtime::spawn(async move {
monitor_backfill_status(monitor_app, monitor_source).await;
});
let _run_task = tauri::async_runtime::spawn(async move {
let state = app.state::<crate::AppState>();
let executed = state.execute_backfill_run(launch).await;
if let std::result::Result::Err(error) = executed {
ksp_logging_lib::warn!(
target: crate::TRACING_TARGET,
domain = crate::TRACING_DOMAIN_RUN,
error_domain = error.code().domain(),
error_code = error.code().code(),
"Backfill Desk async run terminated with an error"
);
}
});
return;
}
async fn monitor_backfill_status(app: tauri::AppHandle, source: ksp_job_backfill_lib::BackfillSnapshotSource) {
let mut notification = <ksp_job_backfill_lib::BackfillSnapshotSource as ksp_job_api::JobSnapshotSource>::current(&source);
loop {
let projected = crate::project_backfill_status(&notification);
match projected {
std::result::Result::Ok(status) => {
let main = app.get_webview_window("main");
if let std::option::Option::Some(window) = main {
let emitted = window.emit(crate::BACKFILL_STATUS_EVENT_NAME, status);
if emitted.is_err() {
ksp_logging_lib::warn!(
target: crate::TRACING_TARGET,
domain = crate::TRACING_DOMAIN_RUN,
"Backfill Desk could not emit latest-value monitoring status to the main window"
);
}
}
},
std::result::Result::Err(error) => {
ksp_logging_lib::warn!(
target: crate::TRACING_TARGET,
domain = crate::TRACING_DOMAIN_RUN,
error_domain = error.code().domain(),
error_code = error.code().code(),
"Backfill Desk could not project latest-value monitoring status"
);
},
}
if notification.state().is_terminal() {
return;
}
let observed = notification.sequence();
notification = <ksp_job_backfill_lib::BackfillSnapshotSource as ksp_job_api::JobSnapshotSource>::wait_for_change(&source, observed).await;
}
}
#[tauri::command]
fn backfill_status(state: tauri::State<'_, crate::AppState>) -> std::result::Result<std::option::Option<crate::BackfillRunStatusDto>, crate::CommandErrorDto> {
let result = state.backfill_status();
return match result {
std::result::Result::Ok(value) => std::result::Result::Ok(value),
std::result::Result::Err(error) => std::result::Result::Err(project_command_error("backfill_status", crate::TRACING_DOMAIN_RUN, &error)),
};
}
#[tauri::command]
fn backfill_validate_request(
request: crate::BackfillStartRequestDto,
state: tauri::State<'_, crate::AppState>,
) -> std::result::Result<crate::BackfillRequestPreviewDto, crate::CommandErrorDto> {
let result = state.validate_backfill_request(request);
return match result {
std::result::Result::Ok(value) => std::result::Result::Ok(value),
std::result::Result::Err(error) => std::result::Result::Err(project_command_error("backfill_validate_request", crate::TRACING_DOMAIN_REQUEST, &error)),
};
}
#[tauri::command]
fn emit_frontend_log(payload: crate::FrontendLogPayloadDto) -> std::result::Result<(), crate::CommandErrorDto> {
let result = crate::emit_frontend_log_event(payload);
return match result {
std::result::Result::Ok(()) => std::result::Result::Ok(()),
std::result::Result::Err(error) => std::result::Result::Err(project_command_error("emit_frontend_log", crate::TRACING_DOMAIN_FRONTEND, &error)),
};
}
#[tauri::command]
fn get_runtime_status(state: tauri::State<'_, crate::AppState>) -> std::result::Result<crate::ShellStatusDto, crate::CommandErrorDto> {
let result = state.shell_status();
return match result {
std::result::Result::Ok(value) => std::result::Result::Ok(value),
std::result::Result::Err(error) => std::result::Result::Err(project_command_error("get_runtime_status", crate::TRACING_DOMAIN_SHELL, &error)),
};
}
#[tauri::command]
async fn splash_frontend_ready(
app: tauri::AppHandle,
webview_window: tauri::WebviewWindow,
state: tauri::State<'_, crate::AppState>,
) -> std::result::Result<(), crate::CommandErrorDto> {
let result = crate::splash_frontend_ready_service(app, webview_window, &state).await;
return match result {
std::result::Result::Ok(()) => std::result::Result::Ok(()),
std::result::Result::Err(error) => std::result::Result::Err(project_command_error("splash_frontend_ready", crate::TRACING_DOMAIN_WINDOWS, &error)),
};
}