Skip to main content

enact_cron/
types.rs

1//! Cron job types and data structures
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6/// Type of job to execute
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
8#[serde(rename_all = "lowercase")]
9pub enum JobType {
10    #[default]
11    Shell,
12    Agent,
13}
14
15impl JobType {
16    pub fn as_str(&self) -> &'static str {
17        match self {
18            Self::Shell => "shell",
19            Self::Agent => "agent",
20        }
21    }
22
23    pub fn parse(raw: &str) -> Self {
24        if raw.eq_ignore_ascii_case("agent") {
25            Self::Agent
26        } else {
27            Self::Shell
28        }
29    }
30}
31
32/// Session target for agent jobs
33#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
34#[serde(rename_all = "lowercase")]
35pub enum SessionTarget {
36    #[default]
37    Isolated,
38    Main,
39}
40
41impl SessionTarget {
42    pub fn as_str(&self) -> &'static str {
43        match self {
44            Self::Isolated => "isolated",
45            Self::Main => "main",
46        }
47    }
48
49    pub fn parse(raw: &str) -> Self {
50        if raw.eq_ignore_ascii_case("main") {
51            Self::Main
52        } else {
53            Self::Isolated
54        }
55    }
56}
57
58/// Schedule definition for cron jobs
59#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
60#[serde(tag = "kind", rename_all = "lowercase")]
61pub enum Schedule {
62    /// Standard cron expression (5, 6, or 7 fields)
63    Cron {
64        expr: String,
65        #[serde(default)]
66        tz: Option<String>,
67    },
68    /// One-shot execution at a specific time
69    At { at: DateTime<Utc> },
70    /// Interval-based execution
71    Every { every_ms: u64 },
72}
73
74/// Configuration for job output delivery
75#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
76pub struct DeliveryConfig {
77    #[serde(default)]
78    pub mode: String,
79    #[serde(default)]
80    pub channel: Option<String>,
81    #[serde(default)]
82    pub to: Option<String>,
83    #[serde(default = "default_true")]
84    pub best_effort: bool,
85}
86
87impl Default for DeliveryConfig {
88    fn default() -> Self {
89        Self {
90            mode: "none".to_string(),
91            channel: None,
92            to: None,
93            best_effort: true,
94        }
95    }
96}
97
98fn default_true() -> bool {
99    true
100}
101
102/// A scheduled cron job
103#[derive(Debug, Clone, Serialize, Deserialize)]
104pub struct CronJob {
105    pub id: String,
106    pub expression: String,
107    pub schedule: Schedule,
108    pub command: String,
109    pub prompt: Option<String>,
110    pub name: Option<String>,
111    pub job_type: JobType,
112    pub session_target: SessionTarget,
113    pub model: Option<String>,
114    pub enabled: bool,
115    pub delivery: DeliveryConfig,
116    pub delete_after_run: bool,
117    pub created_at: DateTime<Utc>,
118    pub next_run: DateTime<Utc>,
119    pub last_run: Option<DateTime<Utc>>,
120    pub last_status: Option<String>,
121    pub last_output: Option<String>,
122}
123
124/// Record of a job execution
125#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct CronRun {
127    pub id: i64,
128    pub job_id: String,
129    pub started_at: DateTime<Utc>,
130    pub finished_at: DateTime<Utc>,
131    pub status: String,
132    pub output: Option<String>,
133    pub duration_ms: Option<i64>,
134}
135
136/// Patch for updating a cron job
137#[derive(Debug, Clone, Default, Serialize, Deserialize)]
138pub struct CronJobPatch {
139    pub schedule: Option<Schedule>,
140    pub command: Option<String>,
141    pub prompt: Option<String>,
142    pub name: Option<String>,
143    pub enabled: Option<bool>,
144    pub delivery: Option<DeliveryConfig>,
145    pub model: Option<String>,
146    pub session_target: Option<SessionTarget>,
147    pub delete_after_run: Option<bool>,
148}