CodeX - Dash and API Fixed
This commit is contained in:
153
bot/utils/tunnel.py
Normal file
153
bot/utils/tunnel.py
Normal file
@@ -0,0 +1,153 @@
|
||||
# ╔══════════════════════════════════════════════════════════════════╗
|
||||
# ║ ║
|
||||
# ║ ░█▀▀░█▀█░█▀▄░█▀▀░█░█ ░█▀▄░█▀▀░█░█░█▀▀ ║
|
||||
# ║ ░█░░░█░█░█░█░█▀▀░▄▀▄ ░█░█░█▀▀░▀▄▀░▀▀█ ║
|
||||
# ║ ░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ ░▀▀░░▀▀▀░░▀░░▀▀▀ ║
|
||||
# ║ ║
|
||||
# ║ © 2026 CodeX Devs — All Rights Reserved ║
|
||||
# ║ ║
|
||||
# ║ discord ── https://discord.gg/codexdev ║
|
||||
# ║ youtube ── https://youtube.com/@CodeXDevs ║
|
||||
# ║ github ── https://github.com/RayExo ║
|
||||
# ║ ║
|
||||
# ╚══════════════════════════════════════════════════════════════════╝
|
||||
|
||||
"""
|
||||
HTTPS Tunnel for the ZyroX API using pyngrok.
|
||||
|
||||
pyngrok is a pure Python package that automatically downloads the ngrok binary
|
||||
on first run — no system installs, works on Pterodactyl out of the box.
|
||||
|
||||
With a free ngrok account + a reserved static domain you get the SAME URL on
|
||||
every restart (free tier gives you 1 static domain).
|
||||
|
||||
──────────────────────────────────────────────────────────────────────────────
|
||||
One-time setup (do this once)
|
||||
──────────────────────────────────────────────────────────────────────────────
|
||||
1. Sign up for a free account at https://ngrok.com
|
||||
2. Copy your authtoken from https://dashboard.ngrok.com/get-started/your-authtoken
|
||||
3. Reserve a free static domain at https://dashboard.ngrok.com/domains
|
||||
(looks like: xxxx-xxxx-xxxx.ngrok-free.app)
|
||||
4. Add these two vars to your .env:
|
||||
NGROK_AUTHTOKEN = your_token_here
|
||||
NGROK_DOMAIN = xxxx-xxxx-xxxx.ngrok-free.app
|
||||
5. Set TUNNEL_ENABLED = "true"
|
||||
|
||||
That's it — pyngrok handles the binary download automatically on first start.
|
||||
──────────────────────────────────────────────────────────────────────────────
|
||||
"""
|
||||
|
||||
import os
|
||||
import time
|
||||
import threading
|
||||
|
||||
# ── env vars ──────────────────────────────────────────────────────────────────
|
||||
TUNNEL_ENABLED = os.getenv("TUNNEL_ENABLED", "true").strip().lower() == "true"
|
||||
NGROK_AUTHTOKEN = os.getenv("NGROK_AUTHTOKEN", "").strip()
|
||||
NGROK_DOMAIN = os.getenv("NGROK_DOMAIN", "").strip() # e.g. xxxx.ngrok-free.app
|
||||
API_PORT = int(os.getenv("API_PORT", "8000"))
|
||||
|
||||
# ── colours ───────────────────────────────────────────────────────────────────
|
||||
_CYAN = "\033[36m"
|
||||
_GREEN = "\033[32m"
|
||||
_YELLOW = "\033[33m"
|
||||
_RED = "\033[31m"
|
||||
_RESET = "\033[0m"
|
||||
|
||||
|
||||
def _run_ngrok(port: int, domain: str) -> None:
|
||||
"""
|
||||
Blocking loop: opens an ngrok tunnel and keeps it alive.
|
||||
Restarts automatically if the connection drops.
|
||||
"""
|
||||
try:
|
||||
from pyngrok import ngrok, conf, exception as ngrok_exc
|
||||
except ImportError:
|
||||
print(
|
||||
f"{_RED}◈ Tunnel: pyngrok is not installed.\n"
|
||||
f" Run: pip install pyngrok{_RESET}"
|
||||
)
|
||||
return
|
||||
|
||||
# Set the authtoken (pyngrok persists it for future runs)
|
||||
if NGROK_AUTHTOKEN:
|
||||
conf.get_default().auth_token = NGROK_AUTHTOKEN
|
||||
|
||||
while True:
|
||||
tunnel = None
|
||||
try:
|
||||
options = {"addr": port, "proto": "http"}
|
||||
if domain:
|
||||
options["hostname"] = domain # use reserved static domain
|
||||
|
||||
# NOTE: request_header_add is NOT supported via the pyngrok API.
|
||||
# Instead the FastAPI middleware injects the ngrok-skip-browser-warning
|
||||
# header on every response, which achieves the same result.
|
||||
|
||||
tunnel = ngrok.connect(**options)
|
||||
public_url = tunnel.public_url.replace("http://", "https://")
|
||||
|
||||
print(f"{_GREEN}◈ Tunnel: API is live at {public_url}{_RESET}")
|
||||
print(f"{_CYAN} ↳ set NEXT_PUBLIC_API_URL={public_url}/api/v1 in your dashboard .env{_RESET}")
|
||||
|
||||
# Block until the tunnel process exits
|
||||
ngrok.get_ngrok_process().proc.wait()
|
||||
|
||||
except ngrok_exc.PyngrokNgrokHTTPError as e:
|
||||
# Catches auth errors (401) and other ngrok HTTP-level errors
|
||||
msg = str(e).lower()
|
||||
if "401" in msg or "auth" in msg or "token" in msg:
|
||||
print(
|
||||
f"{_RED}◈ Tunnel: invalid NGROK_AUTHTOKEN.\n"
|
||||
f" Get your token from https://dashboard.ngrok.com/get-started/your-authtoken{_RESET}"
|
||||
)
|
||||
return # no point retrying with a bad token
|
||||
print(f"{_RED}◈ Tunnel: ngrok HTTP error — {e}{_RESET}")
|
||||
|
||||
except ngrok_exc.PyngrokNgrokError as e:
|
||||
print(f"{_RED}◈ Tunnel: ngrok error — {e}{_RESET}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"{_RED}◈ Tunnel: unexpected error — {e}{_RESET}")
|
||||
|
||||
finally:
|
||||
# Clean up before retrying
|
||||
try:
|
||||
if tunnel:
|
||||
ngrok.disconnect(tunnel.public_url)
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
ngrok.kill()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
print(f"{_YELLOW}◈ Tunnel: connection lost, restarting in 5 s…{_RESET}")
|
||||
time.sleep(5)
|
||||
|
||||
|
||||
def start_tunnel() -> None:
|
||||
"""
|
||||
Start the ngrok HTTPS tunnel in a background daemon thread.
|
||||
Called from CodeX.py after keep_alive().
|
||||
"""
|
||||
if not TUNNEL_ENABLED:
|
||||
print(f"{_YELLOW}◈ Tunnel: disabled via TUNNEL_ENABLED=false{_RESET}")
|
||||
return
|
||||
|
||||
if not NGROK_AUTHTOKEN:
|
||||
print(
|
||||
f"{_YELLOW}◈ Tunnel: NGROK_AUTHTOKEN is not set — tunnel skipped.\n"
|
||||
f" Get your token from https://dashboard.ngrok.com/get-started/your-authtoken{_RESET}"
|
||||
)
|
||||
return
|
||||
|
||||
if not NGROK_DOMAIN:
|
||||
print(
|
||||
f"{_YELLOW}◈ Tunnel: NGROK_DOMAIN is not set — a random URL will be used (changes each restart).\n"
|
||||
f" Reserve a free static domain at https://dashboard.ngrok.com/domains{_RESET}"
|
||||
)
|
||||
|
||||
print(f"{_CYAN}◈ Tunnel: starting ngrok tunnel on port {API_PORT}…{_RESET}")
|
||||
t = threading.Thread(target=_run_ngrok, args=(API_PORT, NGROK_DOMAIN), daemon=True)
|
||||
t.start()
|
||||
Reference in New Issue
Block a user