From 6f1d9ba1b4548bf6fa0cfef56352873a482775d3 Mon Sep 17 00:00:00 2001 From: coolcoala Date: Tue, 15 Jul 2025 03:07:42 +0300 Subject: [PATCH] added support for special headers and displaying their information on the main page --- src-tauri/Cargo.lock | 1 + src-tauri/Cargo.toml | 1 + src-tauri/src/config/prfitem.rs | 79 +++++++++++++++++++++++++++++++- src-tauri/src/config/profiles.rs | 4 ++ src/pages/home.tsx | 42 ++++++++++++++--- src/services/types.d.ts | 3 ++ 6 files changed, 122 insertions(+), 8 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 189debf1..62fd3e22 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1125,6 +1125,7 @@ dependencies = [ "tokio", "tokio-tungstenite 0.27.0", "tungstenite 0.27.0", + "url", "users", "warp", "winapi", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 1ca5b722..4b669df9 100755 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -16,6 +16,7 @@ identifier = "io.github.clash-verge-rev.clash-verge-rev" tauri-build = { version = "2.3.0", features = [] } [dependencies] +url = "2.5.4" os_info = "3.0" machine-uid = "0.2" warp = "0.3.7" diff --git a/src-tauri/src/config/prfitem.rs b/src-tauri/src/config/prfitem.rs index 3671e64b..a6110d23 100644 --- a/src-tauri/src/config/prfitem.rs +++ b/src-tauri/src/config/prfitem.rs @@ -8,6 +8,8 @@ use reqwest::StatusCode; use serde::{Deserialize, Serialize}; use serde_yaml::Mapping; use std::{fs, time::Duration}; +use base64::{engine::general_purpose::STANDARD, Engine as _}; +use url::Url; use super::Config; @@ -53,6 +55,14 @@ pub struct PrfItem { #[serde(skip_serializing_if = "Option::is_none")] pub home: Option, + /// profile support url + #[serde(skip_serializing_if = "Option::is_none")] + pub support_url: Option, + + /// profile announce + #[serde(skip_serializing_if = "Option::is_none")] + pub announce: Option, + /// the file data #[serde(skip)] pub file_data: Option, @@ -234,6 +244,8 @@ impl PrfItem { ..PrfOption::default() }), home: None, + support_url: None, + announce: None, updated: Some(chrono::Local::now().timestamp() as usize), file_data: Some(file_data.unwrap_or(tmpl::ITEM_LOCAL.into())), }) @@ -297,6 +309,21 @@ impl PrfItem { let header = resp.headers(); + let mut final_url = url.to_string(); + + if let Some(new_domain_value) = header.get("new-sub-domain") { + if let Ok(new_domain) = new_domain_value.to_str() { + if !new_domain.is_empty() { + if let Ok(mut parsed_url) = Url::parse(url) { + if parsed_url.set_host(Some(new_domain)).is_ok() { + final_url = parsed_url.to_string(); + log::info!(target: "app", "URL host updated to -> {}", final_url); + } + } + } + } + } + // parse the Subscription UserInfo let extra = match header.get("Subscription-Userinfo") { Some(value) => { @@ -354,9 +381,45 @@ impl PrfItem { None => None, }; + let support_url = match header.get("support-url") { + Some(value) => { + let str_value = value.to_str().unwrap_or(""); + Some(str_value.to_string()) + } + None => None, + }; + + let announce = match header.get("announce") { + Some(value) => { + let str_value = value.to_str().unwrap_or(""); + if let Some(b64_data) = str_value.strip_prefix("base64:") { + STANDARD.decode(b64_data) + .ok() + .and_then(|bytes| String::from_utf8(bytes).ok()) + } else { + Some(str_value.to_string()) + } + } + None => None, + }; + + let profile_title = match header.get("profile-title") { + Some(value) => { + let str_value = value.to_str().unwrap_or(""); + if let Some(b64_data) = str_value.strip_prefix("base64:") { + STANDARD.decode(b64_data) + .ok() + .and_then(|bytes| String::from_utf8(bytes).ok()) + } else { + Some(str_value.to_string()) + } + } + None => None, + }; + let uid = help::get_uid("R"); let file = format!("{uid}.yaml"); - let name = name.unwrap_or(filename.unwrap_or("Remote File".into())); + let name = name.or(profile_title).unwrap_or(filename.unwrap_or("Remote File".into())); let data = resp.text_with_charset("utf-8").await?; // process the charset "UTF-8 with BOM" @@ -404,7 +467,7 @@ impl PrfItem { name: Some(name), desc, file: Some(file), - url: Some(url.into()), + url: Some(final_url), selected: None, extra, option: Some(PrfOption { @@ -417,6 +480,8 @@ impl PrfItem { ..PrfOption::default() }), home, + support_url, + announce, updated: Some(chrono::Local::now().timestamp() as usize), file_data: Some(data.into()), }) @@ -444,6 +509,8 @@ impl PrfItem { extra: None, option: None, home: None, + support_url: None, + announce: None, updated: Some(chrono::Local::now().timestamp() as usize), file_data: Some(template), }) @@ -466,6 +533,8 @@ impl PrfItem { file: Some(file), url: None, home: None, + support_url: None, + announce: None, selected: None, extra: None, option: None, @@ -487,6 +556,8 @@ impl PrfItem { file: Some(file), url: None, home: None, + support_url: None, + announce: None, selected: None, extra: None, option: None, @@ -508,6 +579,8 @@ impl PrfItem { file: Some(file), url: None, home: None, + support_url: None, + announce: None, selected: None, extra: None, option: None, @@ -529,6 +602,8 @@ impl PrfItem { file: Some(file), url: None, home: None, + support_url: None, + announce: None, selected: None, extra: None, option: None, diff --git a/src-tauri/src/config/profiles.rs b/src-tauri/src/config/profiles.rs index c717065b..19857852 100644 --- a/src-tauri/src/config/profiles.rs +++ b/src-tauri/src/config/profiles.rs @@ -220,6 +220,10 @@ impl IProfiles { each.extra = item.extra; each.updated = item.updated; each.home = item.home; + each.announce = item.announce; + each.support_url = item.support_url; + each.name = item.name; + each.url = item.url; each.option = PrfOption::merge(each.option.clone(), item.option); // save the file data // move the field value after save diff --git a/src/pages/home.tsx b/src/pages/home.tsx index 4ffe3300..e19adb21 100644 --- a/src/pages/home.tsx +++ b/src/pages/home.tsx @@ -26,6 +26,8 @@ import { Wrench, AlertTriangle, Loader2, + Globe, + Send, } from "lucide-react"; import { useVerge } from "@/hooks/use-verge"; import { useSystemState } from "@/hooks/use-system-state"; @@ -34,6 +36,7 @@ import { Switch } from "@/components/ui/switch"; import { ProxySelectors } from "@/components/home/proxy-selectors"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { closeAllConnections } from "@/services/api"; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; const MinimalHomePage: React.FC = () => { const { t } = useTranslation(); @@ -50,12 +53,12 @@ const MinimalHomePage: React.FC = () => { return items.filter((i: any) => i && allowedTypes.includes(i.type!)); }, [profiles]); - const currentProfileName = useMemo(() => { - return ( - profileItems.find((p) => p.uid === profiles?.current)?.name || - profiles?.current - ); + const currentProfile = useMemo(() => { + return profileItems.find(p => p.uid === profiles?.current); }, [profileItems, profiles?.current]); + console.log(currentProfile); + const currentProfileName = currentProfile?.name || profiles?.current; + const activateProfile = useCallback( async (uid: string, notifySuccess: boolean) => { try { @@ -200,6 +203,11 @@ const MinimalHomePage: React.FC = () => {
+ {currentProfile?.announce && ( +

+ {currentProfile.announce} +

+ )}

{

- + mutateProfiles()} /> ); diff --git a/src/services/types.d.ts b/src/services/types.d.ts index 823c21b1..27d39c29 100644 --- a/src/services/types.d.ts +++ b/src/services/types.d.ts @@ -181,6 +181,7 @@ interface IClashInfo { } interface IProfileItem { + currentProfile: any; uid: string; type?: "local" | "remote" | "merge" | "script"; name?: string; @@ -200,6 +201,8 @@ interface IProfileItem { }; option?: IProfileOption; home?: string; + support_url?: string; + announce?: string; } interface IProfileOption {