Refactor Tunnel

This commit is contained in:
decolua
2026-05-25 16:15:34 +07:00
parent 96a9a2b36d
commit b876e0225a
35 changed files with 642 additions and 574 deletions

View File

@@ -7,15 +7,14 @@ import {
enableTunnel, enableTailscale,
isTunnelManuallyDisabled, isTunnelReconnecting, isTailscaleReconnecting,
getTunnelService, getTailscaleService, setTunnelUnexpectedExitCallback,
} from "@/lib/tunnel/tunnelManager";
import { killCloudflared, isCloudflaredRunning, ensureCloudflared } from "@/lib/tunnel/cloudflared";
import { isTailscaleRunning } from "@/lib/tunnel/tailscale";
import { loadState } from "@/lib/tunnel/state";
import { checkInternet, probeUrlAlive } from "@/lib/tunnel/networkProbe";
import {
killCloudflared, isCloudflaredRunning, ensureCloudflared,
isTailscaleRunning,
loadState,
checkInternet,
probeCloudflareAlive, probeTailscaleAlive,
RESTART_COOLDOWN_MS, NETWORK_SETTLE_MS,
WATCHDOG_INTERVAL_MS, NETWORK_CHECK_INTERVAL_MS,
} from "@/lib/tunnel/tunnelConfig";
} from "@/lib/tunnel";
import { getMitmStatus, startMitm, loadEncryptedPassword, initDbHooks, restoreToolDNS, removeAllDNSEntriesSync } from "@/mitm/manager";
import { syncToJson as syncMitmAliasCache } from "@/lib/mitmAliasCache";
@@ -130,6 +129,10 @@ async function autoStartMitm() {
}
}
// Cooldown only applies to repeating watchdog ticks (anti hammer-loop).
// Network/exit events are one-shot transitions → bypass to recover fast.
const FORCE_RESTART_REASONS = /^(startup|netchange|sleep|sleep\+netchange|online|unexpected-exit)$/;
// ─── Safe restart (4 guards: spawn / cooldown / alive / internet) ────────────
async function safeRestartTunnel(reason) {
@@ -138,27 +141,33 @@ async function safeRestartTunnel(reason) {
if (!settings.tunnelEnabled) return;
if (svc.cancelToken.cancelled) return;
if (svc.spawnInProgress) return;
// Bypass cooldown when process is dead (real respawn, not restart-loop guard)
const processDead = !isCloudflaredRunning();
if (!processDead && Date.now() - svc.lastRestartAt < RESTART_COOLDOWN_MS) return;
// Alive check: process up + BOTH direct & public URL respond → skip
// Alive check FIRST: probe URLs to decide health (process up but tunnel 530 = dead)
let alive = false;
if (isCloudflaredRunning()) {
const state = loadState();
const publicUrl = state?.shortId ? `https://r${state.shortId}.abc-tunnel.us` : null;
const directUrl = state?.tunnelUrl || null;
if (publicUrl && directUrl) {
const [publicOk, directOk] = await Promise.all([
probeUrlAlive(publicUrl),
probeUrlAlive(directUrl),
probeCloudflareAlive(publicUrl),
probeCloudflareAlive(directUrl),
]);
if (publicOk && directOk) return;
alive = publicOk && directOk;
}
}
if (alive) return;
// Degraded/dead → cooldown only prevents hammer loop after a recent restart attempt.
// Bypass for network transitions (one-shot events) so user recovers fast after wifi change.
const force = FORCE_RESTART_REASONS.test(reason);
if (!force && Date.now() - svc.lastRestartAt < RESTART_COOLDOWN_MS) {
console.log(`[Tunnel] degraded but cooldown active, skip (${reason})`);
return;
}
if (!await checkInternet()) return;
console.log(`[Tunnel] safeRestart (${reason})`);
console.log(`[Tunnel] safeRestart (${reason}) — tunnel unreachable${force ? " [force]" : ""}`);
try {
await enableTunnel();
svc.lastRestartAt = Date.now();
@@ -174,15 +183,22 @@ async function safeRestartTailscale(reason) {
if (!settings.tailscaleEnabled) return;
if (svc.cancelToken.cancelled) return;
if (svc.spawnInProgress) return;
if (Date.now() - svc.lastRestartAt < RESTART_COOLDOWN_MS) return;
// Alive check FIRST: daemon up + URL responds = healthy
let alive = false;
if (isTailscaleRunning() && settings.tailscaleUrl) {
if (await probeUrlAlive(settings.tailscaleUrl)) return;
alive = await probeTailscaleAlive(settings.tailscaleUrl);
}
if (alive) return;
const force = FORCE_RESTART_REASONS.test(reason);
if (!force && Date.now() - svc.lastRestartAt < RESTART_COOLDOWN_MS) {
console.log(`[Tailscale] degraded but cooldown active, skip (${reason})`);
return;
}
if (!await checkInternet()) return;
console.log(`[Tailscale] safeRestart (${reason})`);
console.log(`[Tailscale] safeRestart (${reason}) — tunnel unreachable${force ? " [force]" : ""}`);
try {
await enableTailscale();
svc.lastRestartAt = Date.now();