harmos_operations/storage/
watch_directory.rs1use super::IO_POLICY;
20use harmos_domain::MemorySize;
21use harmos_domain::model::storage::codec::{Flag, Nested, product};
22use harmos_domain::model::storage::{DirectoryCompletion, DirectoryEvent, DirectorySelection};
23use harmos_domain::operations::ReplaySafety;
24#[cfg(feature = "runtime")]
25use harmos_storage::{ErasedCatalog, StorageManager};
26
27product!(WatchDirectory { selection: Nested<DirectorySelection> => 1, include_existing: Flag => 2 });
32
33#[harmos::operation(harmos_path = crate, resources = [StorageManager<ErasedCatalog>], codec = manual,
38 id = "storage.watch_directory",
39 response = DirectoryCompletion,
40 policy = IO_POLICY,
41 output = DirectoryEvent,
42 visibility = Shared,
43 replay = ReplaySafety::Idempotent,
44 grpc(package = "harmos.storage.v1", service = "Storage", method = "WatchDirectory"))]
45#[derive(Clone, Debug, PartialEq, Eq)]
46pub struct WatchDirectory {
47 pub selection: DirectorySelection,
48 pub include_existing: bool,
49}
50
51impl MemorySize for WatchDirectory {
58 fn memory_size(&self) -> usize {
59 std::mem::size_of::<Self>().saturating_add(self.selection.memory_size().saturating_sub(std::mem::size_of_val(&self.selection)))
60 }
61}
62
63#[cfg(feature = "runtime")]
64mod execution {
65
66 use crate::{Error, Result};
70 use harmos_domain::model::storage::{DirectoryCompletion, DirectoryEvent};
71 use harmos_sdk::operations::{Operation, Response};
72
73 impl Operation for super::WatchDirectory {
74 type Error = Error;
75
76 #[tracing::instrument(target = "harmos::storage", name = "storage.operation.watch_directory", level = "trace", skip_all)]
77 async fn run(self, context: harmos_sdk::Context<'_, Self>) -> Result<Response<DirectoryCompletion>> {
78 let storage = context.resource::<harmos_storage::StorageManager<harmos_storage::ErasedCatalog>>();
79 let output = context.streams();
80
81 let mut reader = storage.watch_directory(self.selection.clone(), self.include_existing).await?;
82 let mut entries = 0_u64;
83 while let Some(item) = reader.next().await? {
84 if matches!(&*item, DirectoryEvent::Existing(_) | DirectoryEvent::Created(_) | DirectoryEvent::Modified(_)) {
85 entries = entries.checked_add(1).ok_or(Error::ResourceExhausted { resource: "directory observation count" })?;
86 }
87 let response = Response::from_owner(item.owner());
88 tokio::time::timeout(crate::storage::IO_TIMEOUT, output.send_owned(response))
89 .await
90 .map_err(|_| crate::storage::output_timeout())??;
91 }
92 Ok(DirectoryCompletion { entries }.into())
93 }
94
95 fn classify(error: &Error) -> harmos_sdk::operations::FailureKind {
96 crate::storage::classify(error)
97 }
98 }
99}
100
101