From 9aeb04faf40989e8fd9d3dcac1d430a9e8bd23a9 Mon Sep 17 00:00:00 2001 From: Lucas Fernandes Nogueira Date: Wed, 11 Aug 2021 21:49:09 -0300 Subject: [PATCH] feat(core): `async_runtime` `handle` API, `spawn` returns `JoinHandle` (#2399) --- .changes/async-runtime-handle-api.md | 5 ++ ...async-runtime-spawn-returns-join-handle.md | 5 ++ core/tauri/Cargo.toml | 4 +- core/tauri/src/async_runtime.rs | 85 +++++++++++++++++-- core/tauri/src/error.rs | 3 + core/tauri/src/updater/mod.rs | 4 +- 6 files changed, 97 insertions(+), 9 deletions(-) create mode 100644 .changes/async-runtime-handle-api.md create mode 100644 .changes/async-runtime-spawn-returns-join-handle.md diff --git a/.changes/async-runtime-handle-api.md b/.changes/async-runtime-handle-api.md new file mode 100644 index 000000000..58ab8fb18 --- /dev/null +++ b/.changes/async-runtime-handle-api.md @@ -0,0 +1,5 @@ +--- +"tauri": patch +--- + +Add `handle` API to `tauri::async_runtime`. diff --git a/.changes/async-runtime-spawn-returns-join-handle.md b/.changes/async-runtime-spawn-returns-join-handle.md new file mode 100644 index 000000000..34d76a76b --- /dev/null +++ b/.changes/async-runtime-spawn-returns-join-handle.md @@ -0,0 +1,5 @@ +--- +"tauri": patch +--- + +**Breaking change:** The `tauri::async_runtime::spawn` function now returns `tauri::async_runtime::JoinHandle`. diff --git a/core/tauri/Cargo.toml b/core/tauri/Cargo.toml index 2173e3d2c..b0f5c0e3f 100644 --- a/core/tauri/Cargo.toml +++ b/core/tauri/Cargo.toml @@ -69,7 +69,8 @@ os_pipe = { version = "0.9", optional = true } rfd = "0.4.2" raw-window-handle = { version = "0.3.3", optional = true } minisign-verify = { version = "0.1", optional = true } -os_info = { version = "3.0.6", optional = true} +os_info = { version = "3.0.6", optional = true } +futures-lite = "1.12" [target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies] gtk = { version = "0.14", features = [ "v3_20" ] } @@ -86,6 +87,7 @@ serde = { version = "1.0", features = [ "derive" ] } quickcheck = "1.0.3" quickcheck_macros = "1.0.0" tokio-test = "0.4.2" +tokio = { version = "1.9", features = [ "full" ] } mockito = "0.30" [features] diff --git a/core/tauri/src/async_runtime.rs b/core/tauri/src/async_runtime.rs index 96afd41e6..756af59d7 100644 --- a/core/tauri/src/async_runtime.rs +++ b/core/tauri/src/async_runtime.rs @@ -7,17 +7,73 @@ //! Fox more complex use cases, consider creating your own runtime. //! For command handlers, it's recommended to use a plain `async fn` command. +use futures_lite::future::FutureExt; use once_cell::sync::OnceCell; use tokio::runtime::Runtime; -pub use tokio::sync::{ - mpsc::{channel, Receiver, Sender}, - Mutex, RwLock, +pub use tokio::{ + runtime::Handle, + sync::{ + mpsc::{channel, Receiver, Sender}, + Mutex, RwLock, + }, + task::JoinHandle as TokioJoinHandle, }; -use std::future::Future; +use std::{ + fmt, + future::Future, + pin::Pin, + task::{Context, Poll}, +}; static RUNTIME: OnceCell = OnceCell::new(); +/// An owned permission to join on a task (await its termination). +#[derive(Debug)] +pub struct JoinHandle(TokioJoinHandle); + +impl Future for JoinHandle { + type Output = crate::Result; + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self + .0 + .poll(cx) + .map_err(|e| crate::Error::JoinError(Box::new(e))) + } +} + +/// Runtime handle definition. +pub trait RuntimeHandle: fmt::Debug + Clone + Sync + Sync { + /// Spawn a future onto the runtime. + fn spawn(&self, task: F) -> JoinHandle + where + F: Future + Send + 'static, + F::Output: Send + 'static; + + /// Run a future to completion on runtime. + fn block_on(&self, task: F) -> F::Output; +} + +impl RuntimeHandle for Handle { + fn spawn(&self, task: F) -> JoinHandle + where + F: Future + Send + 'static, + F::Output: Send + 'static, + { + JoinHandle(self.spawn(task)) + } + + fn block_on(&self, task: F) -> F::Output { + self.block_on(task) + } +} + +/// Returns a handle to the async runtime. +pub fn handle() -> impl RuntimeHandle { + let runtime = RUNTIME.get_or_init(|| Runtime::new().unwrap()); + runtime.handle().clone() +} + /// Run a future to completion on runtime. pub fn block_on(task: F) -> F::Output { let runtime = RUNTIME.get_or_init(|| Runtime::new().unwrap()); @@ -25,11 +81,28 @@ pub fn block_on(task: F) -> F::Output { } /// Spawn a future onto the runtime. -pub fn spawn(task: F) +pub fn spawn(task: F) -> JoinHandle where F: Future + Send + 'static, F::Output: Send + 'static, { let runtime = RUNTIME.get_or_init(|| Runtime::new().unwrap()); - runtime.spawn(task); + JoinHandle(runtime.spawn(task)) +} + +#[cfg(test)] +mod tests { + use super::*; + #[tokio::test] + async fn handle_spawn() { + let handle = handle(); + let join = handle.spawn(async { 5 }); + assert_eq!(join.await.unwrap(), 5); + } + + #[test] + fn handle_block_on() { + let handle = handle(); + assert_eq!(handle.block_on(async { 0 }), 0); + } } diff --git a/core/tauri/src/error.rs b/core/tauri/src/error.rs index 3ddc52df9..334d67029 100644 --- a/core/tauri/src/error.rs +++ b/core/tauri/src/error.rs @@ -80,6 +80,9 @@ pub enum Error { /// user-provided URLs and paths. #[error("invalid url: {0}")] InvalidUrl(url::ParseError), + /// Task join error. + #[error(transparent)] + JoinError(Box), } impl From for Error { diff --git a/core/tauri/src/updater/mod.rs b/core/tauri/src/updater/mod.rs index f880301d0..2c96fcc7e 100644 --- a/core/tauri/src/updater/mod.rs +++ b/core/tauri/src/updater/mod.rs @@ -490,7 +490,7 @@ pub(crate) fn listener( // emit {"status": "DONE"} send_status_update(window.clone(), EVENT_STATUS_SUCCESS, None); } - }) + }); }); } else { send_status_update(window.clone(), EVENT_STATUS_UPTODATE, None); @@ -500,7 +500,7 @@ pub(crate) fn listener( send_status_update(window.clone(), EVENT_STATUS_ERROR, Some(e.to_string())); } } - }) + }); }); }