use std::collections::HashMap;
use crate::script::{BoxedScript, IntoScriptConfigs};
use cloud_task_executor::*;
use log::{debug, error, info};
use serde_json::{json, Value};
#[derive(Clone)]
pub struct App {
scripts: Vec<BoxedScript>,
}
impl Default for App {
fn default() -> Self {
Self::new()
}
}
impl App {
pub fn new() -> Self {
Self {
scripts: Vec::new(),
}
}
pub fn add_script(&mut self, script: impl IntoScriptConfigs + 'static) -> &mut Self {
let script = script.into_script();
info!("adding script: {}, shortname: {}", script.name(),script.short_name());
self.scripts.push(script);
self
}
pub fn add_scripts(&mut self, scripts: Vec<impl IntoScriptConfigs + 'static>) -> &mut Self {
for script in scripts {
self.add_script(script);
}
self
}
pub fn scripts(&self) -> &Vec<BoxedScript> {
&self.scripts
}
async fn execute_task(&self, ctx: Context, payload: Value) -> Result<String, String> {
let task_names: Vec<String> = if let Some(tasks) = payload.get("tasks").and_then(|v| v.as_array()) {
tasks.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()
} else {
return Err("no tasks found in payload".to_string());
};
let mut result = HashMap::new();
let mut failed_result = HashMap::new();
let mut cost_time = HashMap::new();
let mut task_done = Vec::new();
for task_name in task_names {
for script in &self.scripts {
let short_name = script.short_name();
if script.name() == task_name || short_name == task_name {
let script_name = script.name();
debug!("executing script: {} start", script_name);
let start = std::time::Instant::now();
let script_result = script.run(ctx.clone(), payload.clone()).await;
debug!("executing script: {} end, elapsed: {:?}", script_name, start.elapsed());
cost_time.insert(script_name, start.elapsed().as_millis());
match script_result {
Ok(script_result) => {
info!("script {} executed successfully, result: {}", script_name, script_result);
result.insert(script_name, script_result);
}
Err(err) => {
error!("script {} executed failed, error: {}", script_name, err);
failed_result.insert(script_name, err);
}
}
task_done.push(script_name);
}
}
}
Ok(json!({
"executed": task_done,
"success": result,
"failed": failed_result,
"cost_time": cost_time
}).to_string())
}
}
impl From<App> for Task {
fn from(val: App) -> Self {
Task::new("elf_script", move |ctx, payload| {
let app = val.clone();
Box::pin(async move {
app.execute_task(ctx, payload).await
})
})
}
}