use croner::Cron;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use super::command::slugify;
use crate::paths::{agent_toml_path, routine_toml_path};
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, utoipa::ToSchema)]
pub struct Repository {
pub repository: String,
#[serde(default)]
pub branch: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, utoipa::ToSchema)]
pub struct Routine {
pub id: String,
pub schedule: String,
pub title: String,
pub agent: String,
pub prompt: String,
#[serde(default)]
pub repositories: Vec<Repository>,
pub enabled: bool,
pub source: String,
pub created_at: u64,
pub updated_at: u64,
pub last_triggered_at: Option<u64>,
#[serde(default)]
pub ttl_secs: Option<u64>,
}
pub const DEFAULT_TTL_SECS: u64 = 7 * 24 * 60 * 60;
impl Routine {
pub fn effective_ttl_secs(&self) -> u64 {
self.ttl_secs.unwrap_or(DEFAULT_TTL_SECS)
}
}
#[derive(Debug, Clone, Serialize, JsonSchema, utoipa::ToSchema)]
pub struct RoutineResponse {
#[serde(flatten)]
pub routine: Routine,
pub agent_registered: bool,
pub file_path: String,
pub schedule_description: Option<String>,
pub timezone: Option<String>,
}
pub fn local_timezone() -> Option<String> {
iana_time_zone::get_timezone().ok()
}
impl RoutineResponse {
pub fn from_routine(routine: Routine) -> Self {
let agent_registered = agent_toml_path(&routine.agent).exists();
let file_path = routine_toml_path(&slugify(&routine.title))
.to_string_lossy()
.into_owned();
let timezone = local_timezone();
let schedule_description = routine.schedule.parse::<Cron>().ok().map(|c| {
let desc = c.describe();
match &timezone {
Some(tz) => format!("{desc} ({tz})"),
None => desc,
}
});
Self {
routine,
agent_registered,
file_path,
schedule_description,
timezone,
}
}
}
pub type RoutineStore = Arc<Mutex<HashMap<String, Routine>>>;
#[cfg(test)]
pub fn new_store() -> RoutineStore {
Arc::new(Mutex::new(HashMap::new()))
}
pub(crate) fn bool_true() -> bool {
true
}
#[derive(Deserialize, JsonSchema, utoipa::ToSchema)]
pub struct CreateRoutineRequest {
pub schedule: String,
pub title: String,
pub agent: String,
pub prompt: String,
#[serde(default)]
pub repositories: Vec<Repository>,
#[serde(default = "bool_true")]
pub enabled: bool,
#[serde(default)]
pub ttl_secs: Option<u64>,
}
#[derive(Deserialize, JsonSchema, utoipa::ToSchema)]
pub struct UpdateRoutineRequest {
pub schedule: Option<String>,
pub title: Option<String>,
pub agent: Option<String>,
pub prompt: Option<String>,
pub repositories: Option<Vec<Repository>>,
pub enabled: Option<bool>,
pub ttl_secs: Option<u64>,
}