From cca8115d9c813d13efb30a38445d5bda009a7f97 Mon Sep 17 00:00:00 2001 From: Edgar Geier Date: Wed, 16 Jun 2021 03:04:06 +0200 Subject: [PATCH] refactor: update wry, simplify script eval (#1965) * refactor: simplify `handle_event_loop` * update wry to git rev Co-authored-by: Lucas Nogueira --- .changes/simplify-handle-event-loop.md | 5 + core/tauri-runtime-wry/Cargo.toml | 2 +- core/tauri-runtime-wry/src/lib.rs | 29 +++--- core/tauri-runtime-wry/src/mime_type.rs | 122 ++++++++++++++++++++++++ 4 files changed, 144 insertions(+), 14 deletions(-) create mode 100644 .changes/simplify-handle-event-loop.md create mode 100644 core/tauri-runtime-wry/src/mime_type.rs diff --git a/.changes/simplify-handle-event-loop.md b/.changes/simplify-handle-event-loop.md new file mode 100644 index 000000000..afaf16340 --- /dev/null +++ b/.changes/simplify-handle-event-loop.md @@ -0,0 +1,5 @@ +--- +"tauri-runtime-wry": patch +--- + +Update `wry` to v0.10.0 and replace the removed `dispatch_script` and `evaluate_script` methods with the new `evaluate_script` method in `handle_event_loop`. diff --git a/core/tauri-runtime-wry/Cargo.toml b/core/tauri-runtime-wry/Cargo.toml index b0454637c..fead0ae52 100644 --- a/core/tauri-runtime-wry/Cargo.toml +++ b/core/tauri-runtime-wry/Cargo.toml @@ -12,7 +12,7 @@ exclude = [ ".license_template", "CHANGELOG.md", "/target" ] readme = "README.md" [dependencies] -wry = { version = "0.9.2", default-features = false, features = [ "file-drop", "protocol", "win32" ] } +wry = { git = "https://github.com/tauri-apps/wry", rev = "6a1475ff76cbdd699df9329ab8e2181c2a794c96", default-features = false, features = [ "file-drop", "protocol", "win32" ] } tauri-runtime = { version = "0.1.1", path = "../tauri-runtime" } tauri-utils = { version = "1.0.0-beta.0", path = "../tauri-utils" } uuid = { version = "0.8.2", features = [ "v4" ] } diff --git a/core/tauri-runtime-wry/src/lib.rs b/core/tauri-runtime-wry/src/lib.rs index e607781d0..7c81d9121 100644 --- a/core/tauri-runtime-wry/src/lib.rs +++ b/core/tauri-runtime-wry/src/lib.rs @@ -42,8 +42,8 @@ use wry::{ window::{Fullscreen, Icon as WindowIcon, Window, WindowBuilder as WryWindowBuilder, WindowId}, }, webview::{ - FileDropEvent as WryFileDropEvent, RpcRequest as WryRpcRequest, RpcResponse, WebView, - WebViewBuilder, + FileDropEvent as WryFileDropEvent, RpcRequest as WryRpcRequest, RpcResponse, WebContext, + WebView, WebViewBuilder, }, }; @@ -62,6 +62,9 @@ mod menu; #[cfg(any(feature = "menu", feature = "system-tray"))] use menu::*; +mod mime_type; +use mime_type::MimeType; + type MainTask = Arc>>>; type CreateWebviewHandler = Box) -> Result + Send>; @@ -1167,12 +1170,6 @@ fn handle_event_loop( } = context; *control_flow = ControlFlow::Wait; - for (_, w) in webviews.iter() { - if let Err(e) = w.inner.evaluate_script() { - eprintln!("{}", e); - } - } - match event { #[cfg(feature = "menu")] Event::MenuEvent { @@ -1362,7 +1359,9 @@ fn handle_event_loop( if let Some(webview) = webviews.get_mut(&id) { match webview_message { WebviewMessage::EvaluateScript(script) => { - let _ = webview.inner.dispatch_script(&script); + if let Err(e) = webview.inner.evaluate_script(&script) { + eprintln!("{}", e); + } } WebviewMessage::Print => { let _ = webview.inner.print(); @@ -1473,12 +1472,16 @@ fn create_webview>( } for (scheme, protocol) in webview_attributes.uri_scheme_protocols { webview_builder = webview_builder.with_custom_protocol(scheme, move |_window, url| { - protocol(url).map_err(|_| wry::Error::InitScriptError) + protocol(url) + .map(|data| { + let mime_type = MimeType::parse(&data, url); + (data, mime_type) + }) + .map_err(|_| wry::Error::InitScriptError) }); } - if let Some(data_directory) = webview_attributes.data_directory { - webview_builder = webview_builder.with_data_directory(data_directory); - } + let context = WebContext::new(webview_attributes.data_directory); + webview_builder = webview_builder.with_web_context(&context); for script in webview_attributes.initialization_scripts { webview_builder = webview_builder.with_initialization_script(&script); } diff --git a/core/tauri-runtime-wry/src/mime_type.rs b/core/tauri-runtime-wry/src/mime_type.rs new file mode 100644 index 000000000..50e40a851 --- /dev/null +++ b/core/tauri-runtime-wry/src/mime_type.rs @@ -0,0 +1,122 @@ +// Copyright 2019-2021 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use std::fmt; + +const MIMETYPE_PLAIN: &str = "text/plain"; + +/// [Web Compatible MimeTypes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#important_mime_types_for_web_developers) +pub(crate) enum MimeType { + Css, + Csv, + Html, + Ico, + Js, + Json, + Jsonld, + OctetStream, + Rtf, + Svg, +} + +impl std::fmt::Display for MimeType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mime = match self { + MimeType::Css => "text/css", + MimeType::Csv => "text/csv", + MimeType::Html => "text/html", + MimeType::Ico => "image/vnd.microsoft.icon", + MimeType::Js => "text/javascript", + MimeType::Json => "application/json", + MimeType::Jsonld => "application/ld+json", + MimeType::OctetStream => "application/octet-stream", + MimeType::Rtf => "application/rtf", + MimeType::Svg => "image/svg+xml", + }; + write!(f, "{}", mime) + } +} + +impl MimeType { + /// parse a URI suffix to convert text/plain mimeType to their actual web compatible mimeType. + pub fn parse_from_uri(uri: &str) -> MimeType { + let suffix = uri.split('.').last(); + match suffix { + Some("bin") => Self::OctetStream, + Some("css") => Self::Css, + Some("csv") => Self::Csv, + Some("html") => Self::Html, + Some("ico") => Self::Ico, + Some("js") => Self::Js, + Some("json") => Self::Json, + Some("jsonld") => Self::Jsonld, + Some("rtf") => Self::Rtf, + Some("svg") => Self::Svg, + // Assume HTML when a TLD is found for eg. `wry:://tauri.studio` | `wry://hello.com` + Some(_) => Self::Html, + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types + // using octet stream according to this: + None => Self::OctetStream, + } + } + + /// infer mimetype from content (or) URI if needed. + pub fn parse(content: &[u8], uri: &str) -> String { + let mime = match infer::get(content) { + Some(info) => info.mime_type(), + None => MIMETYPE_PLAIN, + }; + + if mime == MIMETYPE_PLAIN { + return Self::parse_from_uri(uri).to_string(); + } + + mime.to_string() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn should_parse_mimetype_from_uri() { + let css = MimeType::parse_from_uri( + "https://unpkg.com/browse/bootstrap@4.1.0/dist/css/bootstrap-grid.css", + ) + .to_string(); + assert_eq!(css, "text/css".to_string()); + + let csv: String = MimeType::parse_from_uri("https://example.com/random.csv").to_string(); + assert_eq!(csv, "text/csv".to_string()); + + let ico: String = + MimeType::parse_from_uri("https://icons.duckduckgo.com/ip3/microsoft.com.ico").to_string(); + assert_eq!(ico, String::from("image/vnd.microsoft.icon")); + + let html: String = MimeType::parse_from_uri("https://tauri.studio/index.html").to_string(); + assert_eq!(html, String::from("text/html")); + + let js: String = + MimeType::parse_from_uri("https://unpkg.com/react@17.0.1/umd/react.production.min.js") + .to_string(); + assert_eq!(js, "text/javascript".to_string()); + + let json: String = + MimeType::parse_from_uri("https://unpkg.com/browse/react@17.0.1/build-info.json").to_string(); + assert_eq!(json, String::from("application/json")); + + let jsonld: String = MimeType::parse_from_uri("https:/example.com/hello.jsonld").to_string(); + assert_eq!(jsonld, String::from("application/ld+json")); + + let rtf: String = MimeType::parse_from_uri("https://example.com/document.rtf").to_string(); + assert_eq!(rtf, String::from("application/rtf")); + + let svg: String = MimeType::parse_from_uri("https://example.com/picture.svg").to_string(); + assert_eq!(svg, String::from("image/svg+xml")); + + let custom_scheme = MimeType::parse_from_uri("wry://tauri.studio").to_string(); + assert_eq!(custom_scheme, String::from("text/html")); + } +}