ddat interop with dat js cable interop with cabal js ddat's frontend = dat-thang cable fe = cable-thang dillo support based on cel's dillo-dat bootstrap node xplatform support Signed-off-by: divo <418@cryspace.space>
79 lines
3.6 KiB
JavaScript
79 lines
3.6 KiB
JavaScript
'use strict'
|
|
|
|
// Live Cabal Core/Hyperswarm smoke test for the same S-expression IPC used by
|
|
// cable-thang. Run with `node tests/interop/cabal/cable_cabal_hyperswarm_live.js`.
|
|
const { spawn } = require('child_process')
|
|
const crypto = require('crypto')
|
|
const fs = require('fs')
|
|
const os = require('os')
|
|
const path = require('path')
|
|
const readline = require('readline')
|
|
|
|
const root = path.resolve(__dirname, '../..')
|
|
const bridgePath = path.join(__dirname, 'cable_hyperswarm.js')
|
|
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'dat-gpt-cabal-live-'))
|
|
const room = crypto.randomBytes(32).toString('hex')
|
|
const peers = []
|
|
|
|
function startPeer (name) {
|
|
const child = spawn(process.execPath, [bridgePath], { cwd: root, stdio: ['pipe', 'pipe', 'inherit'] })
|
|
const peer = { name, child, lines: [], error: null, rl: readline.createInterface({ input: child.stdout }) }
|
|
peer.rl.on('line', line => { peer.lines.push(line); process.stdout.write(name + ' ' + line + '\n') })
|
|
child.on('error', err => { peer.error = err })
|
|
child.on('exit', (code, signal) => { if (code && code !== 0) peer.error = new Error(`${name} exited ${code} (${signal || 'no signal'})`) })
|
|
peers.push(peer)
|
|
return peer
|
|
}
|
|
|
|
function send (peer, expression) {
|
|
if (!peer.child.stdin.write(expression + '\n')) throw new Error(`${peer.name} bridge stdin closed`)
|
|
}
|
|
|
|
async function waitFor (peer, predicate, description, timeout = 90000) {
|
|
const start = Date.now()
|
|
while (Date.now() - start < timeout) {
|
|
if (peer.error) throw peer.error
|
|
const found = peer.lines.find(predicate)
|
|
if (found) return found
|
|
await new Promise(resolve => setTimeout(resolve, 100))
|
|
}
|
|
throw new Error(`timeout waiting for ${description}; ${peer.name} last output: ${peer.lines.slice(-5).join(' | ')}`)
|
|
}
|
|
|
|
function startExpression (peer, nick) {
|
|
const storage = path.join(tempRoot, peer.name)
|
|
return `(start ${JSON.stringify(room)} ${JSON.stringify(storage)} ${JSON.stringify(nick)} "default")`
|
|
}
|
|
|
|
async function main () {
|
|
const alice = startPeer('alice')
|
|
const bob = startPeer('bob')
|
|
send(alice, startExpression(alice, 'Alice'))
|
|
send(bob, startExpression(bob, 'Bob'))
|
|
await Promise.all([waitFor(alice, line => line.startsWith('(event ready '), 'Alice Cabal feed'),
|
|
waitFor(bob, line => line.startsWith('(event ready '), 'Bob Cabal feed')])
|
|
await Promise.all([waitFor(alice, line => line.startsWith('(event peer-up '), 'Alice Hyperswarm peer discovery'),
|
|
waitFor(bob, line => line.startsWith('(event peer-up '), 'Bob Hyperswarm peer discovery')])
|
|
|
|
send(alice, `(send "default" "Cable bridge says hello")`)
|
|
await waitFor(bob, line => line.includes('Cable bridge says hello'), 'Alice-to-Bob Cabal message')
|
|
send(bob, `(send "default" "Cabal bridge replies")`)
|
|
await waitFor(alice, line => line.includes('Cabal bridge replies'), 'Bob-to-Alice Cabal message')
|
|
console.log('Cabal Core Hyperswarm discovery and bidirectional chat: PASS')
|
|
}
|
|
|
|
main().catch(err => { console.error(err.stack || err); process.exitCode = 1 }).finally(async () => {
|
|
for (const peer of peers) {
|
|
try { send(peer, '(close)') } catch (_) {}
|
|
peer.child.stdin.end()
|
|
}
|
|
await Promise.all(peers.map(peer => new Promise(resolve => {
|
|
if (peer.child.exitCode !== null) return resolve()
|
|
const timer = setTimeout(() => { peer.child.kill('SIGTERM'); resolve() }, 5000)
|
|
peer.child.once('exit', () => { clearTimeout(timer); resolve() })
|
|
})))
|
|
const resolvedRoot = path.resolve(tempRoot)
|
|
if (resolvedRoot.startsWith(path.resolve(os.tmpdir()) + path.sep) && path.basename(resolvedRoot).startsWith('dat-gpt-cabal-live-'))
|
|
fs.rmSync(resolvedRoot, { recursive: true, force: true })
|
|
})
|