@libp2p/interface-mocks
Version:
Mock implementations of several libp2p interfaces
162 lines • 5.32 kB
JavaScript
import * as STATUS from '@libp2p/interface-connection/status';
import { CodeError } from '@libp2p/interfaces/errors';
import { logger } from '@libp2p/logger';
import * as mss from '@libp2p/multistream-select';
import { peerIdFromString } from '@libp2p/peer-id';
import { duplexPair } from 'it-pair/duplex';
import { pipe } from 'it-pipe';
import { mockMultiaddrConnection } from './multiaddr-connection.js';
import { mockMuxer } from './muxer.js';
import { mockRegistrar } from './registrar.js';
const log = logger('libp2p:mock-connection');
class MockConnection {
id;
remoteAddr;
remotePeer;
direction;
stat;
streams;
tags;
muxer;
maConn;
constructor(init) {
const { remoteAddr, remotePeer, direction, maConn, muxer } = init;
this.id = `mock-connection-${Math.random()}`;
this.remoteAddr = remoteAddr;
this.remotePeer = remotePeer;
this.direction = direction;
this.stat = {
status: STATUS.OPEN,
direction,
timeline: maConn.timeline,
multiplexer: 'test-multiplexer',
encryption: 'yes-yes-very-secure'
};
this.streams = [];
this.tags = [];
this.muxer = muxer;
this.maConn = maConn;
}
async newStream(protocols, options) {
if (!Array.isArray(protocols)) {
protocols = [protocols];
}
if (protocols.length === 0) {
throw new Error('protocols must have a length');
}
if (this.stat.status !== STATUS.OPEN) {
throw new CodeError('connection must be open to create streams', 'ERR_CONNECTION_CLOSED');
}
const id = `${Math.random()}`;
const stream = await this.muxer.newStream(id);
const result = await mss.select(stream, protocols, options);
const streamWithProtocol = {
...stream,
...result.stream,
stat: {
...stream.stat,
direction: 'outbound',
protocol: result.protocol
}
};
this.streams.push(streamWithProtocol);
return streamWithProtocol;
}
addStream(stream) {
this.streams.push(stream);
}
removeStream(id) {
this.streams = this.streams.filter(stream => stream.id !== id);
}
async close() {
this.stat.status = STATUS.CLOSING;
await this.maConn.close();
this.streams.forEach(s => {
s.close();
});
this.stat.status = STATUS.CLOSED;
this.stat.timeline.close = Date.now();
}
}
export function mockConnection(maConn, opts = {}) {
const remoteAddr = maConn.remoteAddr;
const remotePeerIdStr = remoteAddr.getPeerId() ?? '12D3KooWCrhmFM1BCPGBkNzbPfDk4cjYmtAYSpZwUBC69Qg2kZyq';
if (remotePeerIdStr == null) {
throw new Error('Remote multiaddr must contain a peer id');
}
const remotePeer = peerIdFromString(remotePeerIdStr);
const direction = opts.direction ?? 'inbound';
const registrar = opts.registrar ?? mockRegistrar();
const muxerFactory = opts.muxerFactory ?? mockMuxer();
const muxer = muxerFactory.createStreamMuxer({
direction,
onIncomingStream: (muxedStream) => {
try {
mss.handle(muxedStream, registrar.getProtocols())
.then(({ stream, protocol }) => {
log('%s: incoming stream opened on %s', direction, protocol);
muxedStream = { ...muxedStream, ...stream };
muxedStream.stat.protocol = protocol;
connection.addStream(muxedStream);
const { handler } = registrar.getHandler(protocol);
handler({ connection, stream: muxedStream });
}).catch(err => {
log.error(err);
});
}
catch (err) {
log.error(err);
}
},
onStreamEnd: (muxedStream) => {
connection.removeStream(muxedStream.id);
}
});
void pipe(maConn, muxer, maConn);
const connection = new MockConnection({
remoteAddr,
remotePeer,
direction,
maConn,
muxer
});
return connection;
}
export function mockStream(stream) {
return {
...stream,
close: () => { },
closeRead: () => { },
closeWrite: () => { },
abort: () => { },
reset: () => { },
stat: {
direction: 'outbound',
protocol: '/foo/1.0.0',
timeline: {
open: Date.now()
}
},
metadata: {},
id: `stream-${Date.now()}`
};
}
export function multiaddrConnectionPair(a, b) {
const [peerBtoPeerA, peerAtoPeerB] = duplexPair();
return [
mockMultiaddrConnection(peerAtoPeerB, b.peerId),
mockMultiaddrConnection(peerBtoPeerA, a.peerId)
];
}
export function connectionPair(a, b) {
const [peerBtoPeerA, peerAtoPeerB] = multiaddrConnectionPair(a, b);
return [
mockConnection(peerBtoPeerA, {
registrar: a.registrar
}),
mockConnection(peerAtoPeerB, {
registrar: b.registrar
})
];
}
//# sourceMappingURL=connection.js.map