tauri_plugin_config_manager/
lib.rs1use notify::{
2 event::{DataChange, ModifyKind},
3 EventKind, RecommendedWatcher, Watcher,
4};
5use std::sync::Mutex;
6use tauri::{
7 plugin::{Builder, TauriPlugin},
8 Emitter, Manager, Runtime,
9};
10
11mod commands;
12#[cfg(desktop)]
13mod desktop;
14mod error;
15
16pub use error::{Error, Result};
17
18#[cfg(desktop)]
19use desktop::ConfigManager;
20
21pub trait ConfigManagerExt<R: Runtime> {
23 fn config_manager(&self) -> &ConfigManager<R>;
24}
25
26impl<R: Runtime, T: Manager<R>> crate::ConfigManagerExt<R> for T {
27 fn config_manager(&self) -> &ConfigManager<R> {
28 self.state::<ConfigManager<R>>().inner()
29 }
30}
31
32fn watch_config_file<R: Runtime + 'static>(
33 app: &tauri::AppHandle<R>,
34) -> Box<dyn FnMut(notify::Result<notify::Event>) + Send + 'static> {
35 let app_handle = app.clone();
36 Box::new(move |res: notify::Result<notify::Event>| {
37 let Ok(event) = res else {
38 if let Err(e) = res {
39 eprintln!(
40 "[Config Watcher Callback] Error watching config file: {:?}",
41 e
42 );
43 }
44 return;
45 };
46
47 if matches!(
48 event.kind,
49 EventKind::Modify(ModifyKind::Data(DataChange::Any))
50 ) {
51 let app_for_async = app_handle.clone();
53 tauri::async_runtime::spawn(async move {
54 let state = app_for_async.state::<desktop::ConfigManager<R>>();
56 if let Err(e) = state.inner().refresh_cache_from_file().await {
57 eprintln!(
58 "[Config Watcher Callback] Failed to refresh config cache: {}",
59 e
60 );
61 }
62 app_for_async.emit("config-changed", ()).unwrap_or_else(|e| {
64 eprintln!(
65 "[Config Watcher Callback] Failed to emit config-changed event: {}",
66 e
67 );
68 });
69 });
70 }
71 })
72}
73
74pub fn init<R: Runtime>() -> TauriPlugin<R> {
76 Builder::new("config-manager")
77 .invoke_handler(tauri::generate_handler![
78 commands::read_config,
79 commands::write_config,
80 commands::set_darkmode
81 ])
82 .setup(|app, api| {
83 let config_manager = desktop::init(app, api)?;
84 let config_path = config_manager.config_path().to_path_buf();
85 app.manage(config_manager);
86
87 let app_handle_for_watcher = app.clone();
88 let event_handler = watch_config_file(&app_handle_for_watcher);
89
90 let mut watcher: RecommendedWatcher = notify::recommended_watcher(event_handler)
91 .map_err(|e| {
92 Error::Other(format!("Cannot create watcher for config file: {}", e))
93 })?;
94
95 watcher
96 .watch(config_path.as_path(), notify::RecursiveMode::Recursive)
97 .map_err(|e| {
98 Error::Other(format!(
99 "Failed to watch config file {}: {}",
100 config_path.display(),
101 e
102 ))
103 })?;
104
105 app.manage(Mutex::new(watcher));
106
107 Ok(())
108 })
109 .build()
110}