js-libp2p/test/interop.ts
Alex Potsides 633d4a9740
fix: remove ipfs dependency and upgrade multiaddr (#1387)
- Upgrades @multiformats/multiaddr to 11.0.0
- Removes ipfs-http-client and delegate router dependencies
- Test delegation using interface stubs instead of implementations
2022-09-21 14:41:20 +01:00

166 lines
4.2 KiB
TypeScript

import { interopTests } from '@libp2p/interop'
import type { SpawnOptions, Daemon, DaemonFactory } from '@libp2p/interop'
import { createServer } from '@libp2p/daemon-server'
import { createClient } from '@libp2p/daemon-client'
import { createLibp2p, Libp2pOptions } from '../src/index.js'
import { Noise } from '@chainsafe/libp2p-noise'
import { TCP } from '@libp2p/tcp'
import { multiaddr } from '@multiformats/multiaddr'
import { KadDHT } from '@libp2p/kad-dht'
import { path as p2pd } from 'go-libp2p'
import { execa } from 'execa'
import pDefer from 'p-defer'
import { logger } from '@libp2p/logger'
import { Mplex } from '@libp2p/mplex'
import { Yamux } from '@chainsafe/libp2p-yamux'
import fs from 'fs'
import { unmarshalPrivateKey } from '@libp2p/crypto/keys'
import type { PeerId } from '@libp2p/interface-peer-id'
import { peerIdFromKeys } from '@libp2p/peer-id'
import { FloodSub } from '@libp2p/floodsub'
// IPFS_LOGGING=debug DEBUG=libp2p*,go-libp2p:* npm run test:interop
async function createGoPeer (options: SpawnOptions): Promise<Daemon> {
const controlPort = Math.floor(Math.random() * (50000 - 10000 + 1)) + 10000
const apiAddr = multiaddr(`/ip4/0.0.0.0/tcp/${controlPort}`)
const log = logger(`go-libp2p:${controlPort}`)
const opts = [
`-listen=${apiAddr.toString()}`,
'-hostAddrs=/ip4/0.0.0.0/tcp/0'
]
if (options.noise === true) {
opts.push('-noise=true')
}
if (options.dht === true) {
opts.push('-dhtServer')
}
if (options.pubsub === true) {
opts.push('-pubsub')
}
if (options.pubsubRouter != null) {
opts.push(`-pubsubRouter=${options.pubsubRouter}`)
}
if (options.key != null) {
opts.push(`-id=${options.key}`)
}
const deferred = pDefer()
const proc = execa(p2pd(), opts)
proc.stdout?.on('data', (buf: Buffer) => {
const str = buf.toString()
log(str)
// daemon has started
if (str.includes('Control socket:')) {
deferred.resolve()
}
})
proc.stderr?.on('data', (buf) => {
log.error(buf.toString())
})
await deferred.promise
return {
client: createClient(apiAddr),
stop: async () => {
await proc.kill()
}
}
}
async function createJsPeer (options: SpawnOptions): Promise<Daemon> {
let peerId: PeerId | undefined
if (options.key != null) {
const keyFile = fs.readFileSync(options.key)
const privateKey = await unmarshalPrivateKey(keyFile)
peerId = await peerIdFromKeys(privateKey.public.bytes, privateKey.bytes)
}
const opts: Libp2pOptions = {
peerId,
addresses: {
listen: ['/ip4/0.0.0.0/tcp/0']
},
transports: [new TCP()],
streamMuxers: [],
connectionEncryption: [new Noise()]
}
if (options.muxer === 'mplex') {
opts.streamMuxers?.push(new Mplex())
} else {
opts.streamMuxers?.push(new Yamux())
}
if (options.dht === true) {
// go-libp2p-daemon only has the older single-table DHT instead of the dual
// lan/wan version found in recent go-ipfs versions. unfortunately it's been
// abandoned so here we simulate the older config with the js implementation
const dht = new KadDHT({
clientMode: false
})
const lan = dht.lan
const protocol = '/ipfs/kad/1.0.0'
lan.protocol = protocol
// @ts-expect-error
lan.network.protocol = protocol
// @ts-expect-error
lan.topologyListener.protocol = protocol
// @ts-expect-error
opts.dht = lan
}
if (options.pubsub === true) {
if (options.pubsubRouter === 'floodsub') {
opts.pubsub = new FloodSub()
} else {
opts.pubsub = new FloodSub()
}
}
const node = await createLibp2p(opts)
const server = await createServer(multiaddr('/ip4/0.0.0.0/tcp/0'), node)
await server.start()
return {
client: createClient(server.getMultiaddr()),
stop: async () => {
await server.stop()
await node.stop()
}
}
}
async function main () {
const factory: DaemonFactory = {
async spawn (options: SpawnOptions) {
if (options.type === 'go') {
return await createGoPeer(options)
}
return await createJsPeer(options)
}
}
await interopTests(factory)
}
main().catch(err => {
console.error(err) // eslint-disable-line no-console
process.exit(1)
})