2021-03-29 15:59:14 +08:00
|
|
|
use std::{
|
2023-08-02 22:25:54 +08:00
|
|
|
collections::{HashMap, HashSet},
|
2021-03-29 15:59:14 +08:00
|
|
|
fs,
|
2023-08-02 22:25:54 +08:00
|
|
|
io::{Read, Write},
|
2022-12-26 16:41:33 +08:00
|
|
|
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
|
2023-06-18 20:23:54 +08:00
|
|
|
ops::{Deref, DerefMut},
|
2021-03-29 15:59:14 +08:00
|
|
|
path::{Path, PathBuf},
|
2024-03-10 12:48:00 +08:00
|
|
|
sync::{Mutex, RwLock},
|
2023-03-10 11:24:43 +08:00
|
|
|
time::{Duration, Instant, SystemTime},
|
2021-03-29 15:59:14 +08:00
|
|
|
};
|
|
|
|
|
2022-08-01 14:33:08 +08:00
|
|
|
use anyhow::Result;
|
|
|
|
use rand::Rng;
|
2022-11-23 15:07:56 +01:00
|
|
|
use regex::Regex;
|
2022-11-17 18:52:27 +08:00
|
|
|
use serde as de;
|
2022-08-01 14:33:08 +08:00
|
|
|
use serde_derive::{Deserialize, Serialize};
|
2023-08-02 22:25:54 +08:00
|
|
|
use serde_json;
|
2022-11-23 15:07:56 +01:00
|
|
|
use sodiumoxide::base64;
|
2022-08-01 14:33:08 +08:00
|
|
|
use sodiumoxide::crypto::sign;
|
|
|
|
|
|
|
|
use crate::{
|
2023-08-02 22:25:54 +08:00
|
|
|
compress::{compress, decompress},
|
2022-08-01 14:33:08 +08:00
|
|
|
log,
|
|
|
|
password_security::{
|
|
|
|
decrypt_str_or_original, decrypt_vec_or_original, encrypt_str_or_original,
|
2023-08-04 15:32:09 +08:00
|
|
|
encrypt_vec_or_original, symmetric_crypt,
|
2022-08-01 14:33:08 +08:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
pub const RENDEZVOUS_TIMEOUT: u64 = 12_000;
|
|
|
|
pub const CONNECT_TIMEOUT: u64 = 18_000;
|
2023-05-14 18:17:02 +08:00
|
|
|
pub const READ_TIMEOUT: u64 = 18_000;
|
2024-01-02 13:42:32 +08:00
|
|
|
// https://github.com/quic-go/quic-go/issues/525#issuecomment-294531351
|
|
|
|
// https://datatracker.ietf.org/doc/html/draft-hamilton-early-deployment-quic-00#section-6.10
|
|
|
|
// 15 seconds is recommended by quic, though oneSIP recommend 25 seconds,
|
|
|
|
// https://www.onsip.com/voip-resources/voip-fundamentals/what-is-nat-keepalive
|
|
|
|
pub const REG_INTERVAL: i64 = 15_000;
|
2021-03-29 15:59:14 +08:00
|
|
|
pub const COMPRESS_LEVEL: i32 = 3;
|
2022-06-25 02:44:19 +08:00
|
|
|
const SERIAL: i32 = 3;
|
2023-01-27 11:42:08 +08:00
|
|
|
const PASSWORD_ENC_VERSION: &str = "00";
|
2023-08-02 22:25:54 +08:00
|
|
|
const ENCRYPT_MAX_LEN: usize = 128;
|
2023-02-11 00:21:19 +08:00
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
#[cfg(target_os = "macos")]
|
2022-05-12 17:35:25 +08:00
|
|
|
lazy_static::lazy_static! {
|
2024-03-10 12:48:00 +08:00
|
|
|
pub static ref ORG: RwLock<String> = RwLock::new("com.carriez".to_owned());
|
2022-05-12 17:35:25 +08:00
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
|
|
|
|
type Size = (i32, i32, i32, i32);
|
2023-01-27 11:42:08 +08:00
|
|
|
type KeyPair = (Vec<u8>, Vec<u8>);
|
2021-03-29 15:59:14 +08:00
|
|
|
|
|
|
|
lazy_static::lazy_static! {
|
2024-03-10 12:48:00 +08:00
|
|
|
static ref CONFIG: RwLock<Config> = RwLock::new(Config::load());
|
|
|
|
static ref CONFIG2: RwLock<Config2> = RwLock::new(Config2::load());
|
|
|
|
static ref LOCAL_CONFIG: RwLock<LocalConfig> = RwLock::new(LocalConfig::load());
|
|
|
|
static ref ONLINE: Mutex<HashMap<String, i64>> = Default::default();
|
|
|
|
pub static ref PROD_RENDEZVOUS_SERVER: RwLock<String> = RwLock::new(match option_env!("RENDEZVOUS_SERVER") {
|
2023-01-24 01:32:56 +08:00
|
|
|
Some(key) if !key.is_empty() => key,
|
|
|
|
_ => "",
|
2024-03-10 12:48:00 +08:00
|
|
|
}.to_owned());
|
|
|
|
pub static ref EXE_RENDEZVOUS_SERVER: RwLock<String> = Default::default();
|
|
|
|
pub static ref APP_NAME: RwLock<String> = RwLock::new("RustDesk".to_owned());
|
|
|
|
static ref KEY_PAIR: Mutex<Option<KeyPair>> = Default::default();
|
|
|
|
static ref USER_DEFAULT_CONFIG: RwLock<(UserDefaultConfig, Instant)> = RwLock::new((UserDefaultConfig::load(), Instant::now()));
|
|
|
|
pub static ref NEW_STORED_PEER_CONFIG: Mutex<HashSet<String>> = Default::default();
|
|
|
|
pub static ref DEFAULT_SETTINGS: RwLock<HashMap<String, String>> = Default::default();
|
|
|
|
pub static ref OVERWRITE_SETTINGS: RwLock<HashMap<String, String>> = Default::default();
|
|
|
|
pub static ref DEFAULT_DISPLAY_SETTINGS: RwLock<HashMap<String, String>> = Default::default();
|
|
|
|
pub static ref OVERWRITE_DISPLAY_SETTINGS: RwLock<HashMap<String, String>> = Default::default();
|
|
|
|
pub static ref DEFAULT_LOCAL_SETTINGS: RwLock<HashMap<String, String>> = Default::default();
|
|
|
|
pub static ref OVERWRITE_LOCAL_SETTINGS: RwLock<HashMap<String, String>> = Default::default();
|
|
|
|
pub static ref HARD_SETTINGS: RwLock<HashMap<String, String>> = Default::default();
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
2022-08-01 14:33:08 +08:00
|
|
|
|
2022-07-10 23:26:44 +08:00
|
|
|
lazy_static::lazy_static! {
|
2024-03-10 12:48:00 +08:00
|
|
|
pub static ref APP_DIR: RwLock<String> = Default::default();
|
2022-12-01 21:48:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
|
|
|
lazy_static::lazy_static! {
|
2024-03-10 12:48:00 +08:00
|
|
|
pub static ref APP_HOME_DIR: RwLock<String> = Default::default();
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
2022-10-14 11:19:49 +08:00
|
|
|
|
2023-04-01 00:28:56 +08:00
|
|
|
pub const LINK_DOCS_HOME: &str = "https://rustdesk.com/docs/en/";
|
|
|
|
pub const LINK_DOCS_X11_REQUIRED: &str = "https://rustdesk.com/docs/en/manual/linux/#x11-required";
|
|
|
|
pub const LINK_HEADLESS_LINUX_SUPPORT: &str =
|
|
|
|
"https://github.com/rustdesk/rustdesk/wiki/Headless-Linux-Support";
|
2022-10-14 11:19:49 +08:00
|
|
|
lazy_static::lazy_static! {
|
|
|
|
pub static ref HELPER_URL: HashMap<&'static str, &'static str> = HashMap::from([
|
2023-04-01 00:28:56 +08:00
|
|
|
("rustdesk docs home", LINK_DOCS_HOME),
|
|
|
|
("rustdesk docs x11-required", LINK_DOCS_X11_REQUIRED),
|
|
|
|
("rustdesk x11 headless", LINK_HEADLESS_LINUX_SUPPORT),
|
2022-10-14 11:19:49 +08:00
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
2023-01-27 11:42:08 +08:00
|
|
|
const CHARS: &[char] = &[
|
2021-03-29 15:59:14 +08:00
|
|
|
'2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
|
|
|
|
'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
|
|
|
];
|
|
|
|
|
2023-08-13 15:59:07 +08:00
|
|
|
pub const RENDEZVOUS_SERVERS: &[&str] = &["rs-ny.rustdesk.com"];
|
2023-11-06 20:12:01 +08:00
|
|
|
pub const PUBLIC_RS_PUB_KEY: &str = "OeVuKk5nlHiXp+APNn0Y3pC1Iwpwn44JGqrQCsWqmBw=";
|
2023-01-18 14:22:41 +08:00
|
|
|
|
2023-01-27 11:42:08 +08:00
|
|
|
pub const RS_PUB_KEY: &str = match option_env!("RS_PUB_KEY") {
|
2023-01-24 01:32:56 +08:00
|
|
|
Some(key) if !key.is_empty() => key,
|
2023-11-06 20:12:01 +08:00
|
|
|
_ => PUBLIC_RS_PUB_KEY,
|
2023-01-24 01:32:56 +08:00
|
|
|
};
|
2023-01-18 14:22:41 +08:00
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
pub const RENDEZVOUS_PORT: i32 = 21116;
|
|
|
|
pub const RELAY_PORT: i32 = 21117;
|
|
|
|
|
2022-11-17 18:52:27 +08:00
|
|
|
macro_rules! serde_field_string {
|
|
|
|
($default_func:ident, $de_func:ident, $default_expr:expr) => {
|
|
|
|
fn $default_func() -> String {
|
|
|
|
$default_expr
|
|
|
|
}
|
|
|
|
|
|
|
|
fn $de_func<'de, D>(deserializer: D) -> Result<String, D::Error>
|
|
|
|
where
|
|
|
|
D: de::Deserializer<'de>,
|
|
|
|
{
|
2023-05-19 11:10:24 +08:00
|
|
|
let s: String =
|
|
|
|
de::Deserialize::deserialize(deserializer).unwrap_or(Self::$default_func());
|
2023-06-04 19:58:55 +08:00
|
|
|
if s.is_empty() {
|
|
|
|
return Ok(Self::$default_func());
|
|
|
|
}
|
2023-05-19 11:10:24 +08:00
|
|
|
Ok(s)
|
2022-11-17 18:52:27 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-02-02 09:39:14 +08:00
|
|
|
macro_rules! serde_field_bool {
|
2023-03-01 11:55:56 +08:00
|
|
|
($struct_name: ident, $field_name: literal, $func: ident, $default: literal) => {
|
2023-02-02 09:39:14 +08:00
|
|
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
|
|
pub struct $struct_name {
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default = $default, rename = $field_name, deserialize_with = "deserialize_bool")]
|
2023-02-02 09:39:14 +08:00
|
|
|
pub v: bool,
|
|
|
|
}
|
|
|
|
impl Default for $struct_name {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self { v: Self::$func() }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl $struct_name {
|
|
|
|
pub fn $func() -> bool {
|
2024-03-08 00:22:52 +08:00
|
|
|
UserDefaultConfig::read($field_name) == "Y"
|
2023-02-02 09:39:14 +08:00
|
|
|
}
|
|
|
|
}
|
2023-06-18 20:23:54 +08:00
|
|
|
impl Deref for $struct_name {
|
|
|
|
type Target = bool;
|
|
|
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
&self.v
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl DerefMut for $struct_name {
|
|
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
|
|
&mut self.v
|
|
|
|
}
|
|
|
|
}
|
2023-02-02 09:39:14 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-01-04 00:44:50 +08:00
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
2023-01-11 18:59:21 -07:00
|
|
|
pub enum NetworkType {
|
2022-01-04 00:44:50 +08:00
|
|
|
Direct,
|
|
|
|
ProxySocks,
|
|
|
|
}
|
|
|
|
|
2022-04-26 11:19:45 +08:00
|
|
|
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
|
2021-03-29 15:59:14 +08:00
|
|
|
pub struct Config {
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(
|
|
|
|
default,
|
|
|
|
skip_serializing_if = "String::is_empty",
|
|
|
|
deserialize_with = "deserialize_string"
|
|
|
|
)]
|
2022-09-29 15:30:40 +08:00
|
|
|
pub id: String, // use
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_string")]
|
2022-09-29 15:30:40 +08:00
|
|
|
enc_id: String, // store
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_string")]
|
2021-03-29 15:59:14 +08:00
|
|
|
password: String,
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_string")]
|
2021-03-29 15:59:14 +08:00
|
|
|
salt: String,
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_keypair")]
|
2023-01-27 11:42:08 +08:00
|
|
|
key_pair: KeyPair, // sk, pk
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_bool")]
|
2021-03-29 15:59:14 +08:00
|
|
|
key_confirmed: bool,
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_hashmap_string_bool")]
|
2021-03-29 15:59:14 +08:00
|
|
|
keys_confirmed: HashMap<String, bool>,
|
|
|
|
}
|
|
|
|
|
2022-01-05 21:12:07 +08:00
|
|
|
#[derive(Debug, Default, PartialEq, Serialize, Deserialize, Clone)]
|
2022-01-02 22:55:33 +08:00
|
|
|
pub struct Socks5Server {
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_string")]
|
2022-01-02 22:55:33 +08:00
|
|
|
pub proxy: String,
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_string")]
|
2022-01-02 22:55:33 +08:00
|
|
|
pub username: String,
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_string")]
|
2022-01-02 22:55:33 +08:00
|
|
|
pub password: String,
|
|
|
|
}
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
// more variable configs
|
2022-04-26 11:19:45 +08:00
|
|
|
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
|
2021-03-29 15:59:14 +08:00
|
|
|
pub struct Config2 {
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_string")]
|
2021-03-29 15:59:14 +08:00
|
|
|
rendezvous_server: String,
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_i32")]
|
2021-03-29 15:59:14 +08:00
|
|
|
nat_type: i32,
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_i32")]
|
2021-03-29 15:59:14 +08:00
|
|
|
serial: i32,
|
|
|
|
|
2022-01-02 22:55:33 +08:00
|
|
|
#[serde(default)]
|
|
|
|
socks: Option<Socks5Server>,
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
// the other scalar value must before this
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_hashmap_string_string")]
|
2021-03-29 15:59:14 +08:00
|
|
|
pub options: HashMap<String, String>,
|
|
|
|
}
|
|
|
|
|
2023-05-17 23:19:20 +08:00
|
|
|
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
|
|
|
|
pub struct Resolution {
|
|
|
|
pub w: i32,
|
|
|
|
pub h: i32,
|
|
|
|
}
|
|
|
|
|
2023-08-31 22:06:39 +08:00
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
2021-03-29 15:59:14 +08:00
|
|
|
pub struct PeerConfig {
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_vec_u8")]
|
2021-03-29 15:59:14 +08:00
|
|
|
pub password: Vec<u8>,
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_size")]
|
2021-03-29 15:59:14 +08:00
|
|
|
pub size: Size,
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_size")]
|
2021-03-29 15:59:14 +08:00
|
|
|
pub size_ft: Size,
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_size")]
|
2021-03-29 15:59:14 +08:00
|
|
|
pub size_pf: Size,
|
2022-11-17 18:52:27 +08:00
|
|
|
#[serde(
|
|
|
|
default = "PeerConfig::default_view_style",
|
2023-06-04 19:58:55 +08:00
|
|
|
deserialize_with = "PeerConfig::deserialize_view_style",
|
|
|
|
skip_serializing_if = "String::is_empty"
|
2022-11-17 18:52:27 +08:00
|
|
|
)]
|
|
|
|
pub view_style: String,
|
2023-09-10 14:14:57 +08:00
|
|
|
// Image scroll style, scrollbar or scroll auto
|
2022-11-17 18:52:27 +08:00
|
|
|
#[serde(
|
|
|
|
default = "PeerConfig::default_scroll_style",
|
2023-06-04 19:58:55 +08:00
|
|
|
deserialize_with = "PeerConfig::deserialize_scroll_style",
|
|
|
|
skip_serializing_if = "String::is_empty"
|
2022-11-17 18:52:27 +08:00
|
|
|
)]
|
|
|
|
pub scroll_style: String,
|
|
|
|
#[serde(
|
|
|
|
default = "PeerConfig::default_image_quality",
|
2023-06-04 19:58:55 +08:00
|
|
|
deserialize_with = "PeerConfig::deserialize_image_quality",
|
|
|
|
skip_serializing_if = "String::is_empty"
|
2022-11-17 18:52:27 +08:00
|
|
|
)]
|
2021-03-29 15:59:14 +08:00
|
|
|
pub image_quality: String,
|
2023-02-01 19:56:57 +08:00
|
|
|
#[serde(
|
|
|
|
default = "PeerConfig::default_custom_image_quality",
|
2023-06-04 19:58:55 +08:00
|
|
|
deserialize_with = "PeerConfig::deserialize_custom_image_quality",
|
|
|
|
skip_serializing_if = "Vec::is_empty"
|
2023-02-01 19:56:57 +08:00
|
|
|
)]
|
2021-03-29 15:59:14 +08:00
|
|
|
pub custom_image_quality: Vec<i32>,
|
2023-02-02 09:39:14 +08:00
|
|
|
#[serde(flatten)]
|
|
|
|
pub show_remote_cursor: ShowRemoteCursor,
|
|
|
|
#[serde(flatten)]
|
|
|
|
pub lock_after_session_end: LockAfterSessionEnd,
|
|
|
|
#[serde(flatten)]
|
|
|
|
pub privacy_mode: PrivacyMode,
|
2023-02-09 11:54:23 +09:00
|
|
|
#[serde(flatten)]
|
|
|
|
pub allow_swap_key: AllowSwapKey,
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_vec_i32_string_i32")]
|
2021-03-29 15:59:14 +08:00
|
|
|
pub port_forwards: Vec<(i32, String, i32)>,
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_i32")]
|
2021-03-29 15:59:14 +08:00
|
|
|
pub direct_failures: i32,
|
2023-02-02 09:39:14 +08:00
|
|
|
#[serde(flatten)]
|
|
|
|
pub disable_audio: DisableAudio,
|
|
|
|
#[serde(flatten)]
|
|
|
|
pub disable_clipboard: DisableClipboard,
|
|
|
|
#[serde(flatten)]
|
2024-05-18 23:13:54 +08:00
|
|
|
pub enable_file_copy_paste: EnableFileCopyPaste,
|
2023-02-02 09:39:14 +08:00
|
|
|
#[serde(flatten)]
|
|
|
|
pub show_quality_monitor: ShowQualityMonitor,
|
2024-04-25 10:56:02 +05:30
|
|
|
#[serde(flatten)]
|
|
|
|
pub follow_remote_cursor: FollowRemoteCursor,
|
|
|
|
#[serde(flatten)]
|
|
|
|
pub follow_remote_window: FollowRemoteWindow,
|
2023-06-04 19:58:55 +08:00
|
|
|
#[serde(
|
|
|
|
default,
|
|
|
|
deserialize_with = "deserialize_string",
|
|
|
|
skip_serializing_if = "String::is_empty"
|
|
|
|
)]
|
2022-11-15 23:09:29 -08:00
|
|
|
pub keyboard_mode: String,
|
2023-03-17 11:27:22 +08:00
|
|
|
#[serde(flatten)]
|
|
|
|
pub view_only: ViewOnly,
|
2023-09-10 18:31:16 +08:00
|
|
|
// Mouse wheel or touchpad scroll mode
|
2023-09-10 14:14:57 +08:00
|
|
|
#[serde(
|
2023-09-10 18:31:16 +08:00
|
|
|
default = "PeerConfig::default_reverse_mouse_wheel",
|
|
|
|
deserialize_with = "PeerConfig::deserialize_reverse_mouse_wheel",
|
2023-09-10 14:14:57 +08:00
|
|
|
skip_serializing_if = "String::is_empty"
|
|
|
|
)]
|
2023-09-10 18:31:16 +08:00
|
|
|
pub reverse_mouse_wheel: String,
|
2023-10-09 17:22:22 +08:00
|
|
|
#[serde(
|
|
|
|
default = "PeerConfig::default_displays_as_individual_windows",
|
|
|
|
deserialize_with = "PeerConfig::deserialize_displays_as_individual_windows",
|
|
|
|
skip_serializing_if = "String::is_empty"
|
|
|
|
)]
|
|
|
|
pub displays_as_individual_windows: String,
|
2023-10-17 00:30:34 +08:00
|
|
|
#[serde(
|
2023-10-17 13:57:06 +08:00
|
|
|
default = "PeerConfig::default_use_all_my_displays_for_the_remote_session",
|
|
|
|
deserialize_with = "PeerConfig::deserialize_use_all_my_displays_for_the_remote_session",
|
2023-10-17 00:30:34 +08:00
|
|
|
skip_serializing_if = "String::is_empty"
|
|
|
|
)]
|
2023-10-17 13:57:06 +08:00
|
|
|
pub use_all_my_displays_for_the_remote_session: String,
|
2021-03-29 15:59:14 +08:00
|
|
|
|
2023-05-19 11:10:24 +08:00
|
|
|
#[serde(
|
|
|
|
default,
|
2023-06-05 18:01:43 +08:00
|
|
|
deserialize_with = "deserialize_hashmap_resolutions",
|
2023-06-05 19:50:24 +08:00
|
|
|
skip_serializing_if = "HashMap::is_empty"
|
2023-05-19 11:10:24 +08:00
|
|
|
)]
|
2023-06-05 19:50:24 +08:00
|
|
|
pub custom_resolutions: HashMap<String, Resolution>,
|
2023-05-17 23:19:20 +08:00
|
|
|
|
2022-11-10 21:25:12 +08:00
|
|
|
// The other scalar value must before this
|
2024-03-23 20:20:12 -07:00
|
|
|
#[serde(
|
|
|
|
default,
|
|
|
|
deserialize_with = "deserialize_hashmap_string_string",
|
|
|
|
skip_serializing_if = "HashMap::is_empty"
|
|
|
|
)]
|
2023-03-17 11:27:22 +08:00
|
|
|
pub options: HashMap<String, String>, // not use delete to represent default values
|
2022-11-10 21:25:12 +08:00
|
|
|
// Various data for flutter ui
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_hashmap_string_string")]
|
2022-11-10 21:25:12 +08:00
|
|
|
pub ui_flutter: HashMap<String, String>,
|
2021-03-29 15:59:14 +08:00
|
|
|
#[serde(default)]
|
|
|
|
pub info: PeerInfoSerde,
|
2022-05-08 21:01:03 +08:00
|
|
|
#[serde(default)]
|
|
|
|
pub transfer: TransferSerde,
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
2023-08-31 22:06:39 +08:00
|
|
|
impl Default for PeerConfig {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
password: Default::default(),
|
|
|
|
size: Default::default(),
|
|
|
|
size_ft: Default::default(),
|
|
|
|
size_pf: Default::default(),
|
|
|
|
view_style: Self::default_view_style(),
|
|
|
|
scroll_style: Self::default_scroll_style(),
|
|
|
|
image_quality: Self::default_image_quality(),
|
|
|
|
custom_image_quality: Self::default_custom_image_quality(),
|
|
|
|
show_remote_cursor: Default::default(),
|
|
|
|
lock_after_session_end: Default::default(),
|
|
|
|
privacy_mode: Default::default(),
|
|
|
|
allow_swap_key: Default::default(),
|
|
|
|
port_forwards: Default::default(),
|
|
|
|
direct_failures: Default::default(),
|
|
|
|
disable_audio: Default::default(),
|
|
|
|
disable_clipboard: Default::default(),
|
2024-05-18 23:13:54 +08:00
|
|
|
enable_file_copy_paste: Default::default(),
|
2023-08-31 22:06:39 +08:00
|
|
|
show_quality_monitor: Default::default(),
|
2024-04-25 10:56:02 +05:30
|
|
|
follow_remote_cursor: Default::default(),
|
|
|
|
follow_remote_window: Default::default(),
|
2023-08-31 22:06:39 +08:00
|
|
|
keyboard_mode: Default::default(),
|
|
|
|
view_only: Default::default(),
|
2023-09-10 18:31:16 +08:00
|
|
|
reverse_mouse_wheel: Self::default_reverse_mouse_wheel(),
|
2023-10-09 17:22:22 +08:00
|
|
|
displays_as_individual_windows: Self::default_displays_as_individual_windows(),
|
2023-10-17 18:49:34 +08:00
|
|
|
use_all_my_displays_for_the_remote_session:
|
|
|
|
Self::default_use_all_my_displays_for_the_remote_session(),
|
2023-08-31 22:06:39 +08:00
|
|
|
custom_resolutions: Default::default(),
|
|
|
|
options: Self::default_options(),
|
|
|
|
ui_flutter: Default::default(),
|
|
|
|
info: Default::default(),
|
|
|
|
transfer: Default::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
#[derive(Debug, PartialEq, Default, Serialize, Deserialize, Clone)]
|
|
|
|
pub struct PeerInfoSerde {
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_string")]
|
2021-03-29 15:59:14 +08:00
|
|
|
pub username: String,
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_string")]
|
2021-03-29 15:59:14 +08:00
|
|
|
pub hostname: String,
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_string")]
|
2021-03-29 15:59:14 +08:00
|
|
|
pub platform: String,
|
|
|
|
}
|
|
|
|
|
2022-06-22 09:41:35 +08:00
|
|
|
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
|
2022-05-08 21:01:03 +08:00
|
|
|
pub struct TransferSerde {
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_vec_string")]
|
2022-05-13 09:30:52 +08:00
|
|
|
pub write_jobs: Vec<String>,
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_vec_string")]
|
2022-05-13 09:30:52 +08:00
|
|
|
pub read_jobs: Vec<String>,
|
2022-05-08 21:01:03 +08:00
|
|
|
}
|
|
|
|
|
2023-06-24 21:09:45 +08:00
|
|
|
#[inline]
|
2023-07-01 14:43:00 +08:00
|
|
|
pub fn get_online_state() -> i64 {
|
2023-06-24 21:09:45 +08:00
|
|
|
*ONLINE.lock().unwrap().values().max().unwrap_or(&0)
|
|
|
|
}
|
|
|
|
|
2023-03-27 19:13:29 +08:00
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
2021-03-29 15:59:14 +08:00
|
|
|
fn patch(path: PathBuf) -> PathBuf {
|
|
|
|
if let Some(_tmp) = path.to_str() {
|
|
|
|
#[cfg(windows)]
|
|
|
|
return _tmp
|
|
|
|
.replace(
|
|
|
|
"system32\\config\\systemprofile",
|
|
|
|
"ServiceProfiles\\LocalService",
|
|
|
|
)
|
|
|
|
.into();
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
return _tmp.replace("Application Support", "Preferences").into();
|
2021-05-21 19:11:09 +08:00
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
{
|
|
|
|
if _tmp == "/root" {
|
2024-04-02 14:47:13 +08:00
|
|
|
if let Ok(user) = crate::platform::linux::run_cmds_trim_newline("whoami") {
|
2021-05-21 19:11:09 +08:00
|
|
|
if user != "root" {
|
2023-04-23 03:43:47 +02:00
|
|
|
let cmd = format!("getent passwd '{}' | awk -F':' '{{print $6}}'", user);
|
2024-04-12 17:26:24 +08:00
|
|
|
if let Ok(output) = crate::platform::linux::run_cmds_trim_newline(&cmd) {
|
2024-03-15 17:26:33 +08:00
|
|
|
return output.into();
|
2023-04-23 03:43:47 +02:00
|
|
|
}
|
2023-04-23 23:58:04 +02:00
|
|
|
return format!("/home/{user}").into();
|
2021-05-21 19:11:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
path
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Config2 {
|
|
|
|
fn load() -> Config2 {
|
2022-06-22 09:41:35 +08:00
|
|
|
let mut config = Config::load_::<Config2>("2");
|
|
|
|
if let Some(mut socks) = config.socks {
|
2022-07-27 21:30:02 +08:00
|
|
|
let (password, _, store) =
|
|
|
|
decrypt_str_or_original(&socks.password, PASSWORD_ENC_VERSION);
|
2022-06-22 09:41:35 +08:00
|
|
|
socks.password = password;
|
|
|
|
config.socks = Some(socks);
|
|
|
|
if store {
|
|
|
|
config.store();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
config
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
2022-04-26 11:19:45 +08:00
|
|
|
pub fn file() -> PathBuf {
|
|
|
|
Config::file_("2")
|
2022-01-13 15:26:57 +08:00
|
|
|
}
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
fn store(&self) {
|
2022-06-22 09:41:35 +08:00
|
|
|
let mut config = self.clone();
|
|
|
|
if let Some(mut socks) = config.socks {
|
2023-08-02 22:25:54 +08:00
|
|
|
socks.password =
|
|
|
|
encrypt_str_or_original(&socks.password, PASSWORD_ENC_VERSION, ENCRYPT_MAX_LEN);
|
2022-06-22 09:41:35 +08:00
|
|
|
config.socks = Some(socks);
|
|
|
|
}
|
|
|
|
Config::store_(&config, "2");
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
2022-04-26 11:19:45 +08:00
|
|
|
|
|
|
|
pub fn get() -> Config2 {
|
|
|
|
return CONFIG2.read().unwrap().clone();
|
|
|
|
}
|
|
|
|
|
2022-05-04 20:39:07 +08:00
|
|
|
pub fn set(cfg: Config2) -> bool {
|
2022-04-26 11:19:45 +08:00
|
|
|
let mut lock = CONFIG2.write().unwrap();
|
2022-05-04 20:39:07 +08:00
|
|
|
if *lock == cfg {
|
|
|
|
return false;
|
|
|
|
}
|
2022-04-26 11:19:45 +08:00
|
|
|
*lock = cfg;
|
|
|
|
lock.store();
|
2022-05-04 20:39:07 +08:00
|
|
|
true
|
2022-04-26 11:19:45 +08:00
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
2022-05-04 20:39:07 +08:00
|
|
|
pub fn load_path<T: serde::Serialize + serde::de::DeserializeOwned + Default + std::fmt::Debug>(
|
|
|
|
file: PathBuf,
|
|
|
|
) -> T {
|
2023-07-16 08:29:26 +08:00
|
|
|
let cfg = match confy::load_path(&file) {
|
2022-05-04 20:39:07 +08:00
|
|
|
Ok(config) => config,
|
|
|
|
Err(err) => {
|
2023-07-30 11:09:14 +08:00
|
|
|
if let confy::ConfyError::GeneralLoadError(err) = &err {
|
|
|
|
if err.kind() == std::io::ErrorKind::NotFound {
|
|
|
|
return T::default();
|
|
|
|
}
|
|
|
|
}
|
2023-07-16 09:52:32 +08:00
|
|
|
log::error!("Failed to load config '{}': {}", file.display(), err);
|
2022-05-04 20:39:07 +08:00
|
|
|
T::default()
|
|
|
|
}
|
|
|
|
};
|
|
|
|
cfg
|
|
|
|
}
|
|
|
|
|
2022-07-30 02:01:40 +08:00
|
|
|
#[inline]
|
|
|
|
pub fn store_path<T: serde::Serialize>(path: PathBuf, cfg: T) -> crate::ResultType<()> {
|
|
|
|
Ok(confy::store_path(path, cfg)?)
|
|
|
|
}
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
impl Config {
|
|
|
|
fn load_<T: serde::Serialize + serde::de::DeserializeOwned + Default + std::fmt::Debug>(
|
|
|
|
suffix: &str,
|
|
|
|
) -> T {
|
|
|
|
let file = Self::file_(suffix);
|
2022-05-04 20:39:07 +08:00
|
|
|
let cfg = load_path(file);
|
2021-03-29 15:59:14 +08:00
|
|
|
if suffix.is_empty() {
|
2022-10-11 14:56:08 +08:00
|
|
|
log::trace!("{:?}", cfg);
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
cfg
|
|
|
|
}
|
|
|
|
|
|
|
|
fn store_<T: serde::Serialize>(config: &T, suffix: &str) {
|
|
|
|
let file = Self::file_(suffix);
|
2022-07-30 02:01:40 +08:00
|
|
|
if let Err(err) = store_path(file, config) {
|
2024-04-12 17:26:24 +08:00
|
|
|
log::error!("Failed to store {suffix} config: {err}");
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn load() -> Config {
|
2022-06-20 10:41:46 +08:00
|
|
|
let mut config = Config::load_::<Config>("");
|
2022-07-30 07:09:31 +08:00
|
|
|
let mut store = false;
|
|
|
|
let (password, _, store1) = decrypt_str_or_original(&config.password, PASSWORD_ENC_VERSION);
|
2022-06-20 10:41:46 +08:00
|
|
|
config.password = password;
|
2022-07-30 07:09:31 +08:00
|
|
|
store |= store1;
|
|
|
|
let mut id_valid = false;
|
2022-09-29 15:30:40 +08:00
|
|
|
let (id, encrypted, store2) = decrypt_str_or_original(&config.enc_id, PASSWORD_ENC_VERSION);
|
2022-07-30 07:09:31 +08:00
|
|
|
if encrypted {
|
|
|
|
config.id = id;
|
|
|
|
id_valid = true;
|
|
|
|
store |= store2;
|
2023-05-16 15:59:31 +08:00
|
|
|
} else if
|
|
|
|
// Comment out for forward compatible
|
|
|
|
// crate::get_modified_time(&Self::file_(""))
|
|
|
|
// .checked_sub(std::time::Duration::from_secs(30)) // allow modification during installation
|
|
|
|
// .unwrap_or_else(crate::get_exe_time)
|
|
|
|
// < crate::get_exe_time()
|
|
|
|
// &&
|
|
|
|
!config.id.is_empty()
|
2023-01-27 11:42:08 +08:00
|
|
|
&& config.enc_id.is_empty()
|
|
|
|
&& !decrypt_str_or_original(&config.id, PASSWORD_ENC_VERSION).1
|
|
|
|
{
|
|
|
|
id_valid = true;
|
|
|
|
store = true;
|
2022-07-30 07:09:31 +08:00
|
|
|
}
|
|
|
|
if !id_valid {
|
|
|
|
for _ in 0..3 {
|
|
|
|
if let Some(id) = Config::get_auto_id() {
|
|
|
|
config.id = id;
|
|
|
|
store = true;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
log::error!("Failed to generate new id");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-06-20 10:41:46 +08:00
|
|
|
if store {
|
|
|
|
config.store();
|
|
|
|
}
|
|
|
|
config
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn store(&self) {
|
2022-06-20 10:41:46 +08:00
|
|
|
let mut config = self.clone();
|
2023-08-02 22:25:54 +08:00
|
|
|
config.password =
|
|
|
|
encrypt_str_or_original(&config.password, PASSWORD_ENC_VERSION, ENCRYPT_MAX_LEN);
|
|
|
|
config.enc_id = encrypt_str_or_original(&config.id, PASSWORD_ENC_VERSION, ENCRYPT_MAX_LEN);
|
2022-09-29 15:30:40 +08:00
|
|
|
config.id = "".to_owned();
|
2022-06-20 10:41:46 +08:00
|
|
|
Config::store_(&config, "");
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn file() -> PathBuf {
|
|
|
|
Self::file_("")
|
|
|
|
}
|
|
|
|
|
|
|
|
fn file_(suffix: &str) -> PathBuf {
|
2022-05-12 17:35:25 +08:00
|
|
|
let name = format!("{}{}", *APP_NAME.read().unwrap(), suffix);
|
2022-06-10 18:25:25 +08:00
|
|
|
Config::with_extension(Self::path(name))
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
2022-07-30 02:27:03 +08:00
|
|
|
pub fn is_empty(&self) -> bool {
|
2022-09-29 15:30:40 +08:00
|
|
|
(self.id.is_empty() && self.enc_id.is_empty()) || self.key_pair.0.is_empty()
|
2022-07-30 02:27:03 +08:00
|
|
|
}
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
pub fn get_home() -> PathBuf {
|
|
|
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
2023-10-23 16:11:59 +08:00
|
|
|
return PathBuf::from(APP_HOME_DIR.read().unwrap().as_str());
|
2022-11-13 18:11:13 +08:00
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
|
|
|
{
|
|
|
|
if let Some(path) = dirs_next::home_dir() {
|
|
|
|
patch(path)
|
|
|
|
} else if let Ok(path) = std::env::current_dir() {
|
|
|
|
path
|
|
|
|
} else {
|
|
|
|
std::env::temp_dir()
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-13 15:26:57 +08:00
|
|
|
pub fn path<P: AsRef<Path>>(p: P) -> PathBuf {
|
2021-03-29 15:59:14 +08:00
|
|
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
|
|
|
{
|
|
|
|
let mut path: PathBuf = APP_DIR.read().unwrap().clone().into();
|
|
|
|
path.push(p);
|
|
|
|
return path;
|
|
|
|
}
|
2022-11-13 18:11:13 +08:00
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
|
|
|
{
|
|
|
|
#[cfg(not(target_os = "macos"))]
|
2023-01-27 11:42:08 +08:00
|
|
|
let org = "".to_owned();
|
2022-11-13 18:11:13 +08:00
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
let org = ORG.read().unwrap().clone();
|
|
|
|
// /var/root for root
|
2022-11-17 18:52:27 +08:00
|
|
|
if let Some(project) =
|
2023-01-27 11:42:08 +08:00
|
|
|
directories_next::ProjectDirs::from("", &org, &APP_NAME.read().unwrap())
|
2022-11-17 18:52:27 +08:00
|
|
|
{
|
2022-11-13 18:11:13 +08:00
|
|
|
let mut path = patch(project.config_dir().to_path_buf());
|
|
|
|
path.push(p);
|
|
|
|
return path;
|
|
|
|
}
|
2023-01-27 11:42:08 +08:00
|
|
|
"".into()
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-21 16:35:18 +08:00
|
|
|
#[allow(unreachable_code)]
|
2021-03-29 15:59:14 +08:00
|
|
|
pub fn log_path() -> PathBuf {
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
{
|
|
|
|
if let Some(path) = dirs_next::home_dir().as_mut() {
|
2022-05-12 17:35:25 +08:00
|
|
|
path.push(format!("Library/Logs/{}", *APP_NAME.read().unwrap()));
|
2021-03-29 15:59:14 +08:00
|
|
|
return path.clone();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
{
|
2021-05-21 19:11:09 +08:00
|
|
|
let mut path = Self::get_home();
|
2022-05-12 17:35:25 +08:00
|
|
|
path.push(format!(".local/share/logs/{}", *APP_NAME.read().unwrap()));
|
2021-05-21 19:11:09 +08:00
|
|
|
std::fs::create_dir_all(&path).ok();
|
|
|
|
return path;
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
2023-10-17 18:49:34 +08:00
|
|
|
#[cfg(target_os = "android")]
|
|
|
|
{
|
|
|
|
let mut path = Self::get_home();
|
|
|
|
path.push(format!("{}/Logs", *APP_NAME.read().unwrap()));
|
|
|
|
std::fs::create_dir_all(&path).ok();
|
|
|
|
return path;
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
if let Some(path) = Self::path("").parent() {
|
|
|
|
let mut path: PathBuf = path.into();
|
|
|
|
path.push("log");
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
"".into()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn ipc_path(postfix: &str) -> String {
|
|
|
|
#[cfg(windows)]
|
|
|
|
{
|
|
|
|
// \\ServerName\pipe\PipeName
|
|
|
|
// where ServerName is either the name of a remote computer or a period, to specify the local computer.
|
|
|
|
// https://docs.microsoft.com/en-us/windows/win32/ipc/pipe-names
|
2022-05-12 17:35:25 +08:00
|
|
|
format!(
|
|
|
|
"\\\\.\\pipe\\{}\\query{}",
|
|
|
|
*APP_NAME.read().unwrap(),
|
|
|
|
postfix
|
|
|
|
)
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
{
|
|
|
|
use std::os::unix::fs::PermissionsExt;
|
2022-05-12 17:35:25 +08:00
|
|
|
#[cfg(target_os = "android")]
|
|
|
|
let mut path: PathBuf =
|
|
|
|
format!("{}/{}", *APP_DIR.read().unwrap(), *APP_NAME.read().unwrap()).into();
|
|
|
|
#[cfg(not(target_os = "android"))]
|
|
|
|
let mut path: PathBuf = format!("/tmp/{}", *APP_NAME.read().unwrap()).into();
|
2021-03-29 15:59:14 +08:00
|
|
|
fs::create_dir(&path).ok();
|
|
|
|
fs::set_permissions(&path, fs::Permissions::from_mode(0o0777)).ok();
|
2023-02-08 17:26:44 +08:00
|
|
|
path.push(format!("ipc{postfix}"));
|
2021-03-29 15:59:14 +08:00
|
|
|
path.to_str().unwrap_or("").to_owned()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn icon_path() -> PathBuf {
|
|
|
|
let mut path = Self::path("icons");
|
|
|
|
if fs::create_dir_all(&path).is_err() {
|
|
|
|
path = std::env::temp_dir();
|
|
|
|
}
|
|
|
|
path
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2022-12-28 13:52:13 +08:00
|
|
|
pub fn get_any_listen_addr(is_ipv4: bool) -> SocketAddr {
|
|
|
|
if is_ipv4 {
|
|
|
|
SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)
|
|
|
|
} else {
|
|
|
|
SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 0)
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
2022-01-05 13:21:14 +08:00
|
|
|
pub fn get_rendezvous_server() -> String {
|
2023-07-19 14:45:11 +08:00
|
|
|
let mut rendezvous_server = EXE_RENDEZVOUS_SERVER.read().unwrap().clone();
|
|
|
|
if rendezvous_server.is_empty() {
|
|
|
|
rendezvous_server = Self::get_option("custom-rendezvous-server");
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
if rendezvous_server.is_empty() {
|
2022-05-12 17:35:25 +08:00
|
|
|
rendezvous_server = PROD_RENDEZVOUS_SERVER.read().unwrap().clone();
|
|
|
|
}
|
|
|
|
if rendezvous_server.is_empty() {
|
|
|
|
rendezvous_server = CONFIG2.read().unwrap().rendezvous_server.clone();
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
if rendezvous_server.is_empty() {
|
|
|
|
rendezvous_server = Self::get_rendezvous_servers()
|
|
|
|
.drain(..)
|
|
|
|
.next()
|
2023-01-27 11:42:08 +08:00
|
|
|
.unwrap_or_default();
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
2023-01-27 11:42:08 +08:00
|
|
|
if !rendezvous_server.contains(':') {
|
2023-02-08 17:26:44 +08:00
|
|
|
rendezvous_server = format!("{rendezvous_server}:{RENDEZVOUS_PORT}");
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
2022-01-05 13:21:14 +08:00
|
|
|
rendezvous_server
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_rendezvous_servers() -> Vec<String> {
|
2023-07-19 14:45:11 +08:00
|
|
|
let s = EXE_RENDEZVOUS_SERVER.read().unwrap().clone();
|
|
|
|
if !s.is_empty() {
|
|
|
|
return vec![s];
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
let s = Self::get_option("custom-rendezvous-server");
|
|
|
|
if !s.is_empty() {
|
|
|
|
return vec![s];
|
|
|
|
}
|
2022-05-12 17:35:25 +08:00
|
|
|
let s = PROD_RENDEZVOUS_SERVER.read().unwrap().clone();
|
|
|
|
if !s.is_empty() {
|
|
|
|
return vec![s];
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
let serial_obsolute = CONFIG2.read().unwrap().serial > SERIAL;
|
|
|
|
if serial_obsolute {
|
|
|
|
let ss: Vec<String> = Self::get_option("rendezvous-servers")
|
2023-01-27 11:42:08 +08:00
|
|
|
.split(',')
|
|
|
|
.filter(|x| x.contains('.'))
|
2021-03-29 15:59:14 +08:00
|
|
|
.map(|x| x.to_owned())
|
|
|
|
.collect();
|
|
|
|
if !ss.is_empty() {
|
|
|
|
return ss;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return RENDEZVOUS_SERVERS.iter().map(|x| x.to_string()).collect();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn reset_online() {
|
|
|
|
*ONLINE.lock().unwrap() = Default::default();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn update_latency(host: &str, latency: i64) {
|
|
|
|
ONLINE.lock().unwrap().insert(host.to_owned(), latency);
|
|
|
|
let mut host = "".to_owned();
|
|
|
|
let mut delay = i64::MAX;
|
|
|
|
for (tmp_host, tmp_delay) in ONLINE.lock().unwrap().iter() {
|
|
|
|
if tmp_delay > &0 && tmp_delay < &delay {
|
2023-01-27 11:42:08 +08:00
|
|
|
delay = *tmp_delay;
|
2021-03-29 15:59:14 +08:00
|
|
|
host = tmp_host.to_string();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !host.is_empty() {
|
|
|
|
let mut config = CONFIG2.write().unwrap();
|
|
|
|
if host != config.rendezvous_server {
|
|
|
|
log::debug!("Update rendezvous_server in config to {}", host);
|
|
|
|
log::debug!("{:?}", *ONLINE.lock().unwrap());
|
|
|
|
config.rendezvous_server = host;
|
|
|
|
config.store();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_id(id: &str) {
|
|
|
|
let mut config = CONFIG.write().unwrap();
|
|
|
|
if id == config.id {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
config.id = id.into();
|
|
|
|
config.store();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_nat_type(nat_type: i32) {
|
|
|
|
let mut config = CONFIG2.write().unwrap();
|
|
|
|
if nat_type == config.nat_type {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
config.nat_type = nat_type;
|
|
|
|
config.store();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_nat_type() -> i32 {
|
|
|
|
CONFIG2.read().unwrap().nat_type
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_serial(serial: i32) {
|
|
|
|
let mut config = CONFIG2.write().unwrap();
|
|
|
|
if serial == config.serial {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
config.serial = serial;
|
|
|
|
config.store();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_serial() -> i32 {
|
|
|
|
std::cmp::max(CONFIG2.read().unwrap().serial, SERIAL)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_auto_id() -> Option<String> {
|
|
|
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
2022-05-12 17:35:25 +08:00
|
|
|
{
|
|
|
|
return Some(
|
|
|
|
rand::thread_rng()
|
|
|
|
.gen_range(1_000_000_000..2_000_000_000)
|
|
|
|
.to_string(),
|
|
|
|
);
|
|
|
|
}
|
2022-11-13 18:11:13 +08:00
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
2022-11-13 18:11:13 +08:00
|
|
|
{
|
|
|
|
let mut id = 0u32;
|
|
|
|
if let Ok(Some(ma)) = mac_address::get_mac_address() {
|
|
|
|
for x in &ma.bytes()[2..] {
|
|
|
|
id = (id << 8) | (*x as u32);
|
|
|
|
}
|
2023-01-27 11:42:08 +08:00
|
|
|
id &= 0x1FFFFFFF;
|
2022-11-13 18:11:13 +08:00
|
|
|
Some(id.to_string())
|
|
|
|
} else {
|
|
|
|
None
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-24 16:41:12 +08:00
|
|
|
pub fn get_auto_password(length: usize) -> String {
|
2021-03-29 15:59:14 +08:00
|
|
|
let mut rng = rand::thread_rng();
|
2022-07-24 16:41:12 +08:00
|
|
|
(0..length)
|
2021-03-29 15:59:14 +08:00
|
|
|
.map(|_| CHARS[rng.gen::<usize>() % CHARS.len()])
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_key_confirmed() -> bool {
|
|
|
|
CONFIG.read().unwrap().key_confirmed
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_key_confirmed(v: bool) {
|
|
|
|
let mut config = CONFIG.write().unwrap();
|
|
|
|
if config.key_confirmed == v {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
config.key_confirmed = v;
|
|
|
|
if !v {
|
|
|
|
config.keys_confirmed = Default::default();
|
|
|
|
}
|
|
|
|
config.store();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_host_key_confirmed(host: &str) -> bool {
|
2023-01-27 11:42:08 +08:00
|
|
|
matches!(CONFIG.read().unwrap().keys_confirmed.get(host), Some(true))
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_host_key_confirmed(host: &str, v: bool) {
|
|
|
|
if Self::get_host_key_confirmed(host) == v {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let mut config = CONFIG.write().unwrap();
|
|
|
|
config.keys_confirmed.insert(host.to_owned(), v);
|
|
|
|
config.store();
|
|
|
|
}
|
|
|
|
|
2023-01-27 11:42:08 +08:00
|
|
|
pub fn get_key_pair() -> KeyPair {
|
2021-03-29 15:59:14 +08:00
|
|
|
// lock here to make sure no gen_keypair more than once
|
2022-07-30 02:01:40 +08:00
|
|
|
// no use of CONFIG directly here to ensure no recursive calling in Config::load because of password dec which calling this function
|
|
|
|
let mut lock = KEY_PAIR.lock().unwrap();
|
|
|
|
if let Some(p) = lock.as_ref() {
|
|
|
|
return p.clone();
|
|
|
|
}
|
2022-07-30 09:29:01 +08:00
|
|
|
let mut config = Config::load_::<Config>("");
|
2021-03-29 15:59:14 +08:00
|
|
|
if config.key_pair.0.is_empty() {
|
2024-04-01 16:20:36 +08:00
|
|
|
log::info!("Generated new keypair for id: {}", config.id);
|
2021-03-29 15:59:14 +08:00
|
|
|
let (pk, sk) = sign::gen_keypair();
|
2022-07-30 02:01:40 +08:00
|
|
|
let key_pair = (sk.0.to_vec(), pk.0.into());
|
|
|
|
config.key_pair = key_pair.clone();
|
|
|
|
std::thread::spawn(|| {
|
|
|
|
let mut config = CONFIG.write().unwrap();
|
|
|
|
config.key_pair = key_pair;
|
|
|
|
config.store();
|
|
|
|
});
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
2022-07-30 02:01:40 +08:00
|
|
|
*lock = Some(config.key_pair.clone());
|
2023-01-27 11:42:08 +08:00
|
|
|
config.key_pair
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_id() -> String {
|
|
|
|
let mut id = CONFIG.read().unwrap().id.clone();
|
|
|
|
if id.is_empty() {
|
|
|
|
if let Some(tmp) = Config::get_auto_id() {
|
|
|
|
id = tmp;
|
|
|
|
Config::set_id(&id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
id
|
|
|
|
}
|
|
|
|
|
2022-05-12 17:35:25 +08:00
|
|
|
pub fn get_id_or(b: String) -> String {
|
|
|
|
let a = CONFIG.read().unwrap().id.clone();
|
|
|
|
if a.is_empty() {
|
|
|
|
b
|
|
|
|
} else {
|
|
|
|
a
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
pub fn get_options() -> HashMap<String, String> {
|
2024-03-08 00:22:52 +08:00
|
|
|
let mut res = DEFAULT_SETTINGS.read().unwrap().clone();
|
|
|
|
res.extend(CONFIG2.read().unwrap().options.clone());
|
|
|
|
res.extend(OVERWRITE_SETTINGS.read().unwrap().clone());
|
|
|
|
res
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
2024-03-16 01:51:16 +08:00
|
|
|
#[inline]
|
|
|
|
fn purify_options(v: &mut HashMap<String, String>) {
|
2024-06-11 19:51:11 +08:00
|
|
|
v.retain(|k, v| is_option_can_save(&OVERWRITE_SETTINGS, k, &DEFAULT_SETTINGS, v));
|
2024-03-16 01:51:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_options(mut v: HashMap<String, String>) {
|
|
|
|
Self::purify_options(&mut v);
|
2021-03-29 15:59:14 +08:00
|
|
|
let mut config = CONFIG2.write().unwrap();
|
2022-01-05 21:12:07 +08:00
|
|
|
if config.options == v {
|
|
|
|
return;
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
config.options = v;
|
|
|
|
config.store();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_option(k: &str) -> String {
|
2024-03-10 12:48:00 +08:00
|
|
|
get_or(
|
|
|
|
&OVERWRITE_SETTINGS,
|
|
|
|
&CONFIG2.read().unwrap().options,
|
|
|
|
&DEFAULT_SETTINGS,
|
|
|
|
k,
|
|
|
|
)
|
|
|
|
.unwrap_or_default()
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_option(k: String, v: String) {
|
2024-06-11 19:51:11 +08:00
|
|
|
if !is_option_can_save(&OVERWRITE_SETTINGS, &k, &DEFAULT_SETTINGS, &v) {
|
2024-03-16 01:51:16 +08:00
|
|
|
return;
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
let mut config = CONFIG2.write().unwrap();
|
|
|
|
let v2 = if v.is_empty() { None } else { Some(&v) };
|
|
|
|
if v2 != config.options.get(&k) {
|
|
|
|
if v2.is_none() {
|
|
|
|
config.options.remove(&k);
|
|
|
|
} else {
|
|
|
|
config.options.insert(k, v);
|
|
|
|
}
|
|
|
|
config.store();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn update_id() {
|
|
|
|
// to-do: how about if one ip register a lot of ids?
|
|
|
|
let id = Self::get_id();
|
|
|
|
let mut rng = rand::thread_rng();
|
2021-06-25 19:42:51 +08:00
|
|
|
let new_id = rng.gen_range(1_000_000_000..2_000_000_000).to_string();
|
2021-03-29 15:59:14 +08:00
|
|
|
Config::set_id(&new_id);
|
|
|
|
log::info!("id updated from {} to {}", id, new_id);
|
|
|
|
}
|
|
|
|
|
2022-07-24 16:41:12 +08:00
|
|
|
pub fn set_permanent_password(password: &str) {
|
2024-03-16 11:52:30 +08:00
|
|
|
if HARD_SETTINGS
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.get("password")
|
|
|
|
.map_or(false, |v| v == password)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
let mut config = CONFIG.write().unwrap();
|
|
|
|
if password == config.password {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
config.password = password.into();
|
|
|
|
config.store();
|
|
|
|
}
|
|
|
|
|
2022-07-24 16:41:12 +08:00
|
|
|
pub fn get_permanent_password() -> String {
|
2024-03-12 21:47:29 +08:00
|
|
|
let mut password = CONFIG.read().unwrap().password.clone();
|
|
|
|
if password.is_empty() {
|
|
|
|
if let Some(v) = HARD_SETTINGS.read().unwrap().get("password") {
|
|
|
|
password = v.to_owned();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
password
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_salt(salt: &str) {
|
|
|
|
let mut config = CONFIG.write().unwrap();
|
|
|
|
if salt == config.salt {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
config.salt = salt.into();
|
|
|
|
config.store();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_salt() -> String {
|
|
|
|
let mut salt = CONFIG.read().unwrap().salt.clone();
|
|
|
|
if salt.is_empty() {
|
2022-07-24 16:41:12 +08:00
|
|
|
salt = Config::get_auto_password(6);
|
2021-03-29 15:59:14 +08:00
|
|
|
Config::set_salt(&salt);
|
|
|
|
}
|
|
|
|
salt
|
|
|
|
}
|
|
|
|
|
2022-01-02 22:55:33 +08:00
|
|
|
pub fn set_socks(socks: Option<Socks5Server>) {
|
|
|
|
let mut config = CONFIG2.write().unwrap();
|
2022-01-05 21:12:07 +08:00
|
|
|
if config.socks == socks {
|
|
|
|
return;
|
|
|
|
}
|
2022-01-02 22:55:33 +08:00
|
|
|
config.socks = socks;
|
|
|
|
config.store();
|
|
|
|
}
|
|
|
|
|
2024-05-19 16:40:49 +08:00
|
|
|
#[inline]
|
|
|
|
fn get_socks_from_custom_client_advanced_settings(
|
|
|
|
settings: &HashMap<String, String>,
|
|
|
|
) -> Option<Socks5Server> {
|
|
|
|
let url = settings.get(keys::OPTION_PROXY_URL)?;
|
|
|
|
Some(Socks5Server {
|
|
|
|
proxy: url.to_owned(),
|
|
|
|
username: settings
|
|
|
|
.get(keys::OPTION_PROXY_USERNAME)
|
|
|
|
.map(|x| x.to_string())
|
|
|
|
.unwrap_or_default(),
|
|
|
|
password: settings
|
|
|
|
.get(keys::OPTION_PROXY_PASSWORD)
|
|
|
|
.map(|x| x.to_string())
|
|
|
|
.unwrap_or_default(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-01-02 22:55:33 +08:00
|
|
|
pub fn get_socks() -> Option<Socks5Server> {
|
2024-05-19 16:40:49 +08:00
|
|
|
Self::get_socks_from_custom_client_advanced_settings(&OVERWRITE_SETTINGS.read().unwrap())
|
|
|
|
.or(CONFIG2.read().unwrap().socks.clone())
|
|
|
|
.or(Self::get_socks_from_custom_client_advanced_settings(
|
|
|
|
&DEFAULT_SETTINGS.read().unwrap(),
|
|
|
|
))
|
2022-01-02 22:55:33 +08:00
|
|
|
}
|
2022-01-04 00:44:50 +08:00
|
|
|
|
2024-03-23 00:56:18 +08:00
|
|
|
#[inline]
|
|
|
|
pub fn is_proxy() -> bool {
|
|
|
|
Self::get_network_type() != NetworkType::Direct
|
|
|
|
}
|
|
|
|
|
2022-01-04 00:44:50 +08:00
|
|
|
pub fn get_network_type() -> NetworkType {
|
2024-05-19 16:40:49 +08:00
|
|
|
if OVERWRITE_SETTINGS
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.get(keys::OPTION_PROXY_URL)
|
|
|
|
.is_some()
|
|
|
|
{
|
|
|
|
return NetworkType::ProxySocks;
|
|
|
|
}
|
|
|
|
if CONFIG2.read().unwrap().socks.is_some() {
|
|
|
|
return NetworkType::ProxySocks;
|
2022-01-04 00:44:50 +08:00
|
|
|
}
|
2024-05-19 16:40:49 +08:00
|
|
|
if DEFAULT_SETTINGS
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.get(keys::OPTION_PROXY_URL)
|
|
|
|
.is_some()
|
|
|
|
{
|
|
|
|
return NetworkType::ProxySocks;
|
|
|
|
}
|
|
|
|
NetworkType::Direct
|
2022-01-04 00:44:50 +08:00
|
|
|
}
|
2022-01-13 15:26:57 +08:00
|
|
|
|
2022-04-26 11:19:45 +08:00
|
|
|
pub fn get() -> Config {
|
|
|
|
return CONFIG.read().unwrap().clone();
|
|
|
|
}
|
|
|
|
|
2022-05-04 20:39:07 +08:00
|
|
|
pub fn set(cfg: Config) -> bool {
|
2022-04-26 11:19:45 +08:00
|
|
|
let mut lock = CONFIG.write().unwrap();
|
2022-05-04 20:39:07 +08:00
|
|
|
if *lock == cfg {
|
|
|
|
return false;
|
|
|
|
}
|
2022-04-26 11:19:45 +08:00
|
|
|
*lock = cfg;
|
|
|
|
lock.store();
|
2022-05-04 20:39:07 +08:00
|
|
|
true
|
2022-01-13 15:26:57 +08:00
|
|
|
}
|
2022-06-10 18:25:25 +08:00
|
|
|
|
|
|
|
fn with_extension(path: PathBuf) -> PathBuf {
|
|
|
|
let ext = path.extension();
|
|
|
|
if let Some(ext) = ext {
|
|
|
|
let ext = format!("{}.toml", ext.to_string_lossy());
|
2023-01-27 11:42:08 +08:00
|
|
|
path.with_extension(ext)
|
2022-06-10 18:25:25 +08:00
|
|
|
} else {
|
|
|
|
path.with_extension("toml")
|
|
|
|
}
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const PEERS: &str = "peers";
|
|
|
|
|
|
|
|
impl PeerConfig {
|
|
|
|
pub fn load(id: &str) -> PeerConfig {
|
2022-11-01 15:08:21 +01:00
|
|
|
let _lock = CONFIG.read().unwrap();
|
2023-01-27 11:42:08 +08:00
|
|
|
match confy::load_path(Self::path(id)) {
|
2022-06-22 09:41:35 +08:00
|
|
|
Ok(config) => {
|
|
|
|
let mut config: PeerConfig = config;
|
|
|
|
let mut store = false;
|
2022-07-27 21:30:02 +08:00
|
|
|
let (password, _, store2) =
|
2022-06-22 09:41:35 +08:00
|
|
|
decrypt_vec_or_original(&config.password, PASSWORD_ENC_VERSION);
|
|
|
|
config.password = password;
|
|
|
|
store = store || store2;
|
2023-03-30 11:17:24 +08:00
|
|
|
for opt in ["rdp_password", "os-username", "os-password"] {
|
2023-03-31 16:42:35 +08:00
|
|
|
if let Some(v) = config.options.get_mut(opt) {
|
2023-03-31 16:10:52 +08:00
|
|
|
let (encrypted, _, store2) =
|
|
|
|
decrypt_str_or_original(v, PASSWORD_ENC_VERSION);
|
2023-03-31 16:42:35 +08:00
|
|
|
*v = encrypted;
|
|
|
|
store = store || store2;
|
|
|
|
}
|
2023-01-27 11:42:08 +08:00
|
|
|
}
|
2022-06-22 09:41:35 +08:00
|
|
|
if store {
|
|
|
|
config.store(id);
|
|
|
|
}
|
|
|
|
config
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
Err(err) => {
|
2023-08-03 16:48:14 +08:00
|
|
|
if let confy::ConfyError::GeneralLoadError(err) = &err {
|
|
|
|
if err.kind() == std::io::ErrorKind::NotFound {
|
|
|
|
return Default::default();
|
|
|
|
}
|
|
|
|
}
|
2023-07-16 08:29:26 +08:00
|
|
|
log::error!("Failed to load peer config '{}': {}", id, err);
|
2021-03-29 15:59:14 +08:00
|
|
|
Default::default()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn store(&self, id: &str) {
|
2022-11-01 15:08:21 +01:00
|
|
|
let _lock = CONFIG.read().unwrap();
|
2022-06-22 09:41:35 +08:00
|
|
|
let mut config = self.clone();
|
2023-08-02 22:25:54 +08:00
|
|
|
config.password =
|
|
|
|
encrypt_vec_or_original(&config.password, PASSWORD_ENC_VERSION, ENCRYPT_MAX_LEN);
|
2023-03-30 11:17:24 +08:00
|
|
|
for opt in ["rdp_password", "os-username", "os-password"] {
|
2023-03-31 16:42:35 +08:00
|
|
|
if let Some(v) = config.options.get_mut(opt) {
|
2023-08-02 22:25:54 +08:00
|
|
|
*v = encrypt_str_or_original(v, PASSWORD_ENC_VERSION, ENCRYPT_MAX_LEN)
|
2023-03-31 16:42:35 +08:00
|
|
|
}
|
2023-01-27 11:42:08 +08:00
|
|
|
}
|
2022-07-30 02:01:40 +08:00
|
|
|
if let Err(err) = store_path(Self::path(id), config) {
|
2021-03-29 15:59:14 +08:00
|
|
|
log::error!("Failed to store config: {}", err);
|
|
|
|
}
|
2023-08-02 22:25:54 +08:00
|
|
|
NEW_STORED_PEER_CONFIG.lock().unwrap().insert(id.to_owned());
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn remove(id: &str) {
|
2023-01-27 11:42:08 +08:00
|
|
|
fs::remove_file(Self::path(id)).ok();
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn path(id: &str) -> PathBuf {
|
2022-11-23 15:07:56 +01:00
|
|
|
//If the id contains invalid chars, encode it
|
2023-05-02 12:52:27 +08:00
|
|
|
let forbidden_paths = Regex::new(r".*[<>:/\\|\?\*].*");
|
|
|
|
let path: PathBuf;
|
|
|
|
if let Ok(forbidden_paths) = forbidden_paths {
|
|
|
|
let id_encoded = if forbidden_paths.is_match(id) {
|
|
|
|
"base64_".to_string() + base64::encode(id, base64::Variant::Original).as_str()
|
|
|
|
} else {
|
|
|
|
id.to_string()
|
|
|
|
};
|
|
|
|
path = [PEERS, id_encoded.as_str()].iter().collect();
|
2022-11-23 15:07:56 +01:00
|
|
|
} else {
|
2023-05-02 12:52:27 +08:00
|
|
|
log::warn!("Regex create failed: {:?}", forbidden_paths.err());
|
|
|
|
// fallback for failing to create this regex.
|
|
|
|
path = [PEERS, id.replace(":", "_").as_str()].iter().collect();
|
|
|
|
}
|
2022-06-10 18:25:25 +08:00
|
|
|
Config::with_extension(Config::path(path))
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
2023-08-02 22:25:54 +08:00
|
|
|
pub fn peers(id_filters: Option<Vec<String>>) -> Vec<(String, SystemTime, PeerConfig)> {
|
2021-03-29 15:59:14 +08:00
|
|
|
if let Ok(peers) = Config::path(PEERS).read_dir() {
|
|
|
|
if let Ok(peers) = peers
|
|
|
|
.map(|res| res.map(|e| e.path()))
|
|
|
|
.collect::<Result<Vec<_>, _>>()
|
|
|
|
{
|
|
|
|
let mut peers: Vec<_> = peers
|
|
|
|
.iter()
|
|
|
|
.filter(|p| {
|
|
|
|
p.is_file()
|
|
|
|
&& p.extension().map(|p| p.to_str().unwrap_or("")) == Some("toml")
|
|
|
|
})
|
|
|
|
.map(|p| {
|
|
|
|
let id = p
|
|
|
|
.file_stem()
|
|
|
|
.map(|p| p.to_str().unwrap_or(""))
|
|
|
|
.unwrap_or("")
|
|
|
|
.to_owned();
|
2022-11-11 00:00:49 +01:00
|
|
|
|
2023-01-27 11:42:08 +08:00
|
|
|
let id_decoded_string = if id.starts_with("base64_") && id.len() != 7 {
|
2022-11-23 15:07:56 +01:00
|
|
|
let id_decoded = base64::decode(&id[7..], base64::Variant::Original)
|
2023-01-27 11:42:08 +08:00
|
|
|
.unwrap_or_default();
|
|
|
|
String::from_utf8_lossy(&id_decoded).as_ref().to_owned()
|
2022-11-23 15:07:56 +01:00
|
|
|
} else {
|
2023-01-27 11:42:08 +08:00
|
|
|
id
|
|
|
|
};
|
2023-08-02 22:25:54 +08:00
|
|
|
(id_decoded_string, p)
|
|
|
|
})
|
|
|
|
.filter(|(id, _)| {
|
|
|
|
let Some(filters) = &id_filters else {
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
filters.contains(id)
|
|
|
|
})
|
|
|
|
.map(|(id, p)| {
|
|
|
|
let t = crate::get_modified_time(p);
|
|
|
|
let c = PeerConfig::load(&id);
|
2023-07-05 09:58:00 +08:00
|
|
|
if c.info.platform.is_empty() {
|
|
|
|
fs::remove_file(p).ok();
|
|
|
|
}
|
2023-08-02 22:25:54 +08:00
|
|
|
(id, t, c)
|
2021-03-29 15:59:14 +08:00
|
|
|
})
|
2023-07-05 09:58:00 +08:00
|
|
|
.filter(|p| !p.2.info.platform.is_empty())
|
2021-03-29 15:59:14 +08:00
|
|
|
.collect();
|
|
|
|
peers.sort_unstable_by(|a, b| b.1.cmp(&a.1));
|
|
|
|
return peers;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Default::default()
|
|
|
|
}
|
2022-11-17 18:52:27 +08:00
|
|
|
|
2023-08-16 08:59:50 +08:00
|
|
|
pub fn exists(id: &str) -> bool {
|
|
|
|
Self::path(id).exists()
|
|
|
|
}
|
|
|
|
|
2022-11-23 15:21:54 +01:00
|
|
|
serde_field_string!(
|
|
|
|
default_view_style,
|
|
|
|
deserialize_view_style,
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
UserDefaultConfig::read(keys::OPTION_VIEW_STYLE)
|
2022-11-23 15:21:54 +01:00
|
|
|
);
|
|
|
|
serde_field_string!(
|
|
|
|
default_scroll_style,
|
|
|
|
deserialize_scroll_style,
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
UserDefaultConfig::read(keys::OPTION_SCROLL_STYLE)
|
2022-11-23 15:21:54 +01:00
|
|
|
);
|
|
|
|
serde_field_string!(
|
|
|
|
default_image_quality,
|
|
|
|
deserialize_image_quality,
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
UserDefaultConfig::read(keys::OPTION_IMAGE_QUALITY)
|
2022-11-23 15:21:54 +01:00
|
|
|
);
|
2023-09-10 14:14:57 +08:00
|
|
|
serde_field_string!(
|
2023-09-10 18:31:16 +08:00
|
|
|
default_reverse_mouse_wheel,
|
|
|
|
deserialize_reverse_mouse_wheel,
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
UserDefaultConfig::read(keys::OPTION_REVERSE_MOUSE_WHEEL)
|
2023-09-10 14:14:57 +08:00
|
|
|
);
|
2023-10-09 17:22:22 +08:00
|
|
|
serde_field_string!(
|
|
|
|
default_displays_as_individual_windows,
|
|
|
|
deserialize_displays_as_individual_windows,
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
UserDefaultConfig::read(keys::OPTION_DISPLAYS_AS_INDIVIDUAL_WINDOWS)
|
2023-10-09 17:22:22 +08:00
|
|
|
);
|
2023-10-17 00:30:34 +08:00
|
|
|
serde_field_string!(
|
2023-10-17 13:57:06 +08:00
|
|
|
default_use_all_my_displays_for_the_remote_session,
|
|
|
|
deserialize_use_all_my_displays_for_the_remote_session,
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
UserDefaultConfig::read(keys::OPTION_USE_ALL_MY_DISPLAYS_FOR_THE_REMOTE_SESSION)
|
2023-10-17 00:30:34 +08:00
|
|
|
);
|
2022-11-17 18:52:27 +08:00
|
|
|
|
2023-02-01 19:56:57 +08:00
|
|
|
fn default_custom_image_quality() -> Vec<i32> {
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
let f: f64 = UserDefaultConfig::read(keys::OPTION_CUSTOM_IMAGE_QUALITY)
|
2023-02-01 19:56:57 +08:00
|
|
|
.parse()
|
|
|
|
.unwrap_or(50.0);
|
|
|
|
vec![f as _]
|
|
|
|
}
|
|
|
|
|
|
|
|
fn deserialize_custom_image_quality<'de, D>(deserializer: D) -> Result<Vec<i32>, D::Error>
|
|
|
|
where
|
|
|
|
D: de::Deserializer<'de>,
|
|
|
|
{
|
|
|
|
let v: Vec<i32> = de::Deserialize::deserialize(deserializer)?;
|
2023-07-11 22:33:53 +02:00
|
|
|
if v.len() == 1 && v[0] >= 10 && v[0] <= 0xFFF {
|
2023-02-01 19:56:57 +08:00
|
|
|
Ok(v)
|
|
|
|
} else {
|
|
|
|
Ok(Self::default_custom_image_quality())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-31 22:06:39 +08:00
|
|
|
fn default_options() -> HashMap<String, String> {
|
|
|
|
let mut mp: HashMap<String, String> = Default::default();
|
2023-12-11 15:32:13 +08:00
|
|
|
[
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
keys::OPTION_CODEC_PREFERENCE,
|
|
|
|
keys::OPTION_CUSTOM_FPS,
|
|
|
|
keys::OPTION_ZOOM_CURSOR,
|
|
|
|
keys::OPTION_TOUCH_MODE,
|
|
|
|
keys::OPTION_I444,
|
|
|
|
keys::OPTION_SWAP_LEFT_RIGHT_MOUSE,
|
2023-12-11 15:32:13 +08:00
|
|
|
]
|
|
|
|
.map(|key| {
|
2024-03-23 20:20:12 -07:00
|
|
|
mp.insert(key.to_owned(), UserDefaultConfig::read(key));
|
2023-12-11 15:32:13 +08:00
|
|
|
});
|
2024-03-23 20:20:12 -07:00
|
|
|
mp
|
2022-11-17 18:52:27 +08:00
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|
|
|
|
|
2023-02-02 09:39:14 +08:00
|
|
|
serde_field_bool!(
|
|
|
|
ShowRemoteCursor,
|
|
|
|
"show_remote_cursor",
|
2023-03-01 11:55:56 +08:00
|
|
|
default_show_remote_cursor,
|
|
|
|
"ShowRemoteCursor::default_show_remote_cursor"
|
2023-02-02 09:39:14 +08:00
|
|
|
);
|
2024-04-25 10:56:02 +05:30
|
|
|
serde_field_bool!(
|
|
|
|
FollowRemoteCursor,
|
|
|
|
"follow_remote_cursor",
|
|
|
|
default_follow_remote_cursor,
|
|
|
|
"FollowRemoteCursor::default_follow_remote_cursor"
|
|
|
|
);
|
|
|
|
|
|
|
|
serde_field_bool!(
|
|
|
|
FollowRemoteWindow,
|
|
|
|
"follow_remote_window",
|
|
|
|
default_follow_remote_window,
|
|
|
|
"FollowRemoteWindow::default_follow_remote_window"
|
|
|
|
);
|
2023-02-02 09:39:14 +08:00
|
|
|
serde_field_bool!(
|
|
|
|
ShowQualityMonitor,
|
|
|
|
"show_quality_monitor",
|
2023-03-01 11:55:56 +08:00
|
|
|
default_show_quality_monitor,
|
|
|
|
"ShowQualityMonitor::default_show_quality_monitor"
|
2023-02-02 09:39:14 +08:00
|
|
|
);
|
2023-03-10 11:24:43 +08:00
|
|
|
serde_field_bool!(
|
|
|
|
DisableAudio,
|
|
|
|
"disable_audio",
|
|
|
|
default_disable_audio,
|
|
|
|
"DisableAudio::default_disable_audio"
|
|
|
|
);
|
2023-02-02 09:39:14 +08:00
|
|
|
serde_field_bool!(
|
2024-05-18 23:13:54 +08:00
|
|
|
EnableFileCopyPaste,
|
2024-05-19 20:41:19 +08:00
|
|
|
"enable-file-copy-paste",
|
2024-05-18 23:13:54 +08:00
|
|
|
default_enable_file_copy_paste,
|
|
|
|
"EnableFileCopyPaste::default_enable_file_copy_paste"
|
2023-02-02 09:39:14 +08:00
|
|
|
);
|
|
|
|
serde_field_bool!(
|
|
|
|
DisableClipboard,
|
|
|
|
"disable_clipboard",
|
2023-03-01 11:55:56 +08:00
|
|
|
default_disable_clipboard,
|
|
|
|
"DisableClipboard::default_disable_clipboard"
|
2023-02-02 09:39:14 +08:00
|
|
|
);
|
|
|
|
serde_field_bool!(
|
|
|
|
LockAfterSessionEnd,
|
|
|
|
"lock_after_session_end",
|
2023-03-01 11:55:56 +08:00
|
|
|
default_lock_after_session_end,
|
|
|
|
"LockAfterSessionEnd::default_lock_after_session_end"
|
2023-02-02 09:39:14 +08:00
|
|
|
);
|
2023-03-10 11:24:43 +08:00
|
|
|
serde_field_bool!(
|
|
|
|
PrivacyMode,
|
|
|
|
"privacy_mode",
|
|
|
|
default_privacy_mode,
|
|
|
|
"PrivacyMode::default_privacy_mode"
|
|
|
|
);
|
2023-02-02 09:39:14 +08:00
|
|
|
|
2023-03-10 11:24:43 +08:00
|
|
|
serde_field_bool!(
|
|
|
|
AllowSwapKey,
|
|
|
|
"allow_swap_key",
|
|
|
|
default_allow_swap_key,
|
|
|
|
"AllowSwapKey::default_allow_swap_key"
|
|
|
|
);
|
2023-02-09 11:54:23 +09:00
|
|
|
|
2023-03-17 11:27:22 +08:00
|
|
|
serde_field_bool!(
|
|
|
|
ViewOnly,
|
|
|
|
"view_only",
|
|
|
|
default_view_only,
|
|
|
|
"ViewOnly::default_view_only"
|
|
|
|
);
|
|
|
|
|
2022-01-02 21:56:04 +08:00
|
|
|
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
2022-04-26 11:19:45 +08:00
|
|
|
pub struct LocalConfig {
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_string")]
|
2022-04-26 11:19:45 +08:00
|
|
|
remote_id: String, // latest used one
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_string")]
|
2022-12-27 16:45:13 +08:00
|
|
|
kb_layout_type: String,
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_size")]
|
2022-04-26 11:19:45 +08:00
|
|
|
size: Size,
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_vec_string")]
|
2022-04-26 11:19:45 +08:00
|
|
|
pub fav: Vec<String>,
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_hashmap_string_string")]
|
2022-04-26 11:19:45 +08:00
|
|
|
options: HashMap<String, String>,
|
2022-11-10 21:25:12 +08:00
|
|
|
// Various data for flutter ui
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_hashmap_string_string")]
|
2022-11-10 21:25:12 +08:00
|
|
|
ui_flutter: HashMap<String, String>,
|
2022-01-02 21:56:04 +08:00
|
|
|
}
|
|
|
|
|
2022-04-26 11:19:45 +08:00
|
|
|
impl LocalConfig {
|
|
|
|
fn load() -> LocalConfig {
|
|
|
|
Config::load_::<LocalConfig>("_local")
|
|
|
|
}
|
|
|
|
|
|
|
|
fn store(&self) {
|
|
|
|
Config::store_(self, "_local");
|
|
|
|
}
|
|
|
|
|
2022-12-27 16:45:13 +08:00
|
|
|
pub fn get_kb_layout_type() -> String {
|
|
|
|
LOCAL_CONFIG.read().unwrap().kb_layout_type.clone()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_kb_layout_type(kb_layout_type: String) {
|
2022-12-27 17:49:32 +08:00
|
|
|
let mut config = LOCAL_CONFIG.write().unwrap();
|
|
|
|
config.kb_layout_type = kb_layout_type;
|
|
|
|
config.store();
|
2022-12-27 16:45:13 +08:00
|
|
|
}
|
|
|
|
|
2022-04-26 11:19:45 +08:00
|
|
|
pub fn get_size() -> Size {
|
|
|
|
LOCAL_CONFIG.read().unwrap().size
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_size(x: i32, y: i32, w: i32, h: i32) {
|
|
|
|
let mut config = LOCAL_CONFIG.write().unwrap();
|
|
|
|
let size = (x, y, w, h);
|
|
|
|
if size == config.size || size.2 < 300 || size.3 < 300 {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
config.size = size;
|
|
|
|
config.store();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_remote_id(remote_id: &str) {
|
|
|
|
let mut config = LOCAL_CONFIG.write().unwrap();
|
|
|
|
if remote_id == config.remote_id {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
config.remote_id = remote_id.into();
|
|
|
|
config.store();
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_remote_id() -> String {
|
|
|
|
LOCAL_CONFIG.read().unwrap().remote_id.clone()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_fav(fav: Vec<String>) {
|
|
|
|
let mut lock = LOCAL_CONFIG.write().unwrap();
|
|
|
|
if lock.fav == fav {
|
|
|
|
return;
|
2022-01-02 21:56:04 +08:00
|
|
|
}
|
2022-04-26 11:19:45 +08:00
|
|
|
lock.fav = fav;
|
|
|
|
lock.store();
|
2022-01-02 21:56:04 +08:00
|
|
|
}
|
|
|
|
|
2022-04-26 11:19:45 +08:00
|
|
|
pub fn get_fav() -> Vec<String> {
|
|
|
|
LOCAL_CONFIG.read().unwrap().fav.clone()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_option(k: &str) -> String {
|
2024-03-10 12:48:00 +08:00
|
|
|
get_or(
|
|
|
|
&OVERWRITE_LOCAL_SETTINGS,
|
|
|
|
&LOCAL_CONFIG.read().unwrap().options,
|
|
|
|
&DEFAULT_LOCAL_SETTINGS,
|
|
|
|
k,
|
|
|
|
)
|
|
|
|
.unwrap_or_default()
|
2022-04-26 11:19:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_option(k: String, v: String) {
|
2024-06-11 19:51:11 +08:00
|
|
|
if !is_option_can_save(&OVERWRITE_LOCAL_SETTINGS, &k, &DEFAULT_LOCAL_SETTINGS, &v) {
|
2024-03-16 01:51:16 +08:00
|
|
|
return;
|
|
|
|
}
|
2022-04-26 11:19:45 +08:00
|
|
|
let mut config = LOCAL_CONFIG.write().unwrap();
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
// The custom client will explictly set "default" as the default language.
|
|
|
|
let is_custom_client_default_lang = k == keys::OPTION_LANGUAGE && v == "default";
|
|
|
|
if is_custom_client_default_lang {
|
|
|
|
config.options.insert(k, "".to_owned());
|
|
|
|
config.store();
|
|
|
|
return;
|
|
|
|
}
|
2022-04-26 11:19:45 +08:00
|
|
|
let v2 = if v.is_empty() { None } else { Some(&v) };
|
|
|
|
if v2 != config.options.get(&k) {
|
|
|
|
if v2.is_none() {
|
|
|
|
config.options.remove(&k);
|
|
|
|
} else {
|
|
|
|
config.options.insert(k, v);
|
|
|
|
}
|
|
|
|
config.store();
|
2022-01-02 21:56:04 +08:00
|
|
|
}
|
|
|
|
}
|
2022-11-10 21:25:12 +08:00
|
|
|
|
2023-08-10 22:27:35 +08:00
|
|
|
pub fn get_flutter_option(k: &str) -> String {
|
2024-05-18 23:13:54 +08:00
|
|
|
get_or(
|
|
|
|
&OVERWRITE_LOCAL_SETTINGS,
|
|
|
|
&LOCAL_CONFIG.read().unwrap().ui_flutter,
|
|
|
|
&DEFAULT_LOCAL_SETTINGS,
|
|
|
|
k,
|
|
|
|
)
|
|
|
|
.unwrap_or_default()
|
2022-11-10 21:25:12 +08:00
|
|
|
}
|
|
|
|
|
2023-08-10 22:27:35 +08:00
|
|
|
pub fn set_flutter_option(k: String, v: String) {
|
2022-11-10 21:25:12 +08:00
|
|
|
let mut config = LOCAL_CONFIG.write().unwrap();
|
|
|
|
let v2 = if v.is_empty() { None } else { Some(&v) };
|
|
|
|
if v2 != config.ui_flutter.get(&k) {
|
|
|
|
if v2.is_none() {
|
|
|
|
config.ui_flutter.remove(&k);
|
|
|
|
} else {
|
|
|
|
config.ui_flutter.insert(k, v);
|
|
|
|
}
|
|
|
|
config.store();
|
|
|
|
}
|
|
|
|
}
|
2022-01-02 21:56:04 +08:00
|
|
|
}
|
|
|
|
|
2022-07-13 18:06:19 +08:00
|
|
|
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
|
|
|
pub struct DiscoveryPeer {
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_string")]
|
2022-07-13 18:06:19 +08:00
|
|
|
pub id: String,
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_string")]
|
2022-07-13 18:06:19 +08:00
|
|
|
pub username: String,
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_string")]
|
2022-07-13 18:06:19 +08:00
|
|
|
pub hostname: String,
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_string")]
|
2022-07-13 18:06:19 +08:00
|
|
|
pub platform: String,
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_bool")]
|
2022-07-13 18:06:19 +08:00
|
|
|
pub online: bool,
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_hashmap_string_string")]
|
2022-09-18 13:13:45 +08:00
|
|
|
pub ip_mac: HashMap<String, String>,
|
2022-07-13 18:06:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl DiscoveryPeer {
|
|
|
|
pub fn is_same_peer(&self, other: &DiscoveryPeer) -> bool {
|
|
|
|
self.id == other.id && self.username == other.username
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-12 03:10:15 +08:00
|
|
|
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
|
|
|
pub struct LanPeers {
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_vec_discoverypeer")]
|
2022-07-13 18:06:19 +08:00
|
|
|
pub peers: Vec<DiscoveryPeer>,
|
2022-01-12 03:10:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl LanPeers {
|
|
|
|
pub fn load() -> LanPeers {
|
2022-11-01 15:08:21 +01:00
|
|
|
let _lock = CONFIG.read().unwrap();
|
2023-01-27 11:42:08 +08:00
|
|
|
match confy::load_path(Config::file_("_lan_peers")) {
|
2022-01-12 03:10:15 +08:00
|
|
|
Ok(peers) => peers,
|
|
|
|
Err(err) => {
|
|
|
|
log::error!("Failed to load lan peers: {}", err);
|
|
|
|
Default::default()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-27 11:42:08 +08:00
|
|
|
pub fn store(peers: &[DiscoveryPeer]) {
|
2022-07-13 18:06:19 +08:00
|
|
|
let f = LanPeers {
|
2023-01-27 11:42:08 +08:00
|
|
|
peers: peers.to_owned(),
|
2022-07-13 18:06:19 +08:00
|
|
|
};
|
2022-07-30 02:01:40 +08:00
|
|
|
if let Err(err) = store_path(Config::file_("_lan_peers"), f) {
|
2022-01-12 03:10:15 +08:00
|
|
|
log::error!("Failed to store lan peers: {}", err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn modify_time() -> crate::ResultType<u64> {
|
|
|
|
let p = Config::file_("_lan_peers");
|
|
|
|
Ok(fs::metadata(p)?
|
|
|
|
.modified()?
|
|
|
|
.duration_since(SystemTime::UNIX_EPOCH)?
|
|
|
|
.as_millis() as _)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-01 19:56:57 +08:00
|
|
|
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
|
|
|
pub struct UserDefaultConfig {
|
2023-05-16 17:57:40 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_hashmap_string_string")]
|
2023-02-01 19:56:57 +08:00
|
|
|
options: HashMap<String, String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl UserDefaultConfig {
|
2024-03-08 00:22:52 +08:00
|
|
|
fn read(key: &str) -> String {
|
2023-03-10 11:24:43 +08:00
|
|
|
let mut cfg = USER_DEFAULT_CONFIG.write().unwrap();
|
2024-03-08 00:22:52 +08:00
|
|
|
// we do so, because default config may changed in another process, but we don't sync it
|
|
|
|
// but no need to read every time, give a small interval to avoid too many redundant read waste
|
2023-03-10 11:24:43 +08:00
|
|
|
if cfg.1.elapsed() > Duration::from_secs(1) {
|
|
|
|
*cfg = (Self::load(), Instant::now());
|
|
|
|
}
|
2024-03-08 00:22:52 +08:00
|
|
|
cfg.0.get(key)
|
2023-03-10 11:24:43 +08:00
|
|
|
}
|
|
|
|
|
2024-03-08 00:47:21 +08:00
|
|
|
pub fn load() -> UserDefaultConfig {
|
2023-02-01 19:56:57 +08:00
|
|
|
Config::load_::<UserDefaultConfig>("_default")
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn store(&self) {
|
|
|
|
Config::store_(self, "_default");
|
|
|
|
}
|
|
|
|
|
2024-03-08 00:47:21 +08:00
|
|
|
pub fn get(&self, key: &str) -> String {
|
2023-02-01 19:56:57 +08:00
|
|
|
match key {
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
keys::OPTION_VIEW_STYLE => self.get_string(key, "original", vec!["adaptive"]),
|
|
|
|
keys::OPTION_SCROLL_STYLE => self.get_string(key, "scrollauto", vec!["scrollbar"]),
|
|
|
|
keys::OPTION_IMAGE_QUALITY => {
|
|
|
|
self.get_string(key, "balanced", vec!["best", "low", "custom"])
|
|
|
|
}
|
|
|
|
keys::OPTION_CODEC_PREFERENCE => {
|
2023-05-08 20:35:24 +08:00
|
|
|
self.get_string(key, "auto", vec!["vp8", "vp9", "av1", "h264", "h265"])
|
|
|
|
}
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
keys::OPTION_CUSTOM_IMAGE_QUALITY => {
|
|
|
|
self.get_double_string(key, 50.0, 10.0, 0xFFF as f64)
|
|
|
|
}
|
|
|
|
keys::OPTION_CUSTOM_FPS => self.get_double_string(key, 30.0, 5.0, 120.0),
|
2024-05-18 23:13:54 +08:00
|
|
|
keys::OPTION_ENABLE_FILE_COPY_PASTE => self.get_string(key, "Y", vec!["", "N"]),
|
2023-02-01 19:56:57 +08:00
|
|
|
_ => self
|
2024-03-08 00:22:52 +08:00
|
|
|
.get_after(key)
|
2023-02-01 19:56:57 +08:00
|
|
|
.map(|v| v.to_string())
|
|
|
|
.unwrap_or_default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set(&mut self, key: String, value: String) {
|
2024-06-11 19:51:11 +08:00
|
|
|
if !is_option_can_save(
|
|
|
|
&OVERWRITE_DISPLAY_SETTINGS,
|
|
|
|
&key,
|
|
|
|
&DEFAULT_DISPLAY_SETTINGS,
|
|
|
|
&value,
|
|
|
|
) {
|
2024-03-16 01:51:16 +08:00
|
|
|
return;
|
|
|
|
}
|
2023-09-10 18:31:16 +08:00
|
|
|
if value.is_empty() {
|
|
|
|
self.options.remove(&key);
|
|
|
|
} else {
|
|
|
|
self.options.insert(key, value);
|
|
|
|
}
|
2023-02-01 19:56:57 +08:00
|
|
|
self.store();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn get_string(&self, key: &str, default: &str, others: Vec<&str>) -> String {
|
2024-03-08 00:22:52 +08:00
|
|
|
match self.get_after(key) {
|
2023-02-01 19:56:57 +08:00
|
|
|
Some(option) => {
|
|
|
|
if others.contains(&option.as_str()) {
|
|
|
|
option.to_owned()
|
|
|
|
} else {
|
|
|
|
default.to_owned()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => default.to_owned(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn get_double_string(&self, key: &str, default: f64, min: f64, max: f64) -> String {
|
2024-03-08 00:22:52 +08:00
|
|
|
match self.get_after(key) {
|
2023-02-01 19:56:57 +08:00
|
|
|
Some(option) => {
|
|
|
|
let v: f64 = option.parse().unwrap_or(default);
|
|
|
|
if v >= min && v <= max {
|
|
|
|
v.to_string()
|
|
|
|
} else {
|
|
|
|
default.to_string()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => default.to_string(),
|
|
|
|
}
|
|
|
|
}
|
2024-03-08 00:22:52 +08:00
|
|
|
|
2024-03-10 12:48:00 +08:00
|
|
|
fn get_after(&self, k: &str) -> Option<String> {
|
|
|
|
get_or(
|
|
|
|
&OVERWRITE_DISPLAY_SETTINGS,
|
|
|
|
&self.options,
|
|
|
|
&DEFAULT_DISPLAY_SETTINGS,
|
|
|
|
k,
|
|
|
|
)
|
2024-03-08 00:22:52 +08:00
|
|
|
}
|
2023-02-01 19:56:57 +08:00
|
|
|
}
|
|
|
|
|
2023-08-02 22:25:54 +08:00
|
|
|
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
|
|
|
pub struct AbPeer {
|
|
|
|
#[serde(
|
|
|
|
default,
|
|
|
|
deserialize_with = "deserialize_string",
|
|
|
|
skip_serializing_if = "String::is_empty"
|
|
|
|
)]
|
|
|
|
pub id: String,
|
|
|
|
#[serde(
|
|
|
|
default,
|
|
|
|
deserialize_with = "deserialize_string",
|
|
|
|
skip_serializing_if = "String::is_empty"
|
|
|
|
)]
|
|
|
|
pub hash: String,
|
2023-08-11 15:27:50 +08:00
|
|
|
#[serde(
|
|
|
|
default,
|
|
|
|
deserialize_with = "deserialize_string",
|
|
|
|
skip_serializing_if = "String::is_empty"
|
|
|
|
)]
|
|
|
|
pub username: String,
|
|
|
|
#[serde(
|
|
|
|
default,
|
|
|
|
deserialize_with = "deserialize_string",
|
|
|
|
skip_serializing_if = "String::is_empty"
|
|
|
|
)]
|
|
|
|
pub hostname: String,
|
|
|
|
#[serde(
|
|
|
|
default,
|
|
|
|
deserialize_with = "deserialize_string",
|
|
|
|
skip_serializing_if = "String::is_empty"
|
|
|
|
)]
|
|
|
|
pub platform: String,
|
2023-08-15 09:23:55 +08:00
|
|
|
#[serde(
|
|
|
|
default,
|
|
|
|
deserialize_with = "deserialize_string",
|
|
|
|
skip_serializing_if = "String::is_empty"
|
|
|
|
)]
|
|
|
|
pub alias: String,
|
2023-08-11 15:27:50 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_vec_string")]
|
|
|
|
pub tags: Vec<String>,
|
2023-08-02 22:25:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
2024-03-20 15:05:54 +08:00
|
|
|
pub struct AbEntry {
|
2023-08-02 22:25:54 +08:00
|
|
|
#[serde(
|
|
|
|
default,
|
|
|
|
deserialize_with = "deserialize_string",
|
|
|
|
skip_serializing_if = "String::is_empty"
|
|
|
|
)]
|
2024-03-20 15:05:54 +08:00
|
|
|
pub guid: String,
|
|
|
|
#[serde(
|
|
|
|
default,
|
|
|
|
deserialize_with = "deserialize_string",
|
|
|
|
skip_serializing_if = "String::is_empty"
|
|
|
|
)]
|
|
|
|
pub name: String,
|
2023-08-02 22:25:54 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_vec_abpeer")]
|
|
|
|
pub peers: Vec<AbPeer>,
|
2023-08-11 15:27:50 +08:00
|
|
|
#[serde(default, deserialize_with = "deserialize_vec_string")]
|
|
|
|
pub tags: Vec<String>,
|
2023-08-22 19:07:01 +08:00
|
|
|
#[serde(
|
|
|
|
default,
|
|
|
|
deserialize_with = "deserialize_string",
|
|
|
|
skip_serializing_if = "String::is_empty"
|
|
|
|
)]
|
|
|
|
pub tag_colors: String,
|
2023-08-02 22:25:54 +08:00
|
|
|
}
|
|
|
|
|
2024-03-20 15:05:54 +08:00
|
|
|
impl AbEntry {
|
|
|
|
pub fn personal(&self) -> bool {
|
|
|
|
self.name == "My address book" || self.name == "Legacy address book"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
|
|
|
pub struct Ab {
|
|
|
|
#[serde(
|
|
|
|
default,
|
|
|
|
deserialize_with = "deserialize_string",
|
|
|
|
skip_serializing_if = "String::is_empty"
|
|
|
|
)]
|
|
|
|
pub access_token: String,
|
|
|
|
#[serde(default, deserialize_with = "deserialize_vec_abentry")]
|
|
|
|
pub ab_entries: Vec<AbEntry>,
|
|
|
|
}
|
|
|
|
|
2023-08-02 22:25:54 +08:00
|
|
|
impl Ab {
|
|
|
|
fn path() -> PathBuf {
|
|
|
|
let filename = format!("{}_ab", APP_NAME.read().unwrap().clone());
|
|
|
|
Config::path(filename)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn store(json: String) {
|
|
|
|
if let Ok(mut file) = std::fs::File::create(Self::path()) {
|
|
|
|
let data = compress(json.as_bytes());
|
2023-08-04 15:32:09 +08:00
|
|
|
let max_len = 64 * 1024 * 1024;
|
2023-08-02 22:25:54 +08:00
|
|
|
if data.len() > max_len {
|
2023-08-04 15:32:09 +08:00
|
|
|
// maxlen of function decompress
|
2024-03-20 15:05:54 +08:00
|
|
|
log::error!("ab data too large, {} > {}", data.len(), max_len);
|
2023-08-02 22:25:54 +08:00
|
|
|
return;
|
|
|
|
}
|
2023-08-04 15:32:09 +08:00
|
|
|
if let Ok(data) = symmetric_crypt(&data, true) {
|
|
|
|
file.write_all(&data).ok();
|
|
|
|
}
|
2023-08-02 22:25:54 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn load() -> Ab {
|
|
|
|
if let Ok(mut file) = std::fs::File::open(Self::path()) {
|
|
|
|
let mut data = vec![];
|
|
|
|
if file.read_to_end(&mut data).is_ok() {
|
2023-08-04 15:32:09 +08:00
|
|
|
if let Ok(data) = symmetric_crypt(&data, false) {
|
2023-08-02 22:25:54 +08:00
|
|
|
let data = decompress(&data);
|
|
|
|
if let Ok(ab) = serde_json::from_str::<Ab>(&String::from_utf8_lossy(&data)) {
|
|
|
|
return ab;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2023-08-04 15:32:09 +08:00
|
|
|
Self::remove();
|
2023-08-02 22:25:54 +08:00
|
|
|
Ab::default()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn remove() {
|
|
|
|
std::fs::remove_file(Self::path()).ok();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-16 17:57:40 +08:00
|
|
|
// use default value when field type is wrong
|
|
|
|
macro_rules! deserialize_default {
|
|
|
|
($func_name:ident, $return_type:ty) => {
|
|
|
|
fn $func_name<'de, D>(deserializer: D) -> Result<$return_type, D::Error>
|
|
|
|
where
|
|
|
|
D: de::Deserializer<'de>,
|
|
|
|
{
|
|
|
|
Ok(de::Deserialize::deserialize(deserializer).unwrap_or_default())
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-09-14 10:17:03 +08:00
|
|
|
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
|
|
|
pub struct GroupPeer {
|
|
|
|
#[serde(
|
|
|
|
default,
|
|
|
|
deserialize_with = "deserialize_string",
|
|
|
|
skip_serializing_if = "String::is_empty"
|
|
|
|
)]
|
|
|
|
pub id: String,
|
|
|
|
#[serde(
|
|
|
|
default,
|
|
|
|
deserialize_with = "deserialize_string",
|
|
|
|
skip_serializing_if = "String::is_empty"
|
|
|
|
)]
|
|
|
|
pub username: String,
|
|
|
|
#[serde(
|
|
|
|
default,
|
|
|
|
deserialize_with = "deserialize_string",
|
|
|
|
skip_serializing_if = "String::is_empty"
|
|
|
|
)]
|
|
|
|
pub hostname: String,
|
|
|
|
#[serde(
|
|
|
|
default,
|
|
|
|
deserialize_with = "deserialize_string",
|
|
|
|
skip_serializing_if = "String::is_empty"
|
|
|
|
)]
|
|
|
|
pub platform: String,
|
|
|
|
#[serde(
|
|
|
|
default,
|
|
|
|
deserialize_with = "deserialize_string",
|
|
|
|
skip_serializing_if = "String::is_empty"
|
|
|
|
)]
|
|
|
|
pub login_name: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
|
|
|
pub struct GroupUser {
|
|
|
|
#[serde(
|
|
|
|
default,
|
|
|
|
deserialize_with = "deserialize_string",
|
|
|
|
skip_serializing_if = "String::is_empty"
|
|
|
|
)]
|
|
|
|
pub name: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
|
|
|
pub struct Group {
|
|
|
|
#[serde(
|
|
|
|
default,
|
|
|
|
deserialize_with = "deserialize_string",
|
|
|
|
skip_serializing_if = "String::is_empty"
|
|
|
|
)]
|
|
|
|
pub access_token: String,
|
|
|
|
#[serde(default, deserialize_with = "deserialize_vec_groupuser")]
|
|
|
|
pub users: Vec<GroupUser>,
|
|
|
|
#[serde(default, deserialize_with = "deserialize_vec_grouppeer")]
|
|
|
|
pub peers: Vec<GroupPeer>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Group {
|
|
|
|
fn path() -> PathBuf {
|
|
|
|
let filename = format!("{}_group", APP_NAME.read().unwrap().clone());
|
|
|
|
Config::path(filename)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn store(json: String) {
|
|
|
|
if let Ok(mut file) = std::fs::File::create(Self::path()) {
|
|
|
|
let data = compress(json.as_bytes());
|
|
|
|
let max_len = 64 * 1024 * 1024;
|
|
|
|
if data.len() > max_len {
|
|
|
|
// maxlen of function decompress
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if let Ok(data) = symmetric_crypt(&data, true) {
|
|
|
|
file.write_all(&data).ok();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn load() -> Self {
|
|
|
|
if let Ok(mut file) = std::fs::File::open(Self::path()) {
|
|
|
|
let mut data = vec![];
|
|
|
|
if file.read_to_end(&mut data).is_ok() {
|
|
|
|
if let Ok(data) = symmetric_crypt(&data, false) {
|
|
|
|
let data = decompress(&data);
|
|
|
|
if let Ok(group) = serde_json::from_str::<Self>(&String::from_utf8_lossy(&data))
|
|
|
|
{
|
|
|
|
return group;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
Self::remove();
|
|
|
|
Self::default()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn remove() {
|
|
|
|
std::fs::remove_file(Self::path()).ok();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-16 17:57:40 +08:00
|
|
|
deserialize_default!(deserialize_string, String);
|
|
|
|
deserialize_default!(deserialize_bool, bool);
|
|
|
|
deserialize_default!(deserialize_i32, i32);
|
|
|
|
deserialize_default!(deserialize_vec_u8, Vec<u8>);
|
|
|
|
deserialize_default!(deserialize_vec_string, Vec<String>);
|
|
|
|
deserialize_default!(deserialize_vec_i32_string_i32, Vec<(i32, String, i32)>);
|
|
|
|
deserialize_default!(deserialize_vec_discoverypeer, Vec<DiscoveryPeer>);
|
2023-08-02 22:25:54 +08:00
|
|
|
deserialize_default!(deserialize_vec_abpeer, Vec<AbPeer>);
|
2024-03-20 15:05:54 +08:00
|
|
|
deserialize_default!(deserialize_vec_abentry, Vec<AbEntry>);
|
2023-09-14 10:17:03 +08:00
|
|
|
deserialize_default!(deserialize_vec_groupuser, Vec<GroupUser>);
|
|
|
|
deserialize_default!(deserialize_vec_grouppeer, Vec<GroupPeer>);
|
2023-05-16 17:57:40 +08:00
|
|
|
deserialize_default!(deserialize_keypair, KeyPair);
|
|
|
|
deserialize_default!(deserialize_size, Size);
|
2023-06-20 21:15:46 +08:00
|
|
|
deserialize_default!(deserialize_hashmap_string_string, HashMap<String, String>);
|
2023-05-16 17:57:40 +08:00
|
|
|
deserialize_default!(deserialize_hashmap_string_bool, HashMap<String, bool>);
|
2023-06-05 19:50:24 +08:00
|
|
|
deserialize_default!(deserialize_hashmap_resolutions, HashMap<String, Resolution>);
|
2023-05-16 17:57:40 +08:00
|
|
|
|
2024-03-10 12:48:00 +08:00
|
|
|
#[inline]
|
|
|
|
fn get_or(
|
|
|
|
a: &RwLock<HashMap<String, String>>,
|
|
|
|
b: &HashMap<String, String>,
|
|
|
|
c: &RwLock<HashMap<String, String>>,
|
|
|
|
k: &str,
|
|
|
|
) -> Option<String> {
|
|
|
|
a.read()
|
|
|
|
.unwrap()
|
|
|
|
.get(k)
|
|
|
|
.or(b.get(k))
|
|
|
|
.or(c.read().unwrap().get(k))
|
|
|
|
.cloned()
|
|
|
|
}
|
|
|
|
|
2024-03-16 01:51:16 +08:00
|
|
|
#[inline]
|
2024-06-11 19:51:11 +08:00
|
|
|
fn is_option_can_save(
|
|
|
|
overwrite: &RwLock<HashMap<String, String>>,
|
|
|
|
k: &str,
|
|
|
|
defaults: &RwLock<HashMap<String, String>>,
|
|
|
|
v: &str,
|
|
|
|
) -> bool {
|
|
|
|
if overwrite.read().unwrap().contains_key(k)
|
|
|
|
|| defaults.read().unwrap().get(k).map_or(false, |x| x == v)
|
|
|
|
{
|
2024-03-16 01:51:16 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
2024-03-12 21:47:29 +08:00
|
|
|
#[inline]
|
|
|
|
pub fn is_incoming_only() -> bool {
|
|
|
|
HARD_SETTINGS
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.get("conn-type")
|
|
|
|
.map_or(false, |x| x == ("incoming"))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn is_outgoing_only() -> bool {
|
|
|
|
HARD_SETTINGS
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.get("conn-type")
|
|
|
|
.map_or(false, |x| x == ("outgoing"))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn is_some_hard_opton(name: &str) -> bool {
|
|
|
|
HARD_SETTINGS
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.get(name)
|
|
|
|
.map_or(false, |x| x == ("Y"))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn is_disable_tcp_listen() -> bool {
|
|
|
|
is_some_hard_opton("disable-tcp-listen")
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn is_disable_settings() -> bool {
|
|
|
|
is_some_hard_opton("disable-settings")
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn is_disable_ab() -> bool {
|
|
|
|
is_some_hard_opton("disable-ab")
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn is_disable_account() -> bool {
|
|
|
|
is_some_hard_opton("disable-account")
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn is_disable_installation() -> bool {
|
|
|
|
is_some_hard_opton("disable-installation")
|
|
|
|
}
|
|
|
|
|
2024-06-10 00:11:59 +08:00
|
|
|
// This function must be kept the same as the one in flutter and sciter code.
|
|
|
|
// flutter: flutter/lib/common.dart -> option2bool()
|
|
|
|
// sciter: Does not have the function, but it should be kept the same.
|
|
|
|
pub fn option2bool(option: &str, value: &str) -> bool {
|
|
|
|
if option.starts_with("enable-") {
|
|
|
|
value != "N"
|
|
|
|
} else if option.starts_with("allow-")
|
|
|
|
|| option == "stop-service"
|
|
|
|
|| option == keys::OPTION_DIRECT_SERVER
|
|
|
|
|| option == "force-always-relay"
|
|
|
|
{
|
|
|
|
value == "Y"
|
|
|
|
} else {
|
|
|
|
value != "N"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
pub mod keys {
|
|
|
|
pub const OPTION_VIEW_ONLY: &str = "view_only";
|
|
|
|
pub const OPTION_SHOW_MONITORS_TOOLBAR: &str = "show_monitors_toolbar";
|
|
|
|
pub const OPTION_COLLAPSE_TOOLBAR: &str = "collapse_toolbar";
|
|
|
|
pub const OPTION_SHOW_REMOTE_CURSOR: &str = "show_remote_cursor";
|
|
|
|
pub const OPTION_FOLLOW_REMOTE_CURSOR: &str = "follow_remote_cursor";
|
|
|
|
pub const OPTION_FOLLOW_REMOTE_WINDOW: &str = "follow_remote_window";
|
|
|
|
pub const OPTION_ZOOM_CURSOR: &str = "zoom-cursor";
|
|
|
|
pub const OPTION_SHOW_QUALITY_MONITOR: &str = "show_quality_monitor";
|
|
|
|
pub const OPTION_DISABLE_AUDIO: &str = "disable_audio";
|
2024-05-18 23:13:54 +08:00
|
|
|
pub const OPTION_ENABLE_FILE_COPY_PASTE: &str = "enable-file-copy-paste";
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
pub const OPTION_DISABLE_CLIPBOARD: &str = "disable_clipboard";
|
|
|
|
pub const OPTION_LOCK_AFTER_SESSION_END: &str = "lock_after_session_end";
|
|
|
|
pub const OPTION_PRIVACY_MODE: &str = "privacy_mode";
|
|
|
|
pub const OPTION_TOUCH_MODE: &str = "touch-mode";
|
|
|
|
pub const OPTION_I444: &str = "i444";
|
|
|
|
pub const OPTION_REVERSE_MOUSE_WHEEL: &str = "reverse_mouse_wheel";
|
|
|
|
pub const OPTION_SWAP_LEFT_RIGHT_MOUSE: &str = "swap-left-right-mouse";
|
|
|
|
pub const OPTION_DISPLAYS_AS_INDIVIDUAL_WINDOWS: &str = "displays_as_individual_windows";
|
|
|
|
pub const OPTION_USE_ALL_MY_DISPLAYS_FOR_THE_REMOTE_SESSION: &str =
|
|
|
|
"use_all_my_displays_for_the_remote_session";
|
|
|
|
pub const OPTION_VIEW_STYLE: &str = "view_style";
|
|
|
|
pub const OPTION_SCROLL_STYLE: &str = "scroll_style";
|
|
|
|
pub const OPTION_IMAGE_QUALITY: &str = "image_quality";
|
|
|
|
pub const OPTION_CUSTOM_IMAGE_QUALITY: &str = "custom_image_quality";
|
|
|
|
pub const OPTION_CUSTOM_FPS: &str = "custom-fps";
|
|
|
|
pub const OPTION_CODEC_PREFERENCE: &str = "codec-preference";
|
|
|
|
pub const OPTION_THEME: &str = "theme";
|
|
|
|
pub const OPTION_LANGUAGE: &str = "lang";
|
2024-05-18 23:13:54 +08:00
|
|
|
pub const OPTION_REMOTE_MENUBAR_DRAG_LEFT: &str = "remote-menubar-drag-left";
|
|
|
|
pub const OPTION_REMOTE_MENUBAR_DRAG_RIGHT: &str = "remote-menubar-drag-right";
|
|
|
|
pub const OPTION_HIDE_AB_TAGS_PANEL: &str = "hideAbTagsPanel";
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
pub const OPTION_ENABLE_CONFIRM_CLOSING_TABS: &str = "enable-confirm-closing-tabs";
|
|
|
|
pub const OPTION_ENABLE_OPEN_NEW_CONNECTIONS_IN_TABS: &str =
|
|
|
|
"enable-open-new-connections-in-tabs";
|
2024-05-28 16:42:30 +08:00
|
|
|
pub const OPTION_TEXTURE_RENDER: &str = "use-texture-render";
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
pub const OPTION_ENABLE_CHECK_UPDATE: &str = "enable-check-update";
|
|
|
|
pub const OPTION_SYNC_AB_WITH_RECENT_SESSIONS: &str = "sync-ab-with-recent-sessions";
|
|
|
|
pub const OPTION_SYNC_AB_TAGS: &str = "sync-ab-tags";
|
|
|
|
pub const OPTION_FILTER_AB_BY_INTERSECTION: &str = "filter-ab-by-intersection";
|
|
|
|
pub const OPTION_ACCESS_MODE: &str = "access-mode";
|
|
|
|
pub const OPTION_ENABLE_KEYBOARD: &str = "enable-keyboard";
|
|
|
|
pub const OPTION_ENABLE_CLIPBOARD: &str = "enable-clipboard";
|
|
|
|
pub const OPTION_ENABLE_FILE_TRANSFER: &str = "enable-file-transfer";
|
|
|
|
pub const OPTION_ENABLE_AUDIO: &str = "enable-audio";
|
|
|
|
pub const OPTION_ENABLE_TUNNEL: &str = "enable-tunnel";
|
|
|
|
pub const OPTION_ENABLE_REMOTE_RESTART: &str = "enable-remote-restart";
|
|
|
|
pub const OPTION_ENABLE_RECORD_SESSION: &str = "enable-record-session";
|
|
|
|
pub const OPTION_ENABLE_BLOCK_INPUT: &str = "enable-block-input";
|
|
|
|
pub const OPTION_ALLOW_REMOTE_CONFIG_MODIFICATION: &str = "allow-remote-config-modification";
|
|
|
|
pub const OPTION_ENABLE_LAN_DISCOVERY: &str = "enable-lan-discovery";
|
|
|
|
pub const OPTION_DIRECT_SERVER: &str = "direct-server";
|
|
|
|
pub const OPTION_DIRECT_ACCESS_PORT: &str = "direct-access-port";
|
|
|
|
pub const OPTION_WHITELIST: &str = "whitelist";
|
|
|
|
pub const OPTION_ALLOW_AUTO_DISCONNECT: &str = "allow-auto-disconnect";
|
|
|
|
pub const OPTION_AUTO_DISCONNECT_TIMEOUT: &str = "auto-disconnect-timeout";
|
|
|
|
pub const OPTION_ALLOW_ONLY_CONN_WINDOW_OPEN: &str = "allow-only-conn-window-open";
|
|
|
|
pub const OPTION_ALLOW_AUTO_RECORD_INCOMING: &str = "allow-auto-record-incoming";
|
|
|
|
pub const OPTION_VIDEO_SAVE_DIRECTORY: &str = "video-save-directory";
|
|
|
|
pub const OPTION_ENABLE_ABR: &str = "enable-abr";
|
|
|
|
pub const OPTION_ALLOW_REMOVE_WALLPAPER: &str = "allow-remove-wallpaper";
|
|
|
|
pub const OPTION_ALLOW_ALWAYS_SOFTWARE_RENDER: &str = "allow-always-software-render";
|
|
|
|
pub const OPTION_ALLOW_LINUX_HEADLESS: &str = "allow-linux-headless";
|
|
|
|
pub const OPTION_ENABLE_HWCODEC: &str = "enable-hwcodec";
|
|
|
|
pub const OPTION_APPROVE_MODE: &str = "approve-mode";
|
2024-06-11 19:51:11 +08:00
|
|
|
pub const OPTION_CUSTOM_RENDEZVOUS_SERVER: &str = "custom-rendezvous-server";
|
|
|
|
pub const OPTION_API_SERVER: &str = "api-server";
|
|
|
|
pub const OPTION_KEY: &str = "key";
|
|
|
|
pub const OPTION_PRESET_ADDRESS_BOOK_NAME: &str = "preset-address-book-name";
|
|
|
|
pub const OPTION_PRESET_ADDRESS_BOOK_TAG: &str = "preset-address-book-tag";
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
|
2024-05-18 23:13:54 +08:00
|
|
|
// flutter local options
|
|
|
|
pub const OPTION_FLUTTER_REMOTE_MENUBAR_STATE: &str = "remoteMenubarState";
|
|
|
|
pub const OPTION_FLUTTER_PEER_SORTING: &str = "peer-sorting";
|
|
|
|
pub const OPTION_FLUTTER_PEER_TAB_INDEX: &str = "peer-tab-index";
|
|
|
|
pub const OPTION_FLUTTER_PEER_TAB_ORDER: &str = "peer-tab-order";
|
|
|
|
pub const OPTION_FLUTTER_PEER_TAB_VISIBLE: &str = "peer-tab-visible";
|
|
|
|
pub const OPTION_FLUTTER_PEER_CARD_UI_TYLE: &str = "peer-card-ui-type";
|
|
|
|
pub const OPTION_FLUTTER_CURRENT_AB_NAME: &str = "current-ab-name";
|
|
|
|
|
2024-06-05 23:11:44 +08:00
|
|
|
// android floating window options
|
|
|
|
pub const OPTION_DISABLE_FLOATING_WINDOW: &str = "disable-floating-window";
|
|
|
|
pub const OPTION_FLOATING_WINDOW_SIZE: &str = "floating-window-size";
|
2024-06-07 11:04:18 +08:00
|
|
|
pub const OPTION_FLOATING_WINDOW_UNTOUCHABLE: &str = "floating-window-untouchable";
|
2024-06-05 23:11:44 +08:00
|
|
|
pub const OPTION_FLOATING_WINDOW_TRANSPARENCY: &str = "floating-window-transparency";
|
|
|
|
pub const OPTION_FLOATING_WINDOW_SVG: &str = "floating-window-svg";
|
|
|
|
|
2024-06-13 18:30:29 +08:00
|
|
|
// android keep screen on
|
|
|
|
pub const OPTION_KEEP_SCREEN_ON: &str = "keep-screen-on";
|
|
|
|
|
2024-06-11 19:51:11 +08:00
|
|
|
pub const OPTION_DISABLE_GROUP_PANEL: &str = "disable-group-panel";
|
|
|
|
pub const OPTION_PRE_ELEVATE_SERVICE: &str = "pre-elevate-service";
|
|
|
|
|
2024-05-19 16:40:49 +08:00
|
|
|
// proxy settings
|
|
|
|
// The following options are not real keys, they are just used for custom client advanced settings.
|
|
|
|
// The real keys are in Config2::socks.
|
|
|
|
pub const OPTION_PROXY_URL: &str = "proxy-url";
|
|
|
|
pub const OPTION_PROXY_USERNAME: &str = "proxy-username";
|
|
|
|
pub const OPTION_PROXY_PASSWORD: &str = "proxy-password";
|
|
|
|
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
// DEFAULT_DISPLAY_SETTINGS, OVERWRITE_DISPLAY_SETTINGS
|
|
|
|
pub const KEYS_DISPLAY_SETTINGS: &[&str] = &[
|
|
|
|
OPTION_VIEW_ONLY,
|
|
|
|
OPTION_SHOW_MONITORS_TOOLBAR,
|
|
|
|
OPTION_COLLAPSE_TOOLBAR,
|
|
|
|
OPTION_SHOW_REMOTE_CURSOR,
|
|
|
|
OPTION_FOLLOW_REMOTE_CURSOR,
|
|
|
|
OPTION_FOLLOW_REMOTE_WINDOW,
|
|
|
|
OPTION_ZOOM_CURSOR,
|
|
|
|
OPTION_SHOW_QUALITY_MONITOR,
|
|
|
|
OPTION_DISABLE_AUDIO,
|
2024-05-18 23:13:54 +08:00
|
|
|
OPTION_ENABLE_FILE_COPY_PASTE,
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
OPTION_DISABLE_CLIPBOARD,
|
|
|
|
OPTION_LOCK_AFTER_SESSION_END,
|
|
|
|
OPTION_PRIVACY_MODE,
|
|
|
|
OPTION_TOUCH_MODE,
|
|
|
|
OPTION_I444,
|
|
|
|
OPTION_REVERSE_MOUSE_WHEEL,
|
|
|
|
OPTION_SWAP_LEFT_RIGHT_MOUSE,
|
|
|
|
OPTION_DISPLAYS_AS_INDIVIDUAL_WINDOWS,
|
|
|
|
OPTION_USE_ALL_MY_DISPLAYS_FOR_THE_REMOTE_SESSION,
|
|
|
|
OPTION_VIEW_STYLE,
|
|
|
|
OPTION_SCROLL_STYLE,
|
|
|
|
OPTION_IMAGE_QUALITY,
|
|
|
|
OPTION_CUSTOM_IMAGE_QUALITY,
|
|
|
|
OPTION_CUSTOM_FPS,
|
|
|
|
OPTION_CODEC_PREFERENCE,
|
|
|
|
];
|
|
|
|
// DEFAULT_LOCAL_SETTINGS, OVERWRITE_LOCAL_SETTINGS
|
|
|
|
pub const KEYS_LOCAL_SETTINGS: &[&str] = &[
|
|
|
|
OPTION_THEME,
|
|
|
|
OPTION_LANGUAGE,
|
|
|
|
OPTION_ENABLE_CONFIRM_CLOSING_TABS,
|
|
|
|
OPTION_ENABLE_OPEN_NEW_CONNECTIONS_IN_TABS,
|
2024-05-28 16:42:30 +08:00
|
|
|
OPTION_TEXTURE_RENDER,
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
OPTION_SYNC_AB_WITH_RECENT_SESSIONS,
|
|
|
|
OPTION_SYNC_AB_TAGS,
|
|
|
|
OPTION_FILTER_AB_BY_INTERSECTION,
|
2024-05-18 23:13:54 +08:00
|
|
|
OPTION_REMOTE_MENUBAR_DRAG_LEFT,
|
|
|
|
OPTION_REMOTE_MENUBAR_DRAG_RIGHT,
|
|
|
|
OPTION_HIDE_AB_TAGS_PANEL,
|
|
|
|
OPTION_FLUTTER_REMOTE_MENUBAR_STATE,
|
|
|
|
OPTION_FLUTTER_PEER_SORTING,
|
|
|
|
OPTION_FLUTTER_PEER_TAB_INDEX,
|
|
|
|
OPTION_FLUTTER_PEER_TAB_ORDER,
|
|
|
|
OPTION_FLUTTER_PEER_TAB_VISIBLE,
|
|
|
|
OPTION_FLUTTER_PEER_CARD_UI_TYLE,
|
|
|
|
OPTION_FLUTTER_CURRENT_AB_NAME,
|
2024-06-05 23:11:44 +08:00
|
|
|
OPTION_DISABLE_FLOATING_WINDOW,
|
|
|
|
OPTION_FLOATING_WINDOW_SIZE,
|
2024-06-07 11:04:18 +08:00
|
|
|
OPTION_FLOATING_WINDOW_UNTOUCHABLE,
|
2024-06-05 23:11:44 +08:00
|
|
|
OPTION_FLOATING_WINDOW_TRANSPARENCY,
|
|
|
|
OPTION_FLOATING_WINDOW_SVG,
|
2024-06-13 18:30:29 +08:00
|
|
|
OPTION_KEEP_SCREEN_ON,
|
2024-06-11 19:51:11 +08:00
|
|
|
OPTION_DISABLE_GROUP_PANEL,
|
|
|
|
OPTION_PRE_ELEVATE_SERVICE,
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
];
|
|
|
|
// DEFAULT_SETTINGS, OVERWRITE_SETTINGS
|
|
|
|
pub const KEYS_SETTINGS: &[&str] = &[
|
|
|
|
OPTION_ACCESS_MODE,
|
|
|
|
OPTION_ENABLE_KEYBOARD,
|
|
|
|
OPTION_ENABLE_CLIPBOARD,
|
|
|
|
OPTION_ENABLE_FILE_TRANSFER,
|
|
|
|
OPTION_ENABLE_AUDIO,
|
|
|
|
OPTION_ENABLE_TUNNEL,
|
|
|
|
OPTION_ENABLE_REMOTE_RESTART,
|
|
|
|
OPTION_ENABLE_RECORD_SESSION,
|
|
|
|
OPTION_ENABLE_BLOCK_INPUT,
|
|
|
|
OPTION_ALLOW_REMOTE_CONFIG_MODIFICATION,
|
|
|
|
OPTION_ENABLE_LAN_DISCOVERY,
|
|
|
|
OPTION_DIRECT_SERVER,
|
|
|
|
OPTION_DIRECT_ACCESS_PORT,
|
|
|
|
OPTION_WHITELIST,
|
|
|
|
OPTION_ALLOW_AUTO_DISCONNECT,
|
|
|
|
OPTION_AUTO_DISCONNECT_TIMEOUT,
|
|
|
|
OPTION_ALLOW_ONLY_CONN_WINDOW_OPEN,
|
|
|
|
OPTION_ALLOW_AUTO_RECORD_INCOMING,
|
|
|
|
OPTION_VIDEO_SAVE_DIRECTORY,
|
|
|
|
OPTION_ENABLE_ABR,
|
|
|
|
OPTION_ALLOW_REMOVE_WALLPAPER,
|
|
|
|
OPTION_ALLOW_ALWAYS_SOFTWARE_RENDER,
|
|
|
|
OPTION_ALLOW_LINUX_HEADLESS,
|
|
|
|
OPTION_ENABLE_HWCODEC,
|
|
|
|
OPTION_APPROVE_MODE,
|
2024-05-19 16:40:49 +08:00
|
|
|
OPTION_PROXY_URL,
|
|
|
|
OPTION_PROXY_USERNAME,
|
|
|
|
OPTION_PROXY_PASSWORD,
|
2024-06-11 19:51:11 +08:00
|
|
|
OPTION_CUSTOM_RENDEZVOUS_SERVER,
|
|
|
|
OPTION_API_SERVER,
|
|
|
|
OPTION_KEY,
|
|
|
|
OPTION_PRESET_ADDRESS_BOOK_NAME,
|
|
|
|
OPTION_PRESET_ADDRESS_BOOK_TAG,
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
];
|
|
|
|
}
|
|
|
|
|
hwcodec, only process that start ipc server start check process (#8325)
check process send config to ipc server, other process get config from ipc server. Process will save config to toml, and the toml will be used if the config is none.
when start check process: ipc server process start or option changed
from disable to enable
when get config: main window start or option changed from disable to
enable, start_video_audio_threads.
Only windows implements signature, which is used to mark whether the gpu software and hardware information changes. After reboot, the signature doesn't change. https://asawicki.info/news_1773_how_to_programmatically_check_graphics_driver_version, use dxgi way to get software version, it's not consistent with the visible driver version, after updating intel driver with small version change, the signature doesn't change. Linux doesn't use toml file.
Signed-off-by: 21pages <sunboeasy@gmail.com>
2024-06-12 20:40:35 +08:00
|
|
|
pub fn common_load<
|
|
|
|
T: serde::Serialize + serde::de::DeserializeOwned + Default + std::fmt::Debug,
|
|
|
|
>(
|
|
|
|
suffix: &str,
|
|
|
|
) -> T {
|
|
|
|
Config::load_::<T>(suffix)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn common_store<T: serde::Serialize>(config: &T, suffix: &str) {
|
|
|
|
Config::store_(config, suffix);
|
|
|
|
}
|
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
2022-05-08 21:01:03 +08:00
|
|
|
|
2021-03-29 15:59:14 +08:00
|
|
|
#[test]
|
|
|
|
fn test_serialize() {
|
|
|
|
let cfg: Config = Default::default();
|
|
|
|
let res = toml::to_string_pretty(&cfg);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
let cfg: PeerConfig = Default::default();
|
|
|
|
let res = toml::to_string_pretty(&cfg);
|
|
|
|
assert!(res.is_ok());
|
|
|
|
}
|
2023-05-16 17:57:40 +08:00
|
|
|
|
2024-03-08 00:22:52 +08:00
|
|
|
#[test]
|
|
|
|
fn test_overwrite_settings() {
|
|
|
|
DEFAULT_SETTINGS
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.insert("b".to_string(), "a".to_string());
|
|
|
|
DEFAULT_SETTINGS
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.insert("c".to_string(), "a".to_string());
|
|
|
|
CONFIG2
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.options
|
|
|
|
.insert("a".to_string(), "b".to_string());
|
|
|
|
CONFIG2
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.options
|
|
|
|
.insert("b".to_string(), "b".to_string());
|
|
|
|
OVERWRITE_SETTINGS
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.insert("b".to_string(), "c".to_string());
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
OVERWRITE_SETTINGS
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.insert("c".to_string(), "f".to_string());
|
2024-03-08 00:22:52 +08:00
|
|
|
OVERWRITE_SETTINGS
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.insert("d".to_string(), "c".to_string());
|
2024-03-16 01:51:16 +08:00
|
|
|
let mut res: HashMap<String, String> = Default::default();
|
|
|
|
res.insert("b".to_owned(), "c".to_string());
|
|
|
|
res.insert("d".to_owned(), "c".to_string());
|
|
|
|
res.insert("c".to_owned(), "a".to_string());
|
|
|
|
Config::purify_options(&mut res);
|
|
|
|
assert!(res.len() == 0);
|
|
|
|
res.insert("b".to_owned(), "c".to_string());
|
|
|
|
res.insert("d".to_owned(), "c".to_string());
|
|
|
|
res.insert("c".to_owned(), "a".to_string());
|
|
|
|
res.insert("f".to_owned(), "a".to_string());
|
|
|
|
Config::purify_options(&mut res);
|
|
|
|
assert!(res.len() == 1);
|
|
|
|
res.insert("b".to_owned(), "c".to_string());
|
|
|
|
res.insert("d".to_owned(), "c".to_string());
|
|
|
|
res.insert("c".to_owned(), "a".to_string());
|
|
|
|
res.insert("f".to_owned(), "a".to_string());
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
res.insert("e".to_owned(), "d".to_string());
|
2024-03-16 01:51:16 +08:00
|
|
|
Config::purify_options(&mut res);
|
|
|
|
assert!(res.len() == 2);
|
|
|
|
res.insert("b".to_owned(), "c".to_string());
|
|
|
|
res.insert("d".to_owned(), "c".to_string());
|
|
|
|
res.insert("c".to_owned(), "a".to_string());
|
|
|
|
res.insert("f".to_owned(), "a".to_string());
|
|
|
|
res.insert("c".to_owned(), "d".to_string());
|
|
|
|
res.insert("d".to_owned(), "cc".to_string());
|
|
|
|
Config::purify_options(&mut res);
|
2024-06-11 19:51:11 +08:00
|
|
|
DEFAULT_SETTINGS
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.insert("f".to_string(), "c".to_string());
|
|
|
|
Config::purify_options(&mut res);
|
2024-03-16 01:51:16 +08:00
|
|
|
assert!(res.len() == 2);
|
2024-06-11 19:51:11 +08:00
|
|
|
DEFAULT_SETTINGS
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.insert("f".to_string(), "a".to_string());
|
|
|
|
Config::purify_options(&mut res);
|
|
|
|
assert!(res.len() == 1);
|
2024-03-08 00:22:52 +08:00
|
|
|
let res = Config::get_options();
|
|
|
|
assert!(res["a"] == "b");
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
assert!(res["c"] == "f");
|
2024-03-08 00:22:52 +08:00
|
|
|
assert!(res["b"] == "c");
|
|
|
|
assert!(res["d"] == "c");
|
|
|
|
assert!(Config::get_option("a") == "b");
|
Fix/custom client advanced settings (#8066)
* fix: custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, default options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: cargo test
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: remove prefix $ and unify option keys
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* refact: custom client, advanced options
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* debug custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings. Add filter-transfer to display settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* custom client, advanced settings
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, codec
Signed-off-by: fufesou <shuanglongchen@yeah.net>
* fix: custom client, advanced settings, whitelist
Signed-off-by: fufesou <shuanglongchen@yeah.net>
---------
Signed-off-by: fufesou <shuanglongchen@yeah.net>
2024-05-17 14:19:11 +08:00
|
|
|
assert!(Config::get_option("c") == "f");
|
2024-03-08 00:22:52 +08:00
|
|
|
assert!(Config::get_option("b") == "c");
|
|
|
|
assert!(Config::get_option("d") == "c");
|
|
|
|
DEFAULT_SETTINGS.write().unwrap().clear();
|
|
|
|
OVERWRITE_SETTINGS.write().unwrap().clear();
|
|
|
|
CONFIG2.write().unwrap().options.clear();
|
|
|
|
|
|
|
|
DEFAULT_LOCAL_SETTINGS
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.insert("b".to_string(), "a".to_string());
|
|
|
|
DEFAULT_LOCAL_SETTINGS
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.insert("c".to_string(), "a".to_string());
|
|
|
|
LOCAL_CONFIG
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.options
|
|
|
|
.insert("a".to_string(), "b".to_string());
|
|
|
|
LOCAL_CONFIG
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.options
|
|
|
|
.insert("b".to_string(), "b".to_string());
|
|
|
|
OVERWRITE_LOCAL_SETTINGS
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.insert("b".to_string(), "c".to_string());
|
|
|
|
OVERWRITE_LOCAL_SETTINGS
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.insert("d".to_string(), "c".to_string());
|
|
|
|
assert!(LocalConfig::get_option("a") == "b");
|
|
|
|
assert!(LocalConfig::get_option("c") == "a");
|
|
|
|
assert!(LocalConfig::get_option("b") == "c");
|
|
|
|
assert!(LocalConfig::get_option("d") == "c");
|
|
|
|
DEFAULT_LOCAL_SETTINGS.write().unwrap().clear();
|
|
|
|
OVERWRITE_LOCAL_SETTINGS.write().unwrap().clear();
|
|
|
|
LOCAL_CONFIG.write().unwrap().options.clear();
|
|
|
|
|
|
|
|
DEFAULT_DISPLAY_SETTINGS
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.insert("b".to_string(), "a".to_string());
|
|
|
|
DEFAULT_DISPLAY_SETTINGS
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.insert("c".to_string(), "a".to_string());
|
|
|
|
USER_DEFAULT_CONFIG
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.0
|
|
|
|
.options
|
|
|
|
.insert("a".to_string(), "b".to_string());
|
|
|
|
USER_DEFAULT_CONFIG
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.0
|
|
|
|
.options
|
|
|
|
.insert("b".to_string(), "b".to_string());
|
|
|
|
OVERWRITE_DISPLAY_SETTINGS
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.insert("b".to_string(), "c".to_string());
|
|
|
|
OVERWRITE_DISPLAY_SETTINGS
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.insert("d".to_string(), "c".to_string());
|
|
|
|
assert!(UserDefaultConfig::read("a") == "b");
|
|
|
|
assert!(UserDefaultConfig::read("c") == "a");
|
|
|
|
assert!(UserDefaultConfig::read("b") == "c");
|
|
|
|
assert!(UserDefaultConfig::read("d") == "c");
|
|
|
|
DEFAULT_DISPLAY_SETTINGS.write().unwrap().clear();
|
|
|
|
OVERWRITE_DISPLAY_SETTINGS.write().unwrap().clear();
|
|
|
|
LOCAL_CONFIG.write().unwrap().options.clear();
|
|
|
|
}
|
|
|
|
|
2023-05-16 17:57:40 +08:00
|
|
|
#[test]
|
|
|
|
fn test_config_deserialize() {
|
|
|
|
let wrong_type_str = r#"
|
|
|
|
id = true
|
|
|
|
enc_id = []
|
|
|
|
password = 1
|
|
|
|
salt = "123456"
|
|
|
|
key_pair = {}
|
|
|
|
key_confirmed = "1"
|
|
|
|
keys_confirmed = 1
|
|
|
|
"#;
|
|
|
|
let cfg = toml::from_str::<Config>(wrong_type_str);
|
|
|
|
assert_eq!(
|
|
|
|
cfg,
|
|
|
|
Ok(Config {
|
|
|
|
salt: "123456".to_string(),
|
|
|
|
..Default::default()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
|
|
|
|
let wrong_field_str = r#"
|
|
|
|
hello = "world"
|
|
|
|
key_confirmed = true
|
|
|
|
"#;
|
|
|
|
let cfg = toml::from_str::<Config>(wrong_field_str);
|
|
|
|
assert_eq!(
|
|
|
|
cfg,
|
|
|
|
Ok(Config {
|
|
|
|
key_confirmed: true,
|
|
|
|
..Default::default()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
2023-05-19 11:10:24 +08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_peer_config_deserialize() {
|
|
|
|
let default_peer_config = toml::from_str::<PeerConfig>("").unwrap();
|
|
|
|
// test custom_resolution
|
|
|
|
{
|
|
|
|
let wrong_type_str = r#"
|
|
|
|
view_style = "adaptive"
|
|
|
|
scroll_style = "scrollbar"
|
2023-06-05 20:21:21 +08:00
|
|
|
custom_resolutions = true
|
|
|
|
"#;
|
|
|
|
let mut cfg_to_compare = default_peer_config.clone();
|
|
|
|
cfg_to_compare.view_style = "adaptive".to_string();
|
|
|
|
cfg_to_compare.scroll_style = "scrollbar".to_string();
|
|
|
|
let cfg = toml::from_str::<PeerConfig>(wrong_type_str);
|
|
|
|
assert_eq!(cfg, Ok(cfg_to_compare), "Failed to test wrong_type_str");
|
|
|
|
|
|
|
|
let wrong_type_str = r#"
|
|
|
|
view_style = "adaptive"
|
|
|
|
scroll_style = "scrollbar"
|
|
|
|
[custom_resolutions.0]
|
|
|
|
w = "1920"
|
|
|
|
h = 1080
|
2023-05-19 11:10:24 +08:00
|
|
|
"#;
|
2023-05-19 11:43:35 +08:00
|
|
|
let mut cfg_to_compare = default_peer_config.clone();
|
|
|
|
cfg_to_compare.view_style = "adaptive".to_string();
|
|
|
|
cfg_to_compare.scroll_style = "scrollbar".to_string();
|
2023-05-19 11:10:24 +08:00
|
|
|
let cfg = toml::from_str::<PeerConfig>(wrong_type_str);
|
2023-05-19 11:43:35 +08:00
|
|
|
assert_eq!(cfg, Ok(cfg_to_compare), "Failed to test wrong_type_str");
|
2023-05-19 11:10:24 +08:00
|
|
|
|
|
|
|
let wrong_field_str = r#"
|
2023-06-05 20:21:21 +08:00
|
|
|
[custom_resolutions.0]
|
2023-05-19 11:10:24 +08:00
|
|
|
w = 1920
|
|
|
|
h = 1080
|
|
|
|
hello = "world"
|
|
|
|
[ui_flutter]
|
|
|
|
"#;
|
2023-05-19 11:43:35 +08:00
|
|
|
let mut cfg_to_compare = default_peer_config.clone();
|
2023-06-05 20:21:21 +08:00
|
|
|
cfg_to_compare.custom_resolutions =
|
|
|
|
HashMap::from([("0".to_string(), Resolution { w: 1920, h: 1080 })]);
|
2023-05-19 11:10:24 +08:00
|
|
|
let cfg = toml::from_str::<PeerConfig>(wrong_field_str);
|
2023-05-19 11:43:35 +08:00
|
|
|
assert_eq!(cfg, Ok(cfg_to_compare), "Failed to test wrong_field_str");
|
2023-05-19 11:10:24 +08:00
|
|
|
}
|
|
|
|
}
|
2021-03-29 15:59:14 +08:00
|
|
|
}
|