mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-03-28 13:21:04 +00:00
* feat: limit protocol streams per-connection Uses the `maxInboundStreams` and `maxOutboundStreams` of the `registrar.handle` opts to limit the number of concurrent streams open on each connection on a per-protocol basis. Both values default to 1 so some tuning will be necessary to set appropriate values for some protocols. * chore: make error codes consistent * chore: fix up examples
175 lines
5.4 KiB
TypeScript
175 lines
5.4 KiB
TypeScript
/* eslint-env mocha */
|
|
|
|
import { expect } from 'aegir/chai'
|
|
import { Multiaddr } from '@multiformats/multiaddr'
|
|
import pWaitFor from 'p-wait-for'
|
|
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
|
|
import { subsystemMulticodecs, createSubsystemOptions } from './utils.js'
|
|
import { createPeerId } from '../../utils/creators/peer.js'
|
|
import type { PeerId } from '@libp2p/interface-peer-id'
|
|
import { createLibp2pNode, Libp2pNode } from '../../../src/libp2p.js'
|
|
import { start } from '@libp2p/interfaces/startable'
|
|
|
|
const listenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/8000')
|
|
const remoteListenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/8001')
|
|
|
|
async function getRemoteAddr (remotePeerId: PeerId, libp2p: Libp2pNode) {
|
|
const addrs = await libp2p.components.getPeerStore().addressBook.get(remotePeerId)
|
|
|
|
if (addrs.length === 0) {
|
|
throw new Error('No addrs found')
|
|
}
|
|
|
|
const addr = addrs[0]
|
|
|
|
return addr.multiaddr.encapsulate(`/p2p/${remotePeerId.toString()}`)
|
|
}
|
|
|
|
describe('DHT subsystem operates correctly', () => {
|
|
let peerId: PeerId, remotePeerId: PeerId
|
|
let libp2p: Libp2pNode, remoteLibp2p: Libp2pNode
|
|
let remAddr: Multiaddr
|
|
|
|
beforeEach(async () => {
|
|
[peerId, remotePeerId] = await Promise.all([
|
|
createPeerId(),
|
|
createPeerId()
|
|
])
|
|
})
|
|
|
|
describe('dht started before connect', () => {
|
|
beforeEach(async () => {
|
|
libp2p = await createLibp2pNode(createSubsystemOptions({
|
|
peerId,
|
|
addresses: {
|
|
listen: [listenAddr.toString()]
|
|
}
|
|
}))
|
|
|
|
remoteLibp2p = await createLibp2pNode(createSubsystemOptions({
|
|
peerId: remotePeerId,
|
|
addresses: {
|
|
listen: [remoteListenAddr.toString()]
|
|
}
|
|
}))
|
|
|
|
await Promise.all([
|
|
libp2p.start(),
|
|
remoteLibp2p.start()
|
|
])
|
|
|
|
await libp2p.components.getPeerStore().addressBook.set(remotePeerId, [remoteListenAddr])
|
|
remAddr = await getRemoteAddr(remotePeerId, libp2p)
|
|
})
|
|
|
|
afterEach(async () => {
|
|
if (libp2p != null) {
|
|
await libp2p.stop()
|
|
}
|
|
|
|
if (remoteLibp2p != null) {
|
|
await remoteLibp2p.stop()
|
|
}
|
|
})
|
|
|
|
it('should get notified of connected peers on dial', async () => {
|
|
const stream = await libp2p.dialProtocol(remAddr, subsystemMulticodecs)
|
|
|
|
expect(stream).to.exist()
|
|
|
|
return await Promise.all([
|
|
pWaitFor(() => libp2p.dht.lan.routingTable.size === 1),
|
|
pWaitFor(() => remoteLibp2p.dht.lan.routingTable.size === 1)
|
|
])
|
|
})
|
|
|
|
it('should put on a peer and get from the other', async () => {
|
|
const key = uint8ArrayFromString('hello')
|
|
const value = uint8ArrayFromString('world')
|
|
|
|
await libp2p.dialProtocol(remAddr, subsystemMulticodecs)
|
|
await Promise.all([
|
|
pWaitFor(() => libp2p.dht.lan.routingTable.size === 1),
|
|
pWaitFor(() => remoteLibp2p.dht.lan.routingTable.size === 1)
|
|
])
|
|
|
|
await libp2p.components.getContentRouting().put(key, value)
|
|
|
|
const fetchedValue = await remoteLibp2p.components.getContentRouting().get(key)
|
|
expect(fetchedValue).to.equalBytes(value)
|
|
})
|
|
})
|
|
|
|
describe('dht started after connect', () => {
|
|
beforeEach(async () => {
|
|
libp2p = await createLibp2pNode(createSubsystemOptions({
|
|
peerId,
|
|
addresses: {
|
|
listen: [listenAddr.toString()]
|
|
}
|
|
}))
|
|
|
|
remoteLibp2p = await createLibp2pNode(createSubsystemOptions({
|
|
peerId: remotePeerId,
|
|
addresses: {
|
|
listen: [remoteListenAddr.toString()]
|
|
}
|
|
}))
|
|
|
|
await libp2p.start()
|
|
await remoteLibp2p.start()
|
|
|
|
await libp2p.components.getPeerStore().addressBook.set(remotePeerId, [remoteListenAddr])
|
|
remAddr = await getRemoteAddr(remotePeerId, libp2p)
|
|
})
|
|
|
|
afterEach(async () => {
|
|
if (libp2p != null) {
|
|
await libp2p.stop()
|
|
}
|
|
|
|
if (remoteLibp2p != null) {
|
|
await remoteLibp2p.stop()
|
|
}
|
|
})
|
|
|
|
// TODO: we pre-fill the routing tables on dht startup with artificial peers so this test
|
|
// doesn't really work as intended. We should be testing that a connected peer can change
|
|
// it's supported protocols and we should notice that change so there may be something to
|
|
// salvage from here, though it could be better as identify protocol tests.
|
|
it.skip('should get notified of connected peers after starting', async () => {
|
|
const connection = await libp2p.dial(remAddr)
|
|
|
|
expect(connection).to.exist()
|
|
expect(libp2p.dht.lan.routingTable).to.be.empty()
|
|
|
|
const dht = remoteLibp2p.dht
|
|
|
|
await start(dht)
|
|
|
|
// should be 0 directly after start - TODO this may be susceptible to timing bugs, we should have
|
|
// the ability to report stats on the DHT routing table instead of reaching into it's heart like this
|
|
expect(remoteLibp2p.dht.lan.routingTable).to.be.empty()
|
|
|
|
return await pWaitFor(() => libp2p.dht.lan.routingTable.size === 1)
|
|
})
|
|
|
|
it('should put on a peer and get from the other', async () => {
|
|
await libp2p.dial(remAddr)
|
|
|
|
const key = uint8ArrayFromString('hello')
|
|
const value = uint8ArrayFromString('world')
|
|
|
|
const dht = remoteLibp2p.dht
|
|
|
|
await start(dht)
|
|
|
|
await pWaitFor(() => libp2p.dht.lan.routingTable.size === 1)
|
|
await libp2p.components.getContentRouting().put(key, value)
|
|
|
|
const fetchedValue = await remoteLibp2p.components.getContentRouting().get(key)
|
|
expect(fetchedValue).to.equalBytes(value)
|
|
})
|
|
})
|
|
})
|