From f9bea43c605a5088844c65de16814d521db5946a Mon Sep 17 00:00:00 2001 From: Spencer Kohan Date: Sun, 19 Apr 2020 22:25:43 +0200 Subject: [PATCH] added batched updates --- README.md | 14 +++++++-- src/main.rs | 83 ++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 72 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 074e2e1..4587546 100644 --- a/README.md +++ b/README.md @@ -97,11 +97,21 @@ The ignore file specifies paths which should not be synced by dirsync. The form The `.dirsync/actions` directory houses executables which are triggered by certain dirsync events. -Currently the only action supported is `onSyncDidFinish`. This action is triggered after any sync event from the local to the remote (i.e. after a local file in the watched directory has changed, and the resulting sync has completed). +When an event is triggered, dirsync will execute whatever file is located at the trigger location, i.e: + +``` +./dirsync/actions//remote +``` + +Currently there are two action triggers: + +- `onSessionDidStart`: This action is triggered when dirsync starts, after the initial sync from the local directory to the remote. + +- `onSyncDidFinish`: This action is triggered after any sync event from the local to the remote (i.e. after a local file in the watched directory has changed, and the resulting sync has completed). What this means is, any script located at `.dirsync/actionos/onSyncDidFinish` will be executed on the remote following any sync event. -So for example, if you were synchoronizing a rust project with your remote host, and you wanted to build the project every time a change is pushed, you could implement this `onSyncDidFinish` event: +So for example, if you were synchoronizing a rust project with your remote host, and you wanted to build the project every time a change is pushed, you could implement this `onSyncDidFinish` event at `.dirsync/actionos/onSyncDidFinish/remote` ``` #!/bin/bash diff --git a/src/main.rs b/src/main.rs index ab692da..08baa8a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,19 +6,22 @@ mod init; extern crate notify; use notify::{Watcher, RecursiveMode, watcher, DebouncedEvent}; -use std::sync::mpsc::channel; +use std::sync::mpsc::{channel, Sender}; use std::time::Duration; use crate::config::SessionConfig; use crate::cli::SubCommand; use crate::cli::CliOptions; use structopt::StructOpt; use std::path::Path; - +use std::thread; +use std::sync::{Mutex, Arc}; +use std::vec::Vec; +use crate::remote::Remote; +use std::thread::sleep; // Perform rsync from source to destination fn sync(config: &config::SessionConfig) { use std::process::Command; - use std::process::Stdio; fn rsync(source: &str, destinatin: &str, args: &Vec) { println!("executing rsync: {} {}", source, destinatin); @@ -30,7 +33,6 @@ fn sync(config: &config::SessionConfig) { .args(args) .arg(source) .arg(destinatin) - // .stdout(Stdio::inherit()) .spawn() .expect("failed to execute rsync"); @@ -75,35 +77,70 @@ fn filter(event: DebouncedEvent) -> Option { } } +fn start_watch_thread(root: String, flush_signal: Sender<()>, events: &mut Arc>>) { + let events = Arc::clone(events); + thread::spawn(move|| { + + // Create a channel to receive watcher events. + let (tx, rx) = channel(); + let mut watcher = watcher(tx, Duration::from_millis(20)).unwrap(); + watcher.watch(root, RecursiveMode::Recursive).unwrap(); + + + + loop { + match rx.recv() { + Ok(event) => { + println!("handling event: {:?}", event); + match filter(event) { + Some(event) => { + let signal = flush_signal.clone(); + let mut events_vec = events.lock().unwrap(); + events_vec.push(event); + thread::spawn(move|| { + sleep(Duration::from_millis(20)); + signal.send(()).unwrap(); + }); + }, + None => println!("ignoring event") + }; + + }, + Err(e) => println!("watch error: {:?}", e), + } + } + + }); +} + +fn flush_events(config: &SessionConfig, remote: &mut Remote, events: &mut Arc>>) { + let mut events_vec = events.lock().unwrap(); + if !events_vec.is_empty() { + events_vec.clear(); + sync(&config); + println!("Executing onSyncDidFinish action"); + remote.execute_if_exists("onSyncDidFinish"); + } +} + fn start_main_loop(config: &SessionConfig) { println!("config: {:?}", config); sync(&config); - let mut remote = remote::Remote::connect(config); + let mut remote = Remote::connect(config); remote.execute_if_exists("onSessionDidStart"); - // Create a channel to receive the events. + let mut events: Arc>> = Arc::new(Mutex::new(vec![])); + + // create a channel for flush events let (tx, rx) = channel(); - let mut watcher = watcher(tx, Duration::from_millis(20)).unwrap(); - watcher.watch(config.local_root.clone(), RecursiveMode::Recursive).unwrap(); + start_watch_thread(config.local_root.clone(), tx, &mut events); loop { - match rx.recv() { - Ok(event) => { - println!("handling event: {:?}", event); - match filter(event) { - Some(_) => { - sync(&config); - println!("Executing onSyncDidFinish action"); - remote.execute_if_exists("onSyncDidFinish"); - }, - None => println!("ignoring event") - }; - - }, - Err(e) => println!("watch error: {:?}", e), - } + let _ = rx.recv(); + flush_events(&config, &mut remote, &mut events); } + }