cmds.rs 8.8 KB

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