use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
use crate::{ActError, Result, Vars};
pub const TRIGGER_MANUAL: &str = "manual";
pub const TRIGGER_CHAT: &str = "chat";
pub const TRIGGER_HOOK: &str = "hook";
pub const TRIGGER_SCHEDULE: &str = "schedule";
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TriggerKind {
Manual,
Chat,
Hook,
Schedule,
}
impl TriggerKind {
pub fn parse(kind: &str) -> Option<Self> {
match kind {
TRIGGER_MANUAL => Some(Self::Manual),
TRIGGER_CHAT => Some(Self::Chat),
TRIGGER_HOOK => Some(Self::Hook),
TRIGGER_SCHEDULE => Some(Self::Schedule),
_ => None,
}
}
pub fn as_str(&self) -> &'static str {
match self {
Self::Manual => TRIGGER_MANUAL,
Self::Chat => TRIGGER_CHAT,
Self::Hook => TRIGGER_HOOK,
Self::Schedule => TRIGGER_SCHEDULE,
}
}
}
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct Trigger {
#[serde(default)]
pub id: String,
#[serde(default)]
pub name: String,
#[serde(default)]
pub desc: String,
#[serde(default)]
pub kind: String,
#[serde(default)]
pub params: JsonValue,
#[serde(default)]
pub schedule: Option<String>,
#[serde(default)]
pub metadata: Vars,
}
impl Trigger {
pub fn new() -> Self {
Default::default()
}
pub fn with_kind(mut self, kind: &str) -> Self {
self.kind = kind.to_string();
self
}
pub fn with_id(mut self, id: &str) -> Self {
self.id = id.to_string();
self
}
pub fn with_name(mut self, name: &str) -> Self {
self.name = name.to_string();
self
}
pub fn with_desc(mut self, desc: &str) -> Self {
self.desc = desc.to_string();
self
}
pub fn with_params_data(mut self, v: JsonValue) -> Self {
self.params = v;
self
}
pub fn with_params_vars<F: Fn(Vars) -> Vars>(mut self, build: F) -> Self {
let vars = build(Vars::default());
self.params = vars.into();
self
}
pub fn with_schedule(mut self, cron: &str) -> Self {
self.schedule = Some(cron.to_string());
self
}
pub fn with_metadata<T>(mut self, name: &str, value: T) -> Self
where
T: Serialize + Clone,
{
self.metadata.set(name, value);
self
}
pub fn builtin_kind(&self) -> Option<TriggerKind> {
TriggerKind::parse(&self.kind)
}
pub fn is_builtin(&self) -> bool {
self.builtin_kind().is_some()
}
pub fn valid(&self) -> Result<()> {
if self.id.is_empty() {
return Err(ActError::Model("workflow event id is empty".to_string()));
}
if self.kind.is_empty() {
return Err(ActError::Model(format!(
"workflow event({}) kind is empty",
self.id
)));
}
if self.builtin_kind() == Some(TriggerKind::Schedule) {
match &self.schedule {
Some(schedule) if !schedule.trim().is_empty() => {
if let Err(err) = crate::scheduler::cron::Cron::parse(schedule) {
return Err(ActError::Model(format!(
"workflow event({}) invalid schedule '{schedule}': {err}",
self.id
)));
}
}
_ => {
return Err(ActError::Model(format!(
"workflow event({}) missing schedule for kind '{}'",
self.id, self.kind
)));
}
}
}
Ok(())
}
}