Skip to content

Commit 7ec97c0

Browse files
committed
Merge branch 'webserver'
2 parents 569409e + 51ffb4f commit 7ec97c0

File tree

10 files changed

+792
-166
lines changed

10 files changed

+792
-166
lines changed

Cargo.lock

Lines changed: 97 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ config = "0.14"
3737
serde = { version = "1.0", features = ["derive"] }
3838
serde_json = "1"
3939
warp = "0.3"
40+
axum = "0.6"
41+
hyper = { version = "0.14", features = ["full"] }
42+
tower = "0.4"
43+
toml_edit = "0.22"
4044

4145
[build-dependencies]
4246
protoc-bin-vendored = "3.1.0"

src/config.rs

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
use bluer::Address;
2+
use serde::de::{self, Deserializer, Error as DeError, Visitor};
3+
use serde::{Deserialize, Serialize};
4+
use simplelog::*;
5+
use std::fmt::{self, Display};
6+
use std::fs;
7+
use std::path::PathBuf;
8+
use std::str::FromStr;
9+
use toml_edit::{value, DocumentMut};
10+
11+
#[derive(
12+
clap::ValueEnum, Default, Debug, PartialEq, PartialOrd, Clone, Copy, Deserialize, Serialize,
13+
)]
14+
pub enum HexdumpLevel {
15+
#[default]
16+
Disabled,
17+
DecryptedInput,
18+
RawInput,
19+
DecryptedOutput,
20+
RawOutput,
21+
All,
22+
}
23+
24+
#[derive(Debug, Clone, Serialize)]
25+
pub struct UsbId {
26+
pub vid: u16,
27+
pub pid: u16,
28+
}
29+
30+
impl std::str::FromStr for UsbId {
31+
type Err = String;
32+
33+
fn from_str(s: &str) -> Result<Self, Self::Err> {
34+
let parts: Vec<&str> = s.split(':').collect();
35+
if parts.len() != 2 {
36+
return Err("Expected format VID:PID".to_string());
37+
}
38+
let vid = u16::from_str_radix(parts[0], 16).map_err(|e| e.to_string())?;
39+
let pid = u16::from_str_radix(parts[1], 16).map_err(|e| e.to_string())?;
40+
Ok(UsbId { vid, pid })
41+
}
42+
}
43+
44+
impl fmt::Display for UsbId {
45+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46+
write!(f, "{:x}:{:x}", self.vid, self.pid)
47+
}
48+
}
49+
50+
impl<'de> Deserialize<'de> for UsbId {
51+
fn deserialize<D>(deserializer: D) -> Result<UsbId, D::Error>
52+
where
53+
D: Deserializer<'de>,
54+
{
55+
struct UsbIdVisitor;
56+
57+
impl<'de> Visitor<'de> for UsbIdVisitor {
58+
type Value = UsbId;
59+
60+
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
61+
formatter.write_str("a string in the format VID:PID")
62+
}
63+
64+
fn visit_str<E>(self, value: &str) -> Result<UsbId, E>
65+
where
66+
E: de::Error,
67+
{
68+
UsbId::from_str(value).map_err(de::Error::custom)
69+
}
70+
}
71+
72+
deserializer.deserialize_str(UsbIdVisitor)
73+
}
74+
}
75+
76+
pub fn empty_string_as_none<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
77+
where
78+
T: FromStr,
79+
T::Err: Display,
80+
D: Deserializer<'de>,
81+
{
82+
let s: String = Deserialize::deserialize(deserializer)?;
83+
if s.trim().is_empty() {
84+
Ok(None)
85+
} else {
86+
T::from_str(&s).map(Some).map_err(DeError::custom)
87+
}
88+
}
89+
90+
#[derive(Debug, Clone, Deserialize, Serialize)]
91+
#[serde(default)]
92+
pub struct AppConfig {
93+
pub advertise: bool,
94+
pub debug: bool,
95+
pub hexdump_level: HexdumpLevel,
96+
pub disable_console_debug: bool,
97+
pub legacy: bool,
98+
#[serde(default, deserialize_with = "empty_string_as_none")]
99+
pub connect: Option<Address>,
100+
pub logfile: PathBuf,
101+
pub stats_interval: u16,
102+
#[serde(default, deserialize_with = "empty_string_as_none")]
103+
pub udc: Option<String>,
104+
pub iface: String,
105+
pub hostapd_conf: PathBuf,
106+
#[serde(default, deserialize_with = "empty_string_as_none")]
107+
pub btalias: Option<String>,
108+
pub keepalive: bool,
109+
pub timeout_secs: u16,
110+
pub bt_timeout_secs: u16,
111+
pub mitm: bool,
112+
pub dpi: u16,
113+
pub remove_tap_restriction: bool,
114+
pub video_in_motion: bool,
115+
pub disable_media_sink: bool,
116+
pub disable_tts_sink: bool,
117+
pub developer_mode: bool,
118+
#[serde(default, deserialize_with = "empty_string_as_none")]
119+
pub wired: Option<UsbId>,
120+
pub dhu: bool,
121+
pub ev: bool,
122+
#[serde(default, deserialize_with = "empty_string_as_none")]
123+
pub ev_battery_logger: Option<PathBuf>,
124+
pub ev_battery_capacity: u64,
125+
pub ev_factor: f32,
126+
}
127+
128+
impl Default for AppConfig {
129+
fn default() -> Self {
130+
Self {
131+
advertise: false,
132+
debug: false,
133+
hexdump_level: HexdumpLevel::Disabled,
134+
disable_console_debug: false,
135+
legacy: true,
136+
connect: None,
137+
logfile: "/var/log/aa-proxy-rs.log".into(),
138+
stats_interval: 0,
139+
udc: None,
140+
iface: "wlan0".to_string(),
141+
hostapd_conf: "/var/run/hostapd.conf".into(),
142+
btalias: None,
143+
keepalive: false,
144+
timeout_secs: 10,
145+
bt_timeout_secs: 120,
146+
mitm: false,
147+
dpi: 0,
148+
remove_tap_restriction: false,
149+
video_in_motion: false,
150+
disable_media_sink: false,
151+
disable_tts_sink: false,
152+
developer_mode: false,
153+
wired: None,
154+
dhu: false,
155+
ev: false,
156+
ev_battery_logger: None,
157+
ev_battery_capacity: 22000,
158+
ev_factor: 0.075,
159+
}
160+
}
161+
}
162+
163+
impl AppConfig {
164+
pub fn load(config_file: PathBuf) -> Result<Self, Box<dyn std::error::Error>> {
165+
use ::config::File;
166+
let file_config: AppConfig = ::config::Config::builder()
167+
.add_source(File::from(config_file).required(false))
168+
.build()?
169+
.try_deserialize()
170+
.unwrap_or_default();
171+
172+
Ok(file_config)
173+
}
174+
175+
pub fn save(&self, config_file: PathBuf) {
176+
debug!("Saving config: {:?}", self);
177+
let raw = fs::read_to_string(&config_file).unwrap_or_default();
178+
let mut doc = raw.parse::<DocumentMut>().unwrap_or_else(|_| {
179+
// if the file doesn't exists or there is parse error, create a new one
180+
DocumentMut::new()
181+
});
182+
183+
doc["advertise"] = value(self.advertise);
184+
doc["debug"] = value(self.debug);
185+
doc["hexdump_level"] = value(format!("{:?}", self.hexdump_level));
186+
doc["disable_console_debug"] = value(self.disable_console_debug);
187+
doc["legacy"] = value(self.legacy);
188+
doc["connect"] = match &self.connect {
189+
Some(c) => value(c.to_string()),
190+
None => value(""),
191+
};
192+
doc["logfile"] = value(self.logfile.display().to_string());
193+
doc["stats_interval"] = value(self.stats_interval as i64);
194+
if let Some(udc) = &self.udc {
195+
doc["udc"] = value(udc);
196+
}
197+
doc["iface"] = value(&self.iface);
198+
doc["hostapd_conf"] = value(self.hostapd_conf.display().to_string());
199+
if let Some(alias) = &self.btalias {
200+
doc["btalias"] = value(alias);
201+
}
202+
doc["keepalive"] = value(self.keepalive);
203+
doc["timeout_secs"] = value(self.timeout_secs as i64);
204+
doc["bt_timeout_secs"] = value(self.bt_timeout_secs as i64);
205+
doc["mitm"] = value(self.mitm);
206+
doc["dpi"] = value(self.dpi as i64);
207+
doc["remove_tap_restriction"] = value(self.remove_tap_restriction);
208+
doc["video_in_motion"] = value(self.video_in_motion);
209+
doc["disable_media_sink"] = value(self.disable_media_sink);
210+
doc["disable_tts_sink"] = value(self.disable_tts_sink);
211+
doc["developer_mode"] = value(self.developer_mode);
212+
doc["wired"] = value(
213+
self.wired
214+
.as_ref()
215+
.map_or("".to_string(), |w| w.to_string()),
216+
);
217+
doc["dhu"] = value(self.dhu);
218+
doc["ev"] = value(self.ev);
219+
if let Some(path) = &self.ev_battery_logger {
220+
doc["ev_battery_logger"] = value(path.display().to_string());
221+
}
222+
doc["ev_battery_capacity"] = value(self.ev_battery_capacity as i64);
223+
doc["ev_factor"] = value(self.ev_factor as f64);
224+
225+
let _ = fs::write(config_file, doc.to_string());
226+
}
227+
}

0 commit comments

Comments
 (0)