Pārlūkot izejas kodu

feat(core): expose `setup_with_config` on the plugin builder (#3379)

Lucas Fernandes Nogueira 3 gadi atpakaļ
vecāks
revīzija
7918584b5c
3 mainītis faili ar 69 papildinājumiem un 11 dzēšanām
  1. 1 2
      core/tauri/src/api/file.rs
  2. 1 0
      core/tauri/src/app.rs
  3. 67 9
      core/tauri/src/plugin.rs

+ 1 - 2
core/tauri/src/api/file.rs

@@ -48,9 +48,8 @@ mod test {
 
     assert!(res.is_err());
 
+    #[cfg(not(windows))]
     if let Error::Io(e) = res.unwrap_err() {
-      #[cfg(windows)]
-      assert_eq!(e.to_string(), "Access is denied. (os error 5)".to_string());
       #[cfg(not(windows))]
       assert_eq!(e.to_string(), "Is a directory (os error 21)".to_string());
     }

+ 1 - 0
core/tauri/src/app.rs

@@ -681,6 +681,7 @@ impl<R: Runtime> Builder<R> {
   /// - **macOS**: on macOS the application *must* be executed on the main thread, so this function is not exposed.
   #[cfg(any(windows, target_os = "linux"))]
   #[cfg_attr(doc_cfg, doc(any(windows, target_os = "linux")))]
+  #[must_use]
   pub fn any_thread(mut self) -> Self {
     self.runtime_any_thread = true;
     self

+ 67 - 9
core/tauri/src/plugin.rs

@@ -8,6 +8,7 @@ use crate::{
   runtime::Runtime, utils::config::PluginConfig, AppHandle, Invoke, InvokeHandler, OnPageLoad,
   PageLoadPayload, RunEvent, Window,
 };
+use serde::de::DeserializeOwned;
 use serde_json::Value as JsonValue;
 use tauri_macros::default_runtime;
 
@@ -54,26 +55,29 @@ pub trait Plugin<R: Runtime>: Send {
 }
 
 type SetupHook<R> = dyn Fn(&AppHandle<R>) -> Result<()> + Send + Sync;
+type SetupWithConfigHook<R, T> = dyn Fn(&AppHandle<R>, T) -> Result<()> + Send + Sync;
 type OnWebviewReady<R> = dyn Fn(Window<R>) + Send + Sync;
 type OnEvent<R> = dyn Fn(&AppHandle<R>, &RunEvent) + Send + Sync;
 
 /// Builds a [`TauriPlugin`].
-pub struct Builder<R: Runtime> {
+pub struct Builder<R: Runtime, C: DeserializeOwned = ()> {
   name: &'static str,
   invoke_handler: Box<InvokeHandler<R>>,
   setup: Box<SetupHook<R>>,
+  setup_with_config: Option<Box<SetupWithConfigHook<R, C>>>,
   js_init_script: Option<String>,
   on_page_load: Box<OnPageLoad<R>>,
   on_webview_ready: Box<OnWebviewReady<R>>,
   on_event: Box<OnEvent<R>>,
 }
 
-impl<R: Runtime> Builder<R> {
+impl<R: Runtime, C: DeserializeOwned> Builder<R, C> {
   /// Creates a new Plugin builder.
   pub fn new(name: &'static str) -> Self {
     Self {
       name,
       setup: Box::new(|_| Ok(())),
+      setup_with_config: None,
       js_init_script: None,
       invoke_handler: Box::new(|_| ()),
       on_page_load: Box::new(|_, _| ()),
@@ -83,6 +87,7 @@ impl<R: Runtime> Builder<R> {
   }
 
   /// Defines the JS message handler callback.
+  #[must_use]
   pub fn invoke_handler<F>(mut self, invoke_handler: F) -> Self
   where
     F: Fn(Invoke<R>) + Send + Sync + 'static,
@@ -96,12 +101,20 @@ impl<R: Runtime> Builder<R> {
   /// so global variables must be assigned to `window` instead of implicity declared.
   ///
   /// It's guaranteed that this script is executed before the page is loaded.
+  #[must_use]
   pub fn js_init_script(mut self, js_init_script: String) -> Self {
     self.js_init_script = Some(js_init_script);
     self
   }
 
-  /// Define a closure that can setup plugin specific state.
+  /// Define a closure that runs when the app is built.
+  ///
+  /// This is a convenience function around [setup_with_config], without the need to specify a configuration object.
+  ///
+  /// The closure gets called before the [setup_with_config] closure.
+  ///
+  /// [setup_with_config]: struct.Builder.html#method.setup_with_config
+  #[must_use]
   pub fn setup<F>(mut self, setup: F) -> Self
   where
     F: Fn(&AppHandle<R>) -> Result<()> + Send + Sync + 'static,
@@ -110,7 +123,44 @@ impl<R: Runtime> Builder<R> {
     self
   }
 
+  /// Define a closure that runs when the app is built, accepting a configuration object set on `tauri.conf.json > plugins > yourPluginName`.
+  ///
+  /// If your plugin is not pulling a configuration object from `tauri.conf.json`, use [setup].
+  ///
+  /// The closure gets called after the [setup] closure.
+  ///
+  /// # Example
+  ///
+  /// ```rust,no_run
+  /// #[derive(serde::Deserialize)]
+  /// struct Config {
+  ///   api_url: String,
+  /// }
+  ///
+  /// fn get_plugin<R: tauri::Runtime>() -> tauri::plugin::TauriPlugin<R, Config> {
+  ///   tauri::plugin::Builder::<R, Config>::new("api")
+  ///     .setup_with_config(|_app, config| {
+  ///       println!("config: {:?}", config.api_url);
+  ///       Ok(())
+  ///     })
+  ///     .build()
+  /// }
+  ///
+  /// tauri::Builder::default().plugin(get_plugin());
+  /// ```
+  ///
+  /// [setup]: struct.Builder.html#method.setup
+  #[must_use]
+  pub fn setup_with_config<F>(mut self, setup_with_config: F) -> Self
+  where
+    F: Fn(&AppHandle<R>, C) -> Result<()> + Send + Sync + 'static,
+  {
+    self.setup_with_config.replace(Box::new(setup_with_config));
+    self
+  }
+
   /// Callback invoked when the webview performs a navigation to a page.
+  #[must_use]
   pub fn on_page_load<F>(mut self, on_page_load: F) -> Self
   where
     F: Fn(Window<R>, PageLoadPayload) + Send + Sync + 'static,
@@ -120,6 +170,7 @@ impl<R: Runtime> Builder<R> {
   }
 
   /// Callback invoked when the webview is created.
+  #[must_use]
   pub fn on_webview_ready<F>(mut self, on_webview_ready: F) -> Self
   where
     F: Fn(Window<R>) + Send + Sync + 'static,
@@ -129,6 +180,7 @@ impl<R: Runtime> Builder<R> {
   }
 
   /// Callback invoked when the event loop receives a new event.
+  #[must_use]
   pub fn on_event<F>(mut self, on_event: F) -> Self
   where
     F: Fn(&AppHandle<R>, &RunEvent) + Send + Sync + 'static,
@@ -138,11 +190,12 @@ impl<R: Runtime> Builder<R> {
   }
 
   /// Builds the [TauriPlugin].
-  pub fn build(self) -> TauriPlugin<R> {
+  pub fn build(self) -> TauriPlugin<R, C> {
     TauriPlugin {
       name: self.name,
       invoke_handler: self.invoke_handler,
       setup: self.setup,
+      setup_with_config: self.setup_with_config,
       js_init_script: self.js_init_script,
       on_page_load: self.on_page_load,
       on_webview_ready: self.on_webview_ready,
@@ -151,24 +204,29 @@ impl<R: Runtime> Builder<R> {
   }
 }
 
-/// Plugin struct that is returned by the [`PluginBuilder`]. Should only be constructed through the builder.
-pub struct TauriPlugin<R: Runtime> {
+/// Plugin struct that is returned by the [`Builder`]. Should only be constructed through the builder.
+pub struct TauriPlugin<R: Runtime, C: DeserializeOwned = ()> {
   name: &'static str,
   invoke_handler: Box<InvokeHandler<R>>,
   setup: Box<SetupHook<R>>,
+  setup_with_config: Option<Box<SetupWithConfigHook<R, C>>>,
   js_init_script: Option<String>,
   on_page_load: Box<OnPageLoad<R>>,
   on_webview_ready: Box<OnWebviewReady<R>>,
   on_event: Box<OnEvent<R>>,
 }
 
-impl<R: Runtime> Plugin<R> for TauriPlugin<R> {
+impl<R: Runtime, C: DeserializeOwned> Plugin<R> for TauriPlugin<R, C> {
   fn name(&self) -> &'static str {
     self.name
   }
 
-  fn initialize(&mut self, app: &AppHandle<R>, _: JsonValue) -> Result<()> {
-    (self.setup)(app)
+  fn initialize(&mut self, app: &AppHandle<R>, config: JsonValue) -> Result<()> {
+    (self.setup)(app)?;
+    if let Some(s) = &self.setup_with_config {
+      (s)(app, serde_json::from_value(config)?)?;
+    }
+    Ok(())
   }
 
   fn initialization_script(&self) -> Option<String> {