In Rust, the `or` and `or_else` methods have distinct behavioral differences. The `or` method always eagerly evaluates its argument and executes any associated function calls. This can lead to unnecessary performance costs—especially in expensive operations like string processing or file handling—and may even trigger unintended side effects. In contrast, `or_else` evaluates its closure lazily, only when necessary. Introducing a Clippy lint to disallow `or` sacrifices a bit of code simplicity but ensures predictable behavior and enforces lazy evaluation for better performance.
108 lines
3.5 KiB
Rust
108 lines
3.5 KiB
Rust
use serde_yaml_ng::{Mapping, Value};
|
||
|
||
#[cfg(target_os = "macos")]
|
||
use crate::process::AsyncHandler;
|
||
|
||
macro_rules! revise {
|
||
($map: expr, $key: expr, $val: expr) => {
|
||
let ret_key = Value::String($key.into());
|
||
$map.insert(ret_key, Value::from($val));
|
||
};
|
||
}
|
||
|
||
// if key not exists then append value
|
||
#[allow(unused_macros)]
|
||
macro_rules! append {
|
||
($map: expr, $key: expr, $val: expr) => {
|
||
let ret_key = Value::String($key.into());
|
||
if !$map.contains_key(&ret_key) {
|
||
$map.insert(ret_key, Value::from($val));
|
||
}
|
||
};
|
||
}
|
||
|
||
pub fn use_tun(mut config: Mapping, enable: bool) -> Mapping {
|
||
let tun_key = Value::from("tun");
|
||
let tun_val = config.get(&tun_key);
|
||
let mut tun_val = tun_val.map_or_else(Mapping::new, |val| {
|
||
val.as_mapping().cloned().unwrap_or_else(Mapping::new)
|
||
});
|
||
|
||
if enable {
|
||
#[cfg(target_os = "linux")]
|
||
{
|
||
let stack_key = Value::from("stack");
|
||
let should_override = match tun_val.get(&stack_key) {
|
||
Some(value) => value
|
||
.as_str()
|
||
.map(|stack| stack.eq_ignore_ascii_case("gvisor"))
|
||
.unwrap_or(false),
|
||
None => true,
|
||
};
|
||
|
||
if should_override {
|
||
revise!(tun_val, "stack", "mixed");
|
||
log::warn!(
|
||
target: "app",
|
||
"gVisor TUN stack detected on Linux; falling back to 'mixed' for compatibility"
|
||
);
|
||
}
|
||
}
|
||
|
||
// 读取DNS配置
|
||
let dns_key = Value::from("dns");
|
||
let dns_val = config.get(&dns_key);
|
||
let mut dns_val = dns_val.map_or_else(Mapping::new, |val| {
|
||
val.as_mapping().cloned().unwrap_or_else(Mapping::new)
|
||
});
|
||
let ipv6_key = Value::from("ipv6");
|
||
let ipv6_val = config
|
||
.get(&ipv6_key)
|
||
.and_then(|v| v.as_bool())
|
||
.unwrap_or(false);
|
||
|
||
// 检查现有的 enhanced-mode 设置
|
||
let current_mode = dns_val
|
||
.get(Value::from("enhanced-mode"))
|
||
.and_then(|v| v.as_str())
|
||
.unwrap_or("fake-ip");
|
||
|
||
// 只有当 enhanced-mode 是 fake-ip 或未设置时才修改 DNS 配置
|
||
if current_mode == "fake-ip" || !dns_val.contains_key(Value::from("enhanced-mode")) {
|
||
revise!(dns_val, "enable", true);
|
||
revise!(dns_val, "ipv6", ipv6_val);
|
||
|
||
if !dns_val.contains_key(Value::from("enhanced-mode")) {
|
||
revise!(dns_val, "enhanced-mode", "fake-ip");
|
||
}
|
||
|
||
if !dns_val.contains_key(Value::from("fake-ip-range")) {
|
||
revise!(dns_val, "fake-ip-range", "198.18.0.1/16");
|
||
}
|
||
|
||
#[cfg(target_os = "macos")]
|
||
{
|
||
AsyncHandler::spawn(move || async move {
|
||
crate::utils::resolve::dns::restore_public_dns().await;
|
||
crate::utils::resolve::dns::set_public_dns("223.6.6.6".to_string()).await;
|
||
});
|
||
}
|
||
}
|
||
|
||
// 当TUN启用时,将修改后的DNS配置写回
|
||
revise!(config, "dns", dns_val);
|
||
} else {
|
||
// TUN未启用时,仅恢复系统DNS,不修改配置文件中的DNS设置
|
||
#[cfg(target_os = "macos")]
|
||
AsyncHandler::spawn(move || async move {
|
||
crate::utils::resolve::dns::restore_public_dns().await;
|
||
});
|
||
}
|
||
|
||
// 更新TUN配置
|
||
revise!(tun_val, "enable", enable);
|
||
revise!(config, "tun", tun_val);
|
||
|
||
config
|
||
}
|