relay over ws supossedly working
This commit is contained in:
@@ -350,6 +350,51 @@ def test_relay_rpc_round_trips_http_request_to_peer():
|
||||
assert json.loads(response["body"]) == {"ok": True, "path": "/v1/chat/completions"}
|
||||
|
||||
|
||||
def test_node_relay_bridge_reconnects_after_failed_connection(monkeypatch):
|
||||
"""Node-side relay bridge keeps retrying its outbound WebSocket connection."""
|
||||
import websockets.sync.client as wsc # type: ignore[import]
|
||||
from meshnet_node.relay_bridge import RelayHttpBridge
|
||||
|
||||
attempts = []
|
||||
|
||||
class FakeWebSocket:
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc, tb):
|
||||
return False
|
||||
|
||||
def send(self, _message):
|
||||
pass
|
||||
|
||||
def recv(self, timeout=1):
|
||||
raise TimeoutError
|
||||
|
||||
def fake_connect(url, open_timeout=5):
|
||||
attempts.append((url, open_timeout))
|
||||
if len(attempts) == 1:
|
||||
raise OSError("temporary relay outage")
|
||||
return FakeWebSocket()
|
||||
|
||||
monkeypatch.setattr(wsc, "connect", fake_connect)
|
||||
|
||||
bridge = RelayHttpBridge(
|
||||
relay_url="ws://relay.example/ws",
|
||||
peer_id="peer-reconnect",
|
||||
local_base_url="http://127.0.0.1:8001",
|
||||
advertised_addr="http://127.0.0.1:8001",
|
||||
reconnect_interval=0.01,
|
||||
)
|
||||
try:
|
||||
info = bridge.start()
|
||||
assert info.relay_addr == "ws://relay.example/rpc/peer-reconnect"
|
||||
assert bridge.wait_connected(timeout=1.0)
|
||||
finally:
|
||||
bridge.stop()
|
||||
|
||||
assert len(attempts) >= 2
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tracker gossip fields tests
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -389,6 +434,27 @@ def _start_tracker_and_register(extra_fields: dict) -> dict:
|
||||
return resp
|
||||
|
||||
|
||||
def test_tracker_derives_relay_url_from_public_self_url():
|
||||
from meshnet_tracker.server import TrackerServer, derive_relay_url_from_public_tracker_url
|
||||
|
||||
assert derive_relay_url_from_public_tracker_url("https://ai.neuron.d-popov.com") == (
|
||||
"wss://ai.neuron.d-popov.com/ws"
|
||||
)
|
||||
assert derive_relay_url_from_public_tracker_url("http://127.0.0.1:8081") is None
|
||||
|
||||
tracker = TrackerServer(cluster_self_url="https://ai.neuron.d-popov.com")
|
||||
port = tracker.start()
|
||||
try:
|
||||
import json as _json
|
||||
import urllib.request
|
||||
|
||||
with urllib.request.urlopen(f"http://127.0.0.1:{port}/v1/network/map", timeout=5) as resp:
|
||||
body = _json.loads(resp.read())
|
||||
assert body["relay_url"] == "wss://ai.neuron.d-popov.com/ws"
|
||||
finally:
|
||||
tracker.stop()
|
||||
|
||||
|
||||
def test_tracker_accepts_relay_addr_in_registration():
|
||||
resp = _start_tracker_and_register({
|
||||
"relay_addr": "ws://relay.meshnet.ai:8765/relay/abc123",
|
||||
|
||||
@@ -11,7 +11,11 @@ import pytest
|
||||
|
||||
from meshnet_node.downloader import download_shard, write_shard_archive
|
||||
from meshnet_node.hardware import detect_hardware
|
||||
from meshnet_node.startup import _probationary_status_line, run_startup
|
||||
from meshnet_node.startup import (
|
||||
_infer_relay_url_from_tracker,
|
||||
_probationary_status_line,
|
||||
run_startup,
|
||||
)
|
||||
from meshnet_node.wallet import _b58encode, load_or_create_wallet
|
||||
from meshnet_contracts import LocalSolanaContracts
|
||||
from meshnet_tracker.server import TrackerServer
|
||||
@@ -347,6 +351,94 @@ def test_tracker_assign_lists_peers_for_same_model_shard():
|
||||
tracker.stop()
|
||||
|
||||
|
||||
def test_infer_relay_url_from_public_https_tracker():
|
||||
assert _infer_relay_url_from_tracker("https://ai.neuron.d-popov.com") == (
|
||||
"wss://ai.neuron.d-popov.com/ws"
|
||||
)
|
||||
assert _infer_relay_url_from_tracker("https://ai.neuron.d-popov.com/v1/network/map") == (
|
||||
"wss://ai.neuron.d-popov.com/ws"
|
||||
)
|
||||
assert _infer_relay_url_from_tracker("http://192.168.0.179:8081") is None
|
||||
assert _infer_relay_url_from_tracker("http://127.0.0.1:8081") is None
|
||||
|
||||
|
||||
def test_public_https_tracker_infers_relay_when_network_map_omits_relay_url(
|
||||
tmp_path,
|
||||
monkeypatch,
|
||||
capsys,
|
||||
):
|
||||
"""Nodes bootstrap relay from the tracker origin when map relay_url is null."""
|
||||
import meshnet_node.startup as startup_mod
|
||||
|
||||
class FakeBackend:
|
||||
total_layers = 24
|
||||
|
||||
class FakeTorchNodeServer:
|
||||
def __init__(self, **kwargs):
|
||||
self.backend = FakeBackend()
|
||||
self.port = None
|
||||
self.chat_completion_count = 0
|
||||
self.total_requests = 0
|
||||
self.failed_requests = 0
|
||||
self.queue_depth = 0
|
||||
|
||||
def start(self):
|
||||
self.port = 8001
|
||||
return self.port
|
||||
|
||||
def stop(self):
|
||||
pass
|
||||
|
||||
class FakeRelayHttpBridge:
|
||||
def __init__(self, relay_url, peer_id, local_base_url, advertised_addr):
|
||||
self.relay_url = relay_url
|
||||
self.peer_id = peer_id
|
||||
|
||||
@property
|
||||
def relay_addr(self):
|
||||
return f"{self.relay_url.replace('/ws', '')}/rpc/{self.peer_id}"
|
||||
|
||||
def start(self):
|
||||
return types.SimpleNamespace(peer_id=self.peer_id, relay_addr=self.relay_addr)
|
||||
|
||||
def wait_connected(self, timeout=5.0):
|
||||
return True
|
||||
|
||||
def stop(self):
|
||||
pass
|
||||
|
||||
monkeypatch.setattr(
|
||||
startup_mod,
|
||||
"detect_hardware",
|
||||
lambda: {"device": "cpu", "gpu_name": None, "vram_mb": 0},
|
||||
)
|
||||
monkeypatch.setattr(startup_mod, "_detect_num_layers", lambda _model_id: 24)
|
||||
monkeypatch.setattr(startup_mod, "TorchNodeServer", FakeTorchNodeServer)
|
||||
monkeypatch.setattr(startup_mod, "RelayHttpBridge", FakeRelayHttpBridge)
|
||||
monkeypatch.setattr(
|
||||
startup_mod,
|
||||
"_get_json",
|
||||
lambda url, timeout=10.0: {"relay_url": None, "nodes": []},
|
||||
)
|
||||
|
||||
tracker_url = "https://ai.neuron.d-popov.com"
|
||||
node = run_startup(
|
||||
tracker_url=tracker_url,
|
||||
model_id="Qwen/Qwen2.5-0.5B-Instruct",
|
||||
advertise_host="172.29.104.23",
|
||||
wallet_path=tmp_path / "wallet.json",
|
||||
)
|
||||
try:
|
||||
pass
|
||||
finally:
|
||||
node.stop()
|
||||
|
||||
output = capsys.readouterr().out
|
||||
assert "Relay advertised by tracker" in output
|
||||
assert "wss://ai.neuron.d-popov.com/ws" in output
|
||||
assert "Cross-host pipeline hops WILL time out" not in output
|
||||
|
||||
|
||||
def test_real_model_startup_summary_shows_total_layers(tmp_path, monkeypatch, capsys):
|
||||
"""Real-model startup summary prints the shard range plus total model layers."""
|
||||
import meshnet_node.startup as startup_mod
|
||||
@@ -394,6 +486,7 @@ def test_real_model_startup_summary_shows_total_layers(tmp_path, monkeypatch, ca
|
||||
def test_public_tracker_model_node_registers_relay_metadata_from_tracker_url_only(
|
||||
tmp_path,
|
||||
monkeypatch,
|
||||
capsys,
|
||||
):
|
||||
"""A node only needs the public tracker URL to discover relay metadata and register."""
|
||||
import meshnet_node.startup as startup_mod
|
||||
@@ -457,7 +550,6 @@ def test_public_tracker_model_node_registers_relay_metadata_from_tracker_url_onl
|
||||
node = run_startup(
|
||||
tracker_url=tracker_url,
|
||||
model_id="Qwen/Qwen2.5-0.5B-Instruct",
|
||||
advertise_host="203.0.113.10",
|
||||
wallet_path=tmp_path / "wallet.json",
|
||||
)
|
||||
try:
|
||||
@@ -471,9 +563,91 @@ def test_public_tracker_model_node_registers_relay_metadata_from_tracker_url_onl
|
||||
assert len(network_map["nodes"]) == 1
|
||||
registered = network_map["nodes"][0]
|
||||
assert registered["hf_repo"] == "Qwen/Qwen2.5-0.5B-Instruct"
|
||||
assert registered["endpoint"] == "http://203.0.113.10:8001"
|
||||
assert registered["endpoint"].startswith("http://")
|
||||
assert registered["endpoint"].endswith(":8001")
|
||||
assert registered["relay_addr"].startswith("ws://public-relay.example/rpc/")
|
||||
assert registered["peer_id"]
|
||||
output = capsys.readouterr().out
|
||||
assert "Relay advertised by tracker" in output
|
||||
assert "Cross-host pipeline hops WILL time out" not in output
|
||||
|
||||
|
||||
def test_public_tracker_relay_suppresses_virtual_ip_warning(
|
||||
tmp_path,
|
||||
monkeypatch,
|
||||
capsys,
|
||||
):
|
||||
"""A WSL/Docker endpoint is acceptable when the tracker advertises relay RPC."""
|
||||
import meshnet_node.startup as startup_mod
|
||||
|
||||
class FakeBackend:
|
||||
total_layers = 24
|
||||
|
||||
class FakeTorchNodeServer:
|
||||
def __init__(self, **kwargs):
|
||||
self.backend = FakeBackend()
|
||||
self.port = None
|
||||
self.chat_completion_count = 0
|
||||
self.total_requests = 0
|
||||
self.failed_requests = 0
|
||||
self.queue_depth = 0
|
||||
|
||||
def start(self):
|
||||
self.port = 8001
|
||||
return self.port
|
||||
|
||||
def stop(self):
|
||||
pass
|
||||
|
||||
class FakeRelayHttpBridge:
|
||||
def __init__(self, relay_url, peer_id, local_base_url, advertised_addr):
|
||||
self.relay_url = relay_url
|
||||
self.peer_id = peer_id
|
||||
|
||||
@property
|
||||
def relay_addr(self):
|
||||
return f"ws://public-relay.example/rpc/{self.peer_id}"
|
||||
|
||||
def start(self):
|
||||
return types.SimpleNamespace(peer_id=self.peer_id, relay_addr=self.relay_addr)
|
||||
|
||||
def wait_connected(self, timeout=5.0):
|
||||
return True
|
||||
|
||||
def stop(self):
|
||||
pass
|
||||
|
||||
monkeypatch.setattr(
|
||||
startup_mod,
|
||||
"detect_hardware",
|
||||
lambda: {"device": "cpu", "gpu_name": None, "vram_mb": 0},
|
||||
)
|
||||
monkeypatch.setattr(startup_mod, "_detect_num_layers", lambda _model_id: 24)
|
||||
monkeypatch.setattr(startup_mod, "TorchNodeServer", FakeTorchNodeServer)
|
||||
monkeypatch.setattr(startup_mod, "RelayHttpBridge", FakeRelayHttpBridge)
|
||||
|
||||
tracker = TrackerServer(relay_url="ws://public-relay.example/ws")
|
||||
tracker_port = tracker.start()
|
||||
tracker_url = f"http://127.0.0.1:{tracker_port}"
|
||||
try:
|
||||
node = run_startup(
|
||||
tracker_url=tracker_url,
|
||||
model_id="Qwen/Qwen2.5-0.5B-Instruct",
|
||||
advertise_host="172.29.104.23",
|
||||
wallet_path=tmp_path / "wallet.json",
|
||||
)
|
||||
try:
|
||||
network_map = _get_json(f"{tracker_url}/v1/network/map")
|
||||
finally:
|
||||
node.stop()
|
||||
finally:
|
||||
tracker.stop()
|
||||
|
||||
assert network_map["nodes"][0]["endpoint"] == "http://172.29.104.23:8001"
|
||||
assert network_map["nodes"][0]["relay_addr"].startswith("ws://public-relay.example/rpc/")
|
||||
output = capsys.readouterr().out
|
||||
assert "Relay advertised by tracker" in output
|
||||
assert "Cross-host pipeline hops WILL time out" not in output
|
||||
|
||||
|
||||
def test_later_node_auto_joins_existing_public_hf_model_with_only_tracker_url(
|
||||
|
||||
Reference in New Issue
Block a user