verge.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. use crate::config::DEFAULT_PAC;
  2. use crate::utils::{dirs, help};
  3. use anyhow::Result;
  4. use log::LevelFilter;
  5. use serde::{Deserialize, Serialize};
  6. /// ### `verge.yaml` schema
  7. #[derive(Default, Debug, Clone, Deserialize, Serialize)]
  8. pub struct IVerge {
  9. /// app listening port for app singleton
  10. pub app_singleton_port: Option<u16>,
  11. /// app log level
  12. /// silent | error | warn | info | debug | trace
  13. pub app_log_level: Option<String>,
  14. // i18n
  15. pub language: Option<String>,
  16. /// `light` or `dark` or `system`
  17. pub theme_mode: Option<String>,
  18. /// tray click event
  19. pub tray_event: Option<String>,
  20. /// copy env type
  21. pub env_type: Option<String>,
  22. /// start page
  23. pub start_page: Option<String>,
  24. /// startup script path
  25. pub startup_script: Option<String>,
  26. /// enable traffic graph default is true
  27. pub traffic_graph: Option<bool>,
  28. /// show memory info (only for Clash Meta)
  29. pub enable_memory_usage: Option<bool>,
  30. /// enable group icon
  31. pub enable_group_icon: Option<bool>,
  32. /// common tray icon
  33. pub common_tray_icon: Option<bool>,
  34. /// tray icon
  35. #[cfg(target_os = "macos")]
  36. pub tray_icon: Option<String>,
  37. /// menu icon
  38. pub menu_icon: Option<String>,
  39. /// sysproxy tray icon
  40. pub sysproxy_tray_icon: Option<bool>,
  41. /// tun tray icon
  42. pub tun_tray_icon: Option<bool>,
  43. /// clash tun mode
  44. pub enable_tun_mode: Option<bool>,
  45. /// windows service mode
  46. #[serde(skip_serializing_if = "Option::is_none")]
  47. pub enable_service_mode: Option<bool>,
  48. /// can the app auto startup
  49. pub enable_auto_launch: Option<bool>,
  50. /// not show the window on launch
  51. pub enable_silent_start: Option<bool>,
  52. /// set system proxy
  53. pub enable_system_proxy: Option<bool>,
  54. /// enable proxy guard
  55. pub enable_proxy_guard: Option<bool>,
  56. /// always use default bypass
  57. pub use_default_bypass: Option<bool>,
  58. /// set system proxy bypass
  59. pub system_proxy_bypass: Option<String>,
  60. /// proxy guard duration
  61. pub proxy_guard_duration: Option<u64>,
  62. /// use pac mode
  63. pub proxy_auto_config: Option<bool>,
  64. /// pac script content
  65. pub pac_file_content: Option<String>,
  66. /// theme setting
  67. pub theme_setting: Option<IVergeTheme>,
  68. /// web ui list
  69. pub web_ui_list: Option<Vec<String>>,
  70. /// clash core path
  71. #[serde(skip_serializing_if = "Option::is_none")]
  72. pub clash_core: Option<String>,
  73. /// hotkey map
  74. /// format: {func},{key}
  75. pub hotkeys: Option<Vec<String>>,
  76. /// 切换代理时自动关闭连接
  77. pub auto_close_connection: Option<bool>,
  78. /// 是否自动检查更新
  79. pub auto_check_update: Option<bool>,
  80. /// 默认的延迟测试连接
  81. pub default_latency_test: Option<String>,
  82. /// 默认的延迟测试超时时间
  83. pub default_latency_timeout: Option<i32>,
  84. /// 是否使用内部的脚本支持,默认为真
  85. pub enable_builtin_enhanced: Option<bool>,
  86. /// proxy 页面布局 列数
  87. pub proxy_layout_column: Option<i32>,
  88. /// 测试网站列表
  89. pub test_list: Option<Vec<IVergeTestItem>>,
  90. /// 日志清理
  91. /// 0: 不清理; 1: 7天; 2: 30天; 3: 90天
  92. pub auto_log_clean: Option<i32>,
  93. /// window size and position
  94. #[serde(skip_serializing_if = "Option::is_none")]
  95. pub window_size_position: Option<Vec<f64>>,
  96. /// window size and position
  97. #[serde(skip_serializing_if = "Option::is_none")]
  98. pub window_is_maximized: Option<bool>,
  99. /// 是否启用随机端口
  100. pub enable_random_port: Option<bool>,
  101. /// verge 的各种 port 用于覆盖 clash 的各种 port
  102. #[cfg(not(target_os = "windows"))]
  103. pub verge_redir_port: Option<u16>,
  104. #[cfg(not(target_os = "windows"))]
  105. pub verge_redir_enabled: Option<bool>,
  106. #[cfg(target_os = "linux")]
  107. pub verge_tproxy_port: Option<u16>,
  108. #[cfg(target_os = "linux")]
  109. pub verge_tproxy_enabled: Option<bool>,
  110. pub verge_mixed_port: Option<u16>,
  111. pub verge_socks_port: Option<u16>,
  112. pub verge_socks_enabled: Option<bool>,
  113. pub verge_port: Option<u16>,
  114. pub verge_http_enabled: Option<bool>,
  115. }
  116. #[derive(Default, Debug, Clone, Deserialize, Serialize)]
  117. pub struct IVergeTestItem {
  118. pub uid: Option<String>,
  119. pub name: Option<String>,
  120. pub icon: Option<String>,
  121. pub url: Option<String>,
  122. }
  123. #[derive(Default, Debug, Clone, Deserialize, Serialize)]
  124. pub struct IVergeTheme {
  125. pub primary_color: Option<String>,
  126. pub secondary_color: Option<String>,
  127. pub primary_text: Option<String>,
  128. pub secondary_text: Option<String>,
  129. pub info_color: Option<String>,
  130. pub error_color: Option<String>,
  131. pub warning_color: Option<String>,
  132. pub success_color: Option<String>,
  133. pub font_family: Option<String>,
  134. pub css_injection: Option<String>,
  135. }
  136. impl IVerge {
  137. pub fn new() -> Self {
  138. match dirs::verge_path().and_then(|path| help::read_yaml::<IVerge>(&path)) {
  139. Ok(config) => config,
  140. Err(err) => {
  141. log::error!(target: "app", "{err}");
  142. Self::template()
  143. }
  144. }
  145. }
  146. pub fn template() -> Self {
  147. Self {
  148. clash_core: Some("verge-mihomo".into()),
  149. language: Some("zh".into()),
  150. theme_mode: Some("system".into()),
  151. #[cfg(not(target_os = "windows"))]
  152. env_type: Some("bash".into()),
  153. #[cfg(target_os = "windows")]
  154. env_type: Some("powershell".into()),
  155. start_page: Some("/".into()),
  156. traffic_graph: Some(true),
  157. enable_memory_usage: Some(true),
  158. enable_group_icon: Some(true),
  159. #[cfg(target_os = "macos")]
  160. tray_icon: Some("monochrome".into()),
  161. menu_icon: Some("monochrome".into()),
  162. common_tray_icon: Some(false),
  163. sysproxy_tray_icon: Some(false),
  164. tun_tray_icon: Some(false),
  165. enable_auto_launch: Some(false),
  166. enable_silent_start: Some(false),
  167. enable_system_proxy: Some(false),
  168. proxy_auto_config: Some(false),
  169. pac_file_content: Some(DEFAULT_PAC.into()),
  170. enable_random_port: Some(false),
  171. #[cfg(not(target_os = "windows"))]
  172. verge_redir_port: Some(7895),
  173. #[cfg(not(target_os = "windows"))]
  174. verge_redir_enabled: Some(false),
  175. #[cfg(target_os = "linux")]
  176. verge_tproxy_port: Some(7896),
  177. #[cfg(target_os = "linux")]
  178. verge_tproxy_enabled: Some(false),
  179. verge_mixed_port: Some(7897),
  180. verge_socks_port: Some(7898),
  181. verge_socks_enabled: Some(false),
  182. verge_port: Some(7899),
  183. verge_http_enabled: Some(false),
  184. enable_proxy_guard: Some(false),
  185. use_default_bypass: Some(true),
  186. proxy_guard_duration: Some(30),
  187. auto_close_connection: Some(true),
  188. auto_check_update: Some(true),
  189. enable_builtin_enhanced: Some(true),
  190. auto_log_clean: Some(3),
  191. ..Self::default()
  192. }
  193. }
  194. /// Save IVerge App Config
  195. pub fn save_file(&self) -> Result<()> {
  196. help::save_yaml(&dirs::verge_path()?, &self, Some("# Clash Verge Config"))
  197. }
  198. /// patch verge config
  199. /// only save to file
  200. pub fn patch_config(&mut self, patch: IVerge) {
  201. macro_rules! patch {
  202. ($key: tt) => {
  203. if patch.$key.is_some() {
  204. self.$key = patch.$key;
  205. }
  206. };
  207. }
  208. patch!(app_log_level);
  209. patch!(language);
  210. patch!(theme_mode);
  211. patch!(tray_event);
  212. patch!(env_type);
  213. patch!(start_page);
  214. patch!(startup_script);
  215. patch!(traffic_graph);
  216. patch!(enable_memory_usage);
  217. patch!(enable_group_icon);
  218. #[cfg(target_os = "macos")]
  219. patch!(tray_icon);
  220. patch!(menu_icon);
  221. patch!(common_tray_icon);
  222. patch!(sysproxy_tray_icon);
  223. patch!(tun_tray_icon);
  224. patch!(enable_tun_mode);
  225. patch!(enable_service_mode);
  226. patch!(enable_auto_launch);
  227. patch!(enable_silent_start);
  228. patch!(enable_random_port);
  229. #[cfg(not(target_os = "windows"))]
  230. patch!(verge_redir_port);
  231. #[cfg(not(target_os = "windows"))]
  232. patch!(verge_redir_enabled);
  233. #[cfg(target_os = "linux")]
  234. patch!(verge_tproxy_port);
  235. #[cfg(target_os = "linux")]
  236. patch!(verge_tproxy_enabled);
  237. patch!(verge_mixed_port);
  238. patch!(verge_socks_port);
  239. patch!(verge_socks_enabled);
  240. patch!(verge_port);
  241. patch!(verge_http_enabled);
  242. patch!(enable_system_proxy);
  243. patch!(enable_proxy_guard);
  244. patch!(use_default_bypass);
  245. patch!(system_proxy_bypass);
  246. patch!(proxy_guard_duration);
  247. patch!(proxy_auto_config);
  248. patch!(pac_file_content);
  249. patch!(theme_setting);
  250. patch!(web_ui_list);
  251. patch!(clash_core);
  252. patch!(hotkeys);
  253. patch!(auto_close_connection);
  254. patch!(auto_check_update);
  255. patch!(default_latency_test);
  256. patch!(default_latency_timeout);
  257. patch!(enable_builtin_enhanced);
  258. patch!(proxy_layout_column);
  259. patch!(test_list);
  260. patch!(auto_log_clean);
  261. patch!(window_size_position);
  262. patch!(window_is_maximized);
  263. }
  264. /// 在初始化前尝试拿到单例端口的值
  265. pub fn get_singleton_port() -> u16 {
  266. #[cfg(not(feature = "verge-dev"))]
  267. const SERVER_PORT: u16 = 33331;
  268. #[cfg(feature = "verge-dev")]
  269. const SERVER_PORT: u16 = 11233;
  270. match dirs::verge_path().and_then(|path| help::read_yaml::<IVerge>(&path)) {
  271. Ok(config) => config.app_singleton_port.unwrap_or(SERVER_PORT),
  272. Err(_) => SERVER_PORT, // 这里就不log错误了
  273. }
  274. }
  275. /// 获取日志等级
  276. pub fn get_log_level(&self) -> LevelFilter {
  277. if let Some(level) = self.app_log_level.as_ref() {
  278. match level.to_lowercase().as_str() {
  279. "silent" => LevelFilter::Off,
  280. "error" => LevelFilter::Error,
  281. "warn" => LevelFilter::Warn,
  282. "info" => LevelFilter::Info,
  283. "debug" => LevelFilter::Debug,
  284. "trace" => LevelFilter::Trace,
  285. _ => LevelFilter::Info,
  286. }
  287. } else {
  288. LevelFilter::Info
  289. }
  290. }
  291. }