Completed all steps except the monitoring step.
Looking at switching the monitored files into a hashmap.
This commit is contained in:
parent
5c98c8a608
commit
52c5d40420
292
Cargo.lock
generated
292
Cargo.lock
generated
@ -2,6 +2,36 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.24.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.18"
|
||||
@ -52,6 +82,27 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.74"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@ -64,12 +115,41 @@ version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"wasm-bindgen",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.32"
|
||||
@ -116,12 +196,20 @@ version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "file_monitor"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
"notify",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -145,12 +233,41 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify"
|
||||
version = "0.11.0"
|
||||
@ -177,6 +294,16 @@ version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kqueue"
|
||||
version = "1.0.8"
|
||||
@ -220,6 +347,21 @@ version = "0.4.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.0.3"
|
||||
@ -257,12 +399,36 @@ version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.94"
|
||||
@ -290,6 +456,18 @@ dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
@ -299,6 +477,21 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
@ -316,6 +509,32 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.44.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"libc",
|
||||
"mio",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
@ -344,6 +563,64 @@ version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.9"
|
||||
@ -353,6 +630,21 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
|
@ -12,4 +12,6 @@ license-file = "LICENSE.md"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5.32", features = ["derive"] }
|
||||
chrono = "0.4.40"
|
||||
notify = "8.0.0"
|
||||
tokio = { version = "1.44.1", features = ["macros", "rt-multi-thread", "io-std", "fs", "signal", "sync"] }
|
||||
|
@ -1,5 +1,7 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use notify::{EventKind, RecommendedWatcher, Watcher};
|
||||
|
||||
use crate::monitored_files::MonitoredFiles;
|
||||
|
||||
|
||||
@ -11,9 +13,9 @@ use crate::monitored_files::MonitoredFiles;
|
||||
pub struct DirMonitor
|
||||
{
|
||||
/// The directory to monitor.
|
||||
dir: std::path::PathBuf,
|
||||
dir: PathBuf,
|
||||
|
||||
monitored_files: MonitoredFiles
|
||||
monitored_files: MonitoredFiles,
|
||||
}
|
||||
|
||||
|
||||
@ -31,12 +33,9 @@ impl DirMonitor
|
||||
}
|
||||
}
|
||||
|
||||
pub fn monitor(&mut self)
|
||||
{
|
||||
self.build_file_list();
|
||||
}
|
||||
|
||||
fn build_file_list(&mut self)
|
||||
/// Scan the monitored directory and all of its sub directories and monitors
|
||||
/// the files found and their last modification time.
|
||||
pub fn scan(&mut self)
|
||||
{
|
||||
// Start from the directory and add each file to our list,
|
||||
// then recurse through all sub directories and add them to
|
||||
@ -49,8 +48,93 @@ impl DirMonitor
|
||||
|
||||
Err(e) =>
|
||||
{
|
||||
println!("There was an issue during directory scanning.");
|
||||
println!("{}", e);
|
||||
eprintln!("Directory scanning error: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Print out all the monitored files and their last modified date.
|
||||
///
|
||||
/// Each file entry will be printed out as:
|
||||
/// ```
|
||||
/// [Date Time] PATH
|
||||
/// ```
|
||||
pub fn print_monitored_files(&self)
|
||||
{
|
||||
self.monitored_files.print(&self.dir);
|
||||
}
|
||||
|
||||
///
|
||||
pub async fn monitor(&mut self, mut term_receiver: tokio::sync::watch::Receiver<bool>)
|
||||
{
|
||||
let mut running: bool = true;
|
||||
|
||||
//let (notify_sender, notify_receiver) = std::sync::mpsc::channel::<Result<notify::Event, notify::Error>>();
|
||||
let (notify_sender, notify_receiver) = tokio::sync::mpsc::channel::<Result<notify::Event, notify::Error>>(100);
|
||||
let mut fs_watcher: RecommendedWatcher = match notify::recommended_watcher(notify_sender)
|
||||
{
|
||||
Ok(watcher) => { watcher }
|
||||
Err(e) => { eprintln!("Unable to create watcher: {}", e); panic!(); }
|
||||
};
|
||||
fs_watcher.watch(&self.dir, notify::RecursiveMode::Recursive).unwrap();
|
||||
|
||||
while running
|
||||
{
|
||||
// Listen for file changes until termination signal is received.
|
||||
match notify_receiver.recv().await
|
||||
{
|
||||
Ok(msg) =>
|
||||
{
|
||||
match msg
|
||||
{
|
||||
Ok(event) =>
|
||||
{
|
||||
match event.kind
|
||||
{
|
||||
EventKind::Create(_) =>
|
||||
{
|
||||
println!("File Created: {:?}", event.paths);
|
||||
}
|
||||
EventKind::Modify(_) =>
|
||||
{
|
||||
println!("File Modified: {:?}", event.paths);
|
||||
}
|
||||
EventKind::Remove(_) =>
|
||||
{
|
||||
println!("File Removed: {:?}", event.paths);
|
||||
}
|
||||
_ =>
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(e) =>
|
||||
{
|
||||
eprintln!("{}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(e) =>
|
||||
{
|
||||
eprintln!("Error receiving notify event: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle listening for the termination message, the boolean value will
|
||||
// be changed to false when we are meant to terminate.
|
||||
match term_receiver.has_changed()
|
||||
{
|
||||
Ok(_) =>
|
||||
{
|
||||
running = *term_receiver.borrow_and_update();
|
||||
}
|
||||
|
||||
Err(e) =>
|
||||
{
|
||||
eprintln!("Unable to receive: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -58,6 +142,8 @@ impl DirMonitor
|
||||
|
||||
|
||||
|
||||
/// Scans a directory, and all of its sub directories, and creates a list of the files
|
||||
/// inside and their last modification time.
|
||||
fn scan_dir(monitored_files: &mut MonitoredFiles, dir: &Path) -> std::io::Result<()>
|
||||
{
|
||||
let mut dir_list: Vec<PathBuf> = Vec::new();
|
||||
@ -65,12 +151,29 @@ fn scan_dir(monitored_files: &mut MonitoredFiles, dir: &Path) -> std::io::Result
|
||||
for file in std::fs::read_dir(dir)?
|
||||
{
|
||||
let file = file?;
|
||||
if file.file_type()?.is_dir()
|
||||
let meta = file.metadata()?;
|
||||
|
||||
// Handle directory and file types.
|
||||
//
|
||||
// Directories will be added to the list and later recursively scanned.
|
||||
//
|
||||
// Files will be added to the list of monitored files and their
|
||||
// last modification time will be stored.
|
||||
//
|
||||
// TODO: Handle symlinks. Symlinks can be either a file or another directory.
|
||||
if meta.is_dir()
|
||||
{
|
||||
dir_list.push(file.path().clone());
|
||||
}
|
||||
else if meta.is_file()
|
||||
{
|
||||
let last_mod_time: std::time::SystemTime = meta.modified()?;
|
||||
|
||||
monitored_files.add(&file.path(), last_mod_time);
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively scan the sub directories.
|
||||
for sub_dir in dir_list
|
||||
{
|
||||
scan_dir(monitored_files, &sub_dir)?;
|
||||
|
44
src/event.rs
44
src/event.rs
@ -1,8 +1,36 @@
|
||||
enum Event
|
||||
use std::time::SystemTime;
|
||||
|
||||
|
||||
|
||||
///
|
||||
pub enum Event
|
||||
{
|
||||
New,
|
||||
Modify,
|
||||
///
|
||||
New
|
||||
{
|
||||
///
|
||||
path: String,
|
||||
|
||||
///
|
||||
mod_time: SystemTime
|
||||
},
|
||||
|
||||
///
|
||||
Modify
|
||||
{
|
||||
///
|
||||
path: String,
|
||||
|
||||
///
|
||||
mod_time: SystemTime
|
||||
},
|
||||
|
||||
///
|
||||
Delete
|
||||
{
|
||||
///
|
||||
path: String
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -12,17 +40,17 @@ impl std::fmt::Display for Event
|
||||
{
|
||||
match self
|
||||
{
|
||||
Event::New =>
|
||||
Event::New(_) =>
|
||||
{
|
||||
write!(f, "NEW")
|
||||
write!(f, "[NEW] {}", self.path)
|
||||
}
|
||||
Event::Modify =>
|
||||
Event::Modify(_) =>
|
||||
{
|
||||
write!(f, "MOD")
|
||||
write!(f, "[MOD] {}", self.path)
|
||||
}
|
||||
Event::Delete =>
|
||||
{
|
||||
write!(f, "DEL")
|
||||
write!(f, "[DEL] {}", self.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
91
src/main.rs
91
src/main.rs
@ -1,4 +1,4 @@
|
||||
//! Rust challenge
|
||||
//! Rust challenge: FileMonitor
|
||||
|
||||
|
||||
|
||||
@ -10,6 +10,8 @@ mod monitored_files;
|
||||
|
||||
use clap::Parser;
|
||||
|
||||
use tokio::sync::watch;
|
||||
|
||||
use crate::dir_monitor::DirMonitor;
|
||||
|
||||
|
||||
@ -30,13 +32,94 @@ struct Options
|
||||
|
||||
|
||||
|
||||
/// Creates the given directory, and its parents, if it does not exist.
|
||||
fn create_directory(dir: &str) -> bool
|
||||
{
|
||||
match std::fs::create_dir_all(dir)
|
||||
{
|
||||
Ok(_) =>
|
||||
{
|
||||
true
|
||||
}
|
||||
|
||||
Err(e) =>
|
||||
{
|
||||
eprintln!("Creating directory error: {}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Asynchronously listen for CTRL-C to be pressed.
|
||||
///
|
||||
/// This will send a false message across the channel
|
||||
/// when it detects the termination signal.
|
||||
async fn listen_for_termination(sender: watch::Sender<bool>)
|
||||
{
|
||||
tokio::signal::ctrl_c().await.unwrap();
|
||||
|
||||
// CTRL-C was pressed so send a message to everyone that is
|
||||
// watching that the program is to be terminated. Then close the
|
||||
// sender.
|
||||
sender.send_replace(false);
|
||||
sender.closed().await;
|
||||
}
|
||||
|
||||
|
||||
/// The usual starting point of your project.
|
||||
fn main()
|
||||
#[tokio::main]
|
||||
async fn main()
|
||||
{
|
||||
let options: Options = Options::parse();
|
||||
|
||||
println!("Inbox: `{}`", options.inbox_dir);
|
||||
if create_directory(&options.inbox_dir)
|
||||
{
|
||||
// This is our keep running channel. False will be sent
|
||||
// when the application is meant to be closed.
|
||||
let (sender, receiver) = watch::channel(true);
|
||||
|
||||
let mut directory_monitor: DirMonitor = DirMonitor::new(&options.inbox_dir);
|
||||
directory_monitor.monitor();
|
||||
let mut directory_monitor: DirMonitor = DirMonitor::new(&options.inbox_dir);
|
||||
|
||||
// Program workflow step 1.
|
||||
// Async is not needed here. This can be done syncronously because
|
||||
// file systems are not async and the spawn_blocking blocking overhead
|
||||
// isn't needed.
|
||||
directory_monitor.scan();
|
||||
directory_monitor.print_monitored_files();
|
||||
|
||||
// Run our directory monitor.
|
||||
let mon_task = tokio::spawn(async move
|
||||
{
|
||||
// Program workflow step 2 (terminated by step 3).
|
||||
// This can be done async because we are waiting on
|
||||
// events to be loaded from the notify library and
|
||||
// we want this to run continously and not block the
|
||||
// program. This could also be done on a seperate thread,
|
||||
// preferably a green thread, but a fiber is sufficient
|
||||
// and less resource intensive.
|
||||
directory_monitor.monitor(receiver).await;
|
||||
});
|
||||
|
||||
// Run until Ctrl-C is pressed.
|
||||
// Once it is pressed it will send a message to stop.
|
||||
let term_task = tokio::spawn(async move
|
||||
{
|
||||
// Program workflow step 3.
|
||||
// Async with message passing so it can run and listen
|
||||
// for the termination signal. It uses a watch channel
|
||||
// because any task that will need to know when the
|
||||
// program is to end can then catch the change.
|
||||
listen_for_termination(sender).await;
|
||||
});
|
||||
|
||||
// Only need to wait for the monitor task to finish because it will only
|
||||
// finish once the termination task has finished.
|
||||
mon_task.await;
|
||||
|
||||
// Program workflow step 4.
|
||||
// Async is not needed here. This can be done syncronously because it
|
||||
// is the final/clean up step of the program.
|
||||
directory_monitor.print_monitored_files();
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,24 @@
|
||||
use std::path::{PathBuf, Path};
|
||||
use std::time::SystemTime;
|
||||
|
||||
use chrono::{DateTime, Local};
|
||||
|
||||
use crate::event::Event;
|
||||
|
||||
|
||||
|
||||
///
|
||||
pub struct MonitoredFiles
|
||||
{
|
||||
///
|
||||
mod_dates: Vec<Option<std::time::SystemTime>>,
|
||||
mod_dates: Vec<SystemTime>,
|
||||
|
||||
///
|
||||
paths: Vec<Option<std::path::PathBuf>>
|
||||
paths: Vec<PathBuf>
|
||||
}
|
||||
|
||||
|
||||
|
||||
impl MonitoredFiles
|
||||
{
|
||||
pub fn new() -> Self
|
||||
@ -19,13 +29,82 @@ impl MonitoredFiles
|
||||
paths: Vec::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl std::fmt::Display for Point
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
|
||||
pub fn process_event(&mut self, path: &Path, event: Event)
|
||||
{
|
||||
write!(f, "({}, {})", self.x, self.y)
|
||||
match event
|
||||
{
|
||||
Event::New(creation_time) =>
|
||||
{
|
||||
self.add(path, creation_time);
|
||||
}
|
||||
|
||||
Event::Modify(mod_time) =>
|
||||
{
|
||||
self.modify(&path, mod_time);
|
||||
}
|
||||
|
||||
Event::Delete =>
|
||||
{
|
||||
self.remove(&path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&mut self, path: &Path, time: SystemTime)
|
||||
{
|
||||
self.paths.push(PathBuf::from(path));
|
||||
self.mod_dates.push(time);
|
||||
}
|
||||
|
||||
pub fn modify(&mut self, path: &Path, time: SystemTime)
|
||||
{
|
||||
if let Some(index) = self.get_path_index(path)
|
||||
{
|
||||
self.mod_dates[index] = time;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, path: &Path)
|
||||
{
|
||||
if let Some(index) = self.get_path_index(path)
|
||||
{
|
||||
self.mod_dates.remove(index);
|
||||
self.paths.remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print(&self, base: &Path)
|
||||
{
|
||||
for file in 0..self.paths.len()
|
||||
{
|
||||
let date_time: DateTime<Local> = DateTime::from(self.mod_dates[file]);
|
||||
|
||||
match &self.paths[file].strip_prefix(base)
|
||||
{
|
||||
Ok(rel_path) =>
|
||||
{
|
||||
println!("[{}] {}", date_time.format("%d/%m/%Y %H:%M"), rel_path.display());
|
||||
}
|
||||
|
||||
Err(e) =>
|
||||
{
|
||||
eprintln!("Unable to strip base directory: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_path_index(&self, path: &Path) -> Option<usize>
|
||||
{
|
||||
for (index, stored_path) in self.paths.iter().enumerate()
|
||||
{
|
||||
if path == stored_path
|
||||
{
|
||||
return Some(index);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user