mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-08 18:37:46 +08:00
feat: 代理池均衡分发&批量添加代理节点
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
export interface BatchManualProxyNode {
|
||||
name: string
|
||||
proxy_url: string
|
||||
username?: string
|
||||
password?: string
|
||||
}
|
||||
|
||||
export interface BatchProxyNodeParseResult {
|
||||
nodes: BatchManualProxyNode[]
|
||||
errors: string[]
|
||||
}
|
||||
|
||||
const SUPPORTED_PROXY_PROTOCOLS = new Set(['http:', 'https:', 'socks5:', 'socks5h:'])
|
||||
|
||||
export function parseBatchProxyNodeInput(input: string): BatchProxyNodeParseResult {
|
||||
const entries = input
|
||||
.split(/[\n,]+/)
|
||||
.map(entry => entry.trim())
|
||||
.filter(Boolean)
|
||||
|
||||
const nodes: BatchManualProxyNode[] = []
|
||||
const errors: string[] = []
|
||||
|
||||
entries.forEach((entry, index) => {
|
||||
try {
|
||||
nodes.push(parseBatchProxyNodeEntry(entry))
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : '格式不正确'
|
||||
errors.push(`第 ${index + 1} 条 ${entry}: ${message}`)
|
||||
}
|
||||
})
|
||||
|
||||
return { nodes, errors }
|
||||
}
|
||||
|
||||
function parseBatchProxyNodeEntry(entry: string): BatchManualProxyNode {
|
||||
let url: URL
|
||||
try {
|
||||
url = new URL(entry)
|
||||
} catch {
|
||||
throw new Error('必须是合法的代理 URL')
|
||||
}
|
||||
|
||||
if (!SUPPORTED_PROXY_PROTOCOLS.has(url.protocol)) {
|
||||
throw new Error('仅支持 http/https/socks5/socks5h 协议')
|
||||
}
|
||||
|
||||
const host = url.hostname.trim()
|
||||
if (!host) {
|
||||
throw new Error('缺少主机地址')
|
||||
}
|
||||
|
||||
const username = decodeUrlCredential(url.username, '用户名')
|
||||
const password = decodeUrlCredential(url.password, '密码')
|
||||
if (!username && password) {
|
||||
throw new Error('包含密码时必须同时包含用户名')
|
||||
}
|
||||
|
||||
const port = url.port || defaultProxyPort(url.protocol)
|
||||
const proxyHost = url.host || `${host}:${port}`
|
||||
const proxyUrl = `${url.protocol}//${proxyHost}`
|
||||
|
||||
return {
|
||||
name: `${formatNodeNameHost(host)}:${port}`,
|
||||
proxy_url: proxyUrl,
|
||||
username: username || undefined,
|
||||
password: password || undefined,
|
||||
}
|
||||
}
|
||||
|
||||
function defaultProxyPort(protocol: string): string {
|
||||
if (protocol === 'https:') return '443'
|
||||
if (protocol === 'socks5:' || protocol === 'socks5h:') return '1080'
|
||||
return '80'
|
||||
}
|
||||
|
||||
function decodeUrlCredential(value: string, field: string): string {
|
||||
if (!value) return ''
|
||||
try {
|
||||
return decodeURIComponent(value)
|
||||
} catch {
|
||||
throw new Error(`${field}包含无效的 URL 编码`)
|
||||
}
|
||||
}
|
||||
|
||||
function formatNodeNameHost(host: string): string {
|
||||
if (host.includes(':') && !host.startsWith('[')) {
|
||||
return `[${host}]`
|
||||
}
|
||||
return host
|
||||
}
|
||||
Reference in New Issue
Block a user