// One RPC channel per connection — because a retry must not fail for a reason of its own making.
//
// ⛔ WHAT HAPPENED. `connectBridge` built a fresh ProtomuxRPC every call. Protomux keys a channel by
// protocol on a given stream, so the second attempt over an already-open connection opened a SECOND
// channel for the same protocol and failed with "duplicate channel". Observed by a person doing the
// most ordinary thing possible after an error: trying again.
//
// ⚠ The failure is worse than it sounds, because the message describes the plumbing rather than the
// act. Someone who mistyped a name is told about channels.
import test from 'brittle'
import { Duplex } from 'streamx'
import b4a from 'b4a'
import { connectBridge } from '../lib/bridge.js'
const KEY = 'a'.repeat(64)
// A swarm stub whose "connection" is already open to the key we ask for — the retry case.
function swarmWith (conn) {
return { connections: new Set([conn]), join: () => ({ flushed: async () => {} }), on () {}, off () {} }
}
// ⚠ A REAL duplex. Protomux writes a channel-open frame the moment a channel is created, so a plain
// object stub fails inside protomux rather than exercising anything this file is about.
function fakeConn () {
const s = new Duplex({ write (data, cb) { cb(null) } })
s.remotePublicKey = b4a.from(KEY, 'hex')
return s
}
test('★★ asking twice over one connection reuses the channel', async (t) => {
const conn = fakeConn()
const swarm = swarmWith(conn)
const a = await connectBridge(swarm, KEY)
const b = await connectBridge(swarm, KEY)
t.is(a.rpc, b.rpc, 'the same channel — a second one is a "duplicate channel" error on retry')
})
test('⚠ a closed connection does not leave a dead channel behind', async (t) => {
const conn = fakeConn()
const swarm = swarmWith(conn)
const a = await connectBridge(swarm, KEY)
conn.emit('close')
const b = await connectBridge(swarm, KEY)
t.not(a.rpc, b.rpc, 'a reconnect gets a fresh channel rather than one on a dead stream')
})
test('⛔ a bad key is refused before any connection is attempted', async (t) => {
await t.exception(() => connectBridge(swarmWith(fakeConn()), 'nonsense'), /64 hex/)
})