diff --git a/packages/desktop/src/config.rs b/packages/desktop/src/config.rs index dac5b23d4..820901829 100644 --- a/packages/desktop/src/config.rs +++ b/packages/desktop/src/config.rs @@ -2,6 +2,7 @@ use std::borrow::Cow; use std::path::PathBuf; use tao::window::{Icon, WindowBuilder}; use wry::http::{Request as HttpRequest, Response as HttpResponse}; +use wry::RequestAsyncResponder; use crate::menubar::{default_menu_bar, DioxusMenu}; @@ -22,6 +23,7 @@ pub struct Config { pub(crate) window: WindowBuilder, pub(crate) menu: Option, pub(crate) protocols: Vec, + pub(crate) asynchronous_protocols: Vec, pub(crate) pre_rendered: Option, pub(crate) disable_context_menu: bool, pub(crate) resource_dir: Option, @@ -38,6 +40,11 @@ pub(crate) type WryProtocol = ( Box>) -> HttpResponse> + 'static>, ); +pub(crate) type AsyncWryProtocol = ( + String, + Box>, RequestAsyncResponder) + 'static>, +); + impl Config { /// Initializes a new `WindowBuilder` with default values. #[inline] @@ -56,6 +63,7 @@ impl Config { window, menu: Some(default_menu_bar()), protocols: Vec::new(), + asynchronous_protocols: Vec::new(), pre_rendered: None, disable_context_menu: !cfg!(debug_assertions), resource_dir: None, @@ -109,11 +117,46 @@ impl Config { } /// Set a custom protocol - pub fn with_custom_protocol(mut self, name: String, handler: F) -> Self + pub fn with_custom_protocol(mut self, name: impl ToString, handler: F) -> Self where F: Fn(HttpRequest>) -> HttpResponse> + 'static, { - self.protocols.push((name, Box::new(handler))); + self.protocols.push((name.to_string(), Box::new(handler))); + self + } + + /// Set an asynchronous custom protocol + /// + /// **Example Usage** + /// ```rust + /// # use wry::http::response::Response as HTTPResponse; + /// # use std::borrow::Cow; + /// # use dioxus_desktop::Config; + /// # + /// # fn main() { + /// let cfg = Config::new() + /// .with_asynchronous_custom_protocol("asset", |request, responder| { + /// tokio::spawn(async move { + /// responder.respond( + /// HTTPResponse::builder() + /// .status(404) + /// .body(Cow::Borrowed("404 - Not Found".as_bytes())) + /// .unwrap() + /// ); + /// }); + /// }); + /// # } + /// ``` + /// note a key difference between Dioxus and Wry, the protocol name doesn't explicitly need to be a + /// [`String`], but needs to implement [`ToString`]. + /// + /// See [`wry`](wry::WebViewBuilder::with_asynchronous_custom_protocol) for more details on implementation + pub fn with_asynchronous_custom_protocol(mut self, name: impl ToString, handler: F) -> Self + where + F: Fn(HttpRequest>, RequestAsyncResponder) + 'static, + { + self.asynchronous_protocols + .push((name.to_string(), Box::new(handler))); self } diff --git a/packages/desktop/src/webview.rs b/packages/desktop/src/webview.rs index fd1c3dd87..f7342e71e 100644 --- a/packages/desktop/src/webview.rs +++ b/packages/desktop/src/webview.rs @@ -169,6 +169,10 @@ impl WebviewInstance { webview = webview.with_custom_protocol(name, handler); } + for (name, handler) in cfg.asynchronous_protocols.drain(..) { + webview = webview.with_asynchronous_custom_protocol(name, handler); + } + const INITIALIZATION_SCRIPT: &str = r#" if (document.addEventListener) { document.addEventListener('contextmenu', function(e) {