File size: 2,973 Bytes
ae4ceef
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
use notify::{RecursiveMode, Watcher, Config, Event};
use std::sync::{Arc, Mutex};
use tauri::{AppHandle, Emitter, Runtime, State};

#[derive(serde::Serialize, Clone)]
struct FileChangeEvent {
    path: String,
    filename: String,
    action: String,
}

struct WatcherState {
    watcher: Option<notify::RecommendedWatcher>,
}

#[tauri::command]
async fn start_watching<R: Runtime>(
    app: AppHandle<R>,
    path: String,
    state: State<'_, Arc<Mutex<WatcherState>>>,
) -> Result<String, String> {
    let mut watcher_state = state.lock().map_err(|e| e.to_string())?;
    
    // Stop previous watcher if any
    if let Some(mut w) = watcher_state.watcher.take() {
        let _ = w.unwatch(std::path::Path::new(&path));
    }

    let app_clone = app.clone();
    let path_buf = std::path::PathBuf::from(&path);
    
    // Create directory if not exists
    if !path_buf.exists() {
        std::fs::create_dir_all(&path_buf).map_err(|e| e.to_string())?;
    }

    let mut watcher = notify::RecommendedWatcher::new(
        move |res: notify::Result<Event>| {
            if let Ok(event) = res {
                if event.kind.is_create() || event.kind.is_modify() {
                    for p in event.paths {
                        let filename = p.file_name()
                            .and_then(|f| f.to_str())
                            .unwrap_or("")
                            .to_string();
                        
                        let _ = app_clone.emit("file-changed", FileChangeEvent {
                            path: p.to_string_lossy().to_string(),
                            filename,
                            action: if event.kind.is_create() { "create".to_string() } else { "modify".to_string() },
                        });
                    }
                }
            }
        },
        Config::default(),
    ).map_err(|e| e.to_string())?;

    watcher.watch(&path_buf, RecursiveMode::NonRecursive).map_err(|e| e.to_string())?;
    watcher_state.watcher = Some(watcher);
    
    Ok(path)
}

#[tauri::command]
async fn stop_watching(
    state: State<'_, Arc<Mutex<WatcherState>>>,
) -> Result<(), String> {
    let mut watcher_state = state.lock().map_err(|e| e.to_string())?;
    watcher_state.watcher.take();
    Ok(())
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    let watcher_state = Arc::new(Mutex::new(WatcherState { watcher: None }));

    tauri::Builder::default()
        .manage(watcher_state)
        .invoke_handler(tauri::generate_handler![start_watching, stop_watching])
        .setup(|app| {
            if cfg!(debug_assertions) {
                app.handle().plugin(
                    tauri_plugin_log::Builder::default()
                        .level(log::LevelFilter::Info)
                        .build(),
                )?;
            }
            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}