tg-tunnel: rewrite client and worker for stability on CF Workers

The old single-session architecture leaked the 6-slot CF TCP gate on every
error path (via two confused semaphores in tunnel.go), which is why Telegram
degraded progressively after each reconnect and collapsed entirely after a
few cycles. Both sides are rewritten on clean primitives:

- Worker: serialized session state, direct server.send() on the hot path,
  await socket.opened before CONNECT_OK, fire-and-forget writer.write with
  async cleanup. Minimises per-packet CPU to fit within the Worker CPU
  budget.
- Client: single writePump per session, half-close state machine with 10s
  grace (yamux-style), exactly-once gate release, ping/pong keepalive via
  SetPongHandler + SetReadDeadline. N parallel WS sessions (default 6)
  lift the per-invocation CF 6-slot ceiling to 36 concurrent TCP streams.
- Free-plan workaround: --session-ttl=8s voluntarily rotates each session
  before CF kills it for CPU exhaustion. Parallel sessions absorb the gap.
  Not needed on Paid (raise cpu_ms in wrangler.toml when subscription
  activates).
- install.sh / S98tg-tunnel: iptables rules now use -I PREROUTING 1 so
  REDIRECT precedes Keenetic's _NDM_* chains (was silently bypassed).
- Unit tests cover frame round-trip, half-close lifecycle, grim-reaper
  grace, and exactly-once gate release.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Necronicle 2026-04-12 23:58:02 +03:00
parent ca53593f68
commit e7295600ec
15 changed files with 1053 additions and 564 deletions