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

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());
}
}