use chrono::Utc; use std::collections::HashMap; use std::time::Duration; use uuid::Uuid; use crate::{Job, ScriptType, JobError}; /// Builder for constructing and submitting script execution requests. /// /// This builder provides a fluent interface for configuring script execution /// parameters and offers two submission modes: fire-and-forget (`submit()`) /// and request-reply (`await_response()`). /// /// # Example /// /// ```rust,no_run /// use std::time::Duration; /// use hero_supervisor::ScriptType; /// /// # async fn example(client: &hero_supervisor::Supervisor) -> Result { /// let result = client /// .new_job() /// .script_type(ScriptType::OSIS) /// .script(r#"print("Hello, World!");"#) /// .timeout(Duration::from_secs(30)) /// .await_response() /// .await?; /// # Ok(result) /// # } /// ``` pub struct JobBuilder { request_id: String, context_id: String, caller_id: String, script: String, script_type: ScriptType, timeout: Duration, retries: u32, concurrent: bool, log_path: Option, env_vars: HashMap, prerequisites: Vec, dependents: Vec } impl JobBuilder { pub fn new() -> Self { Self { request_id: "".to_string(), context_id: "".to_string(), caller_id: "".to_string(), script: "".to_string(), script_type: ScriptType::OSIS, // Default to OSIS timeout: Duration::from_secs(5), retries: 0, concurrent: false, log_path: None, env_vars: HashMap::new(), prerequisites: Vec::new(), dependents: Vec::new(), } } pub fn request_id(mut self, request_id: &str) -> Self { self.request_id = request_id.to_string(); self } pub fn script_type(mut self, script_type: ScriptType) -> Self { self.script_type = script_type; self } pub fn context_id(mut self, context_id: &str) -> Self { self.context_id = context_id.to_string(); self } pub fn caller_id(mut self, caller_id: &str) -> Self { self.caller_id = caller_id.to_string(); self } pub fn script(mut self, script: &str) -> Self { self.script = script.to_string(); self } pub fn script_path(mut self, script_path: &str) -> Self { self.script = std::fs::read_to_string(script_path).unwrap(); self } pub fn timeout(mut self, timeout: Duration) -> Self { self.timeout = timeout; self } pub fn log_path(mut self, log_path: &str) -> Self { self.log_path = Some(log_path.to_string()); self } /// Set a single environment variable pub fn env_var(mut self, key: &str, value: &str) -> Self { self.env_vars.insert(key.to_string(), value.to_string()); self } /// Set multiple environment variables from a HashMap pub fn env_vars(mut self, env_vars: HashMap) -> Self { self.env_vars.extend(env_vars); self } /// Clear all environment variables pub fn clear_env_vars(mut self) -> Self { self.env_vars.clear(); self } /// Add a prerequisite job ID that must complete before this job can run pub fn prerequisite(mut self, job_id: &str) -> Self { self.prerequisites.push(job_id.to_string()); self } /// Set multiple prerequisite job IDs pub fn prerequisites(mut self, job_ids: Vec) -> Self { self.prerequisites.extend(job_ids); self } /// Add a dependent job ID that depends on this job completing pub fn dependent(mut self, job_id: &str) -> Self { self.dependents.push(job_id.to_string()); self } /// Set multiple dependent job IDs pub fn dependents(mut self, job_ids: Vec) -> Self { self.dependents.extend(job_ids); self } /// Clear all prerequisites pub fn clear_prerequisites(mut self) -> Self { self.prerequisites.clear(); self } /// Clear all dependents pub fn clear_dependents(mut self) -> Self { self.dependents.clear(); self } pub fn build(self) -> Result { let request_id = if self.request_id.is_empty() { // Generate a UUID for the request_id Uuid::new_v4().to_string() } else { self.request_id.clone() }; if self.context_id.is_empty() { return Err(JobError::MissingField("context_id".to_string())); } if self.caller_id.is_empty() { return Err(JobError::MissingField("caller_id".to_string())); } let now = Utc::now(); Ok(Job { id: request_id, caller_id: self.caller_id, context_id: self.context_id, script: self.script, script_type: self.script_type, timeout: self.timeout, retries: self.retries as u8, concurrent: self.concurrent, log_path: self.log_path.clone(), env_vars: self.env_vars.clone(), prerequisites: self.prerequisites.clone(), dependents: self.dependents.clone(), created_at: now, updated_at: now, }) } }