plugin.rs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. use crate::{
  2. api::config::PluginConfig, async_runtime::Mutex, ApplicationExt, PageLoadPayload, WebviewManager,
  3. };
  4. use futures::future::join_all;
  5. use serde_json::Value as JsonValue;
  6. use std::sync::Arc;
  7. /// The plugin interface.
  8. #[async_trait::async_trait]
  9. pub trait Plugin<A: ApplicationExt + 'static>: Send + Sync {
  10. /// The plugin name. Used as key on the plugin config object.
  11. fn name(&self) -> &'static str;
  12. /// Initialize the plugin.
  13. #[allow(unused_variables)]
  14. async fn initialize(&mut self, config: String) -> crate::Result<()> {
  15. Ok(())
  16. }
  17. /// The JS script to evaluate on webview initialization.
  18. /// The script is wrapped into its own context with `(function () { /* your script here */ })();`,
  19. /// so global variables must be assigned to `window` instead of implicity declared.
  20. ///
  21. /// It's guaranteed that this script is executed before the page is loaded.
  22. async fn initialization_script(&self) -> Option<String> {
  23. None
  24. }
  25. /// Callback invoked when the webview is created.
  26. #[allow(unused_variables)]
  27. async fn created(&mut self, webview_manager: WebviewManager<A>) {}
  28. /// Callback invoked when the webview performs a navigation.
  29. #[allow(unused_variables)]
  30. async fn on_page_load(&mut self, webview_manager: WebviewManager<A>, payload: PageLoadPayload) {}
  31. /// Add invoke_handler API extension commands.
  32. #[allow(unused_variables)]
  33. async fn extend_api(
  34. &mut self,
  35. webview_manager: WebviewManager<A>,
  36. command: String,
  37. payload: &JsonValue,
  38. ) -> crate::Result<JsonValue> {
  39. Err(crate::Error::UnknownApi(None))
  40. }
  41. }
  42. /// Plugin collection type.
  43. pub type PluginStore<A> = Arc<Mutex<Vec<Box<dyn Plugin<A> + Sync + Send>>>>;
  44. /// Registers a plugin.
  45. pub async fn register<A: ApplicationExt + 'static>(
  46. store: &PluginStore<A>,
  47. plugin: impl Plugin<A> + Sync + Send + 'static,
  48. ) {
  49. let mut plugins = store.lock().await;
  50. plugins.push(Box::new(plugin));
  51. }
  52. pub(crate) async fn initialize<A: ApplicationExt + 'static>(
  53. store: &PluginStore<A>,
  54. plugins_config: PluginConfig,
  55. ) -> crate::Result<()> {
  56. let mut plugins = store.lock().await;
  57. for plugin in plugins.iter_mut() {
  58. let plugin_config = plugins_config.get(plugin.name());
  59. plugin.initialize(plugin_config).await?;
  60. }
  61. Ok(())
  62. }
  63. pub(crate) async fn initialization_script<A: ApplicationExt + 'static>(
  64. store: &PluginStore<A>,
  65. ) -> String {
  66. let mut plugins = store.lock().await;
  67. let mut futures = Vec::new();
  68. for plugin in plugins.iter_mut() {
  69. futures.push(plugin.initialization_script());
  70. }
  71. let mut initialization_script = String::new();
  72. for res in join_all(futures).await {
  73. if let Some(plugin_initialization_script) = res {
  74. initialization_script.push_str(&format!(
  75. "(function () {{ {} }})();",
  76. plugin_initialization_script
  77. ));
  78. }
  79. }
  80. initialization_script
  81. }
  82. pub(crate) async fn created<A: ApplicationExt + 'static>(
  83. store: &PluginStore<A>,
  84. webview_manager: &crate::WebviewManager<A>,
  85. ) {
  86. let mut plugins = store.lock().await;
  87. let mut futures = Vec::new();
  88. for plugin in plugins.iter_mut() {
  89. futures.push(plugin.created(webview_manager.clone()));
  90. }
  91. join_all(futures).await;
  92. }
  93. pub(crate) async fn on_page_load<A: ApplicationExt + 'static>(
  94. store: &PluginStore<A>,
  95. webview_manager: &crate::WebviewManager<A>,
  96. payload: PageLoadPayload,
  97. ) {
  98. let mut plugins = store.lock().await;
  99. let mut futures = Vec::new();
  100. for plugin in plugins.iter_mut() {
  101. futures.push(plugin.on_page_load(webview_manager.clone(), payload.clone()));
  102. }
  103. join_all(futures).await;
  104. }
  105. pub(crate) async fn extend_api<A: ApplicationExt + 'static>(
  106. store: &PluginStore<A>,
  107. webview_manager: &crate::WebviewManager<A>,
  108. command: String,
  109. arg: &JsonValue,
  110. ) -> crate::Result<Option<JsonValue>> {
  111. let mut plugins = store.lock().await;
  112. for ext in plugins.iter_mut() {
  113. match ext
  114. .extend_api(webview_manager.clone(), command.clone(), arg)
  115. .await
  116. {
  117. Ok(value) => {
  118. return Ok(Some(value));
  119. }
  120. Err(e) => match e {
  121. crate::Error::UnknownApi(_) => {}
  122. _ => return Err(e),
  123. },
  124. }
  125. }
  126. Ok(None)
  127. }