aboutsummaryrefslogtreecommitdiff
path: root/src/observers.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/observers.rs')
-rw-r--r--src/observers.rs142
1 files changed, 142 insertions, 0 deletions
diff --git a/src/observers.rs b/src/observers.rs
new file mode 100644
index 0000000..b321c53
--- /dev/null
+++ b/src/observers.rs
@@ -0,0 +1,142 @@
+use std::ops::Deref;
+
+use bevy::prelude::*;
+use notify::{
+ event::{MetadataKind, ModifyKind, RenameMode},
+ EventKind,
+};
+
+use crate::{
+ components::{DirworldEntity, Persist},
+ events::{DirworldChangeRoot, DirworldEnterRoom, DirworldLeaveRoom},
+ resources::{
+ DirworldCache, DirworldCodecs, DirworldCurrentDir, DirworldObservers, DirworldRootDir,
+ },
+ utils::{despawn_entity_by_path, spawn_entity},
+ DirworldWatcherEvent,
+};
+
+/// On navigation from a room, insert modified payloads into the cache
+pub fn navigate_from_room(
+ _: Trigger<DirworldLeaveRoom>,
+ entities: Query<(Entity, Ref<DirworldEntity>), Without<Persist>>,
+ mut cache: ResMut<DirworldCache>,
+ mut commands: Commands,
+) {
+ for (entity, dirworld_entity) in entities.iter() {
+ if let Some(payload) = &dirworld_entity.payload {
+ info!("Caching {entity:?}");
+ cache.insert(dirworld_entity.path.clone(), payload.clone());
+ }
+ commands.entity(entity).despawn_recursive();
+ }
+}
+
+pub fn navigate_to_room(
+ trigger: Trigger<DirworldEnterRoom>,
+ root_dir: Res<DirworldRootDir>,
+ mut cache: ResMut<DirworldCache>,
+ observers: Res<DirworldObservers>,
+ codecs: Res<DirworldCodecs>,
+ mut commands: Commands,
+) {
+ let path = &trigger.event().0;
+
+ let entries = match path.read_dir() {
+ Ok(entries) => entries
+ .flatten()
+ .map(|entry| entry.path().canonicalize())
+ .flatten()
+ .filter(|entry| {
+ !entry
+ .file_name()
+ .is_some_and(|file_name| file_name.to_string_lossy().starts_with("."))
+ })
+ .chain(
+ root_dir
+ .clone()
+ .map(|root_dir| {
+ if root_dir == *path {
+ None
+ } else {
+ Some(path.join(".."))
+ }
+ })
+ .into_iter()
+ .flatten(),
+ ),
+ Err(e) => {
+ error!("Failed to read directory \"{}\", ({:?})", path.display(), e);
+ return;
+ }
+ };
+
+ for entry in entries {
+ spawn_entity(&entry, &mut cache, &codecs, &observers, &mut commands);
+ }
+}
+
+pub fn handle_changes(
+ trigger: Trigger<DirworldWatcherEvent>,
+ mut commands: Commands,
+ dirworld_entities: Query<(Entity, &DirworldEntity)>,
+ observers: Res<DirworldObservers>,
+ codecs: Res<DirworldCodecs>,
+ mut cache: ResMut<DirworldCache>,
+) {
+ let event = &trigger.event().0;
+ info!("Watcher Event: {event:?}");
+ match event.kind {
+ EventKind::Remove(_) | EventKind::Modify(ModifyKind::Name(RenameMode::From)) => {
+ for path in &event.paths {
+ despawn_entity_by_path(&mut commands, &dirworld_entities, path);
+ }
+ }
+ EventKind::Create(_) | EventKind::Modify(ModifyKind::Name(RenameMode::To)) => {
+ for path in &event.paths {
+ spawn_entity(path, &mut cache, &codecs, &observers, &mut commands);
+ }
+ }
+ EventKind::Modify(ModifyKind::Name(RenameMode::Both)) => {
+ despawn_entity_by_path(&mut commands, &dirworld_entities, &event.paths[0]);
+ spawn_entity(
+ &event.paths[1],
+ &mut cache,
+ &codecs,
+ &observers,
+ &mut commands,
+ );
+ }
+ EventKind::Modify(ModifyKind::Metadata(MetadataKind::Any)) => {
+ despawn_entity_by_path(&mut commands, &dirworld_entities, &event.paths[1]);
+ spawn_entity(
+ &event.paths[0],
+ &mut cache,
+ &codecs,
+ &observers,
+ &mut commands,
+ );
+ }
+ _ => {
+ // warn!("Not Processed.")
+ }
+ }
+}
+
+pub fn change_root(
+ trigger: Trigger<DirworldChangeRoot>,
+ mut root_dir: ResMut<DirworldRootDir>,
+ mut current_dir: ResMut<DirworldCurrentDir>,
+ mut commands: Commands,
+) {
+ if let DirworldRootDir(Some(old_dir)) = root_dir.deref() {
+ commands.trigger(DirworldLeaveRoom(old_dir.to_path_buf()));
+ };
+
+ let new_root = &trigger.event().0;
+ info!("Changing Root to {}", new_root.display());
+ **root_dir = Some(new_root.to_path_buf());
+ **current_dir = Some(new_root.to_path_buf());
+
+ commands.trigger(DirworldEnterRoom(new_root.to_path_buf()));
+}