OverviewFilesCommitsIssuesDocsReleasesPeers

hyperswarm-peer / integration / test_dht_lookup.gd

124 lines · gd ref:
extends SceneTree
## Test: C++ DHT lookup against a JS-announced peer.
## Reads bootstrap from /tmp/layer_bootstrap.txt.
## Writes PASS/FAIL to /tmp/test_dht_lookup_result.txt.

const TIMEOUT := 20.0
const POLL_HZ := 0.05

var _peer: Object
var _found_pks: Array = []

func _init() -> void:
	_start.call_deferred()

func _start() -> void:
	var f := FileAccess.open("/tmp/layer_bootstrap.txt", FileAccess.READ)
	if f == null:
		_result("FAIL: no bootstrap")
		quit()
		return
	var bootstrap := PackedStringArray(f.get_as_text().strip_edges().split(","))
	f.close()
	print("[lookup] bootstrap: %s" % str(bootstrap))

	_peer = ClassDB.instantiate(&"HyperswarmMultiplayerPeer")
	var kp: Dictionary = _peer.generate_dht_keypair()
	var pk: PackedByteArray = kp["public_key"]
	var sk: PackedByteArray = kp["secret_key"]
	print("[lookup] my pk: %s" % pk.hex_encode().left(16))

	_peer.dht_peer_found.connect(func(found_pk: PackedByteArray) -> void:
		var hex := found_pk.hex_encode()
		print("[lookup] dht_peer_found: %s" % hex.left(16))
		_found_pks.append(hex)
	)

	var err = _peer.join_dht(pk, sk, bootstrap)
	if err != OK:
		_result("FAIL: join_dht=%d" % err)
		quit()
		return

	# Wait for DHT active
	var elapsed := 0.0
	while elapsed < 10.0:
		_peer.poll()
		var status: Dictionary = _peer.get_dht_status()
		if status.get("active", false):
			break
		await create_timer(POLL_HZ).timeout
		elapsed += POLL_HZ

	var dht_status: Dictionary = _peer.get_dht_status()
	print("[lookup] DHT active=%s table_size=%s" % [
		str(dht_status.get("active", false)),
		str(dht_status.get("table_size", -1))])

	if not dht_status.get("active", false):
		_result("FAIL: DHT not active after 10s")
		_peer.close()
		quit()
		return

	# Lookup topic
	var topic := "test-p2p-layer2".sha256_buffer()
	err = _peer.lookup_topic(topic)
	if err != OK:
		_result("FAIL: lookup_topic=%d" % err)
		_peer.close()
		quit()
		return

	print("[lookup] lookup_topic called, polling...")

	# Poll and wait for peers
	elapsed = 0.0
	while elapsed < TIMEOUT:
		_peer.poll()
		if _found_pks.size() > 0:
			break
		if int(elapsed * 10) % 20 == 0:
			print("[lookup] elapsed=%.1f found=%d" % [elapsed, _found_pks.size()])
		await create_timer(POLL_HZ).timeout
		elapsed += POLL_HZ

	if _found_pks.size() > 0:
		# Check if we found the JS server's pk
		var js_pk_file := FileAccess.open("/tmp/test_dht_js_pk.txt", FileAccess.READ)
		if js_pk_file != null:
			var js_pk := js_pk_file.get_as_text().strip_edges()
			js_pk_file.close()
			var matched := false
			for fpk in _found_pks:
				if fpk == js_pk:
					matched = true
					break
			if matched:
				print("[lookup] Found JS server pk — PASS")
				_result("PASS")
			else:
				print("[lookup] Found peers but not JS server")
				print("[lookup] expected: %s" % js_pk.left(16))
				print("[lookup] got: %s" % str(_found_pks))
				_result("FAIL: wrong pk")
		else:
			print("[lookup] Found %d peers (no JS pk file to verify)" % _found_pks.size())
			_result("PASS")
	else:
		print("[lookup] No peers found after %.1fs" % elapsed)
		_result("FAIL: no peers found")

	_peer.close()
	quit()


func _result(msg: String) -> void:
	print("[lookup] RESULT: %s" % msg)
	var wf := FileAccess.open("/tmp/test_dht_lookup_result.txt", FileAccess.WRITE)
	if msg.begins_with("PASS"):
		wf.store_string("PASS")
	else:
		wf.store_string("FAIL")
	wf.close()