From 4c2c9d00b938e2c25da3d845f4f99e32fd87563b Mon Sep 17 00:00:00 2001 From: Lucas Fernandes Nogueira Date: Fri, 16 Aug 2019 07:58:30 -0300 Subject: [PATCH] feat(tauri) core template isolated (#18) --- lib/rust/Cargo.toml | 3 + lib/rust/build.rs | 7 +- lib/rust/src/app.rs | 46 +++++++++ lib/rust/src/app/runner.rs | 157 +++++++++++++++++++++++++++++++ lib/rust/src/lib.rs | 3 + lib/rust/src/server.rs | 2 +- templates/rust/Cargo.toml | 5 +- templates/rust/src/main.rs | 188 ++++--------------------------------- 8 files changed, 235 insertions(+), 176 deletions(-) create mode 100644 lib/rust/src/app.rs create mode 100644 lib/rust/src/app/runner.rs diff --git a/lib/rust/Cargo.toml b/lib/rust/Cargo.toml index ab116ba2f..22c184dd2 100644 --- a/lib/rust/Cargo.toml +++ b/lib/rust/Cargo.toml @@ -31,11 +31,14 @@ uuid = { version = "0.7", features = ["v4"] } lazy_static = "1.3.0" includedir = "0.5.0" tiny_http = "0.6" +clap = {version = "2.33", features = ["yaml"]} [build-dependencies] includedir_codegen = "0.5.0" [features] +dev = [] +embedded-server = [] all-api = [] readTextFile = [] readBinaryFile = [] diff --git a/lib/rust/build.rs b/lib/rust/build.rs index 07829cd86..ec0e49e0e 100755 --- a/lib/rust/build.rs +++ b/lib/rust/build.rs @@ -1,10 +1,15 @@ extern crate includedir_codegen; use includedir_codegen::Compression; +use std::env; + +static CARGOENV: &str = "cargo:rustc-env="; fn main() { + let dist_path = format!("{}/../../../../{}", env::var("OUT_DIR").unwrap(), "compiled-web"); + println!("{}TAURI_DIST_DIR={}", CARGOENV, dist_path); includedir_codegen::start("ASSETS") - .dir("./target/compiled-web", Compression::Gzip) + .dir(dist_path, Compression::None) .build("data.rs") .unwrap(); } diff --git a/lib/rust/src/app.rs b/lib/rust/src/app.rs new file mode 100644 index 000000000..3322b73a4 --- /dev/null +++ b/lib/rust/src/app.rs @@ -0,0 +1,46 @@ +mod runner; +use tauri_ui::WebView; + +//type FnMut(&mut InvokeHandler>, &str) = FnMut(&mut FnMut(&mut InvokeHandler>, &str)>, &str); + +pub struct App { + invoke_handler: Option, &str)>> +} + +impl App { + pub fn run(mut self) { + runner::run(&mut self); + } + + pub fn run_invoke_handler(&mut self, webview: &mut WebView<'_, ()>, arg: &str) { + match self.invoke_handler { + Some(ref mut invoke_handler) => { + invoke_handler(webview, arg); + }, + None => {} + } + } +} + +pub struct AppBuilder { + invoke_handler: Option, &str)>> +} + +impl AppBuilder { + pub fn new() -> Self { + Self { + invoke_handler: None + } + } + + pub fn invoke_handler, &str) + 'static>(mut self, invoke_handler: F) -> Self { + self.invoke_handler = Some(Box::new(invoke_handler)); + self + } + + pub fn build(self) -> App { + App { + invoke_handler: self.invoke_handler + } + } +} diff --git a/lib/rust/src/app/runner.rs b/lib/rust/src/app/runner.rs new file mode 100644 index 000000000..0323078af --- /dev/null +++ b/lib/rust/src/app/runner.rs @@ -0,0 +1,157 @@ +#[cfg(feature = "dev")] +use clap::{App, Arg}; + +#[cfg(not(feature = "dev"))] +#[cfg(feature = "embedded-server")] +use std::thread; + +pub(crate) fn run(application: &mut crate::App) { + let debug; + let content; + let config = crate::config::get(); + #[cfg(feature = "embedded-server")] + let server_url: String; + + #[cfg(feature = "updater")] + { + thread::spawn(|| { + crate::command::spawn_relative_command( + "updater".to_string(), + Vec::new(), + std::process::Stdio::inherit(), + ) + .unwrap(); + }); + } + + #[cfg(feature = "dev")] + { + let app = App::new("app") + .version("1.0.0") + .author("Author") + .about("About") + .arg( + Arg::with_name("url") + .short("u") + .long("url") + .value_name("URL") + .help("Loads the specified URL into webview") + .required(true) + .takes_value(true), + ); + + let matches = app.get_matches(); + content = tauri_ui::Content::Url(matches.value_of("url").unwrap().to_owned()); + debug = true; + } + + #[cfg(not(feature = "dev"))] + { + debug = cfg!(debug_assertions); + #[cfg(not(feature = "embedded-server"))] + { + content = tauri_ui::Content::Html(include_str!(concat!(env!("TAURI_DIST_DIR"), "/index.html"))); + } + #[cfg(feature = "embedded-server")] + { + let port; + let port_valid; + if config.embedded_server.port == "random" { + match crate::tcp::get_available_port() { + Some(available_port) => { + port = available_port.to_string(); + port_valid = true; + } + None => { + port = "0".to_string(); + port_valid = false; + } + } + } else { + port = config.embedded_server.port; + port_valid = crate::tcp::port_is_available(port.parse::().expect(&format!("Invalid port {}", port))); + } + if port_valid { + server_url = format!("{}:{}", config.embedded_server.host, port); + content = tauri_ui::Content::Url(server_url.clone()); + } else { + panic!(format!("Port {} is not valid or not open", port)); + } + } + } + + let webview = tauri_ui::builder() + .title(&config.window.title) + .size(config.window.width, config.window.height) + .resizable(config.window.resizable) + .debug(debug) + .user_data(()) + .invoke_handler(|webview, arg| { + // leave this as is to use the tauri API from your JS code + if !crate::api::handler(webview, arg) { + application.run_invoke_handler(webview, arg); + } + + Ok(()) + }) + .content(content) + .build() + .unwrap(); + + webview + .handle() + .dispatch(move |_webview| { + _webview + .eval(&format!( + "window['{queue}'] = []; + window['{fn}'] = function (payload, salt, ignoreQueue) {{ + window.tauri.promisified({{ + cmd: 'validateSalt', + salt + }}).then(function () {{ + const listeners = (window['{listeners}'] && window['{listeners}'][payload.type]) || [] + + if (!ignoreQueue && listeners.length === 0) {{ + window['{queue}'].push({{ + payload: payload, + salt: salt + }}) + }} + + for (let i = listeners.length - 1; i >= 0; i--) {{ + const listener = listeners[i] + if (listener.once) + listeners.splice(i, 1) + listener.handler(payload) + }} + }}) + }}", + fn = crate::event::emit_function_name(), + listeners = crate::event::event_listeners_object_name(), + queue = crate::event::event_queue_object_name() + )) + .unwrap(); + + Ok(()) + }) + .unwrap(); + + #[cfg(not(feature = "dev"))] + { + #[cfg(feature = "embedded-server")] + { + thread::spawn(move || { + let server = tiny_http::Server::http(server_url.clone()).expect(&format!("Could not start embedded server with the specified url: {}", server_url)); + for request in server.incoming_requests() { + let mut url = request.url().to_string(); + if url == "/" { + url = "/index.html".to_string(); + } + request.respond(crate::server::asset_response(&url)).unwrap(); + } + }); + } + } + + webview.run().unwrap(); +} \ No newline at end of file diff --git a/lib/rust/src/lib.rs b/lib/rust/src/lib.rs index d2ab284b1..5ce44ea00 100644 --- a/lib/rust/src/lib.rs +++ b/lib/rust/src/lib.rs @@ -25,7 +25,10 @@ pub mod salt; pub mod tcp; pub mod updater; pub mod version; +#[cfg(feature = "embedded-server")] pub mod server; +mod app; +pub use app::*; use tauri_ui::WebView; diff --git a/lib/rust/src/server.rs b/lib/rust/src/server.rs index 5a7534d15..7e72120fd 100644 --- a/lib/rust/src/server.rs +++ b/lib/rust/src/server.rs @@ -4,7 +4,7 @@ include!(concat!(env!("OUT_DIR"), "/data.rs")); pub fn asset_response(path: &str) -> Response>> { let asset = ASSETS - .get(&format!("./target/compiled-web{}", path)) + .get(&format!("{}{}", env!("TAURI_DIST_DIR"), path)) .unwrap() .into_owned(); let mut response = Response::from_data(asset); diff --git a/templates/rust/Cargo.toml b/templates/rust/Cargo.toml index 96c3c1b04..dcdfdfd4e 100755 --- a/templates/rust/Cargo.toml +++ b/templates/rust/Cargo.toml @@ -15,14 +15,13 @@ serde_json = "1.0.39" serde = "1.0" serde_derive = "1.0" tiny_http = "0.6" -clap = {version = "2.33", features = ["yaml"]} phf = "0.7.21" includedir = "0.5.0" tauri = { path = "../../tauri/lib/rust" } [features] -dev = [] # has no explicit dependencies -embedded-server = [] # has no explicit dependencies +dev = ["tauri/dev"] # has no explicit dependencies +embedded-server = ["tauri/embedded-server"] # has no explicit dependencies [package.metadata.bundle] identifier = "com.quasar.dev" diff --git a/templates/rust/src/main.rs b/templates/rust/src/main.rs index c58d340e5..d93870ed8 100755 --- a/templates/rust/src/main.rs +++ b/templates/rust/src/main.rs @@ -1,181 +1,27 @@ -#[macro_use] -extern crate serde_derive; -extern crate clap; -extern crate tauri; -extern crate tauri_ui; -extern crate serde_json; - -#[cfg(not(feature = "dev"))] -extern crate tiny_http; - -#[cfg(feature = "dev")] -use clap::{App, Arg}; - -#[cfg(not(feature = "dev"))] -#[cfg(feature = "embedded-server")] -use std::thread; - mod cmd; +extern crate tauri; + +#[macro_use] +extern crate serde_derive; + fn main() { - let debug; - let content; - let config = tauri::config::get(); - #[cfg(feature = "embedded-server")] - let server_url: String; - - #[cfg(feature = "updater")] - { - thread::spawn(|| { - tauri::command::spawn_relative_command( - "updater".to_string(), - Vec::new(), - std::process::Stdio::inherit(), - ) - .unwrap(); - }); - } - - #[cfg(feature = "dev")] - { - let app = App::new("app") - .version("1.0.0") - .author("Author") - .about("About") - .arg( - Arg::with_name("url") - .short("u") - .long("url") - .value_name("URL") - .help("Loads the specified URL into webview") - .required(true) - .takes_value(true), - ); - - let matches = app.get_matches(); - content = tauri_ui::Content::Url(matches.value_of("url").unwrap().to_owned()); - debug = true; - } - - #[cfg(not(feature = "dev"))] - { - debug = cfg!(debug_assertions); - #[cfg(not(feature = "embedded-server"))] - { - content = tauri_ui::Content::Html(include_str!("../target/compiled-web/index.html")); - } - #[cfg(feature = "embedded-server")] - { - let port; - let port_valid; - if config.embedded_server.port == "random" { - match tauri::tcp::get_available_port() { - Some(available_port) => { - port = available_port.to_string(); - port_valid = true; - } - None => { - port = "0".to_string(); - port_valid = false; - } - } - } else { - port = config.embedded_server.port; - port_valid = tauri::tcp::port_is_available(port.parse::().expect(&format!("Invalid port {}", port))); - } - if port_valid { - server_url = format!("{}:{}", config.embedded_server.host, port); - content = tauri_ui::Content::Url(server_url.clone()); - } else { - panic!(format!("Port {} is not valid or not open", port)); - } - } - } - - let webview = tauri_ui::builder() - .title(&config.window.title) - .size(config.window.width, config.window.height) - .resizable(config.window.resizable) - .debug(debug) - .user_data(()) - .invoke_handler(|webview, arg| { - // leave this as is to use the tauri API from your JS code - if !tauri::api::handler(webview, arg) { - use cmd::Cmd::*; - match serde_json::from_str(arg) { - Err(_) => {} - Ok(command) => { - match command { - // definitions for your custom commands from Cmd here - MyCustomCommand { argument } => { - // your command code - println!("{}", argument); - } + tauri::AppBuilder::new() + .invoke_handler(|_webview, arg| { + use cmd::Cmd::*; + match serde_json::from_str(arg) { + Err(_) => {} + Ok(command) => { + match command { + // definitions for your custom commands from Cmd here + MyCustomCommand { argument } => { + // your command code + println!("{}", argument); } } } } - - Ok(()) }) - .content(content) .build() - .unwrap(); - - webview - .handle() - .dispatch(move |_webview| { - _webview - .eval(&format!( - "window['{queue}'] = []; - window['{fn}'] = function (payload, salt, ignoreQueue) {{ - window.tauri.promisified({{ - cmd: 'validateSalt', - salt - }}).then(function () {{ - const listeners = (window['{listeners}'] && window['{listeners}'][payload.type]) || [] - - if (!ignoreQueue && listeners.length === 0) {{ - window['{queue}'].push({{ - payload: payload, - salt: salt - }}) - }} - - for (let i = listeners.length - 1; i >= 0; i--) {{ - const listener = listeners[i] - if (listener.once) - listeners.splice(i, 1) - listener.handler(payload) - }} - }}) - }}", - fn = tauri::event::emit_function_name(), - listeners = tauri::event::event_listeners_object_name(), - queue = tauri::event::event_queue_object_name() - )) - .unwrap(); - - Ok(()) - }) - .unwrap(); - - #[cfg(not(feature = "dev"))] - { - #[cfg(feature = "embedded-server")] - { - thread::spawn(move || { - let server = tiny_http::Server::http(server_url.clone()).expect(&format!("Could not start embedded server with the specified url: {}", server_url)); - for request in server.incoming_requests() { - let mut url = request.url().to_string(); - if url == "/" { - url = "/index.html".to_string(); - } - request.respond(tauri::server::asset_response(&url)).unwrap(); - } - }); - } - } - - webview.run().unwrap(); + .run(); }