wd_run/
application.rs

1use std::collections::HashMap;
2use std::env::args;
3use std::sync::Arc;
4use super::Input;
5use wd_tools::sync::WaitGroup;
6use crate::{Cmd,Flags};
7use crate::interface::{Task, TaskInfo};
8
9#[derive(Default)]
10pub struct Application {
11    desc: String,
12    info : Vec<TaskInfo>,
13    tasks : HashMap<String,Arc<dyn Task>>
14}
15
16impl Application {
17    pub fn new(desc:impl ToString)->Self{
18        Self{desc:desc.to_string(),
19            ..Default::default()
20        }
21    }
22    pub fn register_task<T:Task + 'static>(mut self, task:T) ->Self{
23        let info = task.info();
24        let name = info.name.clone();
25        self.info.push(info);
26        self.tasks.insert(name,Arc::new(task));self
27    }
28    fn build(&self,flags:Flags) ->Vec<(Arc<dyn Task>,Input)>{
29        let mut tasks = vec![];
30        for i in flags.cmds.iter() {
31            let task = match self.tasks.get(i.cmd.as_str()){
32                None => { wd_log::log_panic!("not found cmd[{}] handler",i.cmd.as_str())},
33                Some(s)=>s.clone(),
34            };
35            let input = Application::build_input(i, &flags,task.info());
36            tasks.push((task,input));
37        }
38        tasks
39    }
40    pub fn show(self){
41        println!("description:{}",self.desc);
42        println!("format:");
43        let app_name = args().next().unwrap_or("application".to_string());
44        println!("{} [OPTION] [[ARGS]]",app_name);
45        for i in self.info.iter() {
46            println!("  {} {}",i.name,i.help);
47            for (arg,def,des) in i.flags.iter() {
48                println!("      {} : {}. default[{}]",arg,des,def);
49            }
50        }
51    }
52    pub async fn run(self){
53
54        let flags = Flags::parse_args();
55        //如果没有任务需要执行则打印运行参数
56        if flags.cmds.is_empty() {
57            self.show();
58            return;
59        }
60
61        let tasks = self.build(flags);
62        let wg = WaitGroup::default();
63
64        for (t,i) in tasks.iter(){
65            let task = t.clone();
66            let input = i.clone();
67            wg.defer(move ||async move{
68                if let Err(e) = task.run(input).await {
69                    wd_log::log_error_ln!("run failed:{:?}",e);
70                }
71            })
72        }
73
74        Application::wait_exit_sigle(wg).await;
75
76        for (t,i) in tasks.into_iter().rev() {  //倒序一个一个退出
77            if let Err(e) = t.exit(i).await{
78                wd_log::log_error_ln!("exit error:{:?}",e);
79            }
80        }
81        wd_log::log_info_ln!("process exit success")
82    }
83
84    async fn wait_exit_sigle(wg:WaitGroup){
85        let exit = async {
86            if let Err(e) = tokio::signal::ctrl_c().await {
87                wd_log::log_error_ln!("lister exit sigle error:{:?}",e);
88            }
89        };
90        tokio::select! {
91            _= exit =>{
92                wd_log::log_debug_ln!("listed exit sigle, start quit process");
93            }
94            _= wg.wait() =>{
95                wd_log::log_debug_ln!("all task over, start quit process");
96            }
97        }
98    }
99    fn build_input(cmd:&Cmd,flags:&Flags,info:TaskInfo)-> Input {
100        let mut ctx = Input::default();
101        for (k,v) in flags.args.iter() {
102            ctx.store(k,v);
103        }
104        for (k,v,_) in info.flags.iter() {
105            ctx.store(k,v);
106        }
107        for (k,v) in cmd.args.iter() {
108            ctx.store(k,v);
109        }
110        return ctx
111    }
112}