profile.rs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. use crate::{
  2. config::{ProfileItem, ProfilesConfig},
  3. events::state::{ClashInfoState, ProfileLock},
  4. utils::{
  5. app_home_dir,
  6. clash::put_clash_profile,
  7. config::{read_profiles, save_profiles},
  8. fetch::fetch_profile,
  9. },
  10. };
  11. use std::fs::File;
  12. use std::io::Write;
  13. use std::time::{SystemTime, UNIX_EPOCH};
  14. use tauri::State;
  15. /// Import the profile from url
  16. /// and save to `profiles.yaml`
  17. #[tauri::command]
  18. pub async fn import_profile(url: String, lock: State<'_, ProfileLock>) -> Result<(), String> {
  19. let result = match fetch_profile(&url).await {
  20. Some(r) => r,
  21. None => {
  22. log::error!("failed to fetch profile from `{}`", url);
  23. return Err(format!("failed to fetch profile from `{}`", url));
  24. }
  25. };
  26. // get lock
  27. if lock.0.lock().is_err() {
  28. return Err(format!("can not get file lock"));
  29. }
  30. // save the profile file
  31. let path = app_home_dir().join("profiles").join(&result.file);
  32. let file_data = result.data.as_bytes();
  33. File::create(path).unwrap().write(file_data).unwrap();
  34. // update `profiles.yaml`
  35. let mut profiles = read_profiles();
  36. let mut items = profiles.items.unwrap_or(vec![]);
  37. let now = SystemTime::now()
  38. .duration_since(UNIX_EPOCH)
  39. .unwrap()
  40. .as_secs();
  41. items.push(ProfileItem {
  42. name: Some(result.name),
  43. file: Some(result.file),
  44. mode: Some(format!("rule")),
  45. url: Some(url),
  46. selected: Some(vec![]),
  47. extra: Some(result.extra),
  48. updated: Some(now as usize),
  49. });
  50. profiles.items = Some(items);
  51. save_profiles(&profiles)
  52. }
  53. /// Update the profile
  54. /// and save to `profiles.yaml`
  55. /// http request firstly
  56. /// then acquire the lock of `profiles.yaml`
  57. #[tauri::command]
  58. pub async fn update_profile(index: usize, lock: State<'_, ProfileLock>) -> Result<(), String> {
  59. // get lock
  60. if lock.0.lock().is_err() {
  61. return Err(format!("can not get file lock"));
  62. }
  63. // update `profiles.yaml`
  64. let mut profiles = read_profiles();
  65. let mut items = profiles.items.unwrap_or(vec![]);
  66. if index >= items.len() {
  67. return Err(format!("the index out of bound"));
  68. }
  69. let url = match &items[index].url {
  70. Some(u) => u,
  71. None => return Err(format!("invalid url")),
  72. };
  73. let result = match fetch_profile(&url).await {
  74. Some(r) => r,
  75. None => {
  76. log::error!("failed to fetch profile from `{}`", url);
  77. return Err(format!("failed to fetch profile from `{}`", url));
  78. }
  79. };
  80. let now = SystemTime::now()
  81. .duration_since(UNIX_EPOCH)
  82. .unwrap()
  83. .as_secs() as usize;
  84. // update file
  85. let file_path = &items[index].file.as_ref().unwrap();
  86. let file_path = app_home_dir().join("profiles").join(file_path);
  87. let file_data = result.data.as_bytes();
  88. File::create(file_path).unwrap().write(file_data).unwrap();
  89. items[index].name = Some(result.name);
  90. items[index].extra = Some(result.extra);
  91. items[index].updated = Some(now);
  92. profiles.items = Some(items);
  93. save_profiles(&profiles)
  94. }
  95. /// get all profiles from `profiles.yaml`
  96. /// do not acquire the lock of ProfileLock
  97. #[tauri::command]
  98. pub fn get_profiles() -> Result<ProfilesConfig, String> {
  99. Ok(read_profiles())
  100. }
  101. /// patch the profile config
  102. #[tauri::command]
  103. pub fn set_profiles(
  104. index: usize,
  105. profile: ProfileItem,
  106. lock: State<'_, ProfileLock>,
  107. ) -> Result<(), String> {
  108. // get lock
  109. if lock.0.lock().is_err() {
  110. return Err(format!("can not get file lock"));
  111. }
  112. let mut profiles = read_profiles();
  113. let mut items = profiles.items.unwrap_or(vec![]);
  114. if index >= items.len() {
  115. return Err(format!("the index out of bound"));
  116. }
  117. if profile.name.is_some() {
  118. items[index].name = profile.name;
  119. }
  120. if profile.file.is_some() {
  121. items[index].file = profile.file;
  122. }
  123. if profile.mode.is_some() {
  124. items[index].mode = profile.mode;
  125. }
  126. if profile.url.is_some() {
  127. items[index].url = profile.url;
  128. }
  129. if profile.selected.is_some() {
  130. items[index].selected = profile.selected;
  131. }
  132. if profile.extra.is_some() {
  133. items[index].extra = profile.extra;
  134. }
  135. profiles.items = Some(items);
  136. save_profiles(&profiles)
  137. }
  138. /// change the current profile
  139. #[tauri::command]
  140. pub async fn put_profiles(
  141. current: usize,
  142. lock: State<'_, ProfileLock>,
  143. clash_info: State<'_, ClashInfoState>,
  144. ) -> Result<(), String> {
  145. if lock.0.lock().is_err() {
  146. return Err(format!("can not get file lock"));
  147. }
  148. let clash_info = match clash_info.0.lock() {
  149. Ok(arc) => arc.clone(),
  150. _ => return Err(format!("can not get clash info")),
  151. };
  152. let mut profiles = read_profiles();
  153. let items_len = match &profiles.items {
  154. Some(list) => list.len(),
  155. None => 0,
  156. };
  157. if current >= items_len {
  158. return Err(format!("the index out of bound"));
  159. }
  160. profiles.current = Some(current);
  161. match save_profiles(&profiles) {
  162. Ok(_) => put_clash_profile(&clash_info).await,
  163. Err(err) => Err(err),
  164. }
  165. }