From 90eeabae7b80e88f4263504847d35675e494ca04 Mon Sep 17 00:00:00 2001 From: GyDi Date: Tue, 18 Oct 2022 23:19:21 +0800 Subject: [PATCH] feat: update profile with system proxy/clash proxy --- src-tauri/src/data/prfitem.rs | 43 +++++++++++++++------ src/components/profile/info-editor.tsx | 50 ++++++++++++++++++++++++- src/components/profile/profile-item.tsx | 30 ++++++++++++--- src/components/profile/profile-new.tsx | 48 +++++++++++++++++++++++- src/services/types.d.ts | 1 + 5 files changed, 152 insertions(+), 20 deletions(-) diff --git a/src-tauri/src/data/prfitem.rs b/src-tauri/src/data/prfitem.rs index 7f94f13..2a01b1d 100644 --- a/src-tauri/src/data/prfitem.rs +++ b/src-tauri/src/data/prfitem.rs @@ -69,9 +69,15 @@ pub struct PrfOption { pub user_agent: Option, /// for `remote` profile + /// use system proxy #[serde(skip_serializing_if = "Option::is_none")] pub with_proxy: Option, + /// for `remote` profile + /// use self proxy + #[serde(skip_serializing_if = "Option::is_none")] + pub self_proxy: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub update_interval: Option, } @@ -80,9 +86,10 @@ impl PrfOption { pub fn merge(one: Option, other: Option) -> Option { match (one, other) { (Some(mut a), Some(b)) => { - a.user_agent = a.user_agent.or(b.user_agent); - a.with_proxy = a.with_proxy.or(b.with_proxy); - a.update_interval = a.update_interval.or(b.update_interval); + a.user_agent = b.user_agent.or(a.user_agent); + a.with_proxy = b.with_proxy.or(a.with_proxy); + a.self_proxy = b.self_proxy.or(a.self_proxy); + a.update_interval = b.update_interval.or(a.update_interval); Some(a) } t @ _ => t.0.or(t.1), @@ -174,19 +181,31 @@ impl PrfItem { desc: Option, option: Option, ) -> Result { - let with_proxy = match option.as_ref() { - Some(opt) => opt.with_proxy.unwrap_or(false), - None => false, - }; - let user_agent = match option.as_ref() { - Some(opt) => opt.user_agent.clone(), - None => None, - }; + let opt_ref = option.as_ref(); + let with_proxy = opt_ref.map_or(false, |o| o.with_proxy.unwrap_or(false)); + let self_proxy = opt_ref.map_or(false, |o| o.self_proxy.unwrap_or(false)); + let user_agent = opt_ref.map_or(None, |o| o.user_agent.clone()); let mut builder = reqwest::ClientBuilder::new(); - if !with_proxy { + if !with_proxy && !self_proxy { builder = builder.no_proxy(); + } else if self_proxy { + // 使用软件自己的代理 + let data = super::Data::global(); + let port = data.clash.lock().info.port.clone(); + let port = port.ok_or(anyhow::anyhow!("failed to get clash info port"))?; + let proxy_scheme = format!("http://127.0.0.1:{port}"); + + if let Ok(proxy) = reqwest::Proxy::http(&proxy_scheme) { + builder = builder.proxy(proxy); + } + if let Ok(proxy) = reqwest::Proxy::https(&proxy_scheme) { + builder = builder.proxy(proxy); + } + if let Ok(proxy) = reqwest::Proxy::all(&proxy_scheme) { + builder = builder.proxy(proxy); + } } let version = unsafe { dirs::APP_VERSION }; diff --git a/src/components/profile/info-editor.tsx b/src/components/profile/info-editor.tsx index 2f9a107..941dc62 100644 --- a/src/components/profile/info-editor.tsx +++ b/src/components/profile/info-editor.tsx @@ -8,7 +8,9 @@ import { DialogActions, DialogContent, DialogTitle, + FormControlLabel, IconButton, + Switch, TextField, } from "@mui/material"; import { Settings } from "@mui/icons-material"; @@ -34,11 +36,15 @@ const InfoEditor = (props: Props) => { useEffect(() => { if (itemData) { + const { option } = itemData; setForm({ ...itemData }); - setOption(itemData.option ?? {}); + setOption(option ?? {}); setShowOpt( itemData.type === "remote" && - (!!itemData.option?.user_agent || !!itemData.option?.update_interval) + (!!option?.user_agent || + !!option?.update_interval || + !!option?.self_proxy || + !!option?.with_proxy) ); } }, [itemData]); @@ -138,6 +144,46 @@ const InfoEditor = (props: Props) => { onKeyDown={(e) => e.key === "Enter" && onUpdate()} /> )} + + {form.type === "remote" && showOpt && ( + + setOption((o) => ({ + self_proxy: c ? false : o.self_proxy ?? false, + with_proxy: c, + })) + } + /> + } + /> + )} + + {form.type === "remote" && showOpt && ( + + setOption((o) => ({ + with_proxy: c ? false : o.with_proxy ?? false, + self_proxy: c, + })) + } + /> + } + /> + )} diff --git a/src/components/profile/profile-item.tsx b/src/components/profile/profile-item.tsx index 2de20cd..9ad6bfa 100644 --- a/src/components/profile/profile-item.tsx +++ b/src/components/profile/profile-item.tsx @@ -110,12 +110,32 @@ const ProfileItem = (props: Props) => { } }); - const onUpdate = useLockFn(async (withProxy: boolean) => { + /// 0 不使用任何代理 + /// 1 使用配置好的代理 + /// 2 至少使用一个代理,根据配置,如果没配置,默认使用系统代理 + const onUpdate = useLockFn(async (type: 0 | 1 | 2) => { setAnchorEl(null); setLoadingCache((cache) => ({ ...cache, [itemData.uid]: true })); + const option: Partial = {}; + + if (type === 0) { + option.with_proxy = false; + option.self_proxy = false; + } else if (type === 1) { + // nothing + } else if (type === 2) { + if (itemData.option?.self_proxy) { + option.with_proxy = false; + option.self_proxy = true; + } else { + option.with_proxy = true; + option.self_proxy = false; + } + } + try { - await updateProfile(itemData.uid, { with_proxy: withProxy }); + await updateProfile(itemData.uid, option); mutate("getProfiles"); } catch (err: any) { const errmsg = err?.message || err.toString(); @@ -142,8 +162,8 @@ const ProfileItem = (props: Props) => { { label: "Edit Info", handler: onEditInfo }, { label: "Edit File", handler: onEditFile }, { label: "Open File", handler: onOpenFile }, - { label: "Update", handler: () => onUpdate(false) }, - { label: "Update(Proxy)", handler: () => onUpdate(true) }, + { label: "Update", handler: () => onUpdate(0) }, + { label: "Update(Proxy)", handler: () => onUpdate(2) }, { label: "Delete", handler: onDelete }, ]; const fileModeMenu = [ @@ -199,7 +219,7 @@ const ProfileItem = (props: Props) => { disabled={loading} onClick={(e) => { e.stopPropagation(); - onUpdate(false); + onUpdate(1); }} > diff --git a/src/components/profile/profile-new.tsx b/src/components/profile/profile-new.tsx index dfe24bb..7454316 100644 --- a/src/components/profile/profile-new.tsx +++ b/src/components/profile/profile-new.tsx @@ -9,10 +9,12 @@ import { DialogContent, DialogTitle, FormControl, + FormControlLabel, IconButton, InputLabel, MenuItem, Select, + Switch, TextField, } from "@mui/material"; import { Settings } from "@mui/icons-material"; @@ -40,7 +42,11 @@ const ProfileNew = (props: Props) => { const [showOpt, setShowOpt] = useState(false); // can add more option - const [option, setOption] = useSetState({ user_agent: "" }); + const [option, setOption] = useSetState({ + user_agent: "", + with_proxy: false, + self_proxy: false, + }); // file input const fileDataRef = useRef(null); @@ -141,6 +147,46 @@ const ProfileNew = (props: Props) => { onChange={(e) => setOption({ user_agent: e.target.value })} /> )} + + {form.type === "remote" && showOpt && ( + + setOption((o) => ({ + self_proxy: c ? false : o.self_proxy, + with_proxy: c, + })) + } + /> + } + /> + )} + + {form.type === "remote" && showOpt && ( + + setOption((o) => ({ + with_proxy: c ? false : o.with_proxy, + self_proxy: c, + })) + } + /> + } + /> + )} diff --git a/src/services/types.d.ts b/src/services/types.d.ts index 7f8d868..e537af4 100644 --- a/src/services/types.d.ts +++ b/src/services/types.d.ts @@ -124,6 +124,7 @@ declare namespace CmdType { interface ProfileOption { user_agent?: string; with_proxy?: boolean; + self_proxy?: boolean; update_interval?: number; }