feat: IPv6 outbound rotation via curl --interface

- Add IPv6SourcePool for round-robin IP rotation
- fetchViaCurl: Bun.spawn + curl -6 --interface for source binding
- Auto-fallback to regular fetch when IPv6 connection fails
- Response decompression via --compressed flag
- Docker + GHCR build/deploy workflows
- 8 routable IPv6 addresses on VPS
This commit is contained in:
MythEclipse
2026-06-19 19:07:46 +07:00
parent cb6191902e
commit 17338a7dca
13 changed files with 673 additions and 47 deletions
+7 -6
View File
@@ -376,6 +376,7 @@ export async function handleChatCompletion(
proxyPool?: ProxyPool,
sessionPool?: SessionProxyPool,
sessionId?: string,
ipv6Source?: string,
): Promise<Response> {
// -- Input validation -------------------------------------------------------
const validationError = validateChatRequest(body);
@@ -420,8 +421,8 @@ export async function handleChatCompletion(
// -- Execute with session-aware or standard retry --------------------------
let result: FetchWithRetryResult =
sessionPool && sessionId
? await fetchWithSessionRetry(url, init, sessionPool, sessionId, `openai:${req.model}`)
: await fetchWithRetry(url, init, proxyPool, `openai:${req.model}`);
? await fetchWithSessionRetry(url, init, sessionPool, sessionId, `openai:${req.model}`, undefined, ipv6Source)
: await fetchWithRetry(url, init, proxyPool, `openai:${req.model}`, ipv6Source);
// -- Mimo Free: auth failure → invalidate JWT and retry once ---------------
if (
@@ -437,8 +438,8 @@ export async function handleChatCompletion(
};
result =
sessionPool && sessionId
? await fetchWithSessionRetry(url, init, sessionPool, sessionId, `openai:${req.model}`)
: await fetchWithRetry(url, init, proxyPool, `openai:${req.model}`);
? await fetchWithSessionRetry(url, init, sessionPool, sessionId, `openai:${req.model}`, undefined, ipv6Source)
: await fetchWithRetry(url, init, proxyPool, `openai:${req.model}`, ipv6Source);
}
// -- aichat.org: session expiry → invalidate session and retry once ---------
@@ -456,8 +457,8 @@ export async function handleChatCompletion(
};
result =
sessionPool && sessionId
? await fetchWithSessionRetry(url, init, sessionPool, sessionId, `openai:${req.model}`)
: await fetchWithRetry(url, init, proxyPool, `openai:${req.model}`);
? await fetchWithSessionRetry(url, init, sessionPool, sessionId, `openai:${req.model}`, undefined, ipv6Source)
: await fetchWithRetry(url, init, proxyPool, `openai:${req.model}`, ipv6Source);
}
if (result.errorClassification) {