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