1use crate::fs::mapping;
2use crate::fs::state::{Command, DaemonState};
3use crate::fs::sync::sync_local_to_remote;
4use notify::Event;
5
6pub async fn handle_fs_event(event: Event, state: DaemonState) {
7 if event.kind.is_access() || event.kind.is_other() {
8 return;
9 }
10 tracing::debug!("[BraidFS-WATCHER] Event: {:?}", event);
11
12 for path in event.paths {
13 let is_removal = event.kind.is_remove() || !path.exists();
16 let is_create = event.kind.is_create();
17
18 if !is_removal && !path.is_file() {
20 tracing::info!("[BraidFS] Skipping non-file: {:?}", path);
21 continue;
22 }
23
24 if path.components().any(|c| {
26 let s = c.as_os_str().to_string_lossy();
27 s.starts_with('.') || s.ends_with(".tmp")
28 }) {
29 continue;
30 }
31
32 if state.pending.should_ignore(&path) {
34 tracing::info!("[BraidFS] Skipping pending write: {:?}", path);
35 continue;
36 }
37
38 match mapping::path_to_url(&path) {
39 Ok(url) => {
40 tracing::info!("[BraidFS] File changed: {:?} -> {}", path, url);
41
42 if is_create {
44 let is_synced = {
45 let cfg = state.config.read().await;
46 cfg.sync.get(&url).copied().unwrap_or(false)
47 };
48
49 if !is_synced {
50 tracing::info!("[BraidFS] Auto-adding new file to sync: {}", url);
51 {
53 let mut cfg = state.config.write().await;
54 cfg.sync.insert(url.clone(), true);
55 let _ = cfg.save().await;
56 }
57 let _ = state.tx_cmd.send(Command::Sync { url: url.clone() }).await;
59 }
60 }
61
62 state.debouncer.request_sync(url, path).await;
64 }
65 Err(e) => {
66 tracing::debug!("[BraidFS] Ignoring file {:?}: {:?}", path, e);
67 }
68 }
69 }
70}