OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / benchmarks / mesh-ping.cjs

78 lines · javascript ref:
#!/usr/bin/env node
/**
 * Minimal Hyperswarm ephemeral ping/pong — cross-machine reachability test.
 *
 * Exercises the SAME network path the game's HyperswarmMultiplayerPeer
 * GDExtension uses: HyperDHT discovery + NAT hole-punch + UDX + Noise.
 * If two machines connect + exchange pings here, the network/DHT path is
 * fine and any in-game mesh failure is in the extension or its usage.
 * If they DON'T connect here, it's a network/NAT/DHT problem.
 *
 * Usage (run on each machine, same topic):
 *   node mesh-ping.cjs server          # announces, echoes pings
 *   node mesh-ping.cjs client          # looks up, sends pings, prints RTT
 *   node mesh-ping.cjs both            # localhost sanity (real DHT)
 *
 * Optional env TOPIC to override the rendezvous string (default below).
 */

const Hyperswarm = require('hyperswarm')
const crypto = require('crypto')
const os = require('os')

const mode = process.argv[2] || 'both'
const topicStr = process.env.TOPIC || 'hyper-tps-mesh-ping-2026'
const TOPIC = crypto.createHash('sha256').update(topicStr).digest()
const host = os.hostname()

console.log(`[${host}] mode=${mode} topic="${topicStr}" (${TOPIC.toString('hex').slice(0, 16)})`)

function server () {
  const swarm = new Hyperswarm()
  swarm.on('connection', (conn, info) => {
    const pk = info.publicKey.toString('hex').slice(0, 16)
    console.log(`[${host}] SERVER <- connection from ${pk}`)
    conn.on('data', (buf) => { try { conn.write(buf) } catch (e) {} }) // echo
    conn.on('error', () => {})
    conn.on('close', () => console.log(`[${host}] SERVER conn closed ${pk}`))
  })
  swarm.join(TOPIC, { server: true, client: false }).flushed().then(() => {
    console.log(`[${host}] SERVER announced on DHT, waiting for peers...`)
  })
}

function client () {
  const swarm = new Hyperswarm()
  let connected = false
  swarm.on('connection', (conn, info) => {
    const pk = info.publicKey.toString('hex').slice(0, 16)
    connected = true
    console.log(`[${host}] CLIENT -> connected to ${pk}`)
    let seq = 0
    let t0 = 0n
    const send = () => {
      const b = Buffer.alloc(8)
      b.writeUInt32LE(0xBEEF, 0)
      b.writeUInt32LE(seq++, 4)
      t0 = process.hrtime.bigint()
      try { conn.write(b) } catch (e) {}
    }
    conn.on('data', (buf) => {
      const rtt = Number(process.hrtime.bigint() - t0) / 1e6
      console.log(`[${host}] PONG seq=${buf.readUInt32LE(4)} rtt=${rtt.toFixed(2)}ms`)
      setTimeout(send, 1000)
    })
    conn.on('error', () => {})
    send()
  })
  swarm.join(TOPIC, { server: false, client: true })
  console.log(`[${host}] CLIENT looking up peers on DHT...`)
  setInterval(() => {
    if (!connected) console.log(`[${host}] CLIENT still searching... (conns=${swarm.connections.size})`)
  }, 5000)
}

if (mode === 'server') server()
else if (mode === 'client') client()
else { server(); setTimeout(client, 1500) }