agentic_workflow/engine/
trigger.rs1use std::collections::HashMap;
2
3use chrono::Utc;
4use uuid::Uuid;
5
6use crate::types::{
7 Trigger, TriggerActivation, TriggerCondition, TriggerType,
8 WorkflowError, WorkflowResult,
9};
10
11pub struct TriggerEngine {
13 triggers: HashMap<String, Trigger>,
14 activations: Vec<TriggerActivation>,
15}
16
17impl TriggerEngine {
18 pub fn new() -> Self {
19 Self {
20 triggers: HashMap::new(),
21 activations: Vec::new(),
22 }
23 }
24
25 pub fn create_trigger(
27 &mut self,
28 name: &str,
29 workflow_id: &str,
30 trigger_type: TriggerType,
31 condition: Option<TriggerCondition>,
32 debounce_ms: Option<u64>,
33 ) -> WorkflowResult<String> {
34 let id = Uuid::new_v4().to_string();
35 let trigger = Trigger {
36 id: id.clone(),
37 name: name.to_string(),
38 workflow_id: workflow_id.to_string(),
39 trigger_type,
40 condition,
41 debounce_ms,
42 enabled: true,
43 created_at: Utc::now(),
44 metadata: HashMap::new(),
45 };
46
47 self.triggers.insert(id.clone(), trigger);
48 Ok(id)
49 }
50
51 pub fn list_triggers(&self) -> Vec<&Trigger> {
53 self.triggers.values().collect()
54 }
55
56 pub fn triggers_for_workflow(&self, workflow_id: &str) -> Vec<&Trigger> {
58 self.triggers
59 .values()
60 .filter(|t| t.workflow_id == workflow_id)
61 .collect()
62 }
63
64 pub fn set_enabled(&mut self, trigger_id: &str, enabled: bool) -> WorkflowResult<()> {
66 let trigger = self
67 .triggers
68 .get_mut(trigger_id)
69 .ok_or_else(|| WorkflowError::TriggerError(format!("Not found: {}", trigger_id)))?;
70
71 trigger.enabled = enabled;
72 Ok(())
73 }
74
75 pub fn remove_trigger(&mut self, trigger_id: &str) -> WorkflowResult<Trigger> {
77 self.triggers
78 .remove(trigger_id)
79 .ok_or_else(|| WorkflowError::TriggerError(format!("Not found: {}", trigger_id)))
80 }
81
82 pub fn record_activation(
84 &mut self,
85 trigger_id: &str,
86 execution_id: &str,
87 event_data: serde_json::Value,
88 condition_met: bool,
89 ) -> WorkflowResult<()> {
90 if !self.triggers.contains_key(trigger_id) {
91 return Err(WorkflowError::TriggerError(format!(
92 "Not found: {}",
93 trigger_id
94 )));
95 }
96
97 self.activations.push(TriggerActivation {
98 trigger_id: trigger_id.to_string(),
99 execution_id: execution_id.to_string(),
100 activated_at: Utc::now(),
101 event_data,
102 condition_met,
103 });
104
105 Ok(())
106 }
107
108 pub fn activation_history(&self, trigger_id: &str) -> Vec<&TriggerActivation> {
110 self.activations
111 .iter()
112 .filter(|a| a.trigger_id == trigger_id)
113 .collect()
114 }
115
116 pub fn test_condition(
118 &self,
119 trigger_id: &str,
120 event_data: &serde_json::Value,
121 ) -> WorkflowResult<bool> {
122 let trigger = self
123 .triggers
124 .get(trigger_id)
125 .ok_or_else(|| WorkflowError::TriggerError(format!("Not found: {}", trigger_id)))?;
126
127 match &trigger.condition {
128 None => Ok(true),
129 Some(_condition) => {
130 Ok(true)
133 }
134 }
135 }
136}
137
138impl Default for TriggerEngine {
139 fn default() -> Self {
140 Self::new()
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147
148 #[test]
149 fn test_trigger_lifecycle() {
150 let mut engine = TriggerEngine::new();
151 let tid = engine
152 .create_trigger("on-file-change", "wf-1", TriggerType::Manual, None, None)
153 .unwrap();
154
155 assert_eq!(engine.list_triggers().len(), 1);
156 engine.set_enabled(&tid, false).unwrap();
157 assert!(!engine.triggers.get(&tid).unwrap().enabled);
158 engine.remove_trigger(&tid).unwrap();
159 assert_eq!(engine.list_triggers().len(), 0);
160 }
161}