From b31bcee755edadcb185c9d8298aecfbdd36efa8a Mon Sep 17 00:00:00 2001 From: Kamil Jarosz Date: Sat, 4 Jan 2025 20:42:36 +0100 Subject: [PATCH] desktop: Use async IO for file browsing in AVM Using async IO means we're not blocking the main thread and the content doesn't freeze while reading. --- desktop/src/backends/ui.rs | 47 ++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/desktop/src/backends/ui.rs b/desktop/src/backends/ui.rs index 06a9ab71a58da..c32ffdf779e15 100644 --- a/desktop/src/backends/ui.rs +++ b/desktop/src/backends/ui.rs @@ -14,8 +14,10 @@ use ruffle_core::backend::ui::{ DialogLoaderError, DialogResultFuture, FileDialogResult, FileFilter, FontDefinition, FullscreenError, LanguageIdentifier, MouseCursor, UiBackend, }; +use std::path::Path; use std::rc::Rc; use std::sync::Arc; +use tokio::io::AsyncReadExt; use tracing::error; use url::Url; use winit::event_loop::EventLoopProxy; @@ -30,15 +32,40 @@ pub struct DesktopFileDialogResult { impl DesktopFileDialogResult { /// Create a new [`DesktopFileDialogResult`] from a given file handle - pub fn new(handle: Option) -> Self { - let md = handle - .as_ref() - .and_then(|x| std::fs::metadata(x.path()).ok()); + pub async fn new(handle: Option) -> Self { + async fn read_file(path: &Path) -> (Option, Vec) { + let file = match tokio::fs::File::open(path).await { + Ok(file) => file, + Err(err) => { + let path = path.to_string_lossy(); + tracing::error!("Error opening file {path}: {err}"); + return (None, Vec::new()); + } + }; + let metadata = match file.metadata().await { + Ok(metadata) => Some(metadata), + Err(err) => { + let path = path.to_string_lossy(); + tracing::error!("Error reading metadata of file {path}: {err}"); + None + } + }; + + let mut contents = Vec::new(); + let mut file = file; + if let Err(err) = file.read_to_end(&mut contents).await { + contents.clear(); + let path = path.to_string_lossy(); + tracing::error!("Error reading file {path}: {err}"); + } + (metadata, contents) + } - let contents = handle - .as_ref() - .and_then(|handle| std::fs::read(handle.path()).ok()) - .unwrap_or_default(); + let (md, contents) = if let Some(ref handle) = handle { + read_file(handle.path()).await + } else { + (None, Vec::new()) + }; Self { handle, @@ -348,7 +375,7 @@ impl UiBackend for DesktopUiBackend { Some(Box::pin(async move { let result: Result, DialogLoaderError> = - Ok(Box::new(DesktopFileDialogResult::new(result.await))); + Ok(Box::new(DesktopFileDialogResult::new(result.await).await)); result })) } @@ -367,7 +394,7 @@ impl UiBackend for DesktopUiBackend { Some(Box::pin(async move { let result: Result, DialogLoaderError> = - Ok(Box::new(DesktopFileDialogResult::new(result.await))); + Ok(Box::new(DesktopFileDialogResult::new(result.await).await)); result })) }