summaryrefslogtreecommitdiffstats
path: root/zellij-server
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2023-06-16 21:04:22 +0200
committerGitHub <noreply@github.com>2023-06-16 21:04:22 +0200
commitb7436742cddc3987df46371428d1be0d0ebfa282 (patch)
treeb46981be175fe5a9558f0ed0571717492b651934 /zellij-server
parent317bdfc90252058d51b3f2a1847b2074baf5e80e (diff)
performance(plugins): use a debounced fs watcher (#2546)
* performance(plugins): use a debounced fs watcher * style(fmt): rustfmt * fix(macos): use recommended watcher
Diffstat (limited to 'zellij-server')
-rw-r--r--zellij-server/src/plugins/wasm_bridge.rs8
-rw-r--r--zellij-server/src/plugins/watch_filesystem.rs145
2 files changed, 101 insertions, 52 deletions
diff --git a/zellij-server/src/plugins/wasm_bridge.rs b/zellij-server/src/plugins/wasm_bridge.rs
index 0e53ce41e..5ae23be4f 100644
--- a/zellij-server/src/plugins/wasm_bridge.rs
+++ b/zellij-server/src/plugins/wasm_bridge.rs
@@ -13,7 +13,7 @@ use std::{
};
use wasmer::{Instance, Module, Store, Value};
use zellij_utils::async_std::task::{self, JoinHandle};
-use zellij_utils::notify::{RecommendedWatcher, Watcher};
+use zellij_utils::notify_debouncer_full::{notify::RecommendedWatcher, Debouncer, FileIdMap};
use crate::{
background_jobs::BackgroundJob, screen::ScreenInstruction, thread_bus::ThreadSenders,
@@ -50,7 +50,7 @@ pub struct WasmBridge {
loading_plugins: HashMap<(PluginId, RunPlugin), JoinHandle<()>>, // plugin_id to join-handle
pending_plugin_reloads: HashSet<RunPlugin>,
path_to_default_shell: PathBuf,
- watcher: Option<RecommendedWatcher>,
+ watcher: Option<Debouncer<RecommendedWatcher, FileIdMap>>,
zellij_cwd: PathBuf,
capabilities: PluginCapabilities,
client_attributes: ClientAttributes,
@@ -530,7 +530,9 @@ impl WasmBridge {
for plugin_id in &plugin_ids {
drop(self.unload_plugin(*plugin_id));
}
- drop(self.watcher.as_mut().map(|w| w.unwatch(&self.zellij_cwd)));
+ if let Some(watcher) = self.watcher.take() {
+ watcher.stop_nonblocking();
+ }
}
fn run_plugin_of_plugin_id(&self, plugin_id: PluginId) -> Option<&RunPlugin> {
self.loading_plugins
diff --git a/zellij-server/src/plugins/watch_filesystem.rs b/zellij-server/src/plugins/watch_filesystem.rs
index 864bd45f9..9ac0a320c 100644
--- a/zellij-server/src/plugins/watch_filesystem.rs
+++ b/zellij-server/src/plugins/watch_filesystem.rs
@@ -3,61 +3,108 @@ use std::path::PathBuf;
use crate::thread_bus::ThreadSenders;
use std::path::Path;
+use std::time::Duration;
-use zellij_utils::{data::Event, errors::prelude::*};
+use zellij_utils::notify_debouncer_full::{
+ new_debouncer,
+ notify::{EventKind, RecommendedWatcher, RecursiveMode, Watcher},
+ DebounceEventResult, Debouncer, FileIdMap,
+};
+use zellij_utils::{data::Event, errors::prelude::Result};
-use zellij_utils::notify::{self, EventKind, RecommendedWatcher, RecursiveMode, Watcher};
-pub fn watch_filesystem(senders: ThreadSenders, zellij_cwd: &Path) -> Result<RecommendedWatcher> {
+const DEBOUNCE_DURATION_MS: u64 = 500;
+
+pub fn watch_filesystem(
+ senders: ThreadSenders,
+ zellij_cwd: &Path,
+) -> Result<Debouncer<RecommendedWatcher, FileIdMap>> {
let path_prefix_in_plugins = PathBuf::from("/host");
let current_dir = PathBuf::from(zellij_cwd);
- let mut watcher = notify::recommended_watcher({
- move |res: notify::Result<notify::Event>| match res {
- Ok(event) => {
- let paths: Vec<PathBuf> = event
- .paths
- .iter()
- .map(|p| {
- let stripped_prefix_path =
- p.strip_prefix(&current_dir).unwrap_or_else(|_| p);
- path_prefix_in_plugins.join(stripped_prefix_path)
+ let mut debouncer = new_debouncer(
+ Duration::from_millis(DEBOUNCE_DURATION_MS),
+ None,
+ move |result: DebounceEventResult| match result {
+ Ok(events) => {
+ let mut create_events = vec![];
+ let mut read_events = vec![];
+ let mut update_events = vec![];
+ let mut delete_events = vec![];
+ for event in events {
+ match event.kind {
+ EventKind::Access(_) => read_events.push(event),
+ EventKind::Create(_) => create_events.push(event),
+ EventKind::Modify(_) => update_events.push(event),
+ EventKind::Remove(_) => delete_events.push(event),
+ _ => {},
+ }
+ }
+ let create_paths: Vec<PathBuf> = create_events
+ .drain(..)
+ .map(|e| {
+ e.paths
+ .iter()
+ .map(|p| {
+ let stripped_prefix_path =
+ p.strip_prefix(&current_dir).unwrap_or_else(|_| p);
+ path_prefix_in_plugins.join(stripped_prefix_path)
+ })
+ .collect()
})
.collect();
- match event.kind {
- EventKind::Access(_) => {
- let _ = senders.send_to_plugin(PluginInstruction::Update(vec![(
- None,
- None,
- Event::FileSystemRead(paths),
- )]));
- },
- EventKind::Create(_) => {
- let _ = senders.send_to_plugin(PluginInstruction::Update(vec![(
- None,
- None,
- Event::FileSystemCreate(paths),
- )]));
- },
- EventKind::Modify(_) => {
- let _ = senders.send_to_plugin(PluginInstruction::Update(vec![(
- None,
- None,
- Event::FileSystemUpdate(paths),
- )]));
- },
- EventKind::Remove(_) => {
- let _ = senders.send_to_plugin(PluginInstruction::Update(vec![(
- None,
- None,
- Event::FileSystemDelete(paths),
- )]));
- },
- _ => {},
- }
+ let read_paths: Vec<PathBuf> = read_events
+ .drain(..)
+ .map(|e| {
+ e.paths
+ .iter()
+ .map(|p| {
+ let stripped_prefix_path =
+ p.strip_prefix(&current_dir).unwrap_or_else(|_| p);
+ path_prefix_in_plugins.join(stripped_prefix_path)
+ })
+ .collect()
+ })
+ .collect();
+ let update_paths: Vec<PathBuf> = update_events
+ .drain(..)
+ .map(|e| {
+ e.paths
+ .iter()
+ .map(|p| {
+ let stripped_prefix_path =
+ p.strip_prefix(&current_dir).unwrap_or_else(|_| p);
+ path_prefix_in_plugins.join(stripped_prefix_path)
+ })
+ .collect()
+ })
+ .collect();
+ let delete_paths: Vec<PathBuf> = delete_events
+ .drain(..)
+ .map(|e| {
+ e.paths
+ .iter()
+ .map(|p| {
+ let stripped_prefix_path =
+ p.strip_prefix(&current_dir).unwrap_or_else(|_| p);
+ path_prefix_in_plugins.join(stripped_prefix_path)
+ })
+ .collect()
+ })
+ .collect();
+ let _ = senders.send_to_plugin(PluginInstruction::Update(vec![
+ (None, None, Event::FileSystemRead(read_paths)),
+ (None, None, Event::FileSystemCreate(create_paths)),
+ (None, None, Event::FileSystemUpdate(update_paths)),
+ (None, None, Event::FileSystemDelete(delete_paths)),
+ ]));
},
- Err(e) => log::error!("watch error: {:?}", e),
- }
- })?;
+ Err(errors) => errors
+ .iter()
+ .for_each(|error| log::error!("watch error: {error:?}")),
+ },
+ )?;
- watcher.watch(zellij_cwd, RecursiveMode::Recursive)?;
- Ok(watcher)
+ debouncer
+ .watcher()
+ .watch(zellij_cwd, RecursiveMode::Recursive)?;
+ Ok(debouncer)
}