use crate::{ cache::JobCache, executor::{FutRes, Waiter, DynFut}, models::{Agent, AssignedJob, JobMeta, JobType}, utils::{CombinedResult, OneOrMany}, UError, }; use guess_host_triple::guess_host_triple; use std::collections::HashMap; pub struct JobBuilder { jobs: Waiter, } impl JobBuilder { pub fn from_request>(job_requests: J) -> CombinedResult { let job_requests = job_requests.into_vec(); let mut prepared: Vec = vec![]; let mut result = CombinedResult::new(); for req in job_requests { let job_meta = JobCache::get(&req.job_id); if job_meta.is_none() { result.err(UError::NoJob(req.job_id)); continue; } let job_meta = job_meta.unwrap(); let built_req = (|| { Ok(match job_meta.exec_type { JobType::Shell => { let meta = JobCache::get(&req.job_id).ok_or(UError::NoJob(req.job_id))?; let curr_platform = guess_host_triple().unwrap_or("unknown").to_string(); if meta.platform != curr_platform { return Err(UError::InsuitablePlatform( meta.platform.clone(), curr_platform, )); } let job = AssignedJob::new(req.job_id, Some(&req)); prepared.push(Box::pin(job.run())) } JobType::Manage => prepared.push(Box::pin(Agent::run())), _ => todo!(), }) })(); if let Err(e) = built_req { result.err(e) } } result.ok(Self { jobs: Waiter::new(prepared), }); result } pub fn from_meta>(job_metas: J) -> CombinedResult { let job_requests = job_metas .into_vec() .into_iter() .map(|jm| { let j_uid = jm.id; JobCache::insert(jm); AssignedJob::new(j_uid, None) }) .collect::>(); JobBuilder::from_request(job_requests) } /// Spawn jobs and pop results later pub async fn spawn(mut self) -> Self { self.jobs = self.jobs.spawn().await; self } /// Spawn jobs and wait for result pub async fn wait(self) -> Vec { self.jobs.spawn().await.wait().await } /// Spawn one job and wait for result pub async fn wait_one(self) -> FutRes { self.jobs.spawn().await.wait().await.pop().unwrap() } } /// Store jobs and get results by name pub struct NamedJobBuilder { builder: Option, job_names: Vec<&'static str>, results: HashMap<&'static str, FutRes>, } impl NamedJobBuilder { pub fn from_shell>( named_jobs: J, ) -> CombinedResult { let mut result = CombinedResult::new(); let jobs: Vec<(&'static str, JobMeta)> = named_jobs .into_vec() .into_iter() .filter_map( |(alias, cmd)| match JobMeta::builder().with_shell(cmd).build() { Ok(meta) => Some((alias, meta)), Err(e) => { result.err(e); None } }, ) .collect(); result.ok(Self::from_meta(jobs)); result } pub fn from_meta>(named_jobs: J) -> Self { let mut job_names = vec![]; let job_metas: Vec = named_jobs .into_vec() .into_iter() .map(|(alias, meta)| { job_names.push(alias); meta }) .collect(); Self { builder: Some(JobBuilder::from_meta(job_metas).unwrap_one()), job_names, results: HashMap::new(), } } pub async fn wait(mut self) -> Self { let results = self.builder.take().unwrap().wait().await; for (name, result) in self.job_names.iter().zip(results.into_iter()) { self.results.insert(name, result); } self } pub fn pop_opt(&mut self, name: &'static str) -> Option { self.results.remove(name) } pub fn pop(&mut self, name: &'static str) -> FutRes { self.pop_opt(name).unwrap() } }