use anyhow::{anyhow, Result}; use serde::{Serialize, Serializer}; use std::collections::HashMap; use uuid::Uuid; #[derive(Default, Serialize, Clone)] pub struct Job { pub job_type: Option, pub title: String, pub progress: f32, pub state: State, } impl Job { pub fn new(job_type: IS, title: S) -> Self where S: AsRef, IS: Into>, { return Job { job_type: job_type.into().map(|jt| String::from(jt.as_ref())), title: String::from(title.as_ref()), ..Default::default() }; } } pub type JobType = String; #[derive(Serialize, Clone, PartialEq)] pub enum State { InProgress, Done, Failed, } impl Default for State { fn default() -> Self { State::InProgress } } #[derive(Default)] pub struct JobContainer { jobs: HashMap, } #[derive(Clone, Hash, PartialEq, Eq, Copy)] pub struct JobId { uuid: Uuid, } impl From for JobId { fn from(uuid: Uuid) -> Self { JobId { uuid } } } impl Serialize for JobId { fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> where S: Serializer, { serializer.serialize_str(format!("{}", self.uuid).as_str()) } } #[derive(Debug, Clone)] pub struct JobInProgessError(String); impl JobContainer { pub fn add_job(&mut self, job: Job) -> Result { if let Some(job_type) = &job.job_type { if self .jobs .iter() .any(|(_, j)| j.state == State::InProgress && j.job_type == job.job_type) { return Err(JobInProgessError(format!( "Job of type \"{}\" currently in progress.", job_type ))); } } let uuid = Uuid::new_v4(); self.jobs.insert(JobId::from(uuid), job); Ok(JobId::from(uuid)) } pub fn get_jobs(&self) -> HashMap { self.jobs.clone() } pub fn update_progress(&mut self, id: &JobId, progress: f32) -> Result<()> { if let Some(job) = self.jobs.get_mut(id) { job.progress = progress; if progress >= 100.0 { job.state = State::Done; } Ok(()) } else { Err(anyhow!("No such job.")) } } pub fn update_state(&mut self, id: &JobId, state: State) -> Result<()> { if let Some(job) = self.jobs.get_mut(id) { job.state = state; Ok(()) } else { Err(anyhow!("No such job.")) } } }