extends SceneTree
# Two peers in one process: one holds a file, the other fetches it over a real
# UDX connection with real Noise encryption and real Protomux framing. This is
# the first test where bytes cross a socket rather than a loopback object.
func _init():
var n := {"ok": 0, "bad": 0}
var chk := func(c: bool, what: String):
if c: n.ok += 1; print(" ok ", what)
else: n.bad += 1; print(" FAIL ", what)
print("HyperOverlay end-to-end over a live peer connection")
var dir := "/tmp/claude-1000/ho_e2e"
DirAccess.make_dir_recursive_absolute(dir + "/a")
DirAccess.make_dir_recursive_absolute(dir + "/b")
# The asset: 400 KB of deterministic noise, so it is several chunks.
var src := dir + "/asset.bin"
var data := PackedByteArray()
data.resize(400 * 1024)
var x := 12345
for i in data.size():
x = (x * 1103515245 + 12345) & 0x7fffffff
data[i] = x >> 16 & 0xff
var f := FileAccess.open(src, FileAccess.WRITE)
f.store_buffer(data)
f.close()
var oid := FileAccess.get_sha256(src) # placeholder; real hash comes from the overlay
var server: Variant = ClassDB.instantiate("HyperswarmMultiplayerPeer")
var client: Variant = ClassDB.instantiate("HyperswarmMultiplayerPeer")
chk.call(server.create_server(38731) == OK, "server peer listening")
chk.call(client.create_client("127.0.0.1", 38731) == OK, "client peer connecting")
var ov_a: Variant = ClassDB.instantiate("HyperOverlay") # holder
var ov_b: Variant = ClassDB.instantiate("HyperOverlay") # fetcher
chk.call(ov_a.open(dir + "/a"), "holder overlay open")
chk.call(ov_b.open(dir + "/b"), "fetcher overlay open")
chk.call(ov_a.attach(server), "holder attached to the server peer")
chk.call(ov_b.attach(client), "fetcher attached to the client peer")
# ASSERT THE TRANSPORT FIRST. Without this, "no overlay channel" and "the two
# peers never connected" look identical from the outside, and every fix aimed at
# the overlay would be a guess. Establish the layer underneath, then build on it.
var connected := {"server_saw": -1}
server.peer_connected.connect(func(id): connected.server_saw = id)
var t := 0
while t < 15000:
server.poll(); client.poll()
if client.get_connection_status() == MultiplayerPeer.CONNECTION_CONNECTED \
and connected.server_saw != -1:
break
OS.delay_msec(20); t += 20
chk.call(client.get_connection_status() == MultiplayerPeer.CONNECTION_CONNECTED,
"the CLIENT peer reached CONNECTION_CONNECTED (status=%d)" % client.get_connection_status())
chk.call(connected.server_saw != -1,
"the SERVER peer saw a peer connect (id=%d)" % connected.server_saw)
print(" [transport settled after %d ms]" % t)
# Only now does asking about the overlay mean anything.
var waited := 0
while (ov_a.peer_count() == 0 or ov_b.peer_count() == 0) and waited < 15000:
server.poll(); client.poll(); ov_a.poll(); ov_b.poll()
OS.delay_msec(20); waited += 20
chk.call(ov_a.peer_count() > 0, "an overlay channel appeared on the holder (%d)" % ov_a.peer_count())
chk.call(ov_b.peer_count() > 0, "and on the fetcher (%d)" % ov_b.peer_count())
# The overlay's own content hash: register, then read it back from the index by
# fetching with the hash the holder computed. We get it from the holder's
# describe() path instead — simplest is to compute it the same way the library
# does, which GDScript cannot, so use a known-good round trip: the holder serves
# under a caller-chosen id and the fetcher asks for that id.
# (The overlay verifies content against THIS hash, so it must be the real one.)
var real_oid: String = ov_a.content_hash_of(src)
chk.call(real_oid.length() == 64, "the holder can hash a file the overlay's way (%s…)" % real_oid.substr(0, 12))
ov_a.serve(real_oid, src)
var got := {"path": "", "failed": ""}
ov_b.content_fetched.connect(func(h, p): got.path = p)
ov_b.content_failed.connect(func(h, r): got.failed = r)
var dest := dir + "/b/fetched.bin"
ov_b.fetch(real_oid, dest)
waited = 0
while got.path == "" and got.failed == "" and waited < 30000:
server.poll(); client.poll(); ov_a.poll(); ov_b.poll()
OS.delay_msec(20); waited += 20
chk.call(got.failed == "", "the fetch did not fail (%s)" % got.failed)
chk.call(got.path == dest, "it completed at the requested path")
if FileAccess.file_exists(dest):
var rf := FileAccess.open(dest, FileAccess.READ)
var out := rf.get_buffer(rf.get_length())
rf.close()
chk.call(out.size() == data.size(), "%d bytes arrived" % out.size())
chk.call(out == data, "and they are byte-identical to the original")
else:
chk.call(false, "the destination file exists")
ov_b.close(); ov_a.close()
ov_a.free(); ov_b.free() # Nodes; the peers are RefCounted and free themselves
chk.call(false, "(control: must appear as FAIL and be counted)")
var real_bad: int = n.bad - 1
print("\n %d assertions pass, %d fail" % [n.ok, real_bad])
print("PASS" if real_bad == 0 else "FAIL")
quit(0 if real_bad == 0 else 1)