use crate::core::{Result, Host};
use serde_json::{json, Value};
use rayon::prelude::*;
pub type TaskResult = Result<Value>;
pub trait Task<Data: Send> : Send + Sync {
fn prepare(&self, host: Host) -> Result<Data>;
fn apply(&self, host: Host, data: Data) -> TaskResult;
}
pub trait TaskRunner {
fn run_task<Data: Send>(&self, task: &dyn Task<Data>, parallel: bool) -> TaskResult;
fn run_task_seq<Data: Send>(&self, task: &dyn Task<Data>) -> TaskResult;
fn run_task_parallel<Data: Send>(&self, task: &dyn Task<Data>) -> TaskResult;
}
impl TaskRunner for Vec<Host> {
fn run_task<Data: Send>(&self, task: &dyn Task<Data>, parallel: bool) -> TaskResult {
if parallel {
self.run_task_parallel(task)
}
else {
self.run_task_seq(task)
}
}
fn run_task_seq<Data: Send>(&self, task: &dyn Task<Data>) -> TaskResult {
let results: Vec<Value> = self
.into_iter()
.map(|host| prepare_host(task, host))
.collect::<Result<Vec<(&Host, Data)>>>()?
.into_iter()
.map(|(host, data)| apply_to_host(task, host, data))
.collect();
Ok(json!(results))
}
fn run_task_parallel<Data: Send>(&self, task: &dyn Task<Data>) -> TaskResult {
let results: Vec<Value> = self
.into_par_iter()
.map(|host| prepare_host(task, host))
.collect::<Result<Vec<(&Host, Data)>>>()?
.into_par_iter()
.map(|(host, data)| apply_to_host(task, host, data))
.collect();
Ok(json!(results))
}
}
fn prepare_host<'host, Data: Send>(
task: &dyn Task<Data>,
host: &'host Host,
) -> Result<(&'host Host, Data)> {
let data = task.prepare(host.clone())?;
Ok((host, data))
}
fn apply_to_host<'host, Data: Send>(
task: &dyn Task<Data>,
host: &'host Host,
data: Data,
) -> Value {
task.apply(host.clone(), data)
.map_or_else(
|err| json!({
"host": host.id,
"success": false,
"error": format!("{}", err),
}),
|info| json!({
"host": host.id,
"success": true,
"info": info,
})
)
}
pub mod exec;
pub mod info;
pub mod upload;
pub mod download;