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
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Copyright 2020 Jared Forth.

//

// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or

// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license

// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your

// option. This file may not be copied, modified, or distributed

// except according to those terms.


//! A filesystem listener.

//!

//! **listen** listens for filesystem events and executes a function when the event occurs.


use walkdir::WalkDir;

/// `Event` enumerates the possible filesystem events

/// that can be listened for.

#[derive(Debug)]
pub enum Event {
    /// If a file is added or removed from the directory

    /// this event is triggered.

    OnFileChange,
    /// If a file is added to the directory

    /// this event is triggered.

    OnFileAdd,
    /// If a file is removed from the directory

    /// this event is triggered.

    OnFileRemove
}

/// This function takes a path to listen on, the event to listen for,

/// and a function to execute when that event happens.

///

/// `path: &str` is the directory to listen on,

/// `event: Event` is the event to listen for,

/// `arg: T` is the argument to pass to `func`,

/// and

/// `func: fn(T) -> R` is the function to execute when event happens

pub fn listen<T, R>(path: &str, event: Event, arg: T, func: fn(T) -> R) {
    internal_listener(path, event, arg, func);
}

/// A Listener

#[derive(Debug)]
pub struct Listener {
    /// The event to listen for

    event: Event,
    /// If true, the listener will store files in `store_files`;

    /// otherwise it will not

    store_files: bool,
    /// Vector of all files currently in directory

    /// listened to.

    pub files: Vec<String>,
}

impl Default for Listener {
    fn default() -> Self {
        Listener {
            event: Event::OnFileChange,
            store_files: false,
            files: vec![],
        }
    }
}

impl Listener {
    pub fn new() -> Listener {
        Listener::default()
    }
    /// This function takes a path to listen on, the event to listen for,

    /// and a function to execute when that event happens.

    ///

    /// `path: &str` is the directory to listen on,

    /// `arg: T` is the argument to pass to `func`,

    /// and

    /// `func: fn(T) -> R` is the function to execute when event happens

    pub fn listen<T, R>(&mut self, path: &str, arg: T, func: fn(T) -> R) {
        match self.event {
            Event::OnFileChange => {
                if self.file_change_listener(path) {
                    func(arg);
                }
            }
            Event::OnFileAdd => {
                unimplemented!()
            }
            Event::OnFileRemove => {
                unimplemented!()
            }
        }
    }
    fn file_change_listener(&mut self, path: &str) -> bool {
        let mut changed: bool = false;
        let initial_count = self.count_directory_files(path);

        while !changed {
            let count = self.count_directory_files(path);
            if count == initial_count {
                continue;
            } else {
                changed = true
            }
        }

        changed
    }
    fn count_directory_files(&mut self, path: &str) -> i64 {
        let mut count = 0;
        for entry in WalkDir::new(path).max_depth(1) {
            match entry {
                Ok(entry) => {
                    let path = entry.path();
                    // Check if is file

                    if !path.is_dir() {
                        // Increment counter

                        count = count + 1;
                        // Store files if told to in configuration

                        if self.store_files {
                            match path.to_str() {
                                Some(file) => {
                                    // Add path to `files` vector

                                    self.files.push(String::from(file));
                                }
                                None => {
                                    println!("listen | Error adding files");
                                }
                            }
                        }
                    }
                }
                Err(e) => {
                    println!("Error: {:?}", e);
                }
            }
        }
        count
    }
    /// Configure listener to store files

    ///

    /// ## Usage:

    ///

    /// ```

    ///   let mut listener = listen::Listener::new();

    ///

    ///   listener.store_files(true);

    /// ```

    pub fn store_files(&mut self, store_files: bool) {
        self.store_files = store_files;
    }
}

fn internal_listener<T, R>(path: &str, _event: Event, arg: T, func: fn(T) -> R) {
    let mut listener = Listener::new();
    listener.listen(path, arg, func);
}