Files
zclaw_openfang/crates/zclaw-hands/src/trigger.rs

151 lines
3.7 KiB
Rust

//! Hand trigger definitions
use serde::{Deserialize, Serialize};
use serde_json::Value;
use chrono::{DateTime, Utc};
/// Trigger configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TriggerConfig {
/// Unique trigger identifier
pub id: String,
/// Human-readable name
pub name: String,
/// Hand ID to trigger
pub hand_id: String,
/// Trigger type
pub trigger_type: TriggerType,
/// Whether the trigger is enabled
#[serde(default = "default_enabled")]
pub enabled: bool,
/// Maximum executions per hour (rate limiting)
#[serde(default = "default_max_executions")]
pub max_executions_per_hour: u32,
}
fn default_enabled() -> bool { true }
fn default_max_executions() -> u32 { 10 }
/// Trigger type
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum TriggerType {
/// Time-based trigger
Schedule {
/// Cron expression
cron: String,
},
/// Event-based trigger
Event {
/// Event pattern to match
pattern: String,
},
/// Webhook trigger
Webhook {
/// Webhook path
path: String,
/// Secret for verification
secret: Option<String>,
},
/// Message pattern trigger
MessagePattern {
/// Regex pattern
pattern: String,
},
/// File system trigger
FileSystem {
/// Path to watch
path: String,
/// Events to watch for
events: Vec<FileEvent>,
},
/// Manual trigger only
Manual,
}
/// File system event types
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum FileEvent {
Created,
Modified,
Deleted,
Any,
}
/// Trigger state
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TriggerState {
/// Trigger ID
pub trigger_id: String,
/// Last execution time
pub last_execution: Option<DateTime<Utc>>,
/// Execution count in current hour
pub execution_count: u32,
/// Last execution result
pub last_result: Option<TriggerResult>,
/// Whether the trigger is active
pub is_active: bool,
}
impl TriggerState {
pub fn new(trigger_id: impl Into<String>) -> Self {
Self {
trigger_id: trigger_id.into(),
last_execution: None,
execution_count: 0,
last_result: None,
is_active: true,
}
}
}
/// Trigger execution result
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TriggerResult {
/// Execution timestamp
pub timestamp: DateTime<Utc>,
/// Whether execution succeeded
pub success: bool,
/// Output from hand execution
pub output: Option<Value>,
/// Error message if failed
pub error: Option<String>,
/// Input that triggered execution
pub trigger_input: Value,
}
impl TriggerResult {
pub fn success(trigger_input: Value, output: Value) -> Self {
Self {
timestamp: Utc::now(),
success: true,
output: Some(output),
error: None,
trigger_input,
}
}
pub fn error(trigger_input: Value, error: impl Into<String>) -> Self {
Self {
timestamp: Utc::now(),
success: false,
output: None,
error: Some(error.into()),
trigger_input,
}
}
}
/// Trigger trait
pub trait Trigger: Send + Sync {
/// Get trigger configuration
fn config(&self) -> &TriggerConfig;
/// Check if trigger should fire
fn should_fire(&self, input: &Value) -> bool;
/// Update trigger state
fn update_state(&mut self, result: TriggerResult);
}