from __future__ import annotations
import argparse
import os
import sys
import time
from dataclasses import dataclass, field
from pathlib import Path
from typing import Dict, List, Optional
TESTS_DIR = Path(__file__).resolve().parent
NODES_BY_NAME: Dict[str, str] = {
"nyc": "142.93.199.50",
"sfo": "147.182.234.192",
"helsinki": "65.21.157.229",
"nuremberg": "116.203.101.172",
"singapore": "152.42.210.67",
"sydney": "170.64.176.102",
}
@dataclass(frozen=True)
class Network:
name: str api_port: int gossip_port: int token_file: Path var_prefix: str is_prod: bool
@property
def nodes(self) -> Dict[str, str]:
return dict(NODES_BY_NAME)
def token_for(self, node: str) -> str:
node_upper = node.upper()
var = f"{self.var_prefix}_{node_upper}_TK"
if not self.token_file.exists():
raise FileNotFoundError(
f"Token file {self.token_file} missing. "
f"Run `tests/e2e_deploy.sh --network {self.name}` first."
)
for line in self.token_file.read_text().splitlines():
line = line.strip()
if line.startswith(f"{var}="):
value = line[len(var) + 1:].strip()
if value.startswith('"') and value.endswith('"'):
value = value[1:-1]
return value
raise KeyError(f"{var} not in {self.token_file}")
def api_url(self, node: str) -> str:
ip = NODES_BY_NAME.get(node)
if ip is None:
raise KeyError(f"unknown node {node!r}")
return f"http://{ip}:{self.api_port}"
TEST = Network(
name="test",
api_port=13600,
gossip_port=6483,
token_file=TESTS_DIR / ".vps-tokens-test.env",
var_prefix="TEST",
is_prod=False,
)
PROD = Network(
name="prod",
api_port=12600,
gossip_port=5483,
token_file=TESTS_DIR / ".vps-tokens-prod.env",
var_prefix="PROD",
is_prod=True,
)
NETWORKS = {"test": TEST, "prod": PROD}
def add_network_arg(parser: argparse.ArgumentParser) -> None:
parser.add_argument(
"--network",
choices=["test", "prod"],
default="test",
help=(
"Which fleet to target. Default 'test' (isolated testnet on "
"ports 6483/13600). Pass 'prod' to target the production fleet "
"(5483/12600) — REAL USERS, real consequences, will pause 5s "
"for Ctrl-C before any action."
),
)
def select_network(args: Optional[argparse.Namespace] = None) -> Network:
if args is None:
parser = argparse.ArgumentParser(add_help=False)
add_network_arg(parser)
args, _ = parser.parse_known_args()
name = getattr(args, "network", "test")
return NETWORKS[name]
def banner(net: Network, *, hold_seconds: float = 5.0) -> None:
width = 70
if net.is_prod:
bar = "═" * (width - 2)
print(
f"\n\033[1;41;97m╔{bar}╗\n"
f"║{'⚠️ TARGETING: PRODUCTION FLEET ⚠️'.center(width - 2)}║\n"
f"║{('UDP ' + str(net.gossip_port) + ' / TCP ' + str(net.api_port) + ' / REAL USERS').center(width - 2)}║\n"
f"║{('token file: ' + net.token_file.name).center(width - 2)}║\n"
f"║{('Ctrl-C in ' + str(int(hold_seconds)) + 's to abort').center(width - 2)}║\n"
f"╚{bar}╝\033[0m\n",
file=sys.stderr,
)
if hold_seconds > 0 and os.environ.get("X0X_NETWORK_NO_HOLD") != "1":
try:
time.sleep(hold_seconds)
except KeyboardInterrupt:
print("\nAborted by operator.", file=sys.stderr)
sys.exit(130)
else:
bar = "─" * (width - 2)
print(
f"\n\033[1;42;30m┌{bar}┐\n"
f"│{'TARGETING: TESTNET'.center(width - 2)}│\n"
f"│{('UDP ' + str(net.gossip_port) + ' / TCP ' + str(net.api_port) + ' / no real users').center(width - 2)}│\n"
f"│{('token file: ' + net.token_file.name).center(width - 2)}│\n"
f"└{bar}┘\033[0m\n",
file=sys.stderr,
)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="x0x_network self-test")
add_network_arg(parser)
args = parser.parse_args()
net = select_network(args)
banner(net, hold_seconds=2.0)
print(f"network: {net.name}")
print(f"api_port: {net.api_port}")
print(f"gossip_port: {net.gossip_port}")
print(f"token_file: {net.token_file}")
print(f"nodes: {list(net.nodes.keys())}")
print(f"nyc URL: {net.api_url('nyc')}")
try:
tk = net.token_for("nyc")
print(f"nyc token: {tk[:16]}…")
except (FileNotFoundError, KeyError) as e:
print(f"nyc token: ERROR — {e}")