You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							179 lines
						
					
					
						
							4.9 KiB
						
					
					
				
			
		
		
	
	
							179 lines
						
					
					
						
							4.9 KiB
						
					
					
				| use std::{ | |
|     process::Command, | |
|     time::SystemTime, | |
|     cmp::PartialEq | |
| }; | |
| use serde::{ | |
|     Serialize, | |
|     Deserialize | |
| }; | |
| use uuid::Uuid; | |
| //use tokio::process::Command; | |
| use super::*; | |
|  | |
|  | |
| pub struct Job<'meta> { | |
|     pub result: JobResult, | |
|     pub meta: &'meta mut JobMeta, | |
| } | |
|  | |
| impl<'meta> Job<'meta> { | |
|     pub fn new(job_meta: &'meta mut JobMeta) -> Self { | |
|         Self { | |
|             result: JobResult { | |
|                 id: job_meta.id.clone(), | |
|                 state: job_meta.state.clone(), | |
|                 data: None, | |
|             }, | |
|             meta: job_meta, | |
|         } | |
|     } | |
|  | |
|     pub fn run(&mut self) { | |
|         match self.meta.exec_type { | |
|             JobType::Shell => { | |
|                 match self.meta.state { | |
|                     JobState::Queued | JobState::Pending => { | |
|                         self.meta.state = JobState::Running; | |
|                     }, | |
|                     JobState::Finished => { | |
|                         if self.meta.schedule == JobSchedule::Permanent { | |
|                             self.meta.state = JobState::Running; | |
|                         } else { | |
|                             return | |
|                         } | |
|                     }, | |
|                     JobState::Running => return | |
|                 } | |
|  | |
|                 match &self.meta.payload { | |
|                     Some(box_payload) => { | |
|                         let payload = String::from_utf8_lossy(box_payload).into_owned(); | |
|                         let mut cmd_parts = payload | |
|                             .split(" ") | |
|                             .map(String::from) | |
|                             .collect::<Vec<String>>() | |
|                             .into_iter(); | |
|                         let cmd = cmd_parts.nth(0).unwrap(); | |
|                         let args = cmd_parts.collect::<Vec<_>>(); | |
|                         let result = Command::new(cmd) | |
|                             .args(args) | |
|                             .output(); | |
|                         self.result.data = Some(match result { | |
|                             Ok(output) => { | |
|                                 if output.status.success() { | |
|                                     Ok(output.stdout.to_vec()) | |
|                                 } else { | |
|                                     Err(output.stderr.to_vec()) | |
|                                 } | |
|                             } | |
|                             Err(e) => Err(e.to_string().into_bytes()) | |
|                         }) | |
|                     } | |
|                     None => return | |
|                 } | |
|                 self.meta.state = JobState::Finished; | |
|             }, | |
|             _ => unimplemented!() | |
|         } | |
|     } | |
|  | |
|     fn into_result(self) -> JobResult { | |
|         self.result | |
|     } | |
| } | |
|  | |
| #[derive(Serialize, Deserialize, Clone)] | |
| pub enum ManageAction { | |
|     Ping, | |
|     UpdateAvailable, | |
|     JobsResultsRequest, | |
|     Terminate | |
| } | |
|  | |
| #[derive(Serialize, Deserialize, Clone, PartialEq)] | |
| pub enum JobSchedule { | |
|     Once, | |
|     Permanent, | |
|     Terminate // to terminate jobs obvsl | |
|     //TODO: Scheduled | |
| } | |
|  | |
| #[derive(Serialize, Deserialize, Clone)] | |
| pub enum JobState { | |
|     Queued, // server created a job, but client didn't get it yet | |
|     Pending, // client got a job, but not running yet | |
|     Running, // client is currently running a job | |
| //    Rerunning, // if job is cycled | |
|     Finished, | |
| } | |
|  | |
| #[derive(Serialize, Deserialize, Clone)] | |
| pub enum JobType { | |
|     Manage(ManageAction), | |
|     Shell, | |
|     Python, | |
|     Binary | |
| } | |
|  | |
| #[derive(Serialize, Deserialize, Clone)] | |
| pub struct JobMeta { | |
|     pub id: Uuid, | |
|     pub name: String, | |
|     pub created: SystemTime, | |
|     pub updated: SystemTime, | |
|     pub state: JobState, | |
|     pub exec_type: JobType, | |
|     pub schedule: JobSchedule, | |
|     pub append_result: bool, //true: append, false: rewrite | |
|     pub payload: Option<Box<Vec<u8>>>, | |
| } | |
|  | |
| impl JobMeta { | |
|     pub fn from_shell(shell_cmd: Vec<u8>) -> Self { | |
|         let uid = Uuid::new_v4(); | |
|         //let str_payload_name: &[u8] = shell_cmd.split(|b| &[*b] == b" ").collect(); | |
|         //let job_name = format!("{} {}", uid.to_string()[..6], str_payload_name[0]); | |
|         Self { | |
|             id: uid.clone(), | |
|             name: uid.to_string(), | |
|             created: SystemTime::now(), | |
|             updated: SystemTime::now(), | |
|             state: JobState::Pending, | |
|             exec_type: JobType::Shell, | |
|             schedule: JobSchedule::Once, | |
|             append_result: true, | |
|             payload: Some(Box::new(shell_cmd)) | |
|         } | |
|     } | |
|  | |
|     pub fn from_shell_str(shell_cmd: String) -> Self { | |
|         Self::from_shell(shell_cmd.into_bytes()) | |
|     } | |
| } | |
|  | |
| impl ToMsg for JobMeta {} | |
|  | |
| #[derive(Serialize, Deserialize, Clone)] | |
| pub struct JobResult { | |
|     id: Uuid, | |
|     data: Option<Result<Vec<u8>, Vec<u8>>>, | |
|     state: JobState | |
| } | |
|  | |
| impl ToMsg for JobResult {} | |
|  | |
|  | |
| #[cfg(test)] | |
| mod tests { | |
|     use super::*; | |
|     use crate::execute_jobs; | |
|  | |
|     #[test] | |
|     fn test_shell_job() { | |
|         let mut job = JobMeta::from_shell_str("whoami".into()); | |
|         let mut jobs: Vec<Job> = vec![Job::new(&mut job)]; | |
|         execute_jobs(&mut jobs); | |
|         assert_eq!(jobs.pop().unwrap().result.data.unwrap().unwrap(), b"plazmoid\n".to_vec()); | |
|     } | |
| } |