relay over ws supossedly working
This commit is contained in:
@@ -35,13 +35,32 @@ def _get_json(url: str, timeout: float = 10.0) -> dict:
|
||||
return json.loads(r.read())
|
||||
|
||||
|
||||
def _infer_relay_url_from_tracker(tracker_url: str) -> str | None:
|
||||
"""Infer relay WebSocket URL from a public HTTPS tracker origin.
|
||||
|
||||
Public deployments colocate relay at /ws on the same host as the tracker API
|
||||
(see QUICKSTART nginx layout). Local LAN trackers use a separate relay port
|
||||
and must advertise relay_url explicitly via /v1/network/map.
|
||||
"""
|
||||
parsed = urllib.parse.urlparse(tracker_url)
|
||||
if parsed.scheme != "https":
|
||||
return None
|
||||
host = parsed.hostname
|
||||
if not host or host in ("127.0.0.1", "localhost"):
|
||||
return None
|
||||
return f"wss://{parsed.netloc}/ws"
|
||||
|
||||
|
||||
def _discover_relay_url(tracker_url: str) -> str | None:
|
||||
relay_url: str | None = None
|
||||
try:
|
||||
network_map = _get_json(f"{tracker_url}/v1/network/map", timeout=5.0)
|
||||
raw = network_map.get("relay_url")
|
||||
if isinstance(raw, str) and raw:
|
||||
relay_url = raw
|
||||
except Exception:
|
||||
return None
|
||||
relay_url = network_map.get("relay_url")
|
||||
return relay_url if isinstance(relay_url, str) and relay_url else None
|
||||
pass
|
||||
return relay_url or _infer_relay_url_from_tracker(tracker_url)
|
||||
|
||||
|
||||
def _start_relay_bridge_if_available(
|
||||
@@ -49,8 +68,9 @@ def _start_relay_bridge_if_available(
|
||||
wallet_address: str,
|
||||
local_base_url: str,
|
||||
advertised_endpoint: str,
|
||||
relay_url: str | None = None,
|
||||
) -> tuple[RelayHttpBridge | None, dict]:
|
||||
relay_url = _discover_relay_url(tracker_url)
|
||||
relay_url = relay_url or _discover_relay_url(tracker_url)
|
||||
if not relay_url:
|
||||
return None, {}
|
||||
peer_id = peer_id_from_wallet(wallet_address)
|
||||
@@ -222,7 +242,8 @@ def _warn_virtual_network_ip(ip: str | None) -> None:
|
||||
f" This range is used by Docker, WSL2, and virtual machines and is\n"
|
||||
f" NOT reachable from other physical machines on your LAN.\n"
|
||||
f" Cross-host pipeline hops WILL time out.\n"
|
||||
f" Fix: pass --advertise-host <your-LAN-ip> (e.g. 192.168.x.x).\n",
|
||||
f" Fix: use a public tracker with relay (wss://…/ws), or pass\n"
|
||||
f" --advertise-host <your-LAN-ip> (e.g. 192.168.x.x).\n",
|
||||
flush=True,
|
||||
)
|
||||
except Exception:
|
||||
@@ -260,6 +281,7 @@ def run_startup(
|
||||
"""
|
||||
|
||||
tracker_url = tracker_url.rstrip("/")
|
||||
relay_url = _discover_relay_url(tracker_url)
|
||||
|
||||
# 1. Hardware detection
|
||||
if advertise_host is None and host == "0.0.0.0":
|
||||
@@ -275,7 +297,10 @@ def run_startup(
|
||||
except Exception:
|
||||
advertise_host = socket.getfqdn()
|
||||
|
||||
_warn_virtual_network_ip(advertise_host)
|
||||
if relay_url:
|
||||
print(f"Relay advertised by tracker — using outbound tunnel {relay_url}", flush=True)
|
||||
else:
|
||||
_warn_virtual_network_ip(advertise_host)
|
||||
|
||||
print("Detecting hardware...", flush=True)
|
||||
hw = detect_hardware()
|
||||
@@ -361,6 +386,7 @@ def run_startup(
|
||||
address,
|
||||
local_base_url,
|
||||
endpoint,
|
||||
relay_url=relay_url,
|
||||
)
|
||||
_attach_relay_bridge(node, relay_bridge)
|
||||
# Register with tracker so other nodes can auto-join this model.
|
||||
@@ -451,6 +477,7 @@ def run_startup(
|
||||
address,
|
||||
local_base_url,
|
||||
endpoint,
|
||||
relay_url=relay_url,
|
||||
)
|
||||
_attach_relay_bridge(node, relay_bridge)
|
||||
auto_reg_payload = {
|
||||
@@ -548,6 +575,7 @@ def run_startup(
|
||||
address,
|
||||
local_base_url,
|
||||
endpoint,
|
||||
relay_url=relay_url,
|
||||
)
|
||||
_attach_relay_bridge(node, relay_bridge)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import argparse
|
||||
import sys
|
||||
import time
|
||||
|
||||
from .server import TrackerServer
|
||||
from .server import TrackerServer, derive_relay_url_from_public_tracker_url
|
||||
|
||||
|
||||
def main() -> None:
|
||||
@@ -52,6 +52,7 @@ def main() -> None:
|
||||
|
||||
if args.command in {None, "start"}:
|
||||
cluster_peers = [u.strip() for u in args.cluster_peers.split(",") if u.strip()]
|
||||
relay_url = args.relay_url or derive_relay_url_from_public_tracker_url(args.self_url)
|
||||
server = TrackerServer(
|
||||
host=args.host,
|
||||
port=args.port,
|
||||
@@ -59,7 +60,7 @@ def main() -> None:
|
||||
cluster_peers=cluster_peers or None,
|
||||
cluster_self_url=args.self_url,
|
||||
stats_db=getattr(args, "stats_db", None),
|
||||
relay_url=args.relay_url,
|
||||
relay_url=relay_url,
|
||||
)
|
||||
port = server.start()
|
||||
print(f"meshnet-tracker listening on http://{args.host}:{port}", flush=True)
|
||||
|
||||
@@ -37,6 +37,19 @@ from .gossip import NodeGossip
|
||||
from .raft import RaftNode
|
||||
|
||||
|
||||
def derive_relay_url_from_public_tracker_url(url: str | None) -> str | None:
|
||||
"""Return wss://host/ws when url is a public HTTPS tracker origin."""
|
||||
if not url:
|
||||
return None
|
||||
parsed = urllib.parse.urlparse(url)
|
||||
if parsed.scheme != "https":
|
||||
return None
|
||||
host = parsed.hostname
|
||||
if not host or host in ("127.0.0.1", "localhost"):
|
||||
return None
|
||||
return f"wss://{parsed.netloc}/ws"
|
||||
|
||||
|
||||
DEFAULT_MODEL_PRESETS: dict[str, dict] = {
|
||||
"stub-model": {
|
||||
"layers_start": 0,
|
||||
@@ -1228,6 +1241,33 @@ class _TrackerHandler(http.server.BaseHTTPRequestHandler):
|
||||
if auth:
|
||||
req.add_header("Authorization", auth)
|
||||
|
||||
relay_headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Meshnet-Route": downstream_urls,
|
||||
**({"Authorization": auth} if auth else {}),
|
||||
}
|
||||
|
||||
if node.relay_addr:
|
||||
print(
|
||||
f"[tracker] proxy via relay {request_id}: {node.relay_addr} "
|
||||
f"(direct endpoint {target_url})",
|
||||
flush=True,
|
||||
)
|
||||
relayed = _relay_http_request(
|
||||
node.relay_addr,
|
||||
path="/v1/chat/completions",
|
||||
body=raw_body,
|
||||
headers=relay_headers,
|
||||
)
|
||||
if relayed is not None:
|
||||
self._send_relayed_response(relayed)
|
||||
return
|
||||
print(
|
||||
f"[tracker] relay proxy failed {request_id}: {node.relay_addr}; "
|
||||
f"trying direct {target_url}",
|
||||
flush=True,
|
||||
)
|
||||
|
||||
try:
|
||||
upstream = urllib.request.urlopen(req, timeout=300.0)
|
||||
print(f"[tracker] proxy connected {request_id}: {target_url}", flush=True)
|
||||
@@ -1247,23 +1287,11 @@ class _TrackerHandler(http.server.BaseHTTPRequestHandler):
|
||||
if node.relay_addr:
|
||||
print(
|
||||
f"[tracker] direct proxy failed {request_id}: {target_url}: {exc}; "
|
||||
f"trying relay {node.relay_addr}",
|
||||
f"relay already attempted for {node.relay_addr}",
|
||||
flush=True,
|
||||
)
|
||||
relayed = _relay_http_request(
|
||||
node.relay_addr,
|
||||
path="/v1/chat/completions",
|
||||
body=raw_body,
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"X-Meshnet-Route": downstream_urls,
|
||||
**({"Authorization": auth} if auth else {}),
|
||||
},
|
||||
)
|
||||
if relayed is not None:
|
||||
self._send_relayed_response(relayed)
|
||||
return
|
||||
print(f"[tracker] proxy failed {request_id}: {target_url}: {exc}", flush=True)
|
||||
else:
|
||||
print(f"[tracker] proxy failed {request_id}: {target_url}: {exc}", flush=True)
|
||||
self._send_json(503, {"error": {
|
||||
"message": f"upstream node unreachable: {exc}",
|
||||
"type": "service_unavailable",
|
||||
@@ -2040,6 +2068,11 @@ class TrackerServer:
|
||||
if self._server is not None:
|
||||
raise RuntimeError("TrackerServer is already running")
|
||||
|
||||
effective_relay_url = (
|
||||
self._relay_url
|
||||
or derive_relay_url_from_public_tracker_url(self._cluster_self_url)
|
||||
)
|
||||
|
||||
# Start HTTP server first so we know our port
|
||||
self._server = _TrackerHTTPServer(
|
||||
(self._host, self._requested_port),
|
||||
@@ -2050,7 +2083,7 @@ class TrackerServer:
|
||||
self._model_presets,
|
||||
self._contracts,
|
||||
self._minimum_stake,
|
||||
relay_url=self._relay_url,
|
||||
relay_url=effective_relay_url,
|
||||
stats=self._stats,
|
||||
)
|
||||
self.port = self._server.server_address[1]
|
||||
|
||||
Reference in New Issue
Block a user