Skip to main content

lash_remote_protocol/protocol/
triggers.rs

1#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
2pub struct RemoteTriggerOccurrenceRequest {
3    pub protocol_version: u32,
4    pub source_type: String,
5    pub source_key: String,
6    #[serde(default)]
7    pub payload: serde_json::Value,
8    pub idempotency_key: String,
9    #[serde(default, skip_serializing_if = "Option::is_none")]
10    pub source: Option<serde_json::Value>,
11}
12
13impl RemoteTriggerOccurrenceRequest {
14    pub fn new(
15        source_type: impl Into<String>,
16        source_key: impl Into<String>,
17        payload: serde_json::Value,
18        idempotency_key: impl Into<String>,
19    ) -> Self {
20        Self {
21            protocol_version: REMOTE_PROTOCOL_VERSION,
22            source_type: source_type.into(),
23            source_key: source_key.into(),
24            payload,
25            idempotency_key: idempotency_key.into(),
26            source: None,
27        }
28    }
29
30    pub fn with_source(mut self, source: serde_json::Value) -> Self {
31        self.source = Some(source);
32        self
33    }
34
35    pub fn validate(&self) -> Result<(), RemoteProtocolError> {
36        ensure_protocol_version(self.protocol_version)?;
37        require_non_empty(
38            "RemoteTriggerOccurrenceRequest",
39            "source_type",
40            &self.source_type,
41        )?;
42        require_non_empty(
43            "RemoteTriggerOccurrenceRequest",
44            "source_key",
45            &self.source_key,
46        )?;
47        require_non_empty(
48            "RemoteTriggerOccurrenceRequest",
49            "idempotency_key",
50            &self.idempotency_key,
51        )
52    }
53}
54
55#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
56pub struct RemoteTriggerOccurrenceRecord {
57    pub occurrence_id: String,
58    pub source_type: String,
59    pub source_key: String,
60    #[serde(default)]
61    pub payload: serde_json::Value,
62    pub idempotency_key: String,
63    #[serde(default, skip_serializing_if = "Option::is_none")]
64    pub source: Option<serde_json::Value>,
65    pub occurred_at_ms: u64,
66}
67
68#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
69pub struct RemoteTriggerEmitReport {
70    pub protocol_version: u32,
71    #[serde(default, skip_serializing_if = "String::is_empty")]
72    pub occurrence_id: String,
73    #[serde(default, skip_serializing_if = "Vec::is_empty")]
74    pub started_process_ids: Vec<String>,
75}
76
77impl RemoteTriggerEmitReport {
78    pub fn validate(&self) -> Result<(), RemoteProtocolError> {
79        ensure_protocol_version(self.protocol_version)
80    }
81}
82
83#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
84pub struct RemoteTriggerSubscriptionFilter {
85    pub protocol_version: u32,
86    #[serde(default, skip_serializing_if = "Option::is_none")]
87    pub session_id: Option<String>,
88    #[serde(default, skip_serializing_if = "Option::is_none")]
89    pub handle: Option<String>,
90    #[serde(default, skip_serializing_if = "Option::is_none")]
91    pub name: Option<String>,
92    #[serde(default, skip_serializing_if = "Option::is_none")]
93    pub source_type: Option<String>,
94    #[serde(default, skip_serializing_if = "Option::is_none")]
95    pub source_key: Option<String>,
96    #[serde(default, skip_serializing_if = "Option::is_none")]
97    pub target: Option<RemoteTriggerTargetIdentity>,
98    #[serde(default, skip_serializing_if = "Option::is_none")]
99    pub enabled: Option<bool>,
100}
101
102impl Default for RemoteTriggerSubscriptionFilter {
103    fn default() -> Self {
104        Self {
105            protocol_version: REMOTE_PROTOCOL_VERSION,
106            session_id: None,
107            handle: None,
108            name: None,
109            source_type: None,
110            source_key: None,
111            target: None,
112            enabled: None,
113        }
114    }
115}
116
117impl RemoteTriggerSubscriptionFilter {
118    pub fn for_session(session_id: impl Into<String>) -> Self {
119        Self {
120            protocol_version: REMOTE_PROTOCOL_VERSION,
121            session_id: Some(session_id.into()),
122            ..Self::default()
123        }
124    }
125
126    pub fn for_source_type(source_type: impl Into<String>) -> Self {
127        Self {
128            protocol_version: REMOTE_PROTOCOL_VERSION,
129            source_type: Some(source_type.into()),
130            ..Self::default()
131        }
132    }
133
134    pub fn validate(&self) -> Result<(), RemoteProtocolError> {
135        ensure_protocol_version(self.protocol_version)
136    }
137}
138
139#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
140pub struct RemoteTriggerRegistration {
141    pub handle: String,
142    pub source_key: String,
143    #[serde(default, skip_serializing_if = "Option::is_none")]
144    pub name: Option<String>,
145    pub source_type: String,
146    #[serde(default)]
147    pub source: serde_json::Value,
148    pub target: RemoteTriggerTargetSummary,
149    #[serde(default = "default_true")]
150    pub enabled: bool,
151}
152
153#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
154pub struct RemoteTriggerTargetSummary {
155    pub process_name: String,
156    #[serde(default)]
157    pub inputs: RemoteTriggerInputTemplate,
158}
159
160fn default_true() -> bool {
161    true
162}
163
164#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
165pub struct RemoteTriggerTargetIdentity {
166    pub module_ref: String,
167    pub host_requirements_ref: String,
168    pub process_ref: RemoteLashlangProcessRef,
169    pub process_name: String,
170}
171
172impl RemoteTriggerTargetIdentity {
173    pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
174        require_non_empty(type_name, "module_ref", &self.module_ref)?;
175        require_non_empty(type_name, "host_requirements_ref", &self.host_requirements_ref)?;
176        self.process_ref.validate(type_name)?;
177        require_non_empty(type_name, "process_name", &self.process_name)
178    }
179}
180
181#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
182#[serde(transparent)]
183pub struct RemoteTriggerInputTemplate {
184    pub entries: BTreeMap<String, RemoteTriggerInputBinding>,
185}
186
187impl RemoteTriggerInputTemplate {
188    pub fn new(entries: BTreeMap<String, RemoteTriggerInputBinding>) -> Self {
189        Self { entries }
190    }
191
192    pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
193        for name in self.entries.keys() {
194            require_non_empty(type_name, "input_template key", name)?;
195        }
196        Ok(())
197    }
198}
199
200#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
201#[serde(tag = "kind", rename_all = "snake_case")]
202pub enum RemoteTriggerInputBinding {
203    Event,
204    Fixed { value: serde_json::Value },
205}
206
207#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
208pub struct RemoteTriggerSubscriptionDraft {
209    pub protocol_version: u32,
210    pub registrant: RemoteProcessOriginator,
211    pub env_ref: String,
212    #[serde(default, skip_serializing_if = "Option::is_none")]
213    pub wake_target: Option<RemoteSessionScope>,
214    #[serde(default, skip_serializing_if = "Option::is_none")]
215    pub name: Option<String>,
216    pub source_type: String,
217    pub source_key: String,
218    #[serde(default)]
219    pub source: serde_json::Value,
220    #[serde(default)]
221    pub event_ty: serde_json::Value,
222    pub target: RemoteTriggerTargetIdentity,
223    #[serde(default)]
224    pub input_template: RemoteTriggerInputTemplate,
225}
226
227impl RemoteTriggerSubscriptionDraft {
228    pub fn validate(&self) -> Result<(), RemoteProtocolError> {
229        ensure_protocol_version(self.protocol_version)?;
230        self.registrant.validate("RemoteTriggerSubscriptionDraft")?;
231        require_non_empty("RemoteTriggerSubscriptionDraft", "env_ref", &self.env_ref)?;
232        if let Some(wake_target) = &self.wake_target {
233            wake_target.validate("RemoteTriggerSubscriptionDraft")?;
234        }
235        require_non_empty(
236            "RemoteTriggerSubscriptionDraft",
237            "source_type",
238            &self.source_type,
239        )?;
240        require_non_empty(
241            "RemoteTriggerSubscriptionDraft",
242            "source_key",
243            &self.source_key,
244        )?;
245        self.target.validate("RemoteTriggerSubscriptionDraft")?;
246        self.input_template
247            .validate("RemoteTriggerSubscriptionDraft")
248    }
249}
250
251#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
252pub struct RemoteTriggerSubscriptionRecord {
253    pub subscription_id: String,
254    pub registrant: RemoteProcessOriginator,
255    pub env_ref: String,
256    #[serde(default, skip_serializing_if = "Option::is_none")]
257    pub wake_target: Option<RemoteSessionScope>,
258    pub handle: String,
259    #[serde(default, skip_serializing_if = "Option::is_none")]
260    pub name: Option<String>,
261    pub source_type: String,
262    pub source_key: String,
263    #[serde(default)]
264    pub source: serde_json::Value,
265    #[serde(default)]
266    pub event_ty: serde_json::Value,
267    pub target: RemoteTriggerTargetIdentity,
268    #[serde(default)]
269    pub input_template: RemoteTriggerInputTemplate,
270    #[serde(default = "default_true")]
271    pub enabled: bool,
272    pub created_at_ms: u64,
273    pub updated_at_ms: u64,
274}
275
276impl RemoteTriggerSubscriptionRecord {
277    pub fn validate(&self, type_name: &'static str) -> Result<(), RemoteProtocolError> {
278        require_non_empty(type_name, "subscription_id", &self.subscription_id)?;
279        self.registrant.validate(type_name)?;
280        require_non_empty(type_name, "env_ref", &self.env_ref)?;
281        if let Some(wake_target) = &self.wake_target {
282            wake_target.validate(type_name)?;
283        }
284        require_non_empty(type_name, "handle", &self.handle)?;
285        require_non_empty(type_name, "source_type", &self.source_type)?;
286        require_non_empty(type_name, "source_key", &self.source_key)?;
287        self.target.validate(type_name)?;
288        self.input_template.validate(type_name)
289    }
290}
291
292#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
293pub struct RemoteTriggerRegisterSubscriptionRequest {
294    pub protocol_version: u32,
295    pub draft: RemoteTriggerSubscriptionDraft,
296}
297
298impl RemoteTriggerRegisterSubscriptionRequest {
299    pub fn validate(&self) -> Result<(), RemoteProtocolError> {
300        ensure_protocol_version(self.protocol_version)?;
301        if self.draft.protocol_version != self.protocol_version {
302            return Err(RemoteProtocolError::MismatchedNestedProtocolVersion {
303                parent: "RemoteTriggerRegisterSubscriptionRequest",
304                child: "draft",
305                parent_version: self.protocol_version,
306                child_version: self.draft.protocol_version,
307            });
308        }
309        self.draft.validate()
310    }
311}
312
313#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
314pub struct RemoteTriggerRegisterSubscriptionResult {
315    pub protocol_version: u32,
316    pub record: RemoteTriggerSubscriptionRecord,
317}
318
319impl RemoteTriggerRegisterSubscriptionResult {
320    pub fn validate(&self) -> Result<(), RemoteProtocolError> {
321        ensure_protocol_version(self.protocol_version)?;
322        self.record
323            .validate("RemoteTriggerRegisterSubscriptionResult")
324    }
325}
326
327#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
328pub struct RemoteTriggerListSubscriptionsResponse {
329    pub protocol_version: u32,
330    #[serde(default)]
331    pub subscriptions: Vec<RemoteTriggerSubscriptionRecord>,
332}
333
334impl RemoteTriggerListSubscriptionsResponse {
335    pub fn validate(&self) -> Result<(), RemoteProtocolError> {
336        ensure_protocol_version(self.protocol_version)?;
337        for record in &self.subscriptions {
338            record.validate("RemoteTriggerListSubscriptionsResponse")?;
339        }
340        Ok(())
341    }
342}
343
344#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
345pub struct RemoteTriggerCancelSubscriptionRequest {
346    pub protocol_version: u32,
347    pub session_id: String,
348    pub handle: String,
349}
350
351impl RemoteTriggerCancelSubscriptionRequest {
352    pub fn validate(&self) -> Result<(), RemoteProtocolError> {
353        ensure_protocol_version(self.protocol_version)?;
354        require_non_empty(
355            "RemoteTriggerCancelSubscriptionRequest",
356            "session_id",
357            &self.session_id,
358        )?;
359        require_non_empty(
360            "RemoteTriggerCancelSubscriptionRequest",
361            "handle",
362            &self.handle,
363        )
364    }
365}
366
367#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
368pub struct RemoteTriggerCancelSubscriptionResult {
369    pub protocol_version: u32,
370    pub session_id: String,
371    pub handle: String,
372    pub cancelled: bool,
373}
374
375impl RemoteTriggerCancelSubscriptionResult {
376    pub fn validate(&self) -> Result<(), RemoteProtocolError> {
377        ensure_protocol_version(self.protocol_version)?;
378        require_non_empty(
379            "RemoteTriggerCancelSubscriptionResult",
380            "session_id",
381            &self.session_id,
382        )?;
383        require_non_empty(
384            "RemoteTriggerCancelSubscriptionResult",
385            "handle",
386            &self.handle,
387        )
388    }
389}