|
|
@@ -115,6 +115,26 @@ macro_rules! serde_field_string {
|
|
115
|
115
|
};
|
|
116
|
116
|
}
|
|
117
|
117
|
|
|
|
118
|
+macro_rules! serde_field_bool {
|
|
|
119
|
+ ($struct_name: ident, $field_name: literal, $func: ident) => {
|
|
|
120
|
+ #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
|
121
|
+ pub struct $struct_name {
|
|
|
122
|
+ #[serde(rename = $field_name)]
|
|
|
123
|
+ pub v: bool,
|
|
|
124
|
+ }
|
|
|
125
|
+ impl Default for $struct_name {
|
|
|
126
|
+ fn default() -> Self {
|
|
|
127
|
+ Self { v: Self::$func() }
|
|
|
128
|
+ }
|
|
|
129
|
+ }
|
|
|
130
|
+ impl $struct_name {
|
|
|
131
|
+ pub fn $func() -> bool {
|
|
|
132
|
+ UserDefaultConfig::load().get($field_name) == "Y"
|
|
|
133
|
+ }
|
|
|
134
|
+ }
|
|
|
135
|
+ };
|
|
|
136
|
+}
|
|
|
137
|
+
|
|
118
|
138
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
119
|
139
|
pub enum NetworkType {
|
|
120
|
140
|
Direct,
|
|
|
@@ -192,26 +212,29 @@ pub struct PeerConfig {
|
|
192
|
212
|
deserialize_with = "PeerConfig::deserialize_image_quality"
|
|
193
|
213
|
)]
|
|
194
|
214
|
pub image_quality: String,
|
|
195
|
|
- #[serde(default)]
|
|
|
215
|
+ #[serde(
|
|
|
216
|
+ default = "PeerConfig::default_custom_image_quality",
|
|
|
217
|
+ deserialize_with = "PeerConfig::deserialize_custom_image_quality"
|
|
|
218
|
+ )]
|
|
196
|
219
|
pub custom_image_quality: Vec<i32>,
|
|
197
|
|
- #[serde(default)]
|
|
198
|
|
- pub show_remote_cursor: bool,
|
|
199
|
|
- #[serde(default)]
|
|
200
|
|
- pub lock_after_session_end: bool,
|
|
201
|
|
- #[serde(default)]
|
|
202
|
|
- pub privacy_mode: bool,
|
|
|
220
|
+ #[serde(flatten)]
|
|
|
221
|
+ pub show_remote_cursor: ShowRemoteCursor,
|
|
|
222
|
+ #[serde(flatten)]
|
|
|
223
|
+ pub lock_after_session_end: LockAfterSessionEnd,
|
|
|
224
|
+ #[serde(flatten)]
|
|
|
225
|
+ pub privacy_mode: PrivacyMode,
|
|
203
|
226
|
#[serde(default)]
|
|
204
|
227
|
pub port_forwards: Vec<(i32, String, i32)>,
|
|
205
|
228
|
#[serde(default)]
|
|
206
|
229
|
pub direct_failures: i32,
|
|
207
|
|
- #[serde(default)]
|
|
208
|
|
- pub disable_audio: bool,
|
|
209
|
|
- #[serde(default)]
|
|
210
|
|
- pub disable_clipboard: bool,
|
|
211
|
|
- #[serde(default)]
|
|
212
|
|
- pub enable_file_transfer: bool,
|
|
213
|
|
- #[serde(default)]
|
|
214
|
|
- pub show_quality_monitor: bool,
|
|
|
230
|
+ #[serde(flatten)]
|
|
|
231
|
+ pub disable_audio: DisableAudio,
|
|
|
232
|
+ #[serde(flatten)]
|
|
|
233
|
+ pub disable_clipboard: DisableClipboard,
|
|
|
234
|
+ #[serde(flatten)]
|
|
|
235
|
+ pub enable_file_transfer: EnableFileTransfer,
|
|
|
236
|
+ #[serde(flatten)]
|
|
|
237
|
+ pub show_quality_monitor: ShowQualityMonitor,
|
|
215
|
238
|
#[serde(default)]
|
|
216
|
239
|
pub keyboard_mode: String,
|
|
217
|
240
|
|
|
|
@@ -961,31 +984,88 @@ impl PeerConfig {
|
|
961
|
984
|
serde_field_string!(
|
|
962
|
985
|
default_view_style,
|
|
963
|
986
|
deserialize_view_style,
|
|
964
|
|
- "original".to_owned()
|
|
|
987
|
+ UserDefaultConfig::load().get("view_style")
|
|
965
|
988
|
);
|
|
966
|
989
|
serde_field_string!(
|
|
967
|
990
|
default_scroll_style,
|
|
968
|
991
|
deserialize_scroll_style,
|
|
969
|
|
- "scrollauto".to_owned()
|
|
|
992
|
+ UserDefaultConfig::load().get("scroll_style")
|
|
970
|
993
|
);
|
|
971
|
994
|
serde_field_string!(
|
|
972
|
995
|
default_image_quality,
|
|
973
|
996
|
deserialize_image_quality,
|
|
974
|
|
- "balanced".to_owned()
|
|
|
997
|
+ UserDefaultConfig::load().get("image_quality")
|
|
975
|
998
|
);
|
|
976
|
999
|
|
|
|
1000
|
+ fn default_custom_image_quality() -> Vec<i32> {
|
|
|
1001
|
+ let f: f64 = UserDefaultConfig::load()
|
|
|
1002
|
+ .get("custom_image_quality")
|
|
|
1003
|
+ .parse()
|
|
|
1004
|
+ .unwrap_or(50.0);
|
|
|
1005
|
+ vec![f as _]
|
|
|
1006
|
+ }
|
|
|
1007
|
+
|
|
|
1008
|
+ fn deserialize_custom_image_quality<'de, D>(deserializer: D) -> Result<Vec<i32>, D::Error>
|
|
|
1009
|
+ where
|
|
|
1010
|
+ D: de::Deserializer<'de>,
|
|
|
1011
|
+ {
|
|
|
1012
|
+ let v: Vec<i32> = de::Deserialize::deserialize(deserializer)?;
|
|
|
1013
|
+ if v.len() == 1 && v[0] >= 10 && v[0] <= 100 {
|
|
|
1014
|
+ Ok(v)
|
|
|
1015
|
+ } else {
|
|
|
1016
|
+ Ok(Self::default_custom_image_quality())
|
|
|
1017
|
+ }
|
|
|
1018
|
+ }
|
|
|
1019
|
+
|
|
977
|
1020
|
fn deserialize_options<'de, D>(deserializer: D) -> Result<HashMap<String, String>, D::Error>
|
|
978
|
1021
|
where
|
|
979
|
1022
|
D: de::Deserializer<'de>,
|
|
980
|
1023
|
{
|
|
981
|
1024
|
let mut mp: HashMap<String, String> = de::Deserialize::deserialize(deserializer)?;
|
|
982
|
|
- if !mp.contains_key("codec-preference") {
|
|
983
|
|
- mp.insert("codec-preference".to_owned(), "auto".to_owned());
|
|
|
1025
|
+ let mut key = "codec-preference";
|
|
|
1026
|
+ if !mp.contains_key(key) {
|
|
|
1027
|
+ mp.insert(key.to_owned(), UserDefaultConfig::load().get(key));
|
|
|
1028
|
+ }
|
|
|
1029
|
+ key = "custom-fps";
|
|
|
1030
|
+ if !mp.contains_key(key) {
|
|
|
1031
|
+ mp.insert(key.to_owned(), UserDefaultConfig::load().get(key));
|
|
|
1032
|
+ }
|
|
|
1033
|
+ key = "zoom-cursor";
|
|
|
1034
|
+ if !mp.contains_key(key) {
|
|
|
1035
|
+ mp.insert(key.to_owned(), UserDefaultConfig::load().get(key));
|
|
984
|
1036
|
}
|
|
985
|
1037
|
Ok(mp)
|
|
986
|
1038
|
}
|
|
987
|
1039
|
}
|
|
988
|
1040
|
|
|
|
1041
|
+serde_field_bool!(
|
|
|
1042
|
+ ShowRemoteCursor,
|
|
|
1043
|
+ "show_remote_cursor",
|
|
|
1044
|
+ default_show_remote_cursor
|
|
|
1045
|
+);
|
|
|
1046
|
+serde_field_bool!(
|
|
|
1047
|
+ ShowQualityMonitor,
|
|
|
1048
|
+ "show_quality_monitor",
|
|
|
1049
|
+ default_show_quality_monitor
|
|
|
1050
|
+);
|
|
|
1051
|
+serde_field_bool!(DisableAudio, "disable_audio", default_disable_audio);
|
|
|
1052
|
+serde_field_bool!(
|
|
|
1053
|
+ EnableFileTransfer,
|
|
|
1054
|
+ "enable_file_transfer",
|
|
|
1055
|
+ default_enable_file_transfer
|
|
|
1056
|
+);
|
|
|
1057
|
+serde_field_bool!(
|
|
|
1058
|
+ DisableClipboard,
|
|
|
1059
|
+ "disable_clipboard",
|
|
|
1060
|
+ default_disable_clipboard
|
|
|
1061
|
+);
|
|
|
1062
|
+serde_field_bool!(
|
|
|
1063
|
+ LockAfterSessionEnd,
|
|
|
1064
|
+ "lock_after_session_end",
|
|
|
1065
|
+ default_lock_after_session_end
|
|
|
1066
|
+);
|
|
|
1067
|
+serde_field_bool!(PrivacyMode, "privacy_mode", default_privacy_mode);
|
|
|
1068
|
+
|
|
989
|
1069
|
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
|
990
|
1070
|
pub struct LocalConfig {
|
|
991
|
1071
|
#[serde(default)]
|
|
|
@@ -1192,6 +1272,73 @@ impl HwCodecConfig {
|
|
1192
|
1272
|
}
|
|
1193
|
1273
|
}
|
|
1194
|
1274
|
|
|
|
1275
|
+#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
|
|
1276
|
+pub struct UserDefaultConfig {
|
|
|
1277
|
+ #[serde(default)]
|
|
|
1278
|
+ options: HashMap<String, String>,
|
|
|
1279
|
+}
|
|
|
1280
|
+
|
|
|
1281
|
+impl UserDefaultConfig {
|
|
|
1282
|
+ pub fn load() -> UserDefaultConfig {
|
|
|
1283
|
+ Config::load_::<UserDefaultConfig>("_default")
|
|
|
1284
|
+ }
|
|
|
1285
|
+
|
|
|
1286
|
+ #[inline]
|
|
|
1287
|
+ fn store(&self) {
|
|
|
1288
|
+ Config::store_(self, "_default");
|
|
|
1289
|
+ }
|
|
|
1290
|
+
|
|
|
1291
|
+ pub fn get(&self, key: &str) -> String {
|
|
|
1292
|
+ match key {
|
|
|
1293
|
+ "view_style" => self.get_string(key, "original", vec!["adaptive"]),
|
|
|
1294
|
+ "scroll_style" => self.get_string(key, "scrollauto", vec!["scrollbar"]),
|
|
|
1295
|
+ "image_quality" => self.get_string(key, "balanced", vec!["best", "low", "custom"]),
|
|
|
1296
|
+ "codec-preference" => self.get_string(key, "auto", vec!["vp9", "h264", "h265"]),
|
|
|
1297
|
+ "custom_image_quality" => self.get_double_string(key, 50.0, 10.0, 100.0),
|
|
|
1298
|
+ "custom-fps" => self.get_double_string(key, 30.0, 10.0, 120.0),
|
|
|
1299
|
+ _ => self
|
|
|
1300
|
+ .options
|
|
|
1301
|
+ .get(key)
|
|
|
1302
|
+ .map(|v| v.to_string())
|
|
|
1303
|
+ .unwrap_or_default(),
|
|
|
1304
|
+ }
|
|
|
1305
|
+ }
|
|
|
1306
|
+
|
|
|
1307
|
+ pub fn set(&mut self, key: String, value: String) {
|
|
|
1308
|
+ self.options.insert(key, value);
|
|
|
1309
|
+ self.store();
|
|
|
1310
|
+ }
|
|
|
1311
|
+
|
|
|
1312
|
+ #[inline]
|
|
|
1313
|
+ fn get_string(&self, key: &str, default: &str, others: Vec<&str>) -> String {
|
|
|
1314
|
+ match self.options.get(key) {
|
|
|
1315
|
+ Some(option) => {
|
|
|
1316
|
+ if others.contains(&option.as_str()) {
|
|
|
1317
|
+ option.to_owned()
|
|
|
1318
|
+ } else {
|
|
|
1319
|
+ default.to_owned()
|
|
|
1320
|
+ }
|
|
|
1321
|
+ }
|
|
|
1322
|
+ None => default.to_owned(),
|
|
|
1323
|
+ }
|
|
|
1324
|
+ }
|
|
|
1325
|
+
|
|
|
1326
|
+ #[inline]
|
|
|
1327
|
+ fn get_double_string(&self, key: &str, default: f64, min: f64, max: f64) -> String {
|
|
|
1328
|
+ match self.options.get(key) {
|
|
|
1329
|
+ Some(option) => {
|
|
|
1330
|
+ let v: f64 = option.parse().unwrap_or(default);
|
|
|
1331
|
+ if v >= min && v <= max {
|
|
|
1332
|
+ v.to_string()
|
|
|
1333
|
+ } else {
|
|
|
1334
|
+ default.to_string()
|
|
|
1335
|
+ }
|
|
|
1336
|
+ }
|
|
|
1337
|
+ None => default.to_string(),
|
|
|
1338
|
+ }
|
|
|
1339
|
+ }
|
|
|
1340
|
+}
|
|
|
1341
|
+
|
|
1195
|
1342
|
#[cfg(test)]
|
|
1196
|
1343
|
mod tests {
|
|
1197
|
1344
|
use super::*;
|