verge.rs 10 KB

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