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 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() { 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}