1
1
use bluer:: Address ;
2
2
use serde:: de:: { self , Deserializer , Error as DeError , Visitor } ;
3
- use serde:: Deserialize ;
3
+ use serde:: { Deserialize , Serialize } ;
4
+ use simplelog:: * ;
4
5
use std:: fmt:: { self , Display } ;
6
+ use std:: fs;
5
7
use std:: path:: PathBuf ;
6
8
use std:: str:: FromStr ;
9
+ use toml_edit:: { value, DocumentMut } ;
7
10
8
- #[ derive( clap:: ValueEnum , Default , Debug , PartialEq , PartialOrd , Clone , Copy , Deserialize ) ]
11
+ #[ derive(
12
+ clap:: ValueEnum , Default , Debug , PartialEq , PartialOrd , Clone , Copy , Deserialize , Serialize ,
13
+ ) ]
9
14
pub enum HexdumpLevel {
10
15
#[ default]
11
16
Disabled ,
@@ -16,7 +21,7 @@ pub enum HexdumpLevel {
16
21
All ,
17
22
}
18
23
19
- #[ derive( Debug , Clone ) ]
24
+ #[ derive( Debug , Clone , Serialize ) ]
20
25
pub struct UsbId {
21
26
pub vid : u16 ,
22
27
pub pid : u16 ,
@@ -36,6 +41,12 @@ impl std::str::FromStr for UsbId {
36
41
}
37
42
}
38
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
+
39
50
impl < ' de > Deserialize < ' de > for UsbId {
40
51
fn deserialize < D > ( deserializer : D ) -> Result < UsbId , D :: Error >
41
52
where
76
87
}
77
88
}
78
89
79
- #[ derive( Debug , Clone , Deserialize ) ]
90
+ #[ derive( Debug , Clone , Deserialize , Serialize ) ]
80
91
#[ serde( default ) ]
81
92
pub struct AppConfig {
82
93
pub advertise : bool ,
@@ -149,12 +160,68 @@ impl Default for AppConfig {
149
160
}
150
161
}
151
162
152
- pub fn load_config ( config_file : PathBuf ) -> Result < AppConfig , Box < dyn std:: error:: Error > > {
153
- let file_config: AppConfig = config:: Config :: builder ( )
154
- . add_source ( config:: File :: from ( config_file) . required ( false ) )
155
- . build ( ) ?
156
- . try_deserialize ( )
157
- . unwrap_or_default ( ) ;
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
+ } ) ;
158
182
159
- Ok ( file_config)
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
+ }
160
227
}
0 commit comments