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