// hypermosh tunnel tests.
// 1) loopback: UDP echo round-trips through the hyperdht tunnel (no mosh needed)
// 2) real mosh: a mosh session runs end-to-end through the tunnel (if mosh present)
import DHT from 'hyperdht'
import dgram from 'dgram'
import b4a from 'b4a'
import { spawn, execSync } from 'child_process'
import { fileURLToPath } from 'url'
import path from 'path'
import { serve, connect } from '../lib/relay.mjs'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
let failures = 0
async function testLoopback () {
console.log('\n[1] loopback: UDP echo through hyperdht tunnel')
const echo = dgram.createSocket('udp4')
echo.on('message', (msg, r) => echo.send(b4a.concat([b4a.from('echo:'), msg]), r.port, r.address))
await new Promise((res) => echo.bind(0, '127.0.0.1', res))
const keyPair = DHT.keyPair()
const s = await serve({ keyPair, udpPort: echo.address().port })
const c = await connect({ remoteKey: keyPair.publicKey })
const probe = dgram.createSocket('udp4')
const got = new Promise((resolve, reject) => {
const t = setTimeout(() => reject(new Error('timeout')), 45000) // cold self-hairpin DHT connect can be slow on one machine
probe.on('message', (m) => { clearTimeout(t); resolve(b4a.toString(m)) })
})
await new Promise((res) => probe.bind(0, '127.0.0.1', res))
const payload = 'hello-' + Math.floor(process.uptime() * 1000)
probe.send(b4a.from(payload), c.localPort, '127.0.0.1')
try {
const reply = await got
if (reply === 'echo:' + payload) console.log(' ✅ PASS — round-trip ok')
else { console.log(' ❌ FAIL — got', reply); failures++ }
} catch (e) { console.log(' ❌ FAIL —', e.message); failures++ }
finally { probe.close(); echo.close(); await c.close(); await s.close() }
}
async function testRealMosh () {
let hasMosh = true
try { execSync('command -v mosh-server && command -v mosh-client && command -v python3', { stdio: 'ignore' }) } catch { hasMosh = false }
if (!hasMosh) { console.log('\n[2] real mosh: SKIPPED (mosh/python3 not installed)'); return }
console.log('\n[2] real mosh: session through the hyperdht tunnel')
const ms = spawn('mosh-server', ['new', '-i', '127.0.0.1', '--', 'bash', '-lc', 'echo HYPERMOSH_OK; sleep 8'],
{ env: { ...process.env, LC_ALL: 'C.UTF-8', LANG: 'C.UTF-8' } })
let sout = ''
let conn
try {
conn = await new Promise((resolve, reject) => {
const t = setTimeout(() => reject(new Error('no MOSH CONNECT')), 10000)
const scan = (d) => { sout += d; const m = sout.match(/MOSH CONNECT (\d+) (\S+)/); if (m) { clearTimeout(t); resolve({ port: +m[1], key: m[2] }) } }
ms.stdout.on('data', scan); ms.stderr.on('data', scan)
})
} catch (e) { console.log(' ❌ FAIL —', e.message); failures++; try { ms.kill() } catch {}; return }
const keyPair = DHT.keyPair()
const s = await serve({ keyPair, udpPort: conn.port })
const c = await connect({ remoteKey: keyPair.publicKey })
const drv = spawn('python3', [path.join(__dirname, 'pty-mosh.py'), conn.key, '127.0.0.1', String(c.localPort), '12'], { env: process.env })
let cap = ''
drv.stdout.on('data', (d) => { cap += d })
await new Promise((res) => { const t = setTimeout(() => { try { drv.kill() } catch {}; res() }, 20000); drv.on('exit', () => { clearTimeout(t); res() }) })
const clean = cap.replace(/\x1b\[[0-9;?]*[a-zA-Z]/g, '')
if (clean.includes('HYPERMOSH_OK')) console.log(' ✅ PASS — mosh session traversed the tunnel')
else { console.log(' ❌ FAIL — marker not seen'); failures++ }
await c.close(); await s.close(); try { ms.kill() } catch {}
}
await testLoopback()
await testRealMosh()
console.log(failures === 0 ? '\n✅ all tests passed' : '\n❌ ' + failures + ' test(s) failed')
process.exit(failures === 0 ? 0 : 1)