async_file_watcher/
async_file_watcher.rs1use std::{
2 fs,
3 path::PathBuf,
4 time::{Duration, SystemTime},
5};
6
7use wolfram_library_link::{self as wll, sys::mint, AsyncTaskObject, DataStore};
8
9#[wll::export]
13fn start_file_watcher(pause_interval_ms: mint, path: String) -> mint {
14 let pause_interval_ms =
15 u64::try_from(pause_interval_ms).expect("mint interval overflows u64");
16
17 let path = PathBuf::from(path);
18
19 let task = AsyncTaskObject::spawn_with_thread(move |task: AsyncTaskObject| {
22 file_watch_thread_function(task, pause_interval_ms, &path);
23 });
24
25 task.id()
26}
27
28fn file_watch_thread_function(
30 task: AsyncTaskObject,
31 pause_interval_ms: u64,
32 path: &PathBuf,
33) {
34 let mut prev_changed: Option<SystemTime> = fs::metadata(path)
35 .and_then(|metadata| metadata.modified())
36 .ok();
37
38 let mut check_for_modification = || -> Option<_> {
43 let changed: Option<fs::Metadata> = fs::metadata(path).ok();
44
45 let notify: Option<SystemTime> = match (&prev_changed, changed) {
46 (Some(prev), Some(latest)) => {
47 let latest: SystemTime = match latest.modified() {
48 Ok(latest) => latest,
49 Err(_) => return None,
50 };
51
52 if *prev != latest {
53 prev_changed = Some(latest.clone());
54 Some(latest)
55 } else {
56 None
57 }
58 },
59 (Some(_prev), None) => None,
61 (None, Some(latest)) => latest.modified().ok(),
62 (None, None) => None,
63 };
64
65 let time = notify?;
66
67 let since_epoch = match time.duration_since(std::time::UNIX_EPOCH) {
68 Ok(duration) => duration,
69 Err(_) => return None,
70 };
71
72 let since_epoch = since_epoch.as_secs();
73
74 Some(since_epoch)
75 };
76
77 loop {
78 if !task.is_alive() {
79 break;
80 }
81
82 if let Some(modification) = check_for_modification() {
85 let mut data = DataStore::new();
86 data.add_i64(modification as i64);
87
88 task.raise_async_event("change", data);
89 }
90
91 std::thread::sleep(Duration::from_millis(pause_interval_ms));
93 }
94}