diff --git a/src-tauri/src/cmd.rs b/src-tauri/src/cmd.rs
index e976d403d38881b45858b3163429c53a33efc422..7fe8b437ccc67c0c9265a6b4a21019f4dfaa61c1 100644
--- a/src-tauri/src/cmd.rs
+++ b/src-tauri/src/cmd.rs
@@ -1,6 +1,9 @@
 use crate::{
-  config::{read_profiles, save_profiles, ProfileItem},
-  events::{emit::ClashInfoPayload, state::ClashInfoState},
+  config::{read_profiles, save_profiles, ProfileItem, ProfilesConfig},
+  events::{
+    emit::ClashInfoPayload,
+    state::{ClashInfoState, ProfileLock},
+  },
   utils::{app_home_dir, clash, fetch::fetch_profile},
 };
 use std::fs::File;
@@ -28,7 +31,7 @@ pub fn get_clash_info(clash_info: State<'_, ClashInfoState>) -> Option<ClashInfo
 /// Import the Profile from url and
 /// save to the `profiles.yaml` file
 #[tauri::command]
-pub async fn import_profile(url: String) -> Result<String, String> {
+pub async fn import_profile(url: String, lock: State<'_, ProfileLock>) -> Result<String, String> {
   let result = match fetch_profile(&url).await {
     Some(r) => r,
     None => {
@@ -43,6 +46,12 @@ pub async fn import_profile(url: String) -> Result<String, String> {
     .write(result.data.as_bytes())
     .unwrap();
 
+  // get lock
+  match lock.0.lock() {
+    Ok(_) => {}
+    Err(_) => return Err(format!("can not get file locked")),
+  };
+
   // update profiles.yaml
   let mut profiles = read_profiles();
   let mut items = match profiles.items {
@@ -65,3 +74,60 @@ pub async fn import_profile(url: String) -> Result<String, String> {
 
   Ok(format!("success"))
 }
+
+#[tauri::command]
+pub fn get_profiles(lock: State<'_, ProfileLock>) -> Option<ProfilesConfig> {
+  match lock.0.lock() {
+    Ok(_) => Some(read_profiles()),
+    Err(_) => None,
+  }
+}
+
+#[tauri::command]
+pub fn set_profiles(
+  current: usize,
+  profile: ProfileItem,
+  lock: State<'_, ProfileLock>,
+) -> Result<(), String> {
+  match lock.0.lock() {
+    Ok(_) => {}
+    Err(_) => return Err(format!("can not get file locked")),
+  };
+
+  let mut profiles = read_profiles();
+  let mut items = match profiles.items {
+    Some(p) => p,
+    None => vec![],
+  };
+
+  if current >= items.len() {
+    return Err(format!("out of profiles bound"));
+  }
+
+  let mut origin = items[current].clone();
+
+  if profile.name.is_some() {
+    origin.name = profile.name;
+  }
+  if profile.file.is_some() {
+    origin.file = profile.file;
+  }
+  if profile.mode.is_some() {
+    origin.mode = profile.mode;
+  }
+  if profile.url.is_some() {
+    origin.url = profile.url;
+  }
+  if profile.selected.is_some() {
+    origin.selected = profile.selected;
+  }
+  if profile.extra.is_some() {
+    origin.extra = profile.extra;
+  }
+
+  items[current] = origin;
+  profiles.items = Some(items);
+  save_profiles(&profiles);
+
+  Ok(())
+}
diff --git a/src-tauri/src/events/state.rs b/src-tauri/src/events/state.rs
index 22aa77ffa71ab1c92171b860da5e662f68546c71..7640003f97125d859003b93fbe58f5471971cc34 100644
--- a/src-tauri/src/events/state.rs
+++ b/src-tauri/src/events/state.rs
@@ -4,3 +4,6 @@ use super::emit::ClashInfoPayload;
 
 #[derive(Default)]
 pub struct ClashInfoState(pub Arc<Mutex<ClashInfoPayload>>);
+
+#[derive(Default)]
+pub struct ProfileLock(pub Mutex<bool>);
diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs
index 41d97191ad19da54499ebc1e9a5f11b73e12511b..1a47948a45a80a641925d911bd0807741563f333 100644
--- a/src-tauri/src/main.rs
+++ b/src-tauri/src/main.rs
@@ -10,7 +10,7 @@ mod config;
 mod events;
 mod utils;
 
-use crate::{events::state::ClashInfoState, utils::clash::put_clash_profile};
+use crate::{events::state, utils::clash::put_clash_profile};
 use std::sync::{Arc, Mutex};
 use tauri::{
   api, CustomMenuItem, Manager, SystemTray, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem,
@@ -57,9 +57,11 @@ fn main() -> std::io::Result<()> {
       _ => {}
     })
     .invoke_handler(tauri::generate_handler![
-      cmd::import_profile,
       cmd::restart_sidebar,
       cmd::get_clash_info,
+      cmd::import_profile,
+      cmd::get_profiles,
+      cmd::set_profiles
     ])
     .build(tauri::generate_context!())
     .expect("error while running tauri application");
@@ -77,7 +79,8 @@ fn main() -> std::io::Result<()> {
     };
   });
 
-  app.manage(ClashInfoState(Arc::new(Mutex::new(info))));
+  app.manage(state::ClashInfoState(Arc::new(Mutex::new(info))));
+  app.manage(state::ProfileLock::default());
 
   app.run(|app_handle, e| match e {
     tauri::Event::CloseRequested { label, api, .. } => {