cmds.rs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. use crate::{
  2. core::Core,
  3. data::{ClashInfo, Data, PrfItem, PrfOption, Profiles, Verge},
  4. utils::{dirs, help},
  5. };
  6. use crate::{log_if_err, ret_err, wrap_err};
  7. use anyhow::Result;
  8. use serde_yaml::Mapping;
  9. use std::collections::{HashMap, VecDeque};
  10. use sysproxy::Sysproxy;
  11. type CmdResult<T = ()> = Result<T, String>;
  12. /// get all profiles from `profiles.yaml`
  13. #[tauri::command]
  14. pub fn get_profiles() -> CmdResult<Profiles> {
  15. let global = Data::global();
  16. let profiles = global.profiles.lock();
  17. Ok(profiles.clone())
  18. }
  19. /// manually exec enhanced profile
  20. #[tauri::command]
  21. pub fn enhance_profiles() -> CmdResult {
  22. let core = Core::global();
  23. wrap_err!(core.activate())
  24. }
  25. /// import the profile from url
  26. /// and save to `profiles.yaml`
  27. #[tauri::command]
  28. pub async fn import_profile(url: String, option: Option<PrfOption>) -> CmdResult {
  29. let item = wrap_err!(PrfItem::from_url(&url, None, None, option).await)?;
  30. let global = Data::global();
  31. let mut profiles = global.profiles.lock();
  32. wrap_err!(profiles.append_item(item))
  33. }
  34. /// new a profile
  35. /// append a temp profile item file to the `profiles` dir
  36. /// view the temp profile file by using vscode or other editor
  37. #[tauri::command]
  38. pub async fn create_profile(item: PrfItem, file_data: Option<String>) -> CmdResult {
  39. let item = wrap_err!(PrfItem::from(item, file_data).await)?;
  40. let global = Data::global();
  41. let mut profiles = global.profiles.lock();
  42. wrap_err!(profiles.append_item(item))
  43. }
  44. /// Update the profile
  45. #[tauri::command]
  46. pub async fn update_profile(index: String, option: Option<PrfOption>) -> CmdResult {
  47. let core = Core::global();
  48. wrap_err!(core.update_profile_item(index, option).await)
  49. }
  50. /// change the current profile
  51. #[tauri::command]
  52. pub fn select_profile(index: String) -> CmdResult {
  53. let global = Data::global();
  54. let mut profiles = global.profiles.lock();
  55. wrap_err!(profiles.put_current(index))?;
  56. drop(profiles);
  57. let core = Core::global();
  58. wrap_err!(core.activate())
  59. }
  60. /// change the profile chain
  61. #[tauri::command]
  62. pub fn change_profile_chain(chain: Option<Vec<String>>) -> CmdResult {
  63. let global = Data::global();
  64. let mut profiles = global.profiles.lock();
  65. wrap_err!(profiles.put_chain(chain))?;
  66. drop(profiles);
  67. let core = Core::global();
  68. wrap_err!(core.activate())
  69. }
  70. /// change the profile valid fields
  71. #[tauri::command]
  72. pub fn change_profile_valid(valid: Option<Vec<String>>) -> CmdResult {
  73. let global = Data::global();
  74. let mut profiles = global.profiles.lock();
  75. wrap_err!(profiles.put_valid(valid))?;
  76. drop(profiles);
  77. let core = Core::global();
  78. wrap_err!(core.activate())
  79. }
  80. /// delete profile item
  81. #[tauri::command]
  82. pub fn delete_profile(index: String) -> CmdResult {
  83. let global = Data::global();
  84. let mut profiles = global.profiles.lock();
  85. if wrap_err!(profiles.delete_item(index))? {
  86. drop(profiles);
  87. let core = Core::global();
  88. log_if_err!(core.activate());
  89. }
  90. Ok(())
  91. }
  92. /// patch the profile config
  93. #[tauri::command]
  94. pub fn patch_profile(index: String, profile: PrfItem) -> CmdResult {
  95. let global = Data::global();
  96. let mut profiles = global.profiles.lock();
  97. wrap_err!(profiles.patch_item(index, profile))?;
  98. drop(profiles);
  99. // update cron task
  100. let core = Core::global();
  101. let mut timer = core.timer.lock();
  102. wrap_err!(timer.refresh())
  103. }
  104. /// run vscode command to edit the profile
  105. #[tauri::command]
  106. pub fn view_profile(index: String) -> CmdResult {
  107. let global = Data::global();
  108. let profiles = global.profiles.lock();
  109. let item = wrap_err!(profiles.get_item(&index))?;
  110. let file = item.file.clone();
  111. if file.is_none() {
  112. ret_err!("file is null");
  113. }
  114. let path = dirs::app_profiles_dir().join(file.unwrap());
  115. if !path.exists() {
  116. ret_err!("file not found");
  117. }
  118. wrap_err!(help::open_file(path))
  119. }
  120. /// read the profile item file data
  121. #[tauri::command]
  122. pub fn read_profile_file(index: String) -> CmdResult<String> {
  123. let global = Data::global();
  124. let profiles = global.profiles.lock();
  125. let item = wrap_err!(profiles.get_item(&index))?;
  126. let data = wrap_err!(item.read_file())?;
  127. Ok(data)
  128. }
  129. /// save the profile item file data
  130. #[tauri::command]
  131. pub fn save_profile_file(index: String, file_data: Option<String>) -> CmdResult {
  132. if file_data.is_none() {
  133. return Ok(());
  134. }
  135. let global = Data::global();
  136. let profiles = global.profiles.lock();
  137. let item = wrap_err!(profiles.get_item(&index))?;
  138. wrap_err!(item.save_file(file_data.unwrap()))
  139. }
  140. /// get the clash core info from the state
  141. /// the caller can also get the infomation by clash's api
  142. #[tauri::command]
  143. pub fn get_clash_info() -> CmdResult<ClashInfo> {
  144. let global = Data::global();
  145. let clash = global.clash.lock();
  146. Ok(clash.info.clone())
  147. }
  148. /// get the runtime clash config mapping
  149. #[tauri::command]
  150. pub fn get_runtime_config() -> CmdResult<Option<Mapping>> {
  151. let core = Core::global();
  152. let rt = core.runtime.lock();
  153. Ok(rt.config.clone())
  154. }
  155. /// get the runtime clash config yaml string
  156. #[tauri::command]
  157. pub fn get_runtime_yaml() -> CmdResult<Option<String>> {
  158. let core = Core::global();
  159. let rt = core.runtime.lock();
  160. Ok(rt.config_yaml.clone())
  161. }
  162. /// get the runtime config exists keys
  163. #[tauri::command]
  164. pub fn get_runtime_exists() -> CmdResult<Vec<String>> {
  165. let core = Core::global();
  166. let rt = core.runtime.lock();
  167. Ok(rt.exists_keys.clone())
  168. }
  169. /// get the runtime enhanced chain log
  170. #[tauri::command]
  171. pub fn get_runtime_logs() -> CmdResult<HashMap<String, Vec<(String, String)>>> {
  172. let core = Core::global();
  173. let rt = core.runtime.lock();
  174. Ok(rt.chain_logs.clone())
  175. }
  176. /// update the clash core config
  177. /// after putting the change to the clash core
  178. /// then we should save the latest config
  179. #[tauri::command]
  180. pub fn patch_clash_config(payload: Mapping) -> CmdResult {
  181. let core = Core::global();
  182. wrap_err!(core.patch_clash(payload))
  183. }
  184. #[tauri::command]
  185. pub fn get_verge_config() -> CmdResult<Verge> {
  186. let global = Data::global();
  187. let verge = global.verge.lock();
  188. Ok(verge.clone())
  189. }
  190. /// patch the verge config
  191. /// this command only save the config and not responsible for other things
  192. #[tauri::command]
  193. pub fn patch_verge_config(payload: Verge) -> CmdResult {
  194. let core = Core::global();
  195. wrap_err!(core.patch_verge(payload))
  196. }
  197. #[tauri::command]
  198. pub fn update_hotkeys(hotkeys: Vec<String>) -> CmdResult {
  199. let core = Core::global();
  200. let mut hotkey = core.hotkey.lock();
  201. wrap_err!(hotkey.update(hotkeys))
  202. }
  203. /// change clash core
  204. #[tauri::command]
  205. pub fn change_clash_core(clash_core: Option<String>) -> CmdResult {
  206. let core = Core::global();
  207. wrap_err!(core.change_core(clash_core))
  208. }
  209. /// restart the sidecar
  210. #[tauri::command]
  211. pub fn restart_sidecar() -> CmdResult {
  212. let core = Core::global();
  213. wrap_err!(core.restart_clash())
  214. }
  215. /// kill all sidecars when update app
  216. #[tauri::command]
  217. pub fn kill_sidecar() {
  218. tauri::api::process::kill_children();
  219. }
  220. /// get the system proxy
  221. #[tauri::command]
  222. pub fn get_sys_proxy() -> CmdResult<Mapping> {
  223. let current = wrap_err!(Sysproxy::get_system_proxy())?;
  224. let mut map = Mapping::new();
  225. map.insert("enable".into(), current.enable.into());
  226. map.insert(
  227. "server".into(),
  228. format!("{}:{}", current.host, current.port).into(),
  229. );
  230. map.insert("bypass".into(), current.bypass.into());
  231. Ok(map)
  232. }
  233. #[tauri::command]
  234. pub fn get_clash_logs() -> CmdResult<VecDeque<String>> {
  235. let core = Core::global();
  236. let service = core.service.lock();
  237. Ok(service.get_logs())
  238. }
  239. /// open app config dir
  240. #[tauri::command]
  241. pub fn open_app_dir() -> CmdResult<()> {
  242. let app_dir = dirs::app_home_dir();
  243. wrap_err!(open::that(app_dir))
  244. }
  245. /// open logs dir
  246. #[tauri::command]
  247. pub fn open_logs_dir() -> CmdResult<()> {
  248. let log_dir = dirs::app_logs_dir();
  249. wrap_err!(open::that(log_dir))
  250. }
  251. /// open url
  252. #[tauri::command]
  253. pub fn open_web_url(url: String) -> CmdResult<()> {
  254. wrap_err!(open::that(url))
  255. }
  256. /// service mode
  257. #[cfg(windows)]
  258. pub mod service {
  259. use super::*;
  260. use crate::core::win_service::JsonResponse;
  261. #[tauri::command]
  262. pub async fn start_service() -> CmdResult<()> {
  263. wrap_err!(crate::core::Service::start_service().await)
  264. }
  265. #[tauri::command]
  266. pub async fn stop_service() -> CmdResult<()> {
  267. wrap_err!(crate::core::Service::stop_service().await)
  268. }
  269. #[tauri::command]
  270. pub async fn check_service() -> CmdResult<JsonResponse> {
  271. // no log
  272. match crate::core::Service::check_service().await {
  273. Ok(res) => Ok(res),
  274. Err(err) => Err(err.to_string()),
  275. }
  276. }
  277. #[tauri::command]
  278. pub async fn install_service() -> CmdResult<()> {
  279. wrap_err!(crate::core::Service::install_service().await)
  280. }
  281. #[tauri::command]
  282. pub async fn uninstall_service() -> CmdResult<()> {
  283. wrap_err!(crate::core::Service::uninstall_service().await)
  284. }
  285. }
  286. #[cfg(not(windows))]
  287. pub mod service {
  288. use super::*;
  289. #[tauri::command]
  290. pub async fn start_service() -> CmdResult<()> {
  291. Ok(())
  292. }
  293. #[tauri::command]
  294. pub async fn stop_service() -> CmdResult<()> {
  295. Ok(())
  296. }
  297. #[tauri::command]
  298. pub async fn check_service() -> CmdResult<()> {
  299. Ok(())
  300. }
  301. #[tauri::command]
  302. pub async fn install_service() -> CmdResult<()> {
  303. Ok(())
  304. }
  305. #[tauri::command]
  306. pub async fn uninstall_service() -> CmdResult<()> {
  307. Ok(())
  308. }
  309. }