diff --git a/package.json b/package.json index 14135f1..c16c10f 100644 --- a/package.json +++ b/package.json @@ -135,21 +135,21 @@ "release": "semantic-release" }, "dependencies": { - "@libp2p/logger": "^1.0.2", - "@libp2p/utils": "^1.0.6", - "@multiformats/mafmt": "^11.0.0", - "@multiformats/multiaddr": "^10.1.1", + "@libp2p/logger": "^1.1.2", + "@libp2p/utils": "^1.0.9", + "@multiformats/mafmt": "^11.0.2", + "@multiformats/multiaddr": "^10.1.5", "abortable-iterator": "^4.0.2", "err-code": "^3.0.1", "stream-to-it": "^0.2.2" }, "devDependencies": { - "@libp2p/interface-compliance-tests": "^1.1.2", - "@libp2p/interfaces": "^1.3.2", + "@libp2p/interface-compliance-tests": "^1.1.17", + "@libp2p/interfaces": "^1.3.14", "aegir": "^36.1.3", "it-all": "^1.0.6", "it-pipe": "^2.0.3", - "sinon": "^13.0.0", + "sinon": "^13.0.1", "uint8arrays": "^3.0.0" } } diff --git a/src/index.ts b/src/index.ts index 2fd9783..b093568 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,44 +5,25 @@ import { logger } from '@libp2p/logger' import { toMultiaddrConnection } from './socket-to-conn.js' import { createListener } from './listener.js' import { multiaddrToNetConfig } from './utils.js' -import { AbortError } from 'abortable-iterator' +import { AbortError } from '@libp2p/interfaces/errors' import { CODE_CIRCUIT, CODE_P2P } from './constants.js' -import type { Transport, Upgrader, ListenerOptions } from '@libp2p/interfaces/transport' +import { CreateListenerOptions, DialOptions, symbol, Transport } from '@libp2p/interfaces/transport' import type { Multiaddr } from '@multiformats/multiaddr' import type { Socket } from 'net' +import type { AbortOptions } from '@libp2p/interfaces' const log = logger('libp2p:tcp') -/** - * @typedef {import('multiaddr').Multiaddr} Multiaddr - * @typedef {import('libp2p-interfaces/src/connection').Connection} Connection - * @typedef {import('libp2p-interfaces/src/transport/types').Upgrader} Upgrader - * @typedef {import('libp2p-interfaces/src/transport/types').Listener} Listener - * @typedef {import('net').Socket} Socket - */ - -interface TCPOptions { - upgrader: Upgrader -} - -interface DialOptions { - signal?: AbortSignal -} - -export class TCP implements Transport { - private readonly _upgrader: Upgrader - - constructor (options: TCPOptions) { - const { upgrader } = options - - if (upgrader == null) { - throw new Error('An upgrader must be provided. See https://github.com/libp2p/interface-transport#upgrader.') - } +export class TCP implements Transport { + get [symbol] (): true { + return true + } - this._upgrader = upgrader + get [Symbol.toStringTag] () { + return this.constructor.name } - async dial (ma: Multiaddr, options: DialOptions = {}) { + async dial (ma: Multiaddr, options: DialOptions) { const socket = await this._connect(ma, options) // Avoid uncaught errors caused by unstable connections @@ -52,12 +33,12 @@ export class TCP implements Transport { const maConn = toMultiaddrConnection(socket, { remoteAddr: ma, signal: options.signal }) log('new outbound connection %s', maConn.remoteAddr) - const conn = await this._upgrader.upgradeOutbound(maConn) + const conn = await options.upgrader.upgradeOutbound(maConn) log('outbound connection %s upgraded', maConn.remoteAddr) return conn } - async _connect (ma: Multiaddr, options: DialOptions = {}) { + async _connect (ma: Multiaddr, options: AbortOptions = {}) { if (options.signal?.aborted === true) { throw new AbortError() } @@ -125,8 +106,8 @@ export class TCP implements Transport { * anytime a new incoming Connection has been successfully upgraded via * `upgrader.upgradeInbound`. */ - createListener (options: ListenerOptions = {}) { - return createListener({ upgrader: this._upgrader, ...options }) + createListener (options: CreateListenerOptions) { + return createListener(options) } /** diff --git a/src/listener.ts b/src/listener.ts index b849005..2ec7e43 100644 --- a/src/listener.ts +++ b/src/listener.ts @@ -70,7 +70,7 @@ export function createListener (context: Context) { handler(conn) } - listener.dispatchEvent(new CustomEvent('connection', { detail: conn })) + listener.dispatchEvent(new CustomEvent('connection', { detail: conn })) }) .catch(async err => { log.error('inbound connection failed', err) @@ -98,7 +98,7 @@ export function createListener (context: Context) { const address = server.address() if (address == null) { - throw new Error('Listener is not ready yet') + return [] } if (typeof address === 'string') { @@ -151,7 +151,7 @@ export function createListener (context: Context) { server .on('listening', () => listener.dispatchEvent(new CustomEvent('listening'))) - .on('error', err => listener.dispatchEvent(new CustomEvent('error', { detail: err }))) + .on('error', err => listener.dispatchEvent(new CustomEvent('error', { detail: err }))) .on('close', () => listener.dispatchEvent(new CustomEvent('close'))) return listener diff --git a/test/compliance.spec.ts b/test/compliance.spec.ts index 99cd821..3042ca0 100644 --- a/test/compliance.spec.ts +++ b/test/compliance.spec.ts @@ -6,14 +6,8 @@ import { TCP } from '../src/index.js' describe('interface-transport compliance', () => { tests({ - async setup (args) { - if (args == null) { - throw new Error('No args') - } - - const { upgrader } = args - - const tcp = new TCP({ upgrader }) + async setup () { + const tcp = new TCP() const addrs = [ new Multiaddr('/ip4/127.0.0.1/tcp/9091'), new Multiaddr('/ip4/127.0.0.1/tcp/9092'), diff --git a/test/connection.spec.ts b/test/connection.spec.ts index 245ef24..39e4561 100644 --- a/test/connection.spec.ts +++ b/test/connection.spec.ts @@ -3,12 +3,15 @@ import { TCP } from '../src/index.js' import { Multiaddr } from '@multiformats/multiaddr' import { mockUpgrader } from '@libp2p/interface-compliance-tests/mocks' import type { Connection } from '@libp2p/interfaces/connection' +import type { Upgrader } from '@libp2p/interfaces/transport' describe('valid localAddr and remoteAddr', () => { let tcp: TCP + let upgrader: Upgrader beforeEach(() => { - tcp = new TCP({ upgrader: mockUpgrader() }) + tcp = new TCP() + upgrader = mockUpgrader() }) const ma = new Multiaddr('/ip4/127.0.0.1/tcp/0') @@ -22,7 +25,8 @@ describe('valid localAddr and remoteAddr', () => { // Create a listener with the handler const listener = tcp.createListener({ - handler + handler, + upgrader }) // Listen on the multi-address @@ -32,7 +36,9 @@ describe('valid localAddr and remoteAddr', () => { expect(localAddrs.length).to.equal(1) // Dial to that address - await tcp.dial(localAddrs[0]) + await tcp.dial(localAddrs[0], { + upgrader + }) // Wait for the incoming dial to be handled await handlerPromise @@ -50,7 +56,8 @@ describe('valid localAddr and remoteAddr', () => { // Create a listener with the handler const listener = tcp.createListener({ - handler + handler, + upgrader }) // Listen on the multi-address @@ -60,7 +67,9 @@ describe('valid localAddr and remoteAddr', () => { expect(localAddrs.length).to.equal(1) // Dial to that address - const dialerConn = await tcp.dial(localAddrs[0]) + const dialerConn = await tcp.dial(localAddrs[0], { + upgrader + }) // Wait for the incoming dial to be handled await handlerPromise diff --git a/test/filter.spec.ts b/test/filter.spec.ts index c13c024..4fb5db6 100644 --- a/test/filter.spec.ts +++ b/test/filter.spec.ts @@ -1,7 +1,6 @@ import { expect } from 'aegir/utils/chai.js' import { TCP } from '../src/index.js' import { Multiaddr } from '@multiformats/multiaddr' -import { mockUpgrader } from '@libp2p/interface-compliance-tests/mocks' describe('filter addrs', () => { const base = '/ip4/127.0.0.1' @@ -10,7 +9,7 @@ describe('filter addrs', () => { let tcp: TCP before(() => { - tcp = new TCP({ upgrader: mockUpgrader() }) + tcp = new TCP() }) it('filter valid addrs for this transport', () => { diff --git a/test/listen-dial.spec.ts b/test/listen-dial.spec.ts index d32b905..a18072d 100644 --- a/test/listen-dial.spec.ts +++ b/test/listen-dial.spec.ts @@ -7,24 +7,18 @@ import { pipe } from 'it-pipe' import all from 'it-all' import { mockRegistrar, mockUpgrader } from '@libp2p/interface-compliance-tests/mocks' import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import type { Upgrader } from '@libp2p/interfaces/transport' const isCI = process.env.CI -describe('construction', () => { - it('requires an upgrader', () => { - // @ts-expect-error missing args - expect(() => new TCP()).to.throw() - }) -}) - describe('listen', () => { let tcp: TCP let listener: any + let upgrader: Upgrader beforeEach(() => { - tcp = new TCP({ - upgrader: mockUpgrader() - }) + tcp = new TCP() + upgrader = mockUpgrader() }) afterEach(async () => { try { @@ -40,13 +34,17 @@ describe('listen', () => { it.skip('listen on path', async () => { const mh = new Multiaddr(`/unix${path.resolve(os.tmpdir(), `/tmp/p2pd-${Date.now()}.sock`)}`) - listener = tcp.createListener({}) + listener = tcp.createListener({ + upgrader + }) await listener.listen(mh) }) it('listen on port 0', async () => { const mh = new Multiaddr('/ip4/127.0.0.1/tcp/0') - listener = tcp.createListener({}) + listener = tcp.createListener({ + upgrader + }) await listener.listen(mh) }) @@ -55,19 +53,25 @@ describe('listen', () => { return } const mh = new Multiaddr('/ip6/::/tcp/9090') - listener = tcp.createListener({}) + listener = tcp.createListener({ + upgrader + }) await listener.listen(mh) }) it('listen on any Interface', async () => { const mh = new Multiaddr('/ip4/0.0.0.0/tcp/9090') - listener = tcp.createListener({}) + listener = tcp.createListener({ + upgrader + }) await listener.listen(mh) }) it('getAddrs', async () => { const mh = new Multiaddr('/ip4/127.0.0.1/tcp/9090') - listener = tcp.createListener({}) + listener = tcp.createListener({ + upgrader + }) await listener.listen(mh) const multiaddrs = listener.getAddrs() @@ -77,7 +81,9 @@ describe('listen', () => { it('getAddrs on port 0 listen', async () => { const mh = new Multiaddr('/ip4/127.0.0.1/tcp/0') - listener = tcp.createListener({}) + listener = tcp.createListener({ + upgrader + }) await listener.listen(mh) const multiaddrs = listener.getAddrs() @@ -86,7 +92,9 @@ describe('listen', () => { it('getAddrs from listening on 0.0.0.0', async () => { const mh = new Multiaddr('/ip4/0.0.0.0/tcp/9090') - listener = tcp.createListener({}) + listener = tcp.createListener({ + upgrader + }) await listener.listen(mh) const multiaddrs = listener.getAddrs() @@ -96,7 +104,9 @@ describe('listen', () => { it('getAddrs from listening on 0.0.0.0 and port 0', async () => { const mh = new Multiaddr('/ip4/0.0.0.0/tcp/0') - listener = tcp.createListener({}) + listener = tcp.createListener({ + upgrader + }) await listener.listen(mh) const multiaddrs = listener.getAddrs() @@ -106,7 +116,9 @@ describe('listen', () => { it('getAddrs preserves IPFS Id', async () => { const mh = new Multiaddr('/ip4/127.0.0.1/tcp/9090/ipfs/Qmb6owHp6eaWArVbcJJbQSyifyJBttMMjYV76N2hMbf5Vw') - listener = tcp.createListener({}) + listener = tcp.createListener({ + upgrader + }) await listener.listen(mh) const multiaddrs = listener.getAddrs() @@ -118,30 +130,33 @@ describe('listen', () => { describe('dial', () => { const protocol = '/echo/1.0.0' let tcp: TCP + let upgrader: Upgrader beforeEach(async () => { const registrar = mockRegistrar() void registrar.handle(protocol, (evt) => { void pipe( - evt.detail.stream, - evt.detail.stream + evt.stream, + evt.stream ) }) - const upgrader = mockUpgrader({ + upgrader = mockUpgrader({ registrar }) - tcp = new TCP({ - upgrader - }) + tcp = new TCP() }) it('dial on IPv4', async () => { const ma = new Multiaddr('/ip4/127.0.0.1/tcp/9090') - const listener = tcp.createListener() + const listener = tcp.createListener({ + upgrader + }) await listener.listen(ma) - const conn = await tcp.dial(ma) + const conn = await tcp.dial(ma, { + upgrader + }) const { stream } = await conn.newStream([protocol]) const values = await pipe( @@ -161,9 +176,13 @@ describe('dial', () => { } const ma = new Multiaddr('/ip6/::/tcp/9090') - const listener = tcp.createListener({}) + const listener = tcp.createListener({ + upgrader + }) await listener.listen(ma) - const conn = await tcp.dial(ma) + const conn = await tcp.dial(ma, { + upgrader + }) const { stream } = await conn.newStream([protocol]) const values = await pipe( @@ -180,9 +199,13 @@ describe('dial', () => { it.skip('dial on path', async () => { const ma = new Multiaddr(`/unix${path.resolve(os.tmpdir(), `/tmp/p2pd-${Date.now()}.sock`)}`) - const listener = tcp.createListener({}) + const listener = tcp.createListener({ + upgrader + }) await listener.listen(ma) - const conn = await tcp.dial(ma) + const conn = await tcp.dial(ma, { + upgrader + }) const { stream } = await conn.newStream([protocol]) const values = await pipe( @@ -209,13 +232,16 @@ describe('dial', () => { void conn.close() .then(() => handled()) }, 100) - } + }, + upgrader }) await listener.listen(ma) const addrs = listener.getAddrs() - const conn = await tcp.dial(addrs[0]) + const conn = await tcp.dial(addrs[0], { + upgrader + }) const { stream } = await conn.newStream([protocol]) await pipe(stream) @@ -237,12 +263,15 @@ describe('dial', () => { const listener = tcp.createListener({ handler: () => { handled() - } + }, + upgrader }) await listener.listen(ma) const addrs = listener.getAddrs() - const conn = await tcp.dial(addrs[0]) + const conn = await tcp.dial(addrs[0], { + upgrader + }) await conn.close() await handledPromise @@ -251,10 +280,14 @@ describe('dial', () => { it('dials on IPv4 with IPFS Id', async () => { const ma = new Multiaddr('/ip4/127.0.0.1/tcp/9090/ipfs/Qmb6owHp6eaWArVbcJJbQSyifyJBttMMjYV76N2hMbf5Vw') - const listener = tcp.createListener({}) + const listener = tcp.createListener({ + upgrader + }) await listener.listen(ma) - const conn = await tcp.dial(ma) + const conn = await tcp.dial(ma, { + upgrader + }) const { stream } = await conn.newStream([protocol]) const values = await pipe(