1use std::collections::HashMap;
2use crate::script::{BoxedScript, IntoScriptConfigs};
3use cloud_task_executor::*;
4use log::{debug, error, info};
5use serde_json::{json, Value};
6
7#[derive(Clone)]
8pub struct App {
9 scripts: Vec<BoxedScript>,
10}
11
12impl Default for App {
13 fn default() -> Self {
14 Self::new()
15 }
16}
17
18impl App {
19 pub fn new() -> Self {
20 Self {
21 scripts: Vec::new(),
22 }
23 }
24 pub fn add_script(&mut self, script: impl IntoScriptConfigs + 'static) -> &mut Self {
25 let script = script.into_script();
26 info!("adding script: {}, shortname: {}", script.name(),script.short_name());
27 self.scripts.push(script);
28 self
29 }
30 pub fn add_scripts(&mut self, scripts: Vec<impl IntoScriptConfigs + 'static>) -> &mut Self {
31 for script in scripts {
32 self.add_script(script);
33 }
34 self
35 }
36 pub fn scripts(&self) -> &Vec<BoxedScript> {
37 &self.scripts
38 }
39 async fn execute_task(&self, ctx: Context, payload: Value) -> Result<String, String> {
40 let task_names: Vec<String> = if let Some(tasks) = payload.get("tasks").and_then(|v| v.as_array()) {
41 tasks.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect()
42 } else {
43 return Err("no tasks found in payload".to_string());
44 };
45 let mut result = HashMap::new();
46 let mut failed_result = HashMap::new();
47 let mut cost_time = HashMap::new();
48 let mut task_done = Vec::new();
49 for task_name in task_names {
50 for script in &self.scripts {
51 let short_name = script.short_name();
52 if script.name() == task_name || short_name == task_name {
53 let script_name = script.name();
54 debug!("executing script: {} start", script_name);
55 let start = std::time::Instant::now();
56 let script_result = script.run(ctx.clone(), payload.clone()).await;
57 debug!("executing script: {} end, elapsed: {:?}", script_name, start.elapsed());
58 cost_time.insert(script_name, start.elapsed().as_millis());
59 match script_result {
60 Ok(script_result) => {
61 info!("script {} executed successfully, result: {}", script_name, script_result);
62 result.insert(script_name, script_result);
63 }
64 Err(err) => {
65 error!("script {} executed failed, error: {}", script_name, err);
66 failed_result.insert(script_name, err);
67 }
68 }
69 task_done.push(script_name);
70 }
71 }
72 }
73 Ok(json!({
74 "executed": task_done,
75 "success": result,
76 "failed": failed_result,
77 "cost_time": cost_time
78 }).to_string())
79 }
80}
81
82impl From<App> for Task {
83 fn from(val: App) -> Self {
84 Task::new("elf_script", move |ctx, payload| {
85 let app = val.clone();
86 Box::pin(async move {
87 app.execute_task(ctx, payload).await
88 })
89 })
90 }
91}