Browse Source

feat(tauri) make Config globally available (#681)

Lucas Fernandes Nogueira 5 years ago
parent
commit
d3c53ebf30

+ 1 - 0
tauri-api/Cargo.toml

@@ -33,6 +33,7 @@ tauri-utils = {version = "0.5", path = "../tauri-utils"}
 envmnt = "0.8.2"
 clap = { git = "https://github.com/clap-rs/clap", rev = "1a276f8", version = "3.0.0-beta.1", optional = true }
 notify-rust = { version = "4.0.0", optional = true }
+once_cell = "1.4.0"
 
 [dev-dependencies]
 quickcheck = "0.9.2"

+ 10 - 5
tauri-api/src/cli.rs

@@ -1,4 +1,4 @@
-use crate::config::{Cli, Config};
+use crate::config::{get as get_config, Cli};
 
 use clap::{App, Arg, ArgMatches};
 use serde::Serialize;
@@ -36,16 +36,21 @@ impl Matches {
   }
 }
 
-pub fn get_matches(config: Config) -> Matches {
-  let cli = config.tauri.cli.unwrap();
+pub fn get_matches() -> crate::Result<Matches> {
+  let config = get_config()?;
+  let cli = config
+    .tauri
+    .cli
+    .as_ref()
+    .ok_or(anyhow::anyhow!("CLI configuration not defined"))?;
 
   let about = cli
     .description()
     .unwrap_or(&crate_description!().to_string())
     .to_string();
-  let app = get_app(crate_name!(), Some(&about), &cli);
+  let app = get_app(crate_name!(), Some(&about), cli);
   let matches = app.get_matches();
-  get_matches_internal(&cli, &matches)
+  Ok(get_matches_internal(cli, &matches))
 }
 
 fn get_matches_internal<T: Cli + 'static>(config: &T, matches: &ArgMatches) -> Matches {

+ 28 - 15
tauri-api/src/config.rs

@@ -1,9 +1,12 @@
 use serde::Deserialize;
 
+use once_cell::sync::OnceCell;
 use std::collections::HashMap;
 use std::{fs, path};
 
-#[derive(PartialEq, Deserialize, Clone, Debug)]
+static CONFIG: OnceCell<Config> = OnceCell::new();
+
+#[derive(PartialEq, Deserialize, Debug)]
 #[serde(tag = "window", rename_all = "camelCase")]
 pub struct WindowConfig {
   #[serde(default = "default_width")]
@@ -44,7 +47,7 @@ fn default_window() -> WindowConfig {
   }
 }
 
-#[derive(PartialEq, Deserialize, Clone, Debug)]
+#[derive(PartialEq, Deserialize, Debug)]
 #[serde(tag = "embeddedServer", rename_all = "camelCase")]
 pub struct EmbeddedServerConfig {
   #[serde(default = "default_host")]
@@ -68,7 +71,7 @@ fn default_embedded_server() -> EmbeddedServerConfig {
   }
 }
 
-#[derive(PartialEq, Deserialize, Clone, Debug, Default)]
+#[derive(PartialEq, Deserialize, Debug, Default)]
 #[serde(rename_all = "camelCase")]
 pub struct CliArg {
   pub short: Option<char>,
@@ -95,7 +98,7 @@ pub struct CliArg {
   pub require_equals: Option<bool>,
 }
 
-#[derive(PartialEq, Deserialize, Clone, Debug)]
+#[derive(PartialEq, Deserialize, Debug)]
 #[serde(rename_all = "camelCase")]
 pub struct CliSubcommand {
   description: Option<String>,
@@ -106,7 +109,7 @@ pub struct CliSubcommand {
   subcommands: Option<HashMap<String, CliSubcommand>>,
 }
 
-#[derive(PartialEq, Deserialize, Clone, Debug)]
+#[derive(PartialEq, Deserialize, Debug)]
 #[serde(tag = "cli", rename_all = "camelCase")]
 pub struct CliConfig {
   description: Option<String>,
@@ -159,7 +162,7 @@ macro_rules! impl_cli {
   }
 }
 
-#[derive(PartialEq, Deserialize, Clone, Debug)]
+#[derive(PartialEq, Deserialize, Debug)]
 #[serde(tag = "bundle", rename_all = "camelCase")]
 pub struct BundleConfig {
   pub identifier: String,
@@ -173,7 +176,7 @@ fn default_bundle() -> BundleConfig {
 
 impl_cli!(CliSubcommand, CliConfig);
 
-#[derive(PartialEq, Deserialize, Clone, Debug)]
+#[derive(PartialEq, Deserialize, Debug)]
 #[serde(tag = "tauri", rename_all = "camelCase")]
 pub struct TauriConfig {
   #[serde(default = "default_window")]
@@ -186,7 +189,7 @@ pub struct TauriConfig {
   pub bundle: BundleConfig,
 }
 
-#[derive(PartialEq, Deserialize, Clone, Debug)]
+#[derive(PartialEq, Deserialize, Debug)]
 #[serde(tag = "build", rename_all = "camelCase")]
 pub struct BuildConfig {
   #[serde(default = "default_dev_path")]
@@ -197,7 +200,7 @@ fn default_dev_path() -> String {
   "".to_string()
 }
 
-#[derive(PartialEq, Deserialize, Clone, Debug)]
+#[derive(PartialEq, Deserialize, Debug)]
 #[serde(rename_all = "camelCase")]
 pub struct Config {
   #[serde(default = "default_tauri")]
@@ -221,17 +224,27 @@ fn default_build() -> BuildConfig {
   }
 }
 
-pub fn get() -> crate::Result<Config> {
-  match option_env!("TAURI_CONFIG") {
-    Some(config) => Ok(serde_json::from_str(config).expect("failed to parse TAURI_CONFIG env")),
+pub fn get() -> crate::Result<&'static Config> {
+  if let Some(config) = CONFIG.get() {
+    return Ok(config);
+  }
+  let config: Config = match option_env!("TAURI_CONFIG") {
+    Some(config) => serde_json::from_str(config).expect("failed to parse TAURI_CONFIG env"),
     None => {
       let env_var = envmnt::get_or("TAURI_DIR", "../dist");
       let path = path::Path::new(&env_var);
       let contents = fs::read_to_string(path.join("tauri.conf.json"))?;
 
-      Ok(serde_json::from_str(&contents).expect("failed to read tauri.conf.json"))
+      serde_json::from_str(&contents).expect("failed to read tauri.conf.json")
     }
-  }
+  };
+
+  CONFIG
+    .set(config)
+    .map_err(|_| anyhow::anyhow!("failed to set CONFIG"))?;
+
+  let config = CONFIG.get().unwrap();
+  Ok(config)
 }
 
 #[cfg(test)]
@@ -328,7 +341,7 @@ mod test {
       // On Ok, check that the config is the same as the test config.
       Ok(c) => {
         println!("{:?}", c);
-        assert_eq!(c, test_config)
+        assert_eq!(c, &test_config)
       }
       Err(_) => assert!(false),
     }

+ 7 - 7
tauri-api/src/notification.rs

@@ -1,4 +1,5 @@
-use crate::config::Config;
+#[cfg(windows)]
+use crate::config::get as get_config;
 #[cfg(windows)]
 use std::path::MAIN_SEPARATOR;
 
@@ -7,16 +8,14 @@ pub struct Notification {
   body: Option<String>,
   title: Option<String>,
   icon: Option<String>,
-  config: Config,
 }
 
 impl Notification {
-  pub fn new(config: Config) -> Self {
+  pub fn new() -> Self {
     Self {
       body: None,
       title: None,
       icon: None,
-      config,
     }
   }
 
@@ -46,7 +45,7 @@ impl Notification {
     if let Some(icon) = self.icon {
       notification.icon(&icon);
     }
-    #[cfg(windowss)]
+    #[cfg(windows)]
     {
       let exe = std::env::current_exe()?;
       let exe_dir = exe.parent().expect("failed to get exe directory");
@@ -55,8 +54,9 @@ impl Notification {
       if !(curr_dir.ends_with(format!("{S}target{S}debug", S = MAIN_SEPARATOR).as_str())
         || curr_dir.ends_with(format!("{S}target{S}release", S = MAIN_SEPARATOR).as_str()))
       {
-        let identifier = self.config.tauri.bundle.identifier.clone();
-        notification.id(&identifier);
+        let config = get_config()?;
+        let identifier = config.tauri.bundle.identifier.clone();
+        notification.app_id(&identifier);
       }
     }
     notification

+ 1 - 1
tauri/examples/communication/dist/index.tauri.html

@@ -81,7 +81,7 @@ switch (navigator.platform) {
   var Dir = {
     Audio: 1,
     Cache: 2,
-    Config: 3, 
+    Config: 3,
     Data: 4,
     LocalData: 5,
     Desktop: 6,

+ 1 - 1
tauri/examples/communication/src-tauri/tauri.js

@@ -81,7 +81,7 @@ switch (navigator.platform) {
   var Dir = {
     Audio: 1,
     Cache: 2,
-    Config: 3, 
+    Config: 3,
     Data: 4,
     LocalData: 5,
     Desktop: 6,

+ 41 - 59
tauri/src/app/runner.rs

@@ -12,24 +12,12 @@ use web_view::{builder, Content, WebView};
 use super::App;
 #[cfg(feature = "embedded-server")]
 use crate::api::tcp::{get_available_port, port_is_available};
-use tauri_api::config::{get, Config};
-
-#[cfg(feature = "cli")]
-use tauri_api::cli::get_matches;
+use tauri_api::config::get;
 
 // Main entry point function for running the Webview
 pub(crate) fn run(application: &mut App) -> crate::Result<()> {
-  // get the tauri config struct
-  let config = get()?;
-
-  #[cfg(feature = "cli")]
-  {
-    let matches = get_matches(config.clone());
-    crate::cli::set_matches(matches)?;
-  }
-
   // setup the content using the config struct depending on the compile target
-  let main_content = setup_content(config.clone())?;
+  let main_content = setup_content()?;
 
   // setup the server url for the embedded-server
   #[cfg(feature = "embedded-server")]
@@ -44,7 +32,6 @@ pub(crate) fn run(application: &mut App) -> crate::Result<()> {
   // build the webview
   let webview = build_webview(
     application,
-    config,
     main_content,
     if application.splashscreen_html().is_some() {
       Some(Content::Html(
@@ -74,12 +61,13 @@ pub(crate) fn run(application: &mut App) -> crate::Result<()> {
 
 // setup content for dev-server
 #[cfg(not(any(feature = "embedded-server", feature = "no-server")))]
-fn setup_content(config: Config) -> crate::Result<Content<String>> {
+fn setup_content() -> crate::Result<Content<String>> {
+  let config = get()?;
   if config.build.dev_path.starts_with("http") {
-    Ok(Content::Url(config.build.dev_path))
+    Ok(Content::Url(config.build.dev_path.clone()))
   } else {
-    let dev_dir = config.build.dev_path;
-    let dev_path = Path::new(&dev_dir).join("index.tauri.html");
+    let dev_dir = &config.build.dev_path;
+    let dev_path = Path::new(dev_dir).join("index.tauri.html");
     if !dev_path.exists() {
       panic!(
         "Couldn't find 'index.tauri.html' inside {}; did you forget to run 'tauri dev'?",
@@ -92,16 +80,21 @@ fn setup_content(config: Config) -> crate::Result<Content<String>> {
 
 // setup content for embedded server
 #[cfg(feature = "embedded-server")]
-fn setup_content(config: Config) -> crate::Result<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");
+fn setup_content() -> crate::Result<Content<String>> {
+  let (port, valid) = setup_port()?;
+  let url = (if valid {
+    setup_server_url(port)
+  } else {
+    Err(anyhow::anyhow!("invalid 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) -> crate::Result<Content<String>> {
+fn setup_content() -> crate::Result<Content<String>> {
   let dist_dir = match option_env!("TAURI_DIST_DIR") {
     Some(d) => d.to_string(),
     None => env::current_dir()?
@@ -116,35 +109,33 @@ fn setup_content(_: Config) -> crate::Result<Content<String>> {
 
 // get the port for the embedded server
 #[cfg(feature = "embedded-server")]
-fn setup_port(config: Config) -> Option<(String, bool)> {
+fn setup_port() -> crate::Result<(String, bool)> {
+  let config = get()?;
   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)),
+      Some(available_port) => Ok((available_port.to_string(), true)),
+      None => Ok(("0".to_string(), false)),
     }
   } else {
-    let port = config.tauri.embedded_server.port;
+    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))
+    Ok((port.to_string(), port_valid))
   }
 }
 
 // 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
+fn setup_server_url(port: String) -> crate::Result<String> {
+  let config = get()?;
+  let mut url = format!("{}:{}", config.tauri.embedded_server.host, port);
+  if !url.starts_with("http") {
+    url = format!("http://{}", url);
   }
+  Ok(url)
 }
 
 // spawn the embedded server
@@ -186,22 +177,21 @@ fn spawn_updater() -> crate::Result<()> {
 // build the webview struct
 fn build_webview(
   application: &mut App,
-  config: Config,
   content: Content<String>,
   splashscreen_content: Option<Content<String>>,
 ) -> crate::Result<WebView<'_, ()>> {
+  let config = get()?;
   let content_clone = match content {
     Content::Html(ref html) => Content::Html(html.clone()),
     Content::Url(ref url) => Content::Url(url.clone()),
   };
   let debug = cfg!(debug_assertions);
-  let config_clone = config.clone();
   // get properties from config struct
   let width = config.tauri.window.width;
   let height = config.tauri.window.height;
   let resizable = config.tauri.window.resizable;
   let fullscreen = config.tauri.window.fullscreen;
-  let title = config.tauri.window.title.into_boxed_str();
+  let title = config.tauri.window.title.clone().into_boxed_str();
 
   let has_splashscreen = splashscreen_content.is_some();
   let mut initialized_splashscreen = false;
@@ -229,9 +219,7 @@ fn build_webview(
         webview.eval(&format!(r#"window.location.href = "{}""#, content_href))?;
       } else {
         let handler_error;
-        if let Err(tauri_handle_error) =
-          crate::endpoints::handle(webview, arg, config_clone.clone())
-        {
+        if let Err(tauri_handle_error) = crate::endpoints::handle(webview, arg) {
           let tauri_handle_error_str = tauri_handle_error.to_string();
           if tauri_handle_error_str.contains("unknown variant") {
             let handled_by_app = application.run_invoke_handler(webview, arg);
@@ -295,14 +283,13 @@ mod test {
   #[cfg(not(feature = "embedded-server"))]
   use std::{env, fs::read_to_string, path::Path};
 
-  fn init_config() -> tauri_api::config::Config {
+  fn init_config() -> &'static tauri_api::config::Config {
     tauri_api::config::get().expect("unable to setup default config")
   }
 
   #[test]
   fn check_setup_content() {
     let config = init_config();
-    let _c = config.clone();
 
     let tauri_dir = match option_env!("TAURI_DIR") {
       Some(d) => d.to_string(),
@@ -313,7 +300,7 @@ mod test {
         .expect("Unable to convert to normal String"),
     };
     env::set_current_dir(tauri_dir).expect("failed to change cwd");
-    let res = super::setup_content(config);
+    let res = super::setup_content();
 
     #[cfg(feature = "embedded-server")]
     match res {
@@ -342,10 +329,10 @@ mod test {
 
     #[cfg(not(any(feature = "embedded-server", feature = "no-server")))]
     match res {
-      Ok(Content::Url(dp)) => assert_eq!(dp, _c.build.dev_path),
+      Ok(Content::Url(dp)) => assert_eq!(dp, config.build.dev_path),
       Ok(Content::Html(s)) => {
-        let dev_dir = _c.build.dev_path;
-        let dev_path = Path::new(&dev_dir).join("index.tauri.html");
+        let dev_dir = &config.build.dev_path;
+        let dev_path = Path::new(dev_dir).join("index.tauri.html");
         assert_eq!(
           s,
           read_to_string(dev_path).expect("failed to read dev path")
@@ -358,11 +345,9 @@ mod test {
   #[cfg(feature = "embedded-server")]
   #[test]
   fn check_setup_port() {
-    let config = init_config();
-
-    let res = super::setup_port(config);
+    let res = super::setup_port();
     match res {
-      Some((_s, _b)) => assert!(true),
+      Ok((_s, _b)) => assert!(true),
       _ => assert!(false),
     }
   }
@@ -372,16 +357,13 @@ mod test {
     #[cfg(feature = "embedded-server")]
     #[test]
     fn check_server_url(port in (any::<u32>().prop_map(|v| v.to_string()))) {
-      let config = init_config();
-      let valid = true;
-
       let p = port.clone();
 
-      let res = super::setup_server_url(config, valid, port);
+      let res = super::setup_server_url(port);
 
       match res {
-        Some(url) => assert!(url.contains(&p)),
-        None => assert!(false)
+        Ok(url) => assert!(url.contains(&p)),
+        Err(_) => assert!(false)
       }
     }
   }

+ 4 - 10
tauri/src/cli.rs

@@ -1,14 +1,8 @@
-use once_cell::sync::OnceCell;
+use once_cell::sync::Lazy;
 use tauri_api::cli::Matches;
 
-static MATCHES: OnceCell<Matches> = OnceCell::new();
+pub fn get_matches() -> &'static Option<Matches> {
+  static MATCHES: Lazy<Option<Matches>> = Lazy::new(|| tauri_api::cli::get_matches().ok());
 
-pub(crate) fn set_matches(matches: Matches) -> crate::Result<()> {
-  MATCHES
-    .set(matches)
-    .map_err(|_| anyhow::anyhow!("failed to set once_cell matches"))
-}
-
-pub fn get_matches() -> Option<&'static Matches> {
-  MATCHES.get()
+  &MATCHES
 }

+ 3 - 9
tauri/src/endpoints.rs

@@ -6,15 +6,10 @@ mod salt;
 
 #[cfg(any(feature = "embedded-server", feature = "no-server"))]
 use std::path::PathBuf;
-use tauri_api::config::Config;
 use web_view::WebView;
 
 #[allow(unused_variables)]
-pub(crate) fn handle<T: 'static>(
-  webview: &mut WebView<'_, T>,
-  arg: &str,
-  config: Config,
-) -> crate::Result<()> {
+pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> crate::Result<()> {
   use cmd::Cmd::*;
   match serde_json::from_str(arg) {
     Err(e) => Err(e.into()),
@@ -199,7 +194,7 @@ pub(crate) fn handle<T: 'static>(
           callback,
           error,
         } => {
-          notification(webview, options, callback, error, config)?;
+          notification(webview, options, callback, error)?;
         }
         #[cfg(any(feature = "all-api", feature = "notification"))]
         IsNotificationPermissionGranted { callback, error } => {
@@ -413,12 +408,11 @@ fn notification<T: 'static>(
   options: cmd::NotificationOptions,
   callback: String,
   error: String,
-  config: Config,
 ) -> crate::Result<()> {
   crate::execute_promise(
     webview,
     move || {
-      let mut notification = tauri_api::notification::Notification::new(config);
+      let mut notification = tauri_api::notification::Notification::new();
       notification.body(options.body);
       if let Some(title) = options.title {
         notification.title(title);