1use serde_derive::{Deserialize, Serialize};
2use socks5_impl::protocol::{ProxyParameters, UserKey};
3
4#[derive(Debug, Clone, clap::Parser, Serialize, Deserialize)]
6#[command(author, version, about = "SOCKS5 hub for downstreams proxy of HTTP or SOCKS5.", long_about = None)]
7pub struct Config {
8 #[arg(short, long, value_parser = |s: &str| ProxyParameters::try_from(s), value_name = "URL")]
14 pub listen_proxy_role: ProxyParameters,
15
16 #[arg(short, long, value_parser = |s: &str| ProxyParameters::try_from(s), value_name = "URL")]
18 #[serde(skip_serializing_if = "Option::is_none", default)]
19 pub middle_server: Option<ProxyParameters>,
20
21 #[arg(short, long, value_parser = |s: &str| ProxyParameters::try_from(s), value_name = "URL")]
23 pub remote_server: ProxyParameters,
24
25 #[arg(short, long, value_name = "path")]
27 #[serde(skip_serializing_if = "Option::is_none", default)]
28 pub acl_file: Option<std::path::PathBuf>,
29
30 #[arg(short, long, value_name = "level", default_value = "info")]
32 pub verbosity: ArgVerbosity,
33}
34
35impl Default for Config {
36 fn default() -> Self {
37 let remote_server: ProxyParameters = "socks5://127.0.0.1:1080".try_into().unwrap();
38 Config {
39 listen_proxy_role: ProxyParameters::default(),
40 middle_server: None,
41 remote_server,
42 acl_file: None,
43 verbosity: ArgVerbosity::Info,
44 }
45 }
46}
47
48impl Config {
49 pub fn parse_args() -> Self {
50 <Self as clap::Parser>::parse()
51 }
52
53 pub fn new(listen_proxy_role: &str, remote_server: &str) -> Self {
54 Config {
55 listen_proxy_role: listen_proxy_role.try_into().unwrap(),
56 middle_server: None,
57 remote_server: remote_server.try_into().unwrap(),
58 ..Config::default()
59 }
60 }
61
62 pub fn listen_proxy_role(&mut self, listen_proxy_role: &str) -> &mut Self {
63 self.listen_proxy_role = listen_proxy_role.try_into().unwrap();
64 self
65 }
66
67 pub fn remote_server(&mut self, remote_server: &str) -> &mut Self {
68 self.remote_server = remote_server.try_into().unwrap();
69 self
70 }
71
72 pub fn middle_server(&mut self, middle_server: &str) -> &mut Self {
73 self.middle_server = Some(middle_server.try_into().unwrap());
74 self
75 }
76
77 pub fn middle_server_opt(&mut self, middle_server: Option<&str>) -> &mut Self {
78 if let Some(middle_server) = middle_server {
79 self.middle_server(middle_server);
80 }
81 self
82 }
83
84 pub fn acl_file<P: Into<std::path::PathBuf>>(&mut self, acl_file: P) -> &mut Self {
85 self.acl_file = Some(acl_file.into());
86 self
87 }
88
89 pub fn verbosity(&mut self, verbosity: ArgVerbosity) -> &mut Self {
90 self.verbosity = verbosity;
91 self
92 }
93
94 pub fn get_listen_credentials(&self) -> UserKey {
95 self.listen_proxy_role.credentials.clone().unwrap_or_default()
96 }
97
98 pub fn get_s5_credentials(&self) -> UserKey {
99 self.remote_server.credentials.clone().unwrap_or_default()
100 }
101
102 pub fn get_middle_s5_credentials(&self) -> UserKey {
103 self.middle_server
104 .as_ref()
105 .and_then(|proxy| proxy.credentials.clone())
106 .unwrap_or_default()
107 }
108}
109
110#[repr(C)]
111#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, clap::ValueEnum, Serialize, Deserialize)]
112pub enum ArgVerbosity {
113 Off = 0,
114 Error,
115 Warn,
116 #[default]
117 Info,
118 Debug,
119 Trace,
120}
121
122impl From<ArgVerbosity> for log::LevelFilter {
123 fn from(verbosity: ArgVerbosity) -> Self {
124 match verbosity {
125 ArgVerbosity::Off => log::LevelFilter::Off,
126 ArgVerbosity::Error => log::LevelFilter::Error,
127 ArgVerbosity::Warn => log::LevelFilter::Warn,
128 ArgVerbosity::Info => log::LevelFilter::Info,
129 ArgVerbosity::Debug => log::LevelFilter::Debug,
130 ArgVerbosity::Trace => log::LevelFilter::Trace,
131 }
132 }
133}
134
135impl From<log::Level> for ArgVerbosity {
136 fn from(level: log::Level) -> Self {
137 match level {
138 log::Level::Error => ArgVerbosity::Error,
139 log::Level::Warn => ArgVerbosity::Warn,
140 log::Level::Info => ArgVerbosity::Info,
141 log::Level::Debug => ArgVerbosity::Debug,
142 log::Level::Trace => ArgVerbosity::Trace,
143 }
144 }
145}
146
147impl std::fmt::Display for ArgVerbosity {
148 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
149 match self {
150 ArgVerbosity::Off => write!(f, "off"),
151 ArgVerbosity::Error => write!(f, "error"),
152 ArgVerbosity::Warn => write!(f, "warn"),
153 ArgVerbosity::Info => write!(f, "info"),
154 ArgVerbosity::Debug => write!(f, "debug"),
155 ArgVerbosity::Trace => write!(f, "trace"),
156 }
157 }
158}