tauri_plugin_telemetry/
builder.rs1use std::{panic::PanicHookInfo, sync::Arc};
2
3use tauri::{
4 Manager, RunEvent, Runtime,
5 plugin::{self, TauriPlugin},
6};
7
8use crate::{InitOptions, client::TelemetryClient, commands, config::Config};
9
10pub struct Builder {
12 app_key: String,
13 panic_hook: Option<PanicHook>,
14 options: InitOptions,
15}
16
17pub type PanicHook =
18 Box<dyn Fn(&TelemetryClient, &PanicHookInfo<'_>, String) + 'static + Sync + Send>;
19
20fn get_panic_message(info: &PanicHookInfo) -> String {
21 let payload = info.payload();
22 if let Some(s) = payload.downcast_ref::<&str>() {
23 return s.to_string();
24 } else if let Some(s) = payload.downcast_ref::<String>() {
25 return s.to_string();
26 }
27
28 format!("{:?}", payload)
29}
30
31impl Builder {
32 pub fn new(app_key: &str) -> Self {
34 Self {
35 app_key: app_key.into(),
36 panic_hook: None,
37 options: Default::default(),
38 }
39 }
40
41 pub fn with_options(mut self, opts: InitOptions) -> Self {
43 self.options = opts;
44 self
45 }
46
47 pub fn with_host(mut self, host: impl Into<String>) -> Self {
50 self.options.host = Some(host.into());
51 self
52 }
53
54 pub fn with_panic_hook(mut self, hook: PanicHook) -> Self {
56 self.panic_hook = Some(hook);
57 self
58 }
59
60 pub fn build<R: Runtime>(self) -> TauriPlugin<R> {
62 plugin::Builder::new("telemetry")
63 .invoke_handler(tauri::generate_handler![commands::track_event])
64 .setup(|app, _api| {
65 let cfg = Config::new(self.app_key, self.options);
66 let app_version = app.package_info().version.to_string();
67 let client = Arc::new(TelemetryClient::new(&cfg, app_version));
68
69 client.start_polling(cfg.flush_interval);
70
71 if let Some(hook) = self.panic_hook {
72 install_panic_hook(hook, client.clone());
73 }
74
75 app.manage(client);
76 Ok(())
77 })
78 .on_event(move |app, event| {
79 if let RunEvent::Exit = event {
80 let client = app.state::<Arc<TelemetryClient>>();
81 client.flush_blocking();
82 }
83 })
84 .build()
85 }
86}
87
88fn install_panic_hook(hook: PanicHook, client: Arc<TelemetryClient>) {
91 let default_panic = std::panic::take_hook();
92 std::panic::set_hook(Box::new(move |info| {
93 let msg = get_panic_message(info);
94 hook(&client, info, msg);
95 client.flush_blocking();
96 default_panic(info);
97 }));
98}