use async_graphql::{BatchRequest, ObjectType, Request, Schema, SubscriptionType};
use serde_json::Value as JsonValue;
use std::sync::Arc;
use tauri::{webview::PageLoadPayload, AppHandle, RunEvent, Runtime, Url, Webview, Window};
use super::{
MizukiPlugin, OnBatchRequest, OnDrop, OnEvent, OnNavigation, OnPageLoad, OnSubRequst,
OnWebviewReady, OnWindowReady, SetupHook,
};
#[derive(Debug, Clone, Hash, PartialEq, thiserror::Error)]
#[non_exhaustive]
pub enum BuilderError {
#[error("plugin uses reserved name: {0}")]
ReservedName(String),
}
const RESERVED_PLUGIN_NAMES: &[&str] = &["core", "tauri"];
pub struct Builder<R, Q, M, S>
where
R: Runtime,
Q: ObjectType + 'static,
M: ObjectType + 'static,
S: SubscriptionType + 'static,
{
name: &'static str,
schema: Schema<Q, M, S>,
setup: Option<Box<SetupHook<R, Q, M, S>>>,
js_init_script: Option<String>,
on_page_load: Box<OnPageLoad<R>>,
on_webview_ready: Box<OnWebviewReady<R>>,
on_event: Box<OnEvent<R>>,
on_drop: Option<Box<OnDrop<R>>>,
on_batch_request: Box<OnBatchRequest>,
on_sub_request: Box<OnSubRequst>,
on_window_ready: Box<OnWindowReady<R>>,
on_navigation: Box<OnNavigation<R>>,
auto_cancel: bool,
sub_event_label: String,
}
impl<R, Q, M, S> Builder<R, Q, M, S>
where
R: Runtime,
Q: ObjectType + 'static,
M: ObjectType + 'static,
S: SubscriptionType + 'static,
{
pub fn new(name: &'static str, schema: Schema<Q, M, S>) -> Self {
Self {
name,
schema,
on_batch_request: Box::new(|r| r),
on_sub_request: Box::new(|s| s),
setup: None,
js_init_script: None,
on_page_load: Box::new(|_, _| ()),
on_webview_ready: Box::new(|_| ()),
on_event: Box::new(|_, _| ()),
on_drop: None,
on_window_ready: Box::new(|_| ()),
on_navigation: Box::new(|_, _| true),
auto_cancel: true,
sub_event_label: "sub_end".into(),
}
}
#[must_use]
pub fn js_init_script(mut self, js_init_script: String) -> Self {
self.js_init_script = Some(js_init_script);
self
}
#[must_use]
pub fn setup<F>(mut self, setup: F) -> Self
where
F: FnOnce(&AppHandle<R>, JsonValue, &Schema<Q, M, S>) -> Result<(), Box<dyn std::error::Error>>
+ Send
+ 'static,
{
self.setup.replace(Box::new(setup));
self
}
#[must_use]
pub fn on_page_load<F>(mut self, on_page_load: F) -> Self
where
F: FnMut(&Webview<R>, &PageLoadPayload<'_>) + Send + 'static,
{
self.on_page_load = Box::new(on_page_load);
self
}
#[must_use]
pub fn on_webview_ready<F>(mut self, on_webview_ready: F) -> Self
where
F: FnMut(Webview<R>) + Send + 'static,
{
self.on_webview_ready = Box::new(on_webview_ready);
self
}
#[must_use]
pub fn on_event<F>(mut self, on_event: F) -> Self
where
F: FnMut(&AppHandle<R>, &RunEvent) + Send + 'static,
{
self.on_event = Box::new(on_event);
self
}
#[must_use]
pub fn on_drop<F>(mut self, on_drop: F) -> Self
where
F: FnOnce(AppHandle<R>) + Send + 'static,
{
self.on_drop.replace(Box::new(on_drop));
self
}
#[must_use]
pub fn on_batch_request<F>(mut self, on_batch_request: F) -> Self
where
F: Fn(BatchRequest) -> BatchRequest + Send + Sync + 'static,
{
self.on_batch_request = Box::new(on_batch_request);
self
}
#[must_use]
pub fn on_sub_request<F>(mut self, on_sub_request: F) -> Self
where
F: Fn(Request) -> Request + Send + Sync + 'static,
{
self.on_sub_request = Box::new(on_sub_request);
self
}
#[must_use]
pub fn on_navigation<F>(mut self, on_navigation: F) -> Self
where
F: Fn(&Webview<R>, &Url) -> bool + Send + 'static,
{
self.on_navigation = Box::new(on_navigation);
self
}
#[must_use]
pub fn on_window_ready<F>(mut self, on_window_ready: F) -> Self
where
F: FnMut(Window<R>) + Send + 'static,
{
self.on_window_ready = Box::new(on_window_ready);
self
}
#[must_use]
pub fn auto_cancel(mut self, auto_cancel: bool) -> Self {
self.auto_cancel = auto_cancel;
self
}
pub fn subscription_end_label(mut self, label: String) -> Self {
self.sub_event_label = label;
self
}
pub fn try_build(self) -> Result<MizukiPlugin<R, Q, M, S>, BuilderError> {
if let Some(&reserved) = RESERVED_PLUGIN_NAMES.iter().find(|&r| r == &self.name) {
return Err(BuilderError::ReservedName(reserved.into()));
}
Ok(MizukiPlugin {
name: self.name,
app: None,
schema: self.schema,
setup: self.setup,
js_init_script: self.js_init_script,
on_page_load: self.on_page_load,
on_webview_ready: self.on_webview_ready,
on_event: self.on_event,
on_drop: self.on_drop,
on_batch_request: Arc::new(self.on_batch_request),
on_sub_request: Arc::new(self.on_sub_request),
on_navigation: self.on_navigation,
on_window_ready: self.on_window_ready,
auto_cancel: self.auto_cancel,
sub_end_event_label: self.sub_event_label,
})
}
pub fn build(self) -> MizukiPlugin<R, Q, M, S> {
self.try_build().unwrap()
}
}