xref: /xiu/application/xiu/src/main.rs (revision a4ef5d6c)
1 use {
2     //https://rustcc.cn/article?id=6dcbf032-0483-4980-8bfe-c64a7dfb33c7
3     anyhow::Result,
4     clap::{value_parser, Arg, Command},
5     env_logger_extend::logger::{Logger, Rotate},
6     std::{env, str::FromStr},
7     tokio::signal,
8     xiu::{config, config::Config, service::Service},
9 };
10 
11 // #[tokio::main(flavor = "current_thread")]
12 #[tokio::main]
main() -> Result<()>13 async fn main() -> Result<()> {
14     let log_levels = vec!["trace", "debug", "info", "warn", "error"];
15 
16     let mut cmd = Command::new("XIU")
17         .bin_name("xiu")
18         .version("0.9.0")
19         .author("HarlanC <[email protected]>")
20         .about("A secure and easy to use live media server, hope you love it!!!")
21         .arg(
22             Arg::new("config_file_path")
23                 .long("config")
24                 .short('c')
25                 .value_name("path")
26                 .help("Specify the xiu server configuration file path.")
27                 .value_parser(value_parser!(String))
28                 .conflicts_with_all(["rtmp", "rtsp", "httpflv", "hls", "log"]),
29         )
30         .arg(
31             Arg::new("rtmp")
32                 .long("rtmp")
33                 .short('r')
34                 .value_name("port")
35                 .help("Specify the rtmp listening port.(e.g.:1935)")
36                 .value_parser(value_parser!(usize))
37                 .conflicts_with("config_file_path"),
38         )
39         .arg(
40             Arg::new("rtsp")
41                 .long("rtsp")
42                 .short('t')
43                 .value_name("port")
44                 .help("Specify the rtsp listening port.(e.g.:554)")
45                 .value_parser(value_parser!(usize))
46                 .conflicts_with("config_file_path"),
47         )
48         .arg(
49             Arg::new("webrtc")
50                 .long("webrtc")
51                 .short('w')
52                 .value_name("port")
53                 .help("Specify the webrtc(whip/whep) listening port.(e.g.:8900)")
54                 .value_parser(value_parser!(usize))
55                 .conflicts_with("config_file_path"),
56         )
57         .arg(
58             Arg::new("httpflv")
59                 .long("httpflv")
60                 .short('f')
61                 .value_name("port")
62                 .help("Specify the http-flv listening port.(e.g.:8080)")
63                 .value_parser(value_parser!(usize))
64                 .conflicts_with("config_file_path"),
65         )
66         .arg(
67             Arg::new("hls")
68                 .long("hls")
69                 .short('s')
70                 .value_name("port")
71                 .help("Specify the hls listening port.(e.g.:8081)")
72                 .value_parser(value_parser!(usize))
73                 .conflicts_with("config_file_path"),
74         )
75         .arg(
76             Arg::new("log")
77                 .long("log")
78                 .short('l')
79                 .value_name("level")
80                 .help("Specify the log level.")
81                 .value_parser(log_levels)
82                 .conflicts_with("config_file_path"),
83         );
84     // .group(
85     //     ArgGroup::new("one_of_group")
86     //         .args(&["rtsp", "rtmp"])
87     //         .required(true)
88     //         .multiple(true),
89     // );
90     // config_file_path conficts with all the other args,
91     // if not using config_file_path, RTSP/RTMP must be specified one or both
92     // .groups([
93     //     ArgGroup::new("one_of_group")
94     //         .args(&["rtsp", "rtmp"])
95     //         .required(true)
96     //         .is_multiple(), // ArgGroup::new("one_of_group2")
97     //                         //     .args(&["config_file_path", "rtsp"])
98     //                         //     .required(true),
99     // ]);
100 
101     let args: Vec<String> = env::args().collect();
102     if 1 == args.len() {
103         cmd.print_help()?;
104         return Ok(());
105     }
106 
107     let matches = cmd.clone().get_matches();
108 
109     let config = if let Some(path) = matches.get_one::<String>("config_file_path") {
110         let config = config::load(path);
111         match config {
112             Ok(val) => val,
113             Err(err) => {
114                 println!("{path}: {err}");
115                 return Ok(());
116             }
117         }
118     } else {
119         let rtmp_port_o = matches.get_one::<usize>("rtmp");
120         let rtsp_port_o = matches.get_one::<usize>("rtsp");
121         let webrtc_port_o = matches.get_one::<usize>("webrtc");
122 
123         if rtmp_port_o.is_none() && rtsp_port_o.is_none() && webrtc_port_o.is_none() {
124             println!("If you do not specify the config Options, you must enable at least one protocol from RTSP and RTMP.");
125             return Ok(());
126         }
127 
128         let rtmp_port = match rtmp_port_o {
129             Some(val) => *val,
130             None => 0,
131         };
132 
133         let rtsp_port = match rtsp_port_o {
134             Some(val) => *val,
135             None => 0,
136         };
137 
138         let webrtc_port = match webrtc_port_o {
139             Some(val) => *val,
140             None => 0,
141         };
142 
143         let httpflv_port = match matches.get_one::<usize>("httpflv") {
144             Some(val) => *val,
145             None => 0,
146         };
147         let hls_port = match matches.get_one::<usize>("hls") {
148             Some(val) => *val,
149             None => 0,
150         };
151         let log_level = match matches.get_one::<String>("log") {
152             Some(val) => val.clone(),
153             None => String::from("info"),
154         };
155 
156         Config::new(
157             rtmp_port,
158             rtsp_port,
159             webrtc_port,
160             httpflv_port,
161             hls_port,
162             log_level,
163         )
164     };
165 
166     /*set log level*/
167     let logger = if let Some(log_config_value) = &config.log {
168         let (rotate, path) = if let Some(file_info) = &log_config_value.file {
169             if file_info.enabled {
170                 (
171                     Some(Rotate::from_str(&file_info.rotate).unwrap()),
172                     Some(file_info.path.clone()),
173                 )
174             } else {
175                 (None, None)
176             }
177         } else {
178             (None, None)
179         };
180         Logger::new(&log_config_value.level, rotate, path)?
181     } else {
182         Logger::new(&String::from("info"), None, None)?
183     };
184 
185     /*run the service*/
186     let mut service = Service::new(config);
187     service.run().await?;
188 
189     // log::info!("log info...");
190     // log::warn!("log warn...");
191     // log::error!("log err...");
192     // log::trace!("log trace...");
193     // log::debug!("log debug...");
194 
195     signal::ctrl_c().await?;
196     logger.stop();
197     Ok(())
198 }
199