agentmux_srv/backend/storage/
cron.rs1use rusqlite::params;
8use serde::{Deserialize, Serialize};
9
10use super::error::StoreError;
11use super::store::Store;
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct CronJob {
15 pub id: String,
16 pub name: String,
17 pub expression: String,
19 pub prompt: String,
20 pub target: String,
22 #[serde(default)]
28 pub target_uid: String,
29 pub created_by: String,
30 #[serde(default)]
36 pub created_by_uid: String,
37 pub enabled: bool,
38 pub last_fired: Option<i64>,
39 pub fire_count: i64,
40 pub max_fires: Option<i64>,
42 pub created_at: i64,
43 pub max_age_secs: Option<i64>,
48}
49
50impl Store {
51 pub fn cron_create(&self, job: &CronJob) -> Result<(), StoreError> {
52 let conn = self.conn.lock().unwrap();
53 conn.execute(
54 "INSERT INTO db_cron_jobs
55 (id, name, expression, prompt, target, created_by, enabled,
56 last_fired, fire_count, max_fires, created_at, max_age_secs,
57 target_uid, created_by_uid)
58 VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14)",
59 params![
60 job.id,
61 job.name,
62 job.expression,
63 job.prompt,
64 job.target,
65 job.created_by,
66 job.enabled as i64,
67 job.last_fired,
68 job.fire_count,
69 job.max_fires,
70 job.created_at,
71 job.max_age_secs,
72 job.target_uid,
73 job.created_by_uid,
74 ],
75 )?;
76 Ok(())
77 }
78
79 pub fn cron_list(&self) -> Result<Vec<CronJob>, StoreError> {
80 let conn = self.conn.lock().unwrap();
81 let mut stmt = conn.prepare(
82 "SELECT id, name, expression, prompt, target, created_by, enabled,
83 last_fired, fire_count, max_fires, created_at, max_age_secs,
84 target_uid, created_by_uid
85 FROM db_cron_jobs ORDER BY created_at ASC",
86 )?;
87 let iter = stmt.query_map([], map_row)?;
88 iter.collect::<Result<Vec<_>, _>>().map_err(Into::into)
89 }
90
91 pub fn cron_list_enabled(&self) -> Result<Vec<CronJob>, StoreError> {
92 let conn = self.conn.lock().unwrap();
93 let mut stmt = conn.prepare(
94 "SELECT id, name, expression, prompt, target, created_by, enabled,
95 last_fired, fire_count, max_fires, created_at, max_age_secs,
96 target_uid, created_by_uid
97 FROM db_cron_jobs WHERE enabled = 1 ORDER BY created_at ASC",
98 )?;
99 let iter = stmt.query_map([], map_row)?;
100 iter.collect::<Result<Vec<_>, _>>().map_err(Into::into)
101 }
102
103 pub fn cron_get(&self, id: &str) -> Result<Option<CronJob>, StoreError> {
104 let conn = self.conn.lock().unwrap();
105 let mut stmt = conn.prepare(
106 "SELECT id, name, expression, prompt, target, created_by, enabled,
107 last_fired, fire_count, max_fires, created_at, max_age_secs,
108 target_uid, created_by_uid
109 FROM db_cron_jobs WHERE id = ?1",
110 )?;
111 let mut rows = stmt.query_map(params![id], map_row)?;
112 match rows.next() {
113 Some(r) => Ok(Some(r?)),
114 None => Ok(None),
115 }
116 }
117
118 pub fn cron_set_enabled(&self, id: &str, enabled: bool) -> Result<bool, StoreError> {
119 let conn = self.conn.lock().unwrap();
120 let rows = conn.execute(
121 "UPDATE db_cron_jobs SET enabled = ?1 WHERE id = ?2",
122 params![enabled as i64, id],
123 )?;
124 Ok(rows > 0)
125 }
126
127 pub fn cron_record_fire(&self, id: &str, now: i64) -> Result<(), StoreError> {
128 let conn = self.conn.lock().unwrap();
129 conn.execute(
130 "UPDATE db_cron_jobs
131 SET last_fired = ?1,
132 fire_count = fire_count + 1,
133 enabled = CASE
134 WHEN max_fires IS NOT NULL AND fire_count + 1 >= max_fires THEN 0
135 ELSE enabled
136 END
137 WHERE id = ?2",
138 params![now, id],
139 )?;
140 Ok(())
141 }
142
143 pub fn cron_delete(&self, id: &str) -> Result<bool, StoreError> {
144 let conn = self.conn.lock().unwrap();
145 let rows = conn.execute("DELETE FROM db_cron_jobs WHERE id = ?1", params![id])?;
146 Ok(rows > 0)
147 }
148}
149
150fn map_row(row: &rusqlite::Row<'_>) -> rusqlite::Result<CronJob> {
151 Ok(CronJob {
152 id: row.get(0)?,
153 name: row.get(1)?,
154 expression: row.get(2)?,
155 prompt: row.get(3)?,
156 target: row.get(4)?,
157 created_by: row.get(5)?,
158 enabled: row.get::<_, i64>(6)? != 0,
159 last_fired: row.get(7)?,
160 fire_count: row.get(8)?,
161 max_fires: row.get(9)?,
162 created_at: row.get(10)?,
163 max_age_secs: row.get(11)?,
164 target_uid: row.get(12)?,
165 created_by_uid: row.get(13)?,
166 })
167}