use tauri::{plugin::TauriPlugin, Manager, Runtime};
pub struct PluginBuilder {
pub(crate) relays: Vec<String>,
pub(crate) namespace: String,
pub(crate) device_id: String,
pub(crate) max_payload_size: usize,
}
impl PluginBuilder {
pub fn new() -> Self {
Self {
relays: Vec::new(),
namespace: "default".to_string(),
device_id: uuid::Uuid::new_v4().to_string(),
max_payload_size: crate::state::DEFAULT_PAYLOAD_LIMIT,
}
}
pub fn relays(mut self, urls: impl IntoIterator<Item = impl Into<String>>) -> Self {
self.relays = urls.into_iter().map(|u| u.into()).collect();
self
}
pub fn app_namespace(mut self, ns: impl Into<String>) -> Self {
self.namespace = ns.into();
self
}
pub fn device_id(mut self, id: impl Into<String>) -> Self {
self.device_id = id.into();
self
}
pub fn max_payload_size(mut self, bytes: usize) -> Self {
self.max_payload_size = bytes;
self
}
pub fn build<R: Runtime>(self) -> TauriPlugin<R> {
crate::state::validate_namespace(&self.namespace)
.unwrap_or_else(|e| panic!("invalid app_namespace: {e}"));
let relays = self.relays;
let namespace = self.namespace;
let device_id = self.device_id;
let max_payload_size = self.max_payload_size;
tauri::plugin::Builder::<R>::new("nostr-sync")
.invoke_handler(tauri::generate_handler![
crate::commands::publish,
crate::commands::fetch,
crate::commands::sync_all,
crate::commands::add_relay,
crate::commands::remove_relay,
crate::commands::get_relays,
crate::commands::get_pubkey,
crate::commands::get_status,
crate::commands::poll,
])
.setup(move |app, api| {
#[cfg(mobile)]
{
let plugin = crate::mobile::init(
app,
api,
relays,
&namespace,
&device_id,
max_payload_size,
)?;
app.manage(plugin);
}
#[cfg(desktop)]
{
let _ = &api;
let plugin = crate::desktop::init(
app,
relays,
&namespace,
&device_id,
max_payload_size,
)?;
app.manage(plugin);
}
Ok(())
})
.build()
}
}
impl Default for PluginBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn defaults_to_default_namespace() {
let b = PluginBuilder::new();
assert_eq!(b.namespace, "default");
}
#[test]
fn defaults_to_empty_relays() {
let b = PluginBuilder::new();
assert!(b.relays.is_empty());
}
#[test]
fn defaults_to_ephemeral_device_id() {
let b = PluginBuilder::new();
assert!(!b.device_id.is_empty());
assert_ne!(b.device_id, PluginBuilder::new().device_id);
}
#[test]
fn device_id_overrides_ephemeral() {
let b = PluginBuilder::new().device_id("my-stable-device");
assert_eq!(b.device_id, "my-stable-device");
}
#[test]
fn app_namespace_overrides_default() {
let b = PluginBuilder::new().app_namespace("sage");
assert_eq!(b.namespace, "sage");
}
#[test]
fn relays_stores_provided_urls() {
let b = PluginBuilder::new().relays(vec!["wss://relay.damus.io", "wss://nos.lol"]);
assert_eq!(b.relays, vec!["wss://relay.damus.io", "wss://nos.lol"]);
}
#[test]
fn max_payload_size_defaults_to_64kb() {
let b = PluginBuilder::new();
assert_eq!(b.max_payload_size, crate::state::DEFAULT_PAYLOAD_LIMIT);
}
#[test]
fn max_payload_size_setter_stores_value() {
let b = PluginBuilder::new().max_payload_size(128 * 1024);
assert_eq!(b.max_payload_size, 128 * 1024);
}
}