119 lines
3.2 KiB
JavaScript
119 lines
3.2 KiB
JavaScript
/**
|
|
* Integration: TCP + Protomux chat channel — verifies Protomux wiring + ingest when
|
|
* socket.publicKey / remotePublicKey match the Hyperswarm Noise identity pattern.
|
|
*/
|
|
import test from 'brittle'
|
|
import net from 'net'
|
|
import Protomux from 'protomux'
|
|
import b4a from 'b4a'
|
|
import crypto from 'hypercore-crypto'
|
|
import { SwarmDisk } from './lib/swarm-disk.js'
|
|
import { createBareOsChatService } from './lib/bare-os-chat-service.js'
|
|
|
|
/** @returns {Promise<{ srvSock: net.Socket, cliSock: net.Socket }>} */
|
|
function tcpDuplexPair() {
|
|
return new Promise((resolve, reject) => {
|
|
const srv = net.createServer()
|
|
srv.once('error', reject)
|
|
srv.listen(0, '127.0.0.1', () => {
|
|
const addr = srv.address()
|
|
if (!addr || typeof addr === 'string') {
|
|
reject(new Error('tcpDuplexPair: bad address'))
|
|
return
|
|
}
|
|
const cliSock = net.connect(addr.port, '127.0.0.1')
|
|
srv.once('connection', (srvSock) => {
|
|
srv.close(() => {})
|
|
resolve({ srvSock, cliSock })
|
|
})
|
|
cliSock.once('error', reject)
|
|
})
|
|
})
|
|
}
|
|
|
|
function wireNoiseLikeKeys(sockLocal, kpLocal, kpRemote) {
|
|
sockLocal.publicKey = kpLocal.publicKey
|
|
sockLocal.remotePublicKey = kpRemote.publicKey
|
|
}
|
|
|
|
test('TCP + Protomux — chat event roundtrips Alice → Bob', async (t) => {
|
|
process.env.BARE_OS_PROTOMUX_CHAT_CHANNEL = '1'
|
|
|
|
const kpAlice = crypto.keyPair()
|
|
const kpBob = crypto.keyPair()
|
|
|
|
const { srvSock, cliSock } = await tcpDuplexPair()
|
|
|
|
wireNoiseLikeKeys(cliSock, kpAlice, kpBob)
|
|
wireNoiseLikeKeys(srvSock, kpBob, kpAlice)
|
|
|
|
const diskAlice = new SwarmDisk()
|
|
diskAlice.localNoiseWirePk = b4a.from(kpAlice.publicKey)
|
|
|
|
const diskBob = new SwarmDisk()
|
|
|
|
diskAlice.bareOsChatService = createBareOsChatService({
|
|
env: /** @type {Record<string, string>} */ ({ USER: 'aliceuser' })
|
|
})
|
|
diskBob.bareOsChatService = createBareOsChatService({
|
|
env: /** @type {Record<string, string>} */ ({ USER: 'bobuser' })
|
|
})
|
|
|
|
const muxAlice = new Protomux(cliSock)
|
|
const muxBob = new Protomux(srvSock)
|
|
|
|
const peerAliceToBob = {
|
|
chan: /** @type {unknown} */ (null),
|
|
mux: muxAlice,
|
|
socket: cliSock,
|
|
id: null,
|
|
chatChan: null
|
|
}
|
|
|
|
const peerBobFromAlice = {
|
|
chan: /** @type {unknown} */ (null),
|
|
mux: muxBob,
|
|
socket: srvSock,
|
|
id: null,
|
|
chatChan: null
|
|
}
|
|
|
|
diskAlice.bareOsChatService.pairOnMux(
|
|
diskAlice,
|
|
muxAlice,
|
|
cliSock,
|
|
peerAliceToBob
|
|
)
|
|
diskBob.bareOsChatService.pairOnMux(
|
|
diskBob,
|
|
muxBob,
|
|
srvSock,
|
|
peerBobFromAlice
|
|
)
|
|
|
|
diskAlice.peers.add(peerAliceToBob)
|
|
diskBob.peers.add(peerBobFromAlice)
|
|
|
|
await new Promise((r) => setImmediate(r))
|
|
await new Promise((r) => setImmediate(r))
|
|
|
|
/** @type {unknown[]} */
|
|
const bobRx = []
|
|
diskBob.bareOsChatService.subscribe((ev) => bobRx.push(ev))
|
|
|
|
diskAlice.bareOsChatService.broadcastLocal(diskAlice, 'hello-from-tcp', {
|
|
displayName: 'aliceuser'
|
|
})
|
|
|
|
await new Promise((r) => setImmediate(r))
|
|
await new Promise((r) => setImmediate(r))
|
|
|
|
t.ok(bobRx.length >= 1, 'Bob received remote event')
|
|
const last = /** @type {{ body?: string, local?: boolean }} */ (bobRx[bobRx.length - 1])
|
|
t.is(last.body, 'hello-from-tcp')
|
|
t.absent(last.local)
|
|
|
|
srvSock.destroy()
|
|
cliSock.destroy()
|
|
})
|