diff --git a/lib/u_lib/src/client/client.rs b/lib/u_lib/src/client/client.rs index 1b28cdc..eb8841e 100644 --- a/lib/u_lib/src/client/client.rs +++ b/lib/u_lib/src/client/client.rs @@ -11,7 +11,7 @@ use crate::{ pub struct UClient { pub client_info: ClientInfo, - pub jobs: JobPool, // TODO: to futures + pub jobs: Vec, // TODO: to futures } impl UClient { diff --git a/lib/u_lib/src/contracts/jobs.rs b/lib/u_lib/src/contracts/jobs.rs index 8bef23e..e0d83aa 100644 --- a/lib/u_lib/src/contracts/jobs.rs +++ b/lib/u_lib/src/contracts/jobs.rs @@ -1,55 +1,89 @@ use std::{ process::Command, - time::SystemTime + time::SystemTime, + cmp::PartialEq +}; +use serde::{ + Serialize, + Deserialize }; use uuid::Uuid; //use tokio::process::Command; use super::*; -pub type JobPool = Vec; -pub type JobResult = Result, Vec>; -pub struct ShellJob { +pub struct Job<'meta> { pub result: JobResult, - pub cmd: String, - pub args: Vec + pub meta: &'meta mut JobMeta, } -impl ShellJob { - pub fn from_raw(raw_cmd: String) -> Self { - let mut cmd_parts = raw_cmd - .split(" ") - .map(String::from) - .collect::>(); - let args: Vec<_> = cmd_parts.drain(1..).collect(); +impl<'meta> Job<'meta> { + pub fn new(job_meta: &'meta mut JobMeta) -> Self { Self { - cmd: cmd_parts.into_iter().nth(1).unwrap(), - args, - result: Err(b"Did not run".to_vec()) + result: JobResult { + id: job_meta.id.clone(), + state: job_meta.state.clone(), + data: None, + }, + meta: job_meta, } } - fn run(&mut self) { - let result = Command::new(&self.cmd) - .args(&self.args) - .output(); - self.result = match result { - Ok(output) => { - if output.status.success() { - Ok(output.stdout.to_vec()) - } else { - Err(output.stderr.to_vec()) + 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::>() + .into_iter(); + let cmd = cmd_parts.nth(0).unwrap(); + let args = cmd_parts.collect::>(); + 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 } - } - Err(e) => Err(e.to_string().into_bytes()) + self.meta.state = JobState::Finished; + }, + _ => unimplemented!() } } - fn get_result(&self) -> &JobResult { - &self.result + fn into_result(self) -> JobResult { + self.result } } +#[derive(Serialize, Deserialize, Clone)] pub enum ManageAction { Ping, UpdateAvailable, @@ -57,21 +91,24 @@ pub enum ManageAction { 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 { - Dummy, 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 +// Rerunning, // if job is cycled Finished, } +#[derive(Serialize, Deserialize, Clone)] pub enum JobType { Manage(ManageAction), Shell, @@ -79,33 +116,64 @@ pub enum JobType { Binary } +#[derive(Serialize, Deserialize, Clone)] pub struct JobMeta { - id: Uuid, - name: String, - created: SystemTime, - updated: SystemTime, - state: JobState, - exec_type: JobType, - append_result: bool, //true: append, false: rewrite - payload: Option>, + 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>>, } impl JobMeta { pub fn from_shell(shell_cmd: Vec) -> Self { let uid = Uuid::new_v4(); - let str_payload_name = shell_cmd.split(b" ").collect(); - let job_name = format!("{} {}", uid.to_string()[..6], str_payload_name[0]); + //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, - name: job_name, + 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(shell_cmd) + 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, Vec>>, + state: JobState } -impl ToMsg for JobMeta {} \ No newline at end of file +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 = vec![Job::new(&mut job)]; + execute_jobs(&mut jobs); + assert_eq!(jobs.pop().unwrap().result.data.unwrap().unwrap(), b"plazmoid\n".to_vec()); + } +} \ No newline at end of file diff --git a/lib/u_lib/src/executor.rs b/lib/u_lib/src/executor.rs new file mode 100644 index 0000000..a3d80f2 --- /dev/null +++ b/lib/u_lib/src/executor.rs @@ -0,0 +1,23 @@ +// list of jobs: job (cmd, args) OR rust fn OR python func + cron-like timing +// job runner (thread) +// every job runs in other thread/process +/* +use cron::Schedule as CronSchedule; + +enum Schedule { + Persistent, // run forever, restart if stops (set max_retries) + Cron(CronSchedule), + Once +} + + +lazy_static! { + pub static ref EXECUTOR: Vec<> +} +*/ + +use crate::contracts::*; + +pub fn execute_jobs(jobs: &mut Vec) { + jobs.iter_mut().for_each(|job| job.run()) +} \ No newline at end of file diff --git a/lib/u_lib/src/lib.rs b/lib/u_lib/src/lib.rs index 669a574..0628d95 100644 --- a/lib/u_lib/src/lib.rs +++ b/lib/u_lib/src/lib.rs @@ -1,3 +1,4 @@ +pub mod executor; pub mod config; pub mod contracts; pub mod utils; @@ -6,6 +7,7 @@ pub mod client; pub use { utils::*, config::*, + executor::* }; #[macro_use] diff --git a/lib/u_lib/src/utils.rs b/lib/u_lib/src/utils.rs index 90c9284..c3e2352 100644 --- a/lib/u_lib/src/utils.rs +++ b/lib/u_lib/src/utils.rs @@ -44,4 +44,8 @@ pub fn setsig(sig: Signal, hnd: SigHandler) { unsafe { signal(sig, hnd).unwrap(); } -} \ No newline at end of file +} +/* +pub fn generate_auth_token() -> String { + +}*/ \ No newline at end of file