feat: handle interrupts cleanly

This commit is contained in:
Anna 2018-08-13 20:04:16 -04:00
parent 1a2cdf2c2f
commit e3e734c39e
3 changed files with 71 additions and 8 deletions

24
Cargo.lock generated
View File

@ -121,6 +121,15 @@ dependencies = [
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ctrlc"
version = "3.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "deflate"
version = "0.7.18"
@ -360,6 +369,18 @@ dependencies = [
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nix"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nodrop"
version = "0.1.12"
@ -551,6 +572,7 @@ name = "screenshot_organiser"
version = "0.1.0"
dependencies = [
"chrono 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"ctrlc 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
"notify 4.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -750,6 +772,7 @@ dependencies = [
"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150"
"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
"checksum ctrlc 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "630391922b1b893692c6334369ff528dcc3a9d8061ccf4c803aa8f83cb13db5e"
"checksum deflate 0.7.18 (registry+https://github.com/rust-lang/crates.io-index)" = "32c8120d981901a9970a3a1c97cf8b630e0fa8c3ca31e75b6fd6fd5f9f427b31"
"checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd"
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
@ -777,6 +800,7 @@ dependencies = [
"checksum mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a637d1ca14eacae06296a008fa7ad955347e34efcb5891cfd8ba05491a37907e"
"checksum miow 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3e690c5df6b2f60acd45d56378981e827ff8295562fc8d34f573deb267a59cd1"
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
"checksum nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d37e713a259ff641624b6cb20e3b12b2952313ba36b6823c0f16e6cfd9e5de17"
"checksum nix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bfb3ddedaa14746434a02041940495bf11325c22f6d36125d3bdd56090d50a79"
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
"checksum notify 4.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d023ef40ca7680784b07be3f49913e1ea176da1b63949f2eb2fed96438bd7f42"

View File

@ -20,3 +20,4 @@ failure = "0.1"
tempdir = "0.3"
num_cpus = "1"
rayon = "1"
ctrlc = "3"

View File

@ -1,4 +1,4 @@
#![feature(rust_2018_preview, iterator_find_map, use_extern_macros)]
#![feature(rust_2018_preview, iterator_find_map, use_extern_macros, mpsc_select)]
#[macro_use] extern crate serde_derive;
@ -20,34 +20,50 @@ use rayon::prelude::*;
use tempdir::TempDir;
use std::{fs::{self, DirEntry}, path::PathBuf, sync::mpsc};
use std::{fs::{self, DirEntry}, path::PathBuf, sync::mpsc::{self, Receiver}};
pub type Result<T> = std::result::Result<T, Error>;
fn main() -> Result<()> {
println!("Starting FFXIV Screenshot Organiser.");
let ctrlc_rx = set_ctrlc_handler()?;
let config_path = match std::env::args().nth(1) {
Some(x) => x,
None => "config.json".into(),
};
println!("Attempting to read config from `{}`.", config_path);
let f = fs::File::open(config_path)?;
let config: Config = serde_json::from_reader(f)?;
println!("Config successfully read.");
let screenshots_dir = config.options.screenshots_dir.canonicalize()?;
println!("Screenshots are located at `{}`.", screenshots_dir.to_string_lossy());
let (tx, rx) = mpsc::channel();
let temp_dir = TempDir::new("fso-")?;
let temp_path = temp_dir.path().to_owned();
println!("Storing temporary files in `{}`.", temp_path.to_string_lossy());
println!("Collecting existing files.");
let existing_files: Vec<DirEntry> = std::fs::read_dir(&screenshots_dir)?.collect::<std::result::Result<_, _>>()?;
println!("Processing {} existing file(s).", existing_files.len());
existing_files.into_par_iter().for_each(|entry| {
if let Err(e) = handle(&config, temp_path.clone(), entry.path()) {
eprintln!("{}", e);
}
});
println!("Done!");
let mut watcher = notify::watcher(
tx,
Duration::milliseconds(config.options.event_delay).to_std().unwrap(),
@ -58,15 +74,26 @@ fn main() -> Result<()> {
RecursiveMode::NonRecursive
)?;
println!("Waiting for new files.");
loop {
match rx.recv() {
Ok(DebouncedEvent::Create(p)) => if let Err(e) = handle(&config, temp_path.clone(), p) {
eprintln!("{}", e);
},
Ok(_) => {},
Err(e) => eprintln!("{:#?}", e),
select! {
_ = ctrlc_rx.recv() => break,
e = rx.recv() => {
match e {
Ok(DebouncedEvent::Create(p)) => if let Err(e) = handle(&config, temp_path.clone(), p) {
eprintln!("{}", e);
},
Ok(_) => {},
Err(e) => eprintln!("{:#?}", e),
}
}
}
}
println!("Exiting.");
Ok(())
}
fn handle(config: &Config, temp_dir: PathBuf, p: PathBuf) -> Result<()> {
@ -119,3 +146,14 @@ fn parse_screenshot_name(config: &Config, s: &str) -> Option<DateTime<Utc>> {
);
Some(dt.with_timezone(&Utc))
}
fn set_ctrlc_handler() -> Result<Receiver<()>> {
let (tx, rx) = mpsc::channel();
ctrlc::set_handler(move || {
println!("Received interrupt.");
tx.send(()).ok();
})?;
Ok(rx)
}