use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum EventType {
PlaybookStarted,
PlaybookCompleted,
PlaybookFailed,
WorkflowInitialized,
WorkflowCompleted,
WorkflowFailed,
StepEnter,
StepCompleted,
StepFailed,
ActionCompleted,
CommandIssued,
CommandClaimed,
CommandStarted,
CommandCompleted,
CommandFailed,
LoopItem,
LoopDone,
StepResult,
Error,
Custom(String),
}
impl std::fmt::Display for EventType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
EventType::PlaybookStarted => "playbook_started",
EventType::PlaybookCompleted => "playbook.completed",
EventType::PlaybookFailed => "playbook.failed",
EventType::WorkflowInitialized => "workflow.initialized",
EventType::WorkflowCompleted => "workflow.completed",
EventType::WorkflowFailed => "workflow.failed",
EventType::StepEnter => "step.enter",
EventType::StepCompleted => "step_completed",
EventType::StepFailed => "step.failed",
EventType::ActionCompleted => "action_completed",
EventType::CommandIssued => "command.issued",
EventType::CommandClaimed => "command.claimed",
EventType::CommandStarted => "command.started",
EventType::CommandCompleted => "command.completed",
EventType::CommandFailed => "command.failed",
EventType::LoopItem => "loop.item",
EventType::LoopDone => "loop.done",
EventType::StepResult => "step_result",
EventType::Error => "error",
EventType::Custom(s) => s,
};
write!(f, "{}", s)
}
}
impl From<&str> for EventType {
fn from(s: &str) -> Self {
match s {
"playbook_started" => EventType::PlaybookStarted,
"playbook.completed" => EventType::PlaybookCompleted,
"playbook.failed" => EventType::PlaybookFailed,
"workflow.initialized" | "workflow_initialized" => EventType::WorkflowInitialized,
"workflow.completed" => EventType::WorkflowCompleted,
"workflow.failed" => EventType::WorkflowFailed,
"step.enter" => EventType::StepEnter,
"step_completed" => EventType::StepCompleted,
"step.failed" => EventType::StepFailed,
"action_completed" => EventType::ActionCompleted,
"command.issued" => EventType::CommandIssued,
"command.claimed" => EventType::CommandClaimed,
"command.started" => EventType::CommandStarted,
"command.completed" => EventType::CommandCompleted,
"command.failed" => EventType::CommandFailed,
"loop.item" => EventType::LoopItem,
"loop.done" => EventType::LoopDone,
"step_result" => EventType::StepResult,
"error" => EventType::Error,
other => EventType::Custom(other.to_string()),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum EventStatus {
Started,
Running,
Completed,
Failed,
Cancelled,
Pending,
Claimed,
}
impl std::fmt::Display for EventStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
EventStatus::Started => "STARTED",
EventStatus::Running => "RUNNING",
EventStatus::Completed => "COMPLETED",
EventStatus::Failed => "FAILED",
EventStatus::Cancelled => "CANCELLED",
EventStatus::Pending => "PENDING",
EventStatus::Claimed => "CLAIMED",
};
write!(f, "{}", s)
}
}
impl From<&str> for EventStatus {
fn from(s: &str) -> Self {
match s.to_uppercase().as_str() {
"STARTED" => EventStatus::Started,
"RUNNING" => EventStatus::Running,
"COMPLETED" => EventStatus::Completed,
"FAILED" => EventStatus::Failed,
"CANCELLED" => EventStatus::Cancelled,
"PENDING" => EventStatus::Pending,
"CLAIMED" => EventStatus::Claimed,
_ => EventStatus::Pending,
}
}
}
#[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
pub struct Event {
pub id: i64,
pub execution_id: i64,
pub catalog_id: i64,
pub event_id: i64,
pub parent_event_id: Option<i64>,
pub parent_execution_id: Option<i64>,
pub event_type: String,
pub node_id: Option<String>,
pub node_name: Option<String>,
pub node_type: Option<String>,
pub status: String,
pub context: Option<serde_json::Value>,
pub meta: Option<serde_json::Value>,
pub result: Option<serde_json::Value>,
pub worker_id: Option<String>,
pub attempt: Option<i32>,
pub created_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EventCreateRequest {
pub execution_id: i64,
pub catalog_id: i64,
pub parent_event_id: Option<i64>,
pub parent_execution_id: Option<i64>,
pub event_type: String,
pub node_id: Option<String>,
pub node_name: Option<String>,
pub node_type: Option<String>,
pub status: String,
pub context: Option<serde_json::Value>,
pub meta: Option<serde_json::Value>,
pub result: Option<serde_json::Value>,
pub worker_id: Option<String>,
pub attempt: Option<i32>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EventResponse {
pub event_id: String,
pub execution_id: String,
pub event_type: String,
pub node_name: Option<String>,
pub status: String,
pub context: Option<serde_json::Value>,
pub result: Option<serde_json::Value>,
pub created_at: DateTime<Utc>,
}
impl From<Event> for EventResponse {
fn from(e: Event) -> Self {
Self {
event_id: e.event_id.to_string(),
execution_id: e.execution_id.to_string(),
event_type: e.event_type,
node_name: e.node_name,
status: e.status,
context: e.context,
result: e.result,
created_at: e.created_at,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EventListResponse {
pub events: Vec<EventResponse>,
pub total: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WorkerEventPayload {
pub command_id: String,
pub worker_id: String,
pub event_type: String,
pub result: Option<serde_json::Value>,
pub error: Option<String>,
pub duration_ms: Option<i64>,
pub attempt: Option<i32>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_event_type_display() {
assert_eq!(EventType::PlaybookStarted.to_string(), "playbook_started");
assert_eq!(
EventType::WorkflowInitialized.to_string(),
"workflow.initialized"
);
assert_eq!(EventType::CommandCompleted.to_string(), "command.completed");
}
#[test]
fn test_event_type_from_str() {
assert_eq!(
EventType::from("playbook_started"),
EventType::PlaybookStarted
);
assert_eq!(
EventType::from("workflow.initialized"),
EventType::WorkflowInitialized
);
assert_eq!(
EventType::from("command.completed"),
EventType::CommandCompleted
);
assert_eq!(
EventType::from("custom_event"),
EventType::Custom("custom_event".to_string())
);
}
#[test]
fn test_event_status_display() {
assert_eq!(EventStatus::Started.to_string(), "STARTED");
assert_eq!(EventStatus::Completed.to_string(), "COMPLETED");
assert_eq!(EventStatus::Failed.to_string(), "FAILED");
}
#[test]
fn test_event_status_from_str() {
assert_eq!(EventStatus::from("started"), EventStatus::Started);
assert_eq!(EventStatus::from("COMPLETED"), EventStatus::Completed);
assert_eq!(EventStatus::from("Failed"), EventStatus::Failed);
}
}