Files
nym/common/async-file-watcher/src/lib.rs
T
Drazen Urch b5c8b69547 Outfox integration (#3331)
* Experiment with serde

* Framed encoding serde POC

* Outfox framing

* Outfox rest compat (#3333)

* Outfox forwarding compat

* Tidy up interface

* PacketSize compat

* Address PR comments

* Rebase on develop

commit 342883fcbe
Author: durch <durch@users.noreply.github.com>
Date:   Thu Apr 27 09:17:18 2023 +0200

    Put back PacketType 1

commit 61a0ee5a19
Author: Tommy Verrall <tommyvez@protonmail.com>
Date:   Wed Apr 26 16:37:29 2023 +0100

    change output for cpu-cycle management logs

commit 3956109c7e
Author: Tommy Verrall <tommy@nymtech.net>
Date:   Wed Apr 26 12:13:22 2023 +0100

    change the workflow file to build with cpucycles

commit 8d725b13c5
Author: durch <durch@users.noreply.github.com>
Date:   Mon Apr 24 13:14:58 2023 +0200

    Outfox client compat

commit 4d166c389b
Author: durch <durch@users.noreply.github.com>
Date:   Fri Apr 21 00:30:46 2023 +0200

    Address PR comments

commit 145c3c1223
Author: durch <durch@users.noreply.github.com>
Date:   Fri Apr 21 00:12:35 2023 +0200

    Rename PacketMode

commit cbd654d6fd
Author: Drazen Urch <drazen@urch.eu>
Date:   Thu Apr 20 23:59:40 2023 +0200

    Outfox rest compat (#3333)

    * Outfox forwarding compat

    * Tidy up interface

    * PacketSize compat

commit e7be91a94c
Author: durch <durch@users.noreply.github.com>
Date:   Wed Apr 19 16:36:48 2023 +0200

    Remove serde cruft

commit 582e7d566a
Author: durch <durch@users.noreply.github.com>
Date:   Wed Apr 19 16:24:09 2023 +0200

    Outfox framing

commit 6464da5f01
Author: durch <durch@users.noreply.github.com>
Date:   Tue Apr 18 22:23:02 2023 +0200

    Framing compat

commit d5e77e499b
Author: durch <durch@users.noreply.github.com>
Date:   Tue Apr 18 18:18:54 2023 +0200

    Framed encoding serde POC

commit f086f9c35a
Author: durch <durch@users.noreply.github.com>
Date:   Tue Apr 18 16:54:21 2023 +0200

    Experiment with serde

* Client tweaks

* Speed up from_plaintext

* SurbAcks

* More work on the reciever end, and outfox format

* Cleanup and fmt

* Wrap up rebase

* Happy clippy

* Fix lock files

* Final cleanup
2023-05-29 10:05:11 +02:00

159 lines
5.1 KiB
Rust

// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use futures::channel::mpsc;
use futures::StreamExt;
use notify::event::{DataChange, MetadataKind, ModifyKind};
use notify::{Config, Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher};
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::time::Duration;
use tokio::time::Instant;
pub type FileWatcherEventSender = mpsc::UnboundedSender<Event>;
pub type FileWatcherEventReceiver = mpsc::UnboundedReceiver<Event>;
/// Simple file watcher that sends a notification whenever there was any changed in the watched file.
pub struct AsyncFileWatcher {
path: PathBuf,
watcher: RecommendedWatcher,
is_watching: bool,
filters: Option<Vec<EventKind>>,
last_received: HashMap<EventKind, Instant>,
tick_duration: Duration,
inner_rx: mpsc::UnboundedReceiver<notify::Result<Event>>,
event_sender: FileWatcherEventSender,
}
impl AsyncFileWatcher {
pub fn new_file_changes_watcher<P: AsRef<Path>>(
path: P,
event_sender: FileWatcherEventSender,
) -> notify::Result<Self> {
Self::new(
path,
event_sender,
Some(vec![
EventKind::Modify(ModifyKind::Data(DataChange::Content)),
EventKind::Modify(ModifyKind::Data(DataChange::Any)),
EventKind::Modify(ModifyKind::Metadata(MetadataKind::Any)),
]),
None,
)
}
pub fn new<P: AsRef<Path>>(
path: P,
event_sender: FileWatcherEventSender,
filters: Option<Vec<EventKind>>,
tick_duration: Option<Duration>,
) -> notify::Result<Self> {
let watcher_config = Config::default();
let (inner_tx, inner_rx) = mpsc::unbounded();
let watcher = RecommendedWatcher::new(
move |res| {
if let Err(_err) = inner_tx.unbounded_send(res) {
// I guess it's theoretically possible during shutdown?
log::error!(
"failed to send watched file event - the received must have been dropped!"
);
}
},
watcher_config,
)?;
Ok(AsyncFileWatcher {
path: path.as_ref().to_path_buf(),
watcher,
is_watching: false,
filters,
last_received: HashMap::new(),
tick_duration: tick_duration.unwrap_or(Duration::from_secs(5)),
inner_rx,
event_sender,
})
}
pub fn with_filters(mut self, filters: Option<Vec<EventKind>>) -> Self {
self.filters = filters;
self
}
pub fn with_filter(mut self, filter: EventKind) -> Self {
match &mut self.filters {
None => {
self.filters = Some(vec![filter]);
}
Some(filters) => filters.push(filter),
}
self
}
fn should_propagate(&self, event: &Event, now: Instant) -> bool {
// when testing I was consistently getting two `Modify(Data(Any))` events in quick succession
// (probably to modify content and metadata).
// we really only want to propagate one of them
if let Some(previous) = self.last_received.get(&event.kind) {
if now.duration_since(*previous) < self.tick_duration {
return false;
}
}
let Some(filters) = &self.filters else {
return true
};
for filter in filters {
if &event.kind == filter {
return true;
}
}
false
}
fn start_watching(&mut self) -> notify::Result<()> {
self.is_watching = true;
self.watcher.watch(&self.path, RecursiveMode::NonRecursive)
}
fn stop_watching(&mut self) -> notify::Result<()> {
self.is_watching = false;
self.watcher.unwatch(&self.path)
}
pub async fn watch(&mut self) -> notify::Result<()> {
self.start_watching()?;
while let Some(event) = self.inner_rx.next().await {
match event {
Ok(event) => {
let now = Instant::now();
if self.should_propagate(&event, now) {
self.last_received.insert(event.kind, now);
if let Err(_err) = self.event_sender.unbounded_send(event) {
log::error!("the file watcher receiver has been dropped!");
}
} else {
log::debug!("will not propagate information about {:?}", event);
}
}
Err(err) => {
// TODO: to be determined if this should stop the whole thing or not
// (need to know what kind of errors can be returned)
log::error!(
"encountered an error while watching {:?}: {err}",
self.path.as_path()
);
}
}
}
self.stop_watching()
}
pub fn is_watching(&self) -> bool {
self.is_watching
}
}