|
@@ -1,16 +1,49 @@
|
|
|
|
+use crate::api::config::PluginConfig;
|
|
use crate::async_runtime::Mutex;
|
|
use crate::async_runtime::Mutex;
|
|
-
|
|
|
|
use crate::ApplicationDispatcherExt;
|
|
use crate::ApplicationDispatcherExt;
|
|
|
|
|
|
|
|
+use futures::future::join_all;
|
|
|
|
+
|
|
use std::sync::Arc;
|
|
use std::sync::Arc;
|
|
|
|
|
|
|
|
+/// The plugin error type.
|
|
|
|
+#[derive(Debug, thiserror::Error)]
|
|
|
|
+pub enum Error {
|
|
|
|
+ /// Failed to serialize/deserialize.
|
|
|
|
+ #[error("JSON error: {0}")]
|
|
|
|
+ Json(serde_json::Error),
|
|
|
|
+ /// Unknown API type.
|
|
|
|
+ #[error("unknown API")]
|
|
|
|
+ UnknownApi,
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl From<serde_json::Error> for Error {
|
|
|
|
+ fn from(error: serde_json::Error) -> Self {
|
|
|
|
+ if error.to_string().contains("unknown variant") {
|
|
|
|
+ Self::UnknownApi
|
|
|
|
+ } else {
|
|
|
|
+ Self::Json(error)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
/// The plugin interface.
|
|
/// The plugin interface.
|
|
#[async_trait::async_trait]
|
|
#[async_trait::async_trait]
|
|
pub trait Plugin<D: ApplicationDispatcherExt + 'static>: Sync {
|
|
pub trait Plugin<D: ApplicationDispatcherExt + 'static>: Sync {
|
|
|
|
+ /// The plugin name. Used as key on the plugin config object.
|
|
|
|
+ fn name(&self) -> &'static str;
|
|
|
|
+
|
|
|
|
+ /// Initialize the plugin.
|
|
|
|
+ #[allow(unused_variables)]
|
|
|
|
+ async fn initialize(&self, config: String) -> Result<(), Error> {
|
|
|
|
+ Ok(())
|
|
|
|
+ }
|
|
|
|
+
|
|
/// The JS script to evaluate on init.
|
|
/// The JS script to evaluate on init.
|
|
async fn init_script(&self) -> Option<String> {
|
|
async fn init_script(&self) -> Option<String> {
|
|
None
|
|
None
|
|
}
|
|
}
|
|
|
|
+
|
|
/// Callback invoked when the webview is created.
|
|
/// Callback invoked when the webview is created.
|
|
#[allow(unused_variables)]
|
|
#[allow(unused_variables)]
|
|
async fn created(&self, dispatcher: D) {}
|
|
async fn created(&self, dispatcher: D) {}
|
|
@@ -21,8 +54,8 @@ pub trait Plugin<D: ApplicationDispatcherExt + 'static>: Sync {
|
|
|
|
|
|
/// Add invoke_handler API extension commands.
|
|
/// Add invoke_handler API extension commands.
|
|
#[allow(unused_variables)]
|
|
#[allow(unused_variables)]
|
|
- async fn extend_api(&self, dispatcher: D, payload: &str) -> Result<bool, String> {
|
|
|
|
- Err("unknown variant".to_string())
|
|
|
|
|
|
+ async fn extend_api(&self, dispatcher: D, payload: &str) -> Result<(), Error> {
|
|
|
|
+ Err(Error::UnknownApi)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -38,18 +71,39 @@ pub async fn register<D: ApplicationDispatcherExt + 'static>(
|
|
plugins.push(Box::new(plugin));
|
|
plugins.push(Box::new(plugin));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+pub(crate) async fn initialize<D: ApplicationDispatcherExt + 'static>(
|
|
|
|
+ store: &PluginStore<D>,
|
|
|
|
+ plugins_config: PluginConfig,
|
|
|
|
+) -> crate::Result<()> {
|
|
|
|
+ let plugins = store.lock().await;
|
|
|
|
+ let mut futures = Vec::new();
|
|
|
|
+ for plugin in plugins.iter() {
|
|
|
|
+ let plugin_config = plugins_config.get(plugin.name());
|
|
|
|
+ futures.push(plugin.initialize(plugin_config));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for res in join_all(futures).await {
|
|
|
|
+ res?;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Ok(())
|
|
|
|
+}
|
|
|
|
+
|
|
pub(crate) async fn init_script<D: ApplicationDispatcherExt + 'static>(
|
|
pub(crate) async fn init_script<D: ApplicationDispatcherExt + 'static>(
|
|
store: &PluginStore<D>,
|
|
store: &PluginStore<D>,
|
|
) -> String {
|
|
) -> String {
|
|
- let mut init = String::new();
|
|
|
|
-
|
|
|
|
let plugins = store.lock().await;
|
|
let plugins = store.lock().await;
|
|
|
|
+ let mut futures = Vec::new();
|
|
for plugin in plugins.iter() {
|
|
for plugin in plugins.iter() {
|
|
- if let Some(init_script) = plugin.init_script().await {
|
|
|
|
|
|
+ futures.push(plugin.init_script());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let mut init = String::new();
|
|
|
|
+ for res in join_all(futures).await {
|
|
|
|
+ if let Some(init_script) = res {
|
|
init.push_str(&format!("(function () {{ {} }})();", init_script));
|
|
init.push_str(&format!("(function () {{ {} }})();", init_script));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
init
|
|
init
|
|
}
|
|
}
|
|
|
|
|
|
@@ -58,9 +112,11 @@ pub(crate) async fn created<D: ApplicationDispatcherExt + 'static>(
|
|
dispatcher: &mut D,
|
|
dispatcher: &mut D,
|
|
) {
|
|
) {
|
|
let plugins = store.lock().await;
|
|
let plugins = store.lock().await;
|
|
|
|
+ let mut futures = Vec::new();
|
|
for plugin in plugins.iter() {
|
|
for plugin in plugins.iter() {
|
|
- plugin.created(dispatcher.clone()).await;
|
|
|
|
|
|
+ futures.push(plugin.created(dispatcher.clone()));
|
|
}
|
|
}
|
|
|
|
+ join_all(futures).await;
|
|
}
|
|
}
|
|
|
|
|
|
pub(crate) async fn ready<D: ApplicationDispatcherExt + 'static>(
|
|
pub(crate) async fn ready<D: ApplicationDispatcherExt + 'static>(
|
|
@@ -68,29 +124,28 @@ pub(crate) async fn ready<D: ApplicationDispatcherExt + 'static>(
|
|
dispatcher: &mut D,
|
|
dispatcher: &mut D,
|
|
) {
|
|
) {
|
|
let plugins = store.lock().await;
|
|
let plugins = store.lock().await;
|
|
|
|
+ let mut futures = Vec::new();
|
|
for plugin in plugins.iter() {
|
|
for plugin in plugins.iter() {
|
|
- plugin.ready(dispatcher.clone()).await;
|
|
|
|
|
|
+ futures.push(plugin.ready(dispatcher.clone()));
|
|
}
|
|
}
|
|
|
|
+ join_all(futures).await;
|
|
}
|
|
}
|
|
|
|
|
|
pub(crate) async fn extend_api<D: ApplicationDispatcherExt + 'static>(
|
|
pub(crate) async fn extend_api<D: ApplicationDispatcherExt + 'static>(
|
|
store: &PluginStore<D>,
|
|
store: &PluginStore<D>,
|
|
dispatcher: &mut D,
|
|
dispatcher: &mut D,
|
|
arg: &str,
|
|
arg: &str,
|
|
-) -> Result<bool, String> {
|
|
|
|
|
|
+) -> Result<bool, Error> {
|
|
let plugins = store.lock().await;
|
|
let plugins = store.lock().await;
|
|
for ext in plugins.iter() {
|
|
for ext in plugins.iter() {
|
|
match ext.extend_api(dispatcher.clone(), arg).await {
|
|
match ext.extend_api(dispatcher.clone(), arg).await {
|
|
- Ok(handled) => {
|
|
|
|
- if handled {
|
|
|
|
- return Ok(true);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- Err(e) => {
|
|
|
|
- if !e.contains("unknown variant") {
|
|
|
|
- return Err(e);
|
|
|
|
- }
|
|
|
|
|
|
+ Ok(_) => {
|
|
|
|
+ return Ok(true);
|
|
}
|
|
}
|
|
|
|
+ Err(e) => match e {
|
|
|
|
+ Error::UnknownApi => {}
|
|
|
|
+ _ => return Err(e),
|
|
|
|
+ },
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Ok(false)
|
|
Ok(false)
|