Преглед изворни кода

Refactor(runner.rs) Clean up code to make it more composable and… (#259)

* update .gitignore

* remove cargo.lock

* add clone to config

* create functions

* finish merge and fix conflict.

* cleanup

* continue refactor cleanup

* fix logic for embedded server

* bringing back the polymorphisms!

* cleaning it all up...

* add imports

* add basic documentation.

* add a TauriResult type

* cleanup spawn_updater func

* cleanup imports and errors.

* fix error and proliferate it

* cleanup ?s
Tensor-Programming пре 5 година
родитељ
комит
aa149370a4
5 измењених фајлова са 214 додато и 146 уклоњено
  1. 1 1
      tauri/src/app.rs
  2. 182 121
      tauri/src/app/runner.rs
  3. 18 15
      tauri/src/config.rs
  4. 10 9
      tauri/src/endpoints.rs
  5. 3 0
      tauri/src/lib.rs

+ 1 - 1
tauri/src/app.rs

@@ -10,7 +10,7 @@ pub struct App {
 
 impl App {
   pub fn run(mut self) {
-    runner::run(&mut self);
+    runner::run(&mut self).expect("Failed to build webview");
   }
 
   pub(crate) fn run_invoke_handler(&mut self, webview: &mut WebView<'_, ()>, arg: &str) {

+ 182 - 121
tauri/src/app/runner.rs

@@ -1,141 +1,202 @@
-pub(crate) fn run(application: &mut crate::App) {
-  let debug = cfg!(debug_assertions);
-  let config = crate::config::get();
+#[allow(unused_imports)]
+use std::{fs::read_to_string, path::Path, process::Stdio, thread::spawn};
 
-  let content;
-  #[cfg(not(any(feature = "embedded-server", feature = "no-server")))]
-  {
-    content = if config.build.dev_path.starts_with("http") {
-      web_view::Content::Url(config.build.dev_path)
-    } else {
-      let dev_path = std::path::Path::new(&config.build.dev_path).join("index.tauri.html");
-      web_view::Content::Html(
-        std::fs::read_to_string(dev_path).expect("failed to read index.tauri.html"),
-      )
-    };
+use web_view::{builder, Content, WebView};
+
+use crate::config::{get, Config};
+#[cfg(feature = "embedded-server")]
+use crate::tcp::{get_available_port, port_is_available};
+use crate::App;
+use crate::TauriResult;
+
+// JavaScript string literal
+const JS_STRING: &'static str = r#"
+if (window.onTauriInit !== void 0) {
+  window.onTauriInit()
+  window.onTauriInit = void 0
+}
+Object.defineProperty(window, 'onTauriInit', {
+  set: function(val) {
+    if (typeof(val) === 'function') {
+      val()
+    }
   }
+})
+"#;
 
-  #[cfg(feature = "embedded-server")]
-  let server_url;
+// Main entry point function for running the Webview
+pub(crate) fn run(application: &mut App) -> TauriResult<()> {
+  // get the tauri config struct
+  let config = get()?;
 
+  // setup the content using the config struct depending on the compile target
+  let content = setup_content(config.clone())?;
+
+  // setup the server url for the embedded-server
   #[cfg(feature = "embedded-server")]
-  {
-    // define URL
-    let port;
-    let port_valid;
-    if config.tauri.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.tauri.embedded_server.port;
-      port_valid = crate::tcp::port_is_available(
-        port
-          .parse::<u16>()
-          .expect(&format!("Invalid port {}", port)),
-      );
-    }
-    if port_valid {
-      let mut url = format!("{}:{}", config.tauri.embedded_server.host, port);
-      if !url.starts_with("http") {
-        url = format!("http://{}", url);
-      }
-      server_url = url.clone();
-      content = web_view::Content::Url(url.to_string());
+  let server_url = {
+    if let Content::Url(ref url) = &content {
+      String::from(url)
     } else {
-      panic!(format!("Port {} is not valid or not open", port));
+      String::from("")
     }
+  };
+
+  // build the webview
+  let webview = build_webview(application, config, content)?;
+
+  // on dev-server grab a handler and execute the tauri.js API entry point.
+  #[cfg(feature = "dev-server")]
+  webview
+    .handle()
+    .dispatch(|_webview| _webview.eval(include_str!(concat!(env!("TAURI_DIR"), "/tauri.js"))))?;
+
+  // spawn the embedded server on our server url
+  #[cfg(feature = "embedded-server")]
+  spawn_server(server_url.to_string())?;
+
+  // spin up the updater process
+  #[cfg(feature = "updater")]
+  spawn_updater()?;
+
+  // run the webview
+  webview.run()?;
+
+  Ok(())
+}
+
+// setup content for dev-server
+#[cfg(not(any(feature = "embedded-server", feature = "no-server")))]
+fn setup_content(config: Config) -> TauriResult<Content<String>> {
+  if config.build.dev_path.starts_with("http") {
+    Ok(Content::Url(config.build.dev_path))
+  } else {
+    let dev_path = Path::new(env!("TAURI_DIST_DIR")).join("index.tauri.html");
+    Ok(Content::Html(read_to_string(dev_path)?))
   }
+}
+
+// setup content for embedded server
+#[cfg(feature = "embedded-server")]
+fn setup_content(config: Config) -> TauriResult<Content<String>> {
+  let (port, valid) = setup_port(config.clone()).expect("Unable to setup Port");
+  let url = setup_server_url(config.clone(), valid, port).expect("Unable to setup URL");
+
+  Ok(Content::Url(url.to_string()))
+}
+
+// setup content for no-server
+#[cfg(feature = "no-server")]
+fn setup_content(_: Config) -> TauriResult<Content<String>> {
+  let index_path = Path::new(env!("TAURI_DIST_DIR")).join("index.tauri.html");
+  Ok(Content::Html(read_to_string(index_path)?))
+}
 
-  #[cfg(feature = "no-server")]
-  {
-    let index_path = std::path::Path::new(env!("TAURI_DIST_DIR")).join("index.tauri.html");
-    content =
-      web_view::Content::Html(std::fs::read_to_string(index_path).expect("failed to read string"));
+// get the port for the embedded server
+#[cfg(feature = "embedded-server")]
+fn setup_port(config: Config) -> Option<(String, bool)> {
+  if config.tauri.embedded_server.port == "random" {
+    match get_available_port() {
+      Some(available_port) => Some((available_port.to_string(), true)),
+      None => Some(("0".to_string(), false)),
+    }
+  } else {
+    let port = config.tauri.embedded_server.port;
+    let port_valid = port_is_available(
+      port
+        .parse::<u16>()
+        .expect(&format!("Invalid port {}", port)),
+    );
+    Some((port, port_valid))
   }
+}
 
-  #[cfg(feature = "updater")]
-  {
-    std::thread::spawn(|| {
-      crate::command::spawn_relative_command(
-        "updater".to_string(),
-        Vec::new(),
-        std::process::Stdio::inherit(),
-      )
-      .expect("Failed to spawn updater thread");
-    });
+// setup the server url for embedded server
+#[cfg(feature = "embedded-server")]
+fn setup_server_url(config: Config, valid: bool, port: String) -> Option<String> {
+  if valid {
+    let mut url = format!("{}:{}", config.tauri.embedded_server.host, port);
+    if !url.starts_with("http") {
+      url = format!("http://{}", url);
+    }
+    Some(url)
+  } else {
+    None
   }
+}
 
-  let webview = web_view::builder()
-    .title(&config.tauri.window.title)
-    .size(config.tauri.window.width, config.tauri.window.height)
-    .resizable(config.tauri.window.resizable)
-    .debug(debug)
-    .user_data(())
-    .invoke_handler(|webview, arg| {
-      if arg == r#"{"cmd":"__initialized"}"# {
-        application.run_setup(webview);
-        webview.eval("
-          if (window.onTauriInit !== void 0) {
-            window.onTauriInit()
-            window.onTauriInit = void 0
-          }
-          Object.defineProperty(window, 'onTauriInit', {
-            set: function(val) {
-              if (typeof(val) === 'function') {
-                val()
-              }
-            }
-          })
-        ").expect("failed to evaluate window.onTauriInit");
-      } else if !crate::endpoints::handle(webview, arg) {
-        application.run_invoke_handler(webview, arg);
+// spawn the embedded server
+#[cfg(feature = "embedded-server")]
+fn spawn_server(server_url: String) -> TauriResult<()> {
+  spawn(move || {
+    let server = tiny_http::Server::http(
+      server_url
+        .clone()
+        .replace("http://", "")
+        .replace("https://", ""),
+    )
+    .expect("Unable to spawn server");
+    for request in server.incoming_requests() {
+      let url = match request.url() {
+        "/" => "/index.tauri.html",
+        url => url,
       }
+      .to_string();
+      request
+        .respond(crate::server::asset_response(&url))
+        .expect("unable to setup response");
+    }
+  });
 
-      Ok(())
-    })
-    .content(content)
-    .build()
-    .expect("Failed to build webview builder");
+  Ok(())
+}
 
-  #[cfg(feature = "dev-server")]
-  webview
-    .handle()
-    .dispatch(|_webview| _webview.eval(include_str!(concat!(env!("TAURI_DIR"), "/tauri.js"))))
-    .expect("Failed to grab webview handle");
+// spawn an updater process.
+#[cfg(feature = "updater")]
+fn spawn_updater() -> TauriResult<()> {
+  spawn(|| {
+    tauri_api::command::spawn_relative_command(
+      "updater".to_string(),
+      Vec::new(),
+      Stdio::inherit(),
+    )?;
+  });
+  Ok(())
+}
 
-  #[cfg(feature = "embedded-server")]
-  {
-    std::thread::spawn(move || {
-      let server = tiny_http::Server::http(
-        server_url
-          .clone()
-          .replace("http://", "")
-          .replace("https://", ""),
-      )
-      .expect(&format!(
-        "Could not start embedded server with the specified url: {}",
-        server_url
-      ));
-      for request in server.incoming_requests() {
-        let url = match request.url() {
-          "/" => "/index.tauri.html",
-          url => url,
+// build the webview struct
+fn build_webview(
+  application: &mut App,
+  config: Config,
+  content: Content<String>,
+) -> TauriResult<WebView<'_, ()>> {
+  let debug = cfg!(debug_assertions);
+  // get properties from config struct
+  let width = config.tauri.window.width;
+  let height = config.tauri.window.height;
+  let resizable = config.tauri.window.resizable;
+  let title = config.tauri.window.title.into_boxed_str();
+
+  Ok(
+    builder()
+      .title(Box::leak(title))
+      .size(width, height)
+      .resizable(resizable)
+      .debug(debug)
+      .user_data(())
+      .invoke_handler(move |webview, arg| {
+        if arg == r#"{"cmd":"__initialized"}"# {
+          application.run_setup(webview);
+          webview.eval(JS_STRING)?;
+        } else if let Ok(b) = crate::endpoints::handle(webview, arg) {
+          if !b {
+            application.run_invoke_handler(webview, arg);
+          }
         }
-        .to_string();
-        request
-          .respond(crate::server::asset_response(&url))
-          .expect("Failed to read asset type");
-      }
-    });
-  }
 
-  webview.run().expect("Failed to run webview");
+        Ok(())
+      })
+      .content(content)
+      .build()?,
+  )
 }

+ 18 - 15
tauri/src/config.rs

@@ -1,6 +1,8 @@
 use std::env;
 
-#[derive(Deserialize)]
+use crate::TauriResult;
+
+#[derive(Deserialize, Clone)]
 #[serde(tag = "window", rename_all = "camelCase")]
 pub struct WindowConfig {
   #[serde(default = "default_width")]
@@ -38,7 +40,7 @@ fn default_window() -> WindowConfig {
   };
 }
 
-#[derive(Deserialize)]
+#[derive(Deserialize, Clone)]
 #[serde(tag = "embeddedServer", rename_all = "camelCase")]
 pub struct EmbeddedServerConfig {
   #[serde(default = "default_host")]
@@ -62,53 +64,54 @@ fn default_embedded_server() -> EmbeddedServerConfig {
   }
 }
 
-#[derive(Deserialize)]
+#[derive(Deserialize, Clone)]
 #[serde(tag = "tauri", rename_all = "camelCase")]
 pub struct TauriConfig {
   #[serde(default = "default_window")]
   pub window: WindowConfig,
   #[serde(default = "default_embedded_server")]
-  pub embedded_server: EmbeddedServerConfig
+  pub embedded_server: EmbeddedServerConfig,
 }
 
-#[derive(Deserialize)]
+#[derive(Deserialize, Clone)]
 #[serde(tag = "build", rename_all = "camelCase")]
 pub struct BuildConfig {
   #[serde(default = "default_dev_path")]
-  pub dev_path: String
+  pub dev_path: String,
 }
 
 fn default_dev_path() -> String {
   "".to_string()
 }
 
-#[derive(Deserialize)]
+#[derive(Deserialize, Clone)]
 #[serde(rename_all = "camelCase")]
 pub struct Config {
   #[serde(default = "default_tauri")]
   pub tauri: TauriConfig,
   #[serde(default = "default_build")]
-  pub build: BuildConfig
+  pub build: BuildConfig,
 }
 
 fn default_tauri() -> TauriConfig {
   TauriConfig {
     window: default_window(),
-    embedded_server: default_embedded_server()
+    embedded_server: default_embedded_server(),
   }
 }
 
 fn default_build() -> BuildConfig {
   BuildConfig {
-    dev_path: default_dev_path()
+    dev_path: default_dev_path(),
   }
 }
 
-pub fn get() -> Config {
+pub fn get() -> TauriResult<Config> {
   match option_env!("TAURI_CONFIG") {
-    Some(config) => serde_json::from_str(config)
-      .expect("failed to parse TAURI_CONFIG env"),
-    None => serde_json::from_str(include_str!(concat!(env!("TAURI_DIR"), "/tauri.conf.json")))
-      .expect("failed to read tauri.conf.json")
+    Some(config) => Ok(serde_json::from_str(config).expect("failed to parse TAURI_CONFIG env")),
+    None => Ok(
+      serde_json::from_str(include_str!(concat!(env!("TAURI_DIR"), "/tauri.conf.json")))
+        .expect("failed to read tauri.conf.json"),
+    ),
   }
 }

+ 10 - 9
tauri/src/endpoints.rs

@@ -2,11 +2,13 @@ mod cmd;
 
 use web_view::WebView;
 
+use crate::TauriResult;
+
 #[allow(unused_variables)]
-pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> bool {
+pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> TauriResult<bool> {
   use cmd::Cmd::*;
   match serde_json::from_str(arg) {
-    Err(_) => false,
+    Err(_) => Ok(false),
     Ok(command) => {
       match command {
         Init {} => {
@@ -44,13 +46,12 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> boo
             listeners = crate::event::event_listeners_object_name(),
             queue = crate::event::event_queue_object_name()
           );
-          webview
-            .eval(&format!(
-              r#"{event_init}
+          webview.eval(&format!(
+            r#"{event_init}
                 window.external.invoke('{{"cmd":"__initialized"}}')
               "#,
-              event_init = event_init
-            )).expect("Failed to call webview.eval from init");
+            event_init = event_init
+          ))?;
         }
         #[cfg(any(feature = "all-api", feature = "readTextFile"))]
         ReadTextFile {
@@ -95,7 +96,7 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> boo
         }
         #[cfg(any(feature = "all-api", feature = "setTitle"))]
         SetTitle { title } => {
-          webview.set_title(&title).expect("Failed to set title");
+          webview.set_title(&title)?;
         }
         #[cfg(any(feature = "all-api", feature = "execute"))]
         Execute {
@@ -211,7 +212,7 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> boo
           );
         }
       }
-      true
+      Ok(true)
     }
   }
 }

+ 3 - 0
tauri/src/lib.rs

@@ -34,6 +34,9 @@ use web_view::*;
 
 pub use tauri_api as api;
 
+// Result alias
+type TauriResult<T> = Result<T, Box<dyn std::error::Error>>;
+
 thread_local!(static POOL: ThreadPool = ThreadPool::new(4));
 
 pub fn spawn<F: FnOnce() -> () + Send + 'static>(task: F) {