aboutsummaryrefslogtreecommitdiff
path: root/crates/server/src/vfs.rs
blob: 2acc3f55f336438919b9d8a1ff6577e4087c2ac2 (plain)
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
use std::{
    path::PathBuf,
    fs,
};

use crossbeam_channel::{Sender, Receiver, bounded};
use walkdir::WalkDir;

use {
    thread_watcher::ThreadWatcher,
};


#[derive(Debug)]
pub struct FileEvent {
    pub path: PathBuf,
    pub kind: FileEventKind,
}

#[derive(Debug)]
pub enum FileEventKind {
    Add(String),
    #[allow(unused)]
    Remove,
}

pub fn watch(roots: Vec<PathBuf>) -> (Receiver<Vec<FileEvent>>, ThreadWatcher) {
    let (sender, receiver) = bounded(16);
    let watcher = ThreadWatcher::spawn("vfs", move || run(roots, sender));
    (receiver, watcher)
}

fn run(roots: Vec<PathBuf>, sender: Sender<Vec<FileEvent>>) {
    for root in roots {
        let mut events = Vec::new();
        for entry in WalkDir::new(root.as_path()) {
            let entry = match entry {
                Ok(entry) => entry,
                Err(e) => {
                    warn!("watcher error: {}", e);
                    continue;
                }
            };
            if !entry.file_type().is_file() {
                continue;
            }
            let path = entry.path();
            if path.extension().and_then(|os| os.to_str()) != Some("rs") {
                continue;
            }
            let text = match fs::read_to_string(path) {
                Ok(text) => text,
                Err(e) => {
                    warn!("watcher error: {}", e);
                    continue;
                }
            };
            events.push(FileEvent {
                path: path.to_owned(),
                kind: FileEventKind::Add(text),
            })
        }
        sender.send(events)
    }
}