diff --git a/apps/desktop-shell/scripts/check-config.mjs b/apps/desktop-shell/scripts/check-config.mjs index 56a467e7e..f6433f93e 100644 --- a/apps/desktop-shell/scripts/check-config.mjs +++ b/apps/desktop-shell/scripts/check-config.mjs @@ -2235,9 +2235,14 @@ const requiredRustHostSnippets = [ '"copied_to_clipboard"', 'file_export_cancelled_response', 'file_import_cancelled_response', + 'file_export_unavailable_response', + 'file_import_unavailable_response', 'desktop_file_cancelled_responses_are_stable', + 'desktop_file_unavailable_responses_are_stable', '"file export cancelled"', '"file import cancelled"', + '"file export unavailable"', + '"file import unavailable"', 'BASE64_STANDARD.decode', 'blocking_pick_file', 'import_text_file_payload', diff --git a/apps/desktop-shell/src-tauri/src/host_bridge/files.rs b/apps/desktop-shell/src-tauri/src/host_bridge/files.rs index 02c2b5785..c63f15273 100644 --- a/apps/desktop-shell/src-tauri/src/host_bridge/files.rs +++ b/apps/desktop-shell/src-tauri/src/host_bridge/files.rs @@ -15,6 +15,22 @@ fn file_import_cancelled_response(request: &HostBridgeRequest) -> HostBridgeResp failed(request.id.clone(), "cancelled", "file import cancelled") } +fn file_export_unavailable_response(request: &HostBridgeRequest) -> HostBridgeResponse { + failed( + request.id.clone(), + "host_error", + "file export unavailable", + ) +} + +fn file_import_unavailable_response(request: &HostBridgeRequest) -> HostBridgeResponse { + failed( + request.id.clone(), + "host_error", + "file import unavailable", + ) +} + pub(crate) async fn export_desktop_host_bridge_text_file( app: &tauri::AppHandle, request: &HostBridgeRequest, @@ -40,8 +56,7 @@ pub(crate) async fn export_desktop_host_bridge_text_file( tauri::async_runtime::spawn_blocking(move || write_export_text_file(path, content)).await; let bytes = match export_result { Ok(Ok(bytes)) => bytes, - Ok(Err(error)) => return failed(request.id.clone(), "host_error", error), - Err(error) => return failed(request.id.clone(), "host_error", error.to_string()), + Ok(Err(_)) | Err(_) => return file_export_unavailable_response(request), }; ok( @@ -75,7 +90,7 @@ pub(crate) async fn import_desktop_host_bridge_text_file( match import_result { Ok(Ok(payload)) => ok(request.id.clone(), payload), Ok(Err(error)) => failed(request.id.clone(), "invalid_request", error), - Err(error) => failed(request.id.clone(), "host_error", error.to_string()), + Err(_) => file_import_unavailable_response(request), } } @@ -103,7 +118,7 @@ pub(crate) async fn import_desktop_host_bridge_document_file( match import_result { Ok(Ok(payload)) => ok(request.id.clone(), payload), Ok(Err(error)) => failed(request.id.clone(), "invalid_request", error), - Err(error) => failed(request.id.clone(), "host_error", error.to_string()), + Err(_) => file_import_unavailable_response(request), } } @@ -132,8 +147,7 @@ pub(crate) async fn export_desktop_host_bridge_image_file( tauri::async_runtime::spawn_blocking(move || write_export_bytes_file(path, bytes)).await; let byte_count = match export_result { Ok(Ok(byte_count)) => byte_count, - Ok(Err(error)) => return failed(request.id.clone(), "host_error", error), - Err(error) => return failed(request.id.clone(), "host_error", error.to_string()), + Ok(Err(_)) | Err(_) => return file_export_unavailable_response(request), }; ok( request.id.clone(), @@ -168,7 +182,7 @@ pub(crate) async fn import_desktop_host_bridge_image_file( match import_result { Ok(Ok(payload)) => ok(request.id.clone(), payload), Ok(Err(error)) => failed(request.id.clone(), "invalid_request", error), - Err(error) => failed(request.id.clone(), "host_error", error.to_string()), + Err(_) => file_import_unavailable_response(request), } } @@ -193,7 +207,7 @@ pub(crate) async fn import_desktop_host_bridge_audio_file( match import_result { Ok(Ok(payload)) => ok(request.id.clone(), payload), Ok(Err(error)) => failed(request.id.clone(), "invalid_request", error), - Err(error) => failed(request.id.clone(), "host_error", error.to_string()), + Err(_) => file_import_unavailable_response(request), } } @@ -222,8 +236,7 @@ pub(crate) async fn export_desktop_host_bridge_audio_file( tauri::async_runtime::spawn_blocking(move || write_export_bytes_file(path, bytes)).await; let byte_count = match export_result { Ok(Ok(byte_count)) => byte_count, - Ok(Err(error)) => return failed(request.id.clone(), "host_error", error), - Err(error) => return failed(request.id.clone(), "host_error", error.to_string()), + Ok(Err(_)) | Err(_) => return file_export_unavailable_response(request), }; ok( request.id.clone(), @@ -256,4 +269,21 @@ mod tests { assert_eq!(import_error.code, "cancelled"); assert_eq!(import_error.message, "file import cancelled"); } + + #[test] + fn desktop_file_unavailable_responses_are_stable() { + let request = request("file.importText"); + + let export_error = file_export_unavailable_response(&request) + .error + .expect("export error"); + assert_eq!(export_error.code, "host_error"); + assert_eq!(export_error.message, "file export unavailable"); + + let import_error = file_import_unavailable_response(&request) + .error + .expect("import error"); + assert_eq!(import_error.code, "host_error"); + assert_eq!(import_error.message, "file import unavailable"); + } }