harmos_runtime/observers/
mod.rs1mod driver;
21
22#[cfg(feature = "plugin-sidecar")]
23mod native;
24
25pub use crate::operations::resident::Staged as ObserverRegistration;
28pub use driver::ObserverActivation;
29
30pub(crate) use driver::Backend;
31#[cfg(feature = "plugin-sidecar")]
32pub(crate) use driver::ChildSettlement;
33#[cfg(feature = "plugin-sidecar")]
34pub(crate) use native::Native;
35
36use std::collections::BTreeSet;
40use std::future::Future;
41use std::sync::Arc;
42use std::time::Duration;
43use crate::{Error, Result};
47use harmos_domain::inventory::StreamDeclaration;
48
49#[derive(Clone, Debug)]
58pub struct ObserverDefinition {
59 pub id: String,
60 pub interval: Duration,
61 pub streams: Vec<StreamDeclaration>,
62 pub demand_keys: Vec<String>,
63}
64
65pub trait ObserverBackend: Send + Sync + 'static {
70 fn definition(&self) -> crate::Result<ObserverDefinition>;
71 fn run(
72 &self, resources: Arc<harmos_sdk::ExecutionContext>, activation: ObserverActivation,
73 ) -> impl Future<Output = crate::Result<()>> + Send;
74}
75
76pub(crate) fn validate(definition: &ObserverDefinition) -> Result<()> {
83 if definition.id.trim().is_empty() || definition.id.chars().any(char::is_control) {
84 return Err(Error::InvalidInput {
85 field: "observer identity",
86 reason: "must be nonempty and contain no control characters",
87 });
88 }
89 if definition.interval.is_zero() {
90 return Err(Error::InvalidInput {
91 field: "observer interval",
92 reason: "must be positive",
93 });
94 }
95 let mut names = BTreeSet::new();
96 for stream in &definition.streams {
97 if stream.id.is_empty() || stream.schema == 0 || stream.window == 0 || !names.insert(stream.id.as_str()) {
98 return Err(Error::InvalidInput {
99 field: "observer streams",
100 reason: "stream identities must be unique and schema/window must be positive",
101 });
102 }
103 }
104 for key in &definition.demand_keys {
105 if key.is_empty() || !names.insert(key.as_str()) {
106 return Err(Error::InvalidInput {
107 field: "observer demand",
108 reason: "demand keys must be nonempty, unique, and distinct from streams",
109 });
110 }
111 }
112 Ok(())
113}
114
115