perf: refactor PrfOption merge logic and streamline update_item method in IProfiles

This commit is contained in:
Tunglies 2026-01-16 11:47:36 +08:00
parent f246ea4469
commit c5233a9c2c
No known key found for this signature in database
GPG Key ID: B9B01B389469B3E8
2 changed files with 39 additions and 50 deletions

View File

@ -124,25 +124,22 @@ pub struct PrfOption {
impl PrfOption { impl PrfOption {
pub fn merge(one: Option<&Self>, other: Option<&Self>) -> Option<Self> { pub fn merge(one: Option<&Self>, other: Option<&Self>) -> Option<Self> {
match (one, other) { match (one, other) {
(Some(a_ref), Some(b_ref)) => { (Some(a), Some(b)) => Some(Self {
let mut result = a_ref.clone(); user_agent: b.user_agent.as_ref().or(a.user_agent.as_ref()).cloned(),
result.user_agent = b_ref.user_agent.clone().or(result.user_agent); with_proxy: b.with_proxy.or(a.with_proxy),
result.with_proxy = b_ref.with_proxy.or(result.with_proxy); self_proxy: b.self_proxy.or(a.self_proxy),
result.self_proxy = b_ref.self_proxy.or(result.self_proxy); danger_accept_invalid_certs: b.danger_accept_invalid_certs.or(a.danger_accept_invalid_certs),
result.danger_accept_invalid_certs = allow_auto_update: b.allow_auto_update.or(a.allow_auto_update),
b_ref.danger_accept_invalid_certs.or(result.danger_accept_invalid_certs); update_interval: b.update_interval.or(a.update_interval),
result.allow_auto_update = b_ref.allow_auto_update.or(result.allow_auto_update); merge: b.merge.as_ref().or(a.merge.as_ref()).cloned(),
result.update_interval = b_ref.update_interval.or(result.update_interval); script: b.script.as_ref().or(a.script.as_ref()).cloned(),
result.merge = b_ref.merge.clone().or(result.merge); rules: b.rules.as_ref().or(a.rules.as_ref()).cloned(),
result.script = b_ref.script.clone().or(result.script); proxies: b.proxies.as_ref().or(a.proxies.as_ref()).cloned(),
result.rules = b_ref.rules.clone().or(result.rules); groups: b.groups.as_ref().or(a.groups.as_ref()).cloned(),
result.proxies = b_ref.proxies.clone().or(result.proxies); timeout_seconds: b.timeout_seconds.or(a.timeout_seconds),
result.groups = b_ref.groups.clone().or(result.groups); }),
result.timeout_seconds = b_ref.timeout_seconds.or(result.timeout_seconds); (Some(a), None) => Some(a.clone()),
Some(result) (None, Some(b)) => Some(b.clone()),
}
(Some(a_ref), None) => Some(a_ref.clone()),
(None, Some(b_ref)) => Some(b_ref.clone()),
(None, None) => None, (None, None) => None,
} }
} }

View File

@ -217,43 +217,35 @@ impl IProfiles {
/// be used to update the remote item /// be used to update the remote item
/// only patch `updated` `extra` `file_data` /// only patch `updated` `extra` `file_data`
pub async fn update_item(&mut self, uid: &String, item: &mut PrfItem) -> Result<()> { pub async fn update_item(&mut self, uid: &String, item: &mut PrfItem) -> Result<()> {
if self.items.is_none() { let target = self
self.items = Some(vec![]); .items
} .get_or_insert_default()
.iter_mut()
.find(|each| each.uid.as_ref() == Some(uid))
.ok_or_else(|| anyhow::anyhow!("Item not found"))?;
// find the item target.extra = item.extra;
let _ = self.get_item(uid)?; target.updated = item.updated;
target.home = std::mem::take(&mut item.home);
target.option = PrfOption::merge(target.option.as_ref(), item.option.as_ref());
if let Some(items) = self.items.as_mut() { let Some(file_data) = item.file_data.take() else {
let some_uid = Some(uid.clone()); return self.save_file().await;
};
for each in items.iter_mut() { let file = target
if each.uid == some_uid { .file
each.extra = item.extra; .take()
each.updated = item.updated; .or_else(|| item.file.take())
each.home = item.home.to_owned(); .unwrap_or_else(|| format!("{}.yaml", uid).into());
each.option = PrfOption::merge(each.option.as_ref(), item.option.as_ref());
// save the file data
// move the field value after save
if let Some(file_data) = item.file_data.take() {
let file = each.file.take();
let file =
file.unwrap_or_else(|| item.file.take().unwrap_or_else(|| format!("{}.yaml", &uid).into()));
// the file must exists
each.file = Some(file.clone());
let path = dirs::app_profiles_dir()?.join(file.as_str()); let path = dirs::app_profiles_dir()?.join(file.as_str());
fs::write(&path, file_data.as_bytes()) fs::write(&path, file_data.as_bytes())
.await .await
.with_context(|| format!("failed to write to file \"{file}\""))?; .with_context(|| format!("failed to write to file \"{file}\""))?;
}
break; target.file = Some(file);
}
}
}
self.save_file().await self.save_file().await
} }