Add relay-backed public node registration
This commit is contained in:
@@ -295,6 +295,61 @@ def test_relay_circuit_relay_proxies_message():
|
||||
assert received_via_relay, "NAT'd peer did not receive message via circuit relay"
|
||||
|
||||
|
||||
def test_relay_rpc_round_trips_http_request_to_peer():
|
||||
"""Relay /rpc/<peer> sends one HTTP-shaped request to a connected peer."""
|
||||
import websockets.sync.client as wsc # type: ignore[import]
|
||||
from meshnet_relay.server import RelayServer
|
||||
|
||||
relay = RelayServer(host="127.0.0.1", port=0)
|
||||
port = relay.start()
|
||||
ready = threading.Event()
|
||||
|
||||
def run_peer():
|
||||
with wsc.connect(f"ws://127.0.0.1:{port}/ws") as ws:
|
||||
ws.send(json.dumps({
|
||||
"topic": "peer-register",
|
||||
"version": 1,
|
||||
"from_peer": "rpc_peer",
|
||||
"msg_id": "rpc-reg-001",
|
||||
"payload": {"peer_id": "rpc_peer", "addr": ""},
|
||||
}))
|
||||
ws.recv()
|
||||
ready.set()
|
||||
envelope = json.loads(ws.recv(timeout=3))
|
||||
payload = envelope["payload"]
|
||||
ws.send(json.dumps({
|
||||
"topic": "relay-http-response",
|
||||
"version": 1,
|
||||
"from_peer": "rpc_peer",
|
||||
"payload": {
|
||||
"request_id": payload["request_id"],
|
||||
"status": 200,
|
||||
"headers": {"Content-Type": "application/json"},
|
||||
"body": json.dumps({"ok": True, "path": payload["path"]}),
|
||||
},
|
||||
}))
|
||||
|
||||
peer_thread = threading.Thread(target=run_peer, daemon=True)
|
||||
peer_thread.start()
|
||||
assert ready.wait(timeout=5)
|
||||
|
||||
with wsc.connect(f"ws://127.0.0.1:{port}/rpc/rpc_peer") as ws:
|
||||
ws.send(json.dumps({
|
||||
"request_id": "req-1",
|
||||
"method": "POST",
|
||||
"path": "/v1/chat/completions",
|
||||
"headers": {"Content-Type": "application/json"},
|
||||
"body": "{}",
|
||||
}))
|
||||
response = json.loads(ws.recv(timeout=5))
|
||||
|
||||
relay.stop()
|
||||
peer_thread.join(timeout=3)
|
||||
|
||||
assert response["status"] == 200
|
||||
assert json.loads(response["body"]) == {"ok": True, "path": "/v1/chat/completions"}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tracker gossip fields tests
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -349,6 +404,41 @@ def test_tracker_accepts_registration_without_gossip_fields():
|
||||
assert "node_id" in resp
|
||||
|
||||
|
||||
def test_tracker_network_map_exposes_relay_and_registered_peer():
|
||||
import json as _json
|
||||
import urllib.request
|
||||
|
||||
from meshnet_tracker.server import TrackerServer
|
||||
|
||||
tracker = TrackerServer(host="127.0.0.1", port=0, relay_url="wss://ai.neuron.d-popov.com/ws")
|
||||
port = tracker.start()
|
||||
url = f"http://127.0.0.1:{port}"
|
||||
try:
|
||||
req = urllib.request.Request(
|
||||
f"{url}/v1/nodes/register",
|
||||
data=_json.dumps({
|
||||
"endpoint": "http://192.0.2.10:7000",
|
||||
"model": "stub-model",
|
||||
"shard_start": 0,
|
||||
"shard_end": 31,
|
||||
"relay_addr": "wss://ai.neuron.d-popov.com/rpc/peer123",
|
||||
"peer_id": "peer123",
|
||||
}).encode(),
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="POST",
|
||||
)
|
||||
with urllib.request.urlopen(req, timeout=5):
|
||||
pass
|
||||
with urllib.request.urlopen(f"{url}/v1/network/map", timeout=5) as resp:
|
||||
body = _json.loads(resp.read())
|
||||
finally:
|
||||
tracker.stop()
|
||||
|
||||
assert body["relay_url"] == "wss://ai.neuron.d-popov.com/ws"
|
||||
assert body["nodes"][0]["relay_addr"] == "wss://ai.neuron.d-popov.com/rpc/peer123"
|
||||
assert body["nodes"][0]["peer_id"] == "peer123"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# mDNS (no-op without zeroconf installed)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user