Files
clash-verge-rev/src/services/proxy-test-url.ts
T
Tunglies 6e08a77a84 refactor(backend): specta ipc bindings (#8195)
* refactor(ipc): generate bindings with Specta

* fix(profile): project IPC inputs to consumed fields

* fix(events): remove unused refresh payloads

* fix(webdav): return only consumed backup metadata

* fix(network): trim unused interface metadata

* fix(sysinfo): return only displayed system fields

* chore(knip): check generated runtime exports

* fix(proxy): confirm runtime chain updates before UI changes

* fix(clipboard): propagate proxy environment copy failures

* refactor(dns): remove ignored runtime patch

* refactor(core): trim unused upgrade response fields

* refactor(ipc): avoid redundant response copies

* refactor(proxy): clarify automatic proxy query naming

* chore(tests): remove added IPC regression tests

* refactor(ipc): enforce typed command boundaries

* chore(contract): check generated bindings before push

* refactor(ipc): remove unused proxy liveness payloads
2026-10-12 06:16:05 +00:00

102 lines
2.8 KiB
TypeScript

import {
getProfiles,
patchProfile,
syncTrayProxySelection,
} from '@/services/cmds'
import { mutate } from '@/services/mutate'
function readLegacyTestUrls(uid: string): Record<string, string> {
try {
const states = JSON.parse(localStorage.getItem('proxy-head-state') || '{}')[
uid
]
return Object.fromEntries(
Object.entries(states || {}).flatMap(([name, state]) => {
const url = (state as { testUrl?: string }).testUrl
return typeof url === 'string' && url.trim() ? [[name, url.trim()]] : []
}),
)
} catch {
return {}
}
}
export async function saveProfileTestUrls(
uid: string,
urls: Record<string, string>,
migrateOnly = false,
) {
return mutate(
async () => {
const profiles = await getProfiles()
const profile = profiles.items?.find((item) => item.uid === uid)
if (!profile || (migrateOnly && profile.latency_test_urls !== undefined))
return
await patchProfile(uid, {
latency_test_urls: {
...(profile.latency_test_urls ?? readLegacyTestUrls(uid)),
...urls,
},
})
await syncTrayProxySelection().catch((error) => {
console.error(
'Failed to refresh tray after saving latency test URL:',
error,
)
})
},
{ id: `patch-profile:${uid}`, revalidate: [['getProfiles']] },
)
}
const migrating = new Set<string>()
export function migrateProfileTestUrls(profiles: IProfilesConfig) {
for (const profile of profiles.items || []) {
const uid = profile.uid
if (!uid) continue
if (profile.latency_test_urls !== undefined || migrating.has(uid)) continue
const urls = readLegacyTestUrls(uid)
if (!Object.keys(urls).length) continue
migrating.add(uid)
void saveProfileTestUrls(uid, urls, true)
.catch((error) => {
console.error('Failed to migrate latency test URLs:', error)
})
.finally(() => migrating.delete(uid))
}
}
const pending = new Map<string, Record<string, { url: string }>>()
export async function commitProfileTestUrl(
uid: string,
group: string,
url: string,
) {
const edit = { url: url.trim() }
const urls = { ...pending.get(uid), [group]: edit }
pending.set(uid, urls)
try {
await saveProfileTestUrls(uid, { [group]: edit.url })
const current = pending.get(uid)
if (current?.[group] === edit) {
delete current[group]
if (!Object.keys(current).length) pending.delete(uid)
}
} catch (error) {
console.error('Failed to save latency test URL:', error)
}
}
export function profileTestUrls(profile: IProfileItem): Record<string, string> {
return {
...profile.latency_test_urls,
...Object.fromEntries(
Object.entries(
(profile.uid ? pending.get(profile.uid) : undefined) ?? {},
).map(([group, edit]) => [group, edit.url]),
),
}
}