From d27459ab10b40bf71ee3d62fd7da15742b58ed9b Mon Sep 17 00:00:00 2001 From: Suchitra Swain Date: Wed, 4 Jun 2025 12:39:04 +0200 Subject: [PATCH 01/15] chore: use %e token anywhere we are logging errors with @libp2p/logger --- package.json | 5 +- packages/integration-tests/test/interop.ts | 253 ++++++----- .../src/mocks/connection.ts | 424 ++++++++++-------- packages/kad-dht/src/query/manager.ts | 273 ++++++----- .../private-to-private/initiate-connection.ts | 288 +++++++----- .../signaling-stream-handler.ts | 161 ++++--- packages/transport-webtransport/src/muxer.ts | 116 +++-- 7 files changed, 846 insertions(+), 674 deletions(-) diff --git a/package.json b/package.json index 63f09d20e9..44620acedc 100644 --- a/package.json +++ b/package.json @@ -46,5 +46,8 @@ "doc", "interop", "packages/*" - ] + ], + "dependencies": { + "@libp2p/interface": "^2.10.3" + } } diff --git a/packages/integration-tests/test/interop.ts b/packages/integration-tests/test/interop.ts index f02c7271cc..724e0e6cee 100644 --- a/packages/integration-tests/test/interop.ts +++ b/packages/integration-tests/test/interop.ts @@ -1,32 +1,35 @@ -import fs from 'fs' -import { gossipsub } from '@chainsafe/libp2p-gossipsub' -import { noise } from '@chainsafe/libp2p-noise' -import { yamux } from '@chainsafe/libp2p-yamux' -import { circuitRelayServer, circuitRelayTransport } from '@libp2p/circuit-relay-v2' -import { privateKeyFromProtobuf } from '@libp2p/crypto/keys' -import { createClient } from '@libp2p/daemon-client' -import { createServer } from '@libp2p/daemon-server' -import { floodsub } from '@libp2p/floodsub' -import { identify } from '@libp2p/identify' -import { UnsupportedError, interopTests } from '@libp2p/interop' -import { kadDHT, passthroughMapper } from '@libp2p/kad-dht' -import { logger } from '@libp2p/logger' -import { mplex } from '@libp2p/mplex' -import { ping } from '@libp2p/ping' -import { plaintext } from '@libp2p/plaintext' -import { tcp } from '@libp2p/tcp' -import { tls } from '@libp2p/tls' -import { webRTCDirect } from '@libp2p/webrtc' -import { multiaddr } from '@multiformats/multiaddr' -import { execa } from 'execa' -import { path as p2pd } from 'go-libp2p' -import { createLibp2p } from 'libp2p' -import pDefer from 'p-defer' -import type { Identify } from '@libp2p/identify' -import type { ServiceMap, PrivateKey } from '@libp2p/interface' -import type { SpawnOptions, Daemon, DaemonFactory } from '@libp2p/interop' -import type { PingService } from '@libp2p/ping' -import type { Libp2pOptions, ServiceFactoryMap } from 'libp2p' +import fs from "fs"; +import { gossipsub } from "@chainsafe/libp2p-gossipsub"; +import { noise } from "@chainsafe/libp2p-noise"; +import { yamux } from "@chainsafe/libp2p-yamux"; +import { + circuitRelayServer, + circuitRelayTransport, +} from "@libp2p/circuit-relay-v2"; +import { privateKeyFromProtobuf } from "@libp2p/crypto/keys"; +import { createClient } from "@libp2p/daemon-client"; +import { createServer } from "@libp2p/daemon-server"; +import { floodsub } from "@libp2p/floodsub"; +import { identify } from "@libp2p/identify"; +import { UnsupportedError, interopTests } from "@libp2p/interop"; +import { kadDHT, passthroughMapper } from "@libp2p/kad-dht"; +import { logger } from "@libp2p/logger"; +import { mplex } from "@libp2p/mplex"; +import { ping } from "@libp2p/ping"; +import { plaintext } from "@libp2p/plaintext"; +import { tcp } from "@libp2p/tcp"; +import { tls } from "@libp2p/tls"; +import { webRTCDirect } from "@libp2p/webrtc"; +import { multiaddr } from "@multiformats/multiaddr"; +import { execa } from "execa"; +import { path as p2pd } from "go-libp2p"; +import { createLibp2p } from "libp2p"; +import pDefer from "p-defer"; +import type { Identify } from "@libp2p/identify"; +import type { ServiceMap, PrivateKey } from "@libp2p/interface"; +import type { SpawnOptions, Daemon, DaemonFactory } from "@libp2p/interop"; +import type { PingService } from "@libp2p/ping"; +import type { Libp2pOptions, ServiceFactoryMap } from "libp2p"; /** * @packageDocumentation @@ -38,198 +41,194 @@ import type { Libp2pOptions, ServiceFactoryMap } from 'libp2p' * ``` */ -async function createGoPeer (options: SpawnOptions): Promise { - const controlPort = Math.floor(Math.random() * (50000 - 10000 + 1)) + 10000 - const apiAddr = multiaddr(`/ip4/127.0.0.1/tcp/${controlPort}`) +async function createGoPeer(options: SpawnOptions): Promise { + const controlPort = Math.floor(Math.random() * (50000 - 10000 + 1)) + 10000; + const apiAddr = multiaddr(`/ip4/127.0.0.1/tcp/${controlPort}`); - const log = logger(`go-libp2p:${controlPort}`) + const log = logger(`go-libp2p:${controlPort}`); - const opts = [ - `-listen=${apiAddr.toString()}` - ] + const opts = [`-listen=${apiAddr.toString()}`]; if (options.noListen === true) { - opts.push('-noListenAddrs') + opts.push("-noListenAddrs"); } else { - if (options.transport == null || options.transport === 'tcp') { - opts.push('-hostAddrs=/ip4/127.0.0.1/tcp/0') - } else if (options.transport === 'webtransport') { - opts.push('-hostAddrs=/ip4/127.0.0.1/udp/0/quic-v1/webtransport') - } else if (options.transport === 'webrtc-direct') { - opts.push('-hostAddrs=/ip4/127.0.0.1/udp/0/webrtc-direct') + if (options.transport == null || options.transport === "tcp") { + opts.push("-hostAddrs=/ip4/127.0.0.1/tcp/0"); + } else if (options.transport === "webtransport") { + opts.push("-hostAddrs=/ip4/127.0.0.1/udp/0/quic-v1/webtransport"); + } else if (options.transport === "webrtc-direct") { + opts.push("-hostAddrs=/ip4/127.0.0.1/udp/0/webrtc-direct"); } else { - throw new UnsupportedError() + throw new UnsupportedError(); } } if (options.encryption != null) { - opts.push(`-${options.encryption}=true`) + opts.push(`-${options.encryption}=true`); } if (options.dht === true) { - opts.push('-dhtServer') + opts.push("-dhtServer"); } if (options.relay === true) { - opts.push('-relay') + opts.push("-relay"); } if (options.pubsub === true) { - opts.push('-pubsub') + opts.push("-pubsub"); } if (options.pubsubRouter != null) { - opts.push(`-pubsubRouter=${options.pubsubRouter}`) + opts.push(`-pubsubRouter=${options.pubsubRouter}`); } if (options.key != null) { - opts.push(`-id=${options.key}`) + opts.push(`-id=${options.key}`); } - if (options.muxer === 'mplex') { - opts.push('-muxer=mplex') + if (options.muxer === "mplex") { + opts.push("-muxer=mplex"); } else { - opts.push('-muxer=yamux') + opts.push("-muxer=yamux"); } - const deferred = pDefer() + const deferred = pDefer(); const proc = execa(p2pd(), opts, { env: { - GOLOG_LOG_LEVEL: 'debug' - } - }) + GOLOG_LOG_LEVEL: "debug", + }, + }); - proc.stdout?.on('data', (buf: Buffer) => { - const str = buf.toString() - log(str) + proc.stdout?.on("data", (buf: Buffer) => { + const str = buf.toString(); + log(str); // daemon has started - if (str.includes('Control socket:')) { - deferred.resolve() + if (str.includes("Control socket:")) { + deferred.resolve(); } - }) + }); - proc.stderr?.on('data', (buf) => { - log.error(buf.toString()) - }) + proc.stderr?.on("data", (buf) => { + log.error("interop main error - %e", buf.toString()); + }); - await deferred.promise + await deferred.promise; return { client: createClient(apiAddr), stop: async () => { - proc.kill() - } - } + proc.kill(); + }, + }; } -async function createJsPeer (options: SpawnOptions): Promise { - let privateKey: PrivateKey | undefined +async function createJsPeer(options: SpawnOptions): Promise { + let privateKey: PrivateKey | undefined; if (options.key != null) { - const keyFile = fs.readFileSync(options.key) - privateKey = privateKeyFromProtobuf(keyFile) + const keyFile = fs.readFileSync(options.key); + privateKey = privateKeyFromProtobuf(keyFile); } const opts: Libp2pOptions = { privateKey, addresses: { - listen: [] + listen: [], }, - transports: [ - tcp(), - circuitRelayTransport(), - webRTCDirect() - ], + transports: [tcp(), circuitRelayTransport(), webRTCDirect()], streamMuxers: [], - connectionEncrypters: [] - } + connectionEncrypters: [], + }; if (options.noListen !== true) { - if (options.transport == null || options.transport === 'tcp') { - opts.addresses?.listen?.push('/ip4/127.0.0.1/tcp/0') - } else if (options.transport === 'webrtc-direct') { - opts.addresses?.listen?.push('/ip4/127.0.0.1/udp/0/webrtc-direct') + if (options.transport == null || options.transport === "tcp") { + opts.addresses?.listen?.push("/ip4/127.0.0.1/tcp/0"); + } else if (options.transport === "webrtc-direct") { + opts.addresses?.listen?.push("/ip4/127.0.0.1/udp/0/webrtc-direct"); } else { - throw new UnsupportedError() + throw new UnsupportedError(); } } - if (options.transport === 'webtransport') { - throw new UnsupportedError() + if (options.transport === "webtransport") { + throw new UnsupportedError(); } - const services: ServiceFactoryMap<{ identify: Identify, ping: PingService } & Record> = { + const services: ServiceFactoryMap< + { identify: Identify; ping: PingService } & Record + > = { identify: identify(), - ping: ping() - } + ping: ping(), + }; - if (options.encryption === 'tls') { - opts.connectionEncrypters?.push(tls()) - } else if (options.encryption === 'plaintext') { - opts.connectionEncrypters?.push(plaintext()) + if (options.encryption === "tls") { + opts.connectionEncrypters?.push(tls()); + } else if (options.encryption === "plaintext") { + opts.connectionEncrypters?.push(plaintext()); } else { - opts.connectionEncrypters?.push(noise()) + opts.connectionEncrypters?.push(noise()); } - if (options.muxer === 'mplex') { - opts.streamMuxers?.push(mplex()) + if (options.muxer === "mplex") { + opts.streamMuxers?.push(mplex()); } else { - opts.streamMuxers?.push(yamux()) + opts.streamMuxers?.push(yamux()); } if (options.pubsub === true) { - if (options.pubsubRouter === 'floodsub') { - services.pubsub = floodsub() + if (options.pubsubRouter === "floodsub") { + services.pubsub = floodsub(); } else { - services.pubsub = gossipsub() + services.pubsub = gossipsub(); } } if (options.relay === true) { - services.relay = circuitRelayServer() + services.relay = circuitRelayServer(); } if (options.dht === true) { services.dht = kadDHT({ - protocol: '/ipfs/kad/1.0.0', + protocol: "/ipfs/kad/1.0.0", peerInfoMapper: passthroughMapper, - clientMode: false - }) + clientMode: false, + }); } const node: any = await createLibp2p({ ...opts, - services - }) + services, + }); - const server = createServer(multiaddr('/ip4/127.0.0.1/tcp/0'), node) - await server.start() + const server = createServer(multiaddr("/ip4/127.0.0.1/tcp/0"), node); + await server.start(); return { client: createClient(server.getMultiaddr()), stop: async () => { - await server.stop() - await node.stop() - } - } + await server.stop(); + await node.stop(); + }, + }; } -async function main (): Promise { +async function main(): Promise { const factory: DaemonFactory = { - async spawn (options: SpawnOptions) { - if (options.type === 'go') { - return createGoPeer(options) + async spawn(options: SpawnOptions) { + if (options.type === "go") { + return createGoPeer(options); } - return createJsPeer(options) - } - } + return createJsPeer(options); + }, + }; - await interopTests(factory) + await interopTests(factory); } -main().catch(err => { - console.error(err) // eslint-disable-line no-console - process.exit(1) -}) +main().catch((err) => { + console.error(err); // eslint-disable-line no-console + process.exit(1); +}); diff --git a/packages/interface-compliance-tests/src/mocks/connection.ts b/packages/interface-compliance-tests/src/mocks/connection.ts index 7cc2c34a0e..b89c348481 100644 --- a/packages/interface-compliance-tests/src/mocks/connection.ts +++ b/packages/interface-compliance-tests/src/mocks/connection.ts @@ -1,173 +1,198 @@ -import { ConnectionClosedError } from '@libp2p/interface' -import { defaultLogger, logger } from '@libp2p/logger' -import * as mss from '@libp2p/multistream-select' -import { peerIdFromString } from '@libp2p/peer-id' -import { closeSource } from '@libp2p/utils/close-source' -import { duplexPair } from 'it-pair/duplex' -import { pipe } from 'it-pipe' -import { Uint8ArrayList } from 'uint8arraylist' -import { mockMultiaddrConnection } from './multiaddr-connection.js' -import { mockMuxer } from './muxer.js' -import { mockRegistrar } from './registrar.js' -import type { AbortOptions, ComponentLogger, Logger, MultiaddrConnection, Connection, Stream, Direction, ConnectionTimeline, ConnectionStatus, PeerId, StreamMuxer, StreamMuxerFactory, NewStreamOptions, ConnectionLimits } from '@libp2p/interface' -import type { Registrar } from '@libp2p/interface-internal' -import type { Multiaddr } from '@multiformats/multiaddr' -import type { Duplex, Source } from 'it-stream-types' +import { ConnectionClosedError } from "@libp2p/interface"; +import { defaultLogger, logger } from "@libp2p/logger"; +import * as mss from "@libp2p/multistream-select"; +import { peerIdFromString } from "@libp2p/peer-id"; +import { closeSource } from "@libp2p/utils/close-source"; +import { duplexPair } from "it-pair/duplex"; +import { pipe } from "it-pipe"; +import { Uint8ArrayList } from "uint8arraylist"; +import { mockMultiaddrConnection } from "./multiaddr-connection.js"; +import { mockMuxer } from "./muxer.js"; +import { mockRegistrar } from "./registrar.js"; +import type { + AbortOptions, + ComponentLogger, + Logger, + MultiaddrConnection, + Connection, + Stream, + Direction, + ConnectionTimeline, + ConnectionStatus, + PeerId, + StreamMuxer, + StreamMuxerFactory, + NewStreamOptions, + ConnectionLimits, +} from "@libp2p/interface"; +import type { Registrar } from "@libp2p/interface-internal"; +import type { Multiaddr } from "@multiformats/multiaddr"; +import type { Duplex, Source } from "it-stream-types"; export interface MockConnectionOptions { - direction?: Direction - registrar?: Registrar - muxerFactory?: StreamMuxerFactory - logger?: ComponentLogger + direction?: Direction; + registrar?: Registrar; + muxerFactory?: StreamMuxerFactory; + logger?: ComponentLogger; } interface MockConnectionInit { - remoteAddr: Multiaddr - remotePeer: PeerId - direction: Direction - maConn: MultiaddrConnection - muxer: StreamMuxer - logger: ComponentLogger + remoteAddr: Multiaddr; + remotePeer: PeerId; + direction: Direction; + maConn: MultiaddrConnection; + muxer: StreamMuxer; + logger: ComponentLogger; } class MockConnection implements Connection { - public id: string - public remoteAddr: Multiaddr - public remotePeer: PeerId - public direction: Direction - public timeline: ConnectionTimeline - public multiplexer?: string - public encryption?: string - public status: ConnectionStatus - public streams: Stream[] - public tags: string[] - public limits?: ConnectionLimits - public log: Logger - - private readonly muxer: StreamMuxer - private readonly maConn: MultiaddrConnection - private readonly logger: ComponentLogger - - constructor (init: MockConnectionInit) { - const { remoteAddr, remotePeer, direction, maConn, muxer, logger } = init - - this.id = `mock-connection-${Math.random()}` - this.remoteAddr = remoteAddr - this.remotePeer = remotePeer - this.direction = direction - this.status = 'open' - this.direction = direction - this.timeline = maConn.timeline - this.multiplexer = 'test-multiplexer' - this.encryption = 'yes-yes-very-secure' - this.streams = [] - this.tags = [] - this.muxer = muxer - this.maConn = maConn - this.logger = logger - this.log = logger.forComponent(this.id) + public id: string; + public remoteAddr: Multiaddr; + public remotePeer: PeerId; + public direction: Direction; + public timeline: ConnectionTimeline; + public multiplexer?: string; + public encryption?: string; + public status: ConnectionStatus; + public streams: Stream[]; + public tags: string[]; + public limits?: ConnectionLimits; + public log: Logger; + + private readonly muxer: StreamMuxer; + private readonly maConn: MultiaddrConnection; + private readonly logger: ComponentLogger; + + constructor(init: MockConnectionInit) { + const { remoteAddr, remotePeer, direction, maConn, muxer, logger } = init; + + this.id = `mock-connection-${Math.random()}`; + this.remoteAddr = remoteAddr; + this.remotePeer = remotePeer; + this.direction = direction; + this.status = "open"; + this.direction = direction; + this.timeline = maConn.timeline; + this.multiplexer = "test-multiplexer"; + this.encryption = "yes-yes-very-secure"; + this.streams = []; + this.tags = []; + this.muxer = muxer; + this.maConn = maConn; + this.logger = logger; + this.log = logger.forComponent(this.id); } - async newStream (protocols: string | string[], options?: NewStreamOptions): Promise { + async newStream( + protocols: string | string[], + options?: NewStreamOptions + ): Promise { if (!Array.isArray(protocols)) { - protocols = [protocols] + protocols = [protocols]; } if (protocols.length === 0) { - throw new Error('protocols must have a length') + throw new Error("protocols must have a length"); } - if (this.status !== 'open') { - throw new ConnectionClosedError('connection must be open to create streams') + if (this.status !== "open") { + throw new ConnectionClosedError( + "connection must be open to create streams" + ); } - options?.signal?.throwIfAborted() + options?.signal?.throwIfAborted(); - const id = `${Math.random()}` - const stream = await this.muxer.newStream(id) + const id = `${Math.random()}`; + const stream = await this.muxer.newStream(id); const result = await mss.select(stream, protocols, { ...options, - log: this.logger.forComponent('libp2p:mock-connection:stream:mss:select') - }) + log: this.logger.forComponent("libp2p:mock-connection:stream:mss:select"), + }); - stream.protocol = result.protocol - stream.direction = 'outbound' - stream.sink = result.stream.sink - stream.source = result.stream.source + stream.protocol = result.protocol; + stream.direction = "outbound"; + stream.sink = result.stream.sink; + stream.source = result.stream.source; - this.streams.push(stream) + this.streams.push(stream); - return stream + return stream; } - async close (options?: AbortOptions): Promise { - this.status = 'closing' - await Promise.all( - this.streams.map(async s => s.close(options)) - ) - await this.maConn.close() - this.status = 'closed' - this.timeline.close = Date.now() + async close(options?: AbortOptions): Promise { + this.status = "closing"; + await Promise.all(this.streams.map(async (s) => s.close(options))); + await this.maConn.close(); + this.status = "closed"; + this.timeline.close = Date.now(); } - abort (err: Error): void { - this.status = 'closing' - this.streams.forEach(s => { - s.abort(err) - }) - this.maConn.abort(err) - this.status = 'closed' - this.timeline.close = Date.now() + abort(err: Error): void { + this.status = "closing"; + this.streams.forEach((s) => { + s.abort(err); + }); + this.maConn.abort(err); + this.status = "closed"; + this.timeline.close = Date.now(); } } -export function mockConnection (maConn: MultiaddrConnection, opts: MockConnectionOptions = {}): Connection { - const remoteAddr = maConn.remoteAddr - const remotePeerIdStr = remoteAddr.getPeerId() ?? '12D3KooWCrhmFM1BCPGBkNzbPfDk4cjYmtAYSpZwUBC69Qg2kZyq' - const logger = opts.logger ?? defaultLogger() +export function mockConnection( + maConn: MultiaddrConnection, + opts: MockConnectionOptions = {} +): Connection { + const remoteAddr = maConn.remoteAddr; + const remotePeerIdStr = + remoteAddr.getPeerId() ?? + "12D3KooWCrhmFM1BCPGBkNzbPfDk4cjYmtAYSpZwUBC69Qg2kZyq"; + const logger = opts.logger ?? defaultLogger(); if (remotePeerIdStr == null) { - throw new Error('Remote multiaddr must contain a peer id') + 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 log = logger.forComponent('libp2p:mock-muxer') + const remotePeer = peerIdFromString(remotePeerIdStr); + const direction = opts.direction ?? "inbound"; + const registrar = opts.registrar ?? mockRegistrar(); + const muxerFactory = opts.muxerFactory ?? mockMuxer(); + const log = logger.forComponent("libp2p:mock-muxer"); const muxer = muxerFactory.createStreamMuxer({ direction, onIncomingStream: (muxedStream) => { try { - mss.handle(muxedStream, registrar.getProtocols(), { - log - }) + mss + .handle(muxedStream, registrar.getProtocols(), { + log, + }) .then(({ stream, protocol }) => { - log('%s: incoming stream opened on %s', direction, protocol) - muxedStream.protocol = protocol - muxedStream.sink = stream.sink - muxedStream.source = stream.source + log("%s: incoming stream opened on %s", direction, protocol); + muxedStream.protocol = protocol; + muxedStream.sink = stream.sink; + muxedStream.source = stream.source; - connection.streams.push(muxedStream) - const { handler } = registrar.getHandler(protocol) + connection.streams.push(muxedStream); + const { handler } = registrar.getHandler(protocol); - handler({ connection, stream: muxedStream }) - }).catch(err => { - log.error(err) + handler({ connection, stream: muxedStream }); }) + .catch((err) => { + log.error("incoming stream handler error - %e", err); + }); } catch (err: any) { - log.error(err) + log.error("error handling incoming stream - %e", err); } }, onStreamEnd: (muxedStream) => { - connection.streams = connection.streams.filter(stream => stream.id !== muxedStream.id) - } - }) + connection.streams = connection.streams.filter( + (stream) => stream.id !== muxedStream.id + ); + }, + }); - void pipe( - maConn, muxer, maConn - ) + void pipe(maConn, muxer, maConn); const connection = new MockConnection({ remoteAddr, @@ -175,133 +200,160 @@ export function mockConnection (maConn: MultiaddrConnection, opts: MockConnectio direction, maConn, muxer, - logger - }) + logger, + }); - return connection + return connection; } export interface StreamInit { - direction?: Direction - protocol?: string - id?: string + direction?: Direction; + protocol?: string; + id?: string; } -export function mockStream (stream: Duplex, Source, Promise>, init: StreamInit = {}): Stream { - const id = `stream-${Date.now()}` - const log = logger(`libp2p:mock-stream:${id}`) +export function mockStream( + stream: Duplex< + AsyncGenerator, + Source, + Promise + >, + init: StreamInit = {} +): Stream { + const id = `stream-${Date.now()}`; + const log = logger(`libp2p:mock-stream:${id}`); // ensure stream output is `Uint8ArrayList` as it would be from an actual // Stream where everything is length-varint encoded - const originalSource = stream.source - stream.source = (async function * (): AsyncGenerator { + const originalSource = stream.source; + stream.source = (async function* (): AsyncGenerator< + Uint8ArrayList, + any, + unknown + > { for await (const buf of originalSource) { if (buf instanceof Uint8Array) { - yield new Uint8ArrayList(buf) + yield new Uint8ArrayList(buf); } else { - yield buf + yield buf; } } - })() + })(); - const abortSinkController = new AbortController() - const originalSink = stream.sink.bind(stream) + const abortSinkController = new AbortController(); + const originalSink = stream.sink.bind(stream); stream.sink = async (source) => { - abortSinkController.signal.addEventListener('abort', () => { - closeSource(source, log) - }) + abortSinkController.signal.addEventListener("abort", () => { + closeSource(source, log); + }); - await originalSink(source) - } + await originalSink(source); + }; const mockStream: Stream = { ...stream, close: async (options) => { - await mockStream.closeRead(options) - await mockStream.closeWrite(options) + await mockStream.closeRead(options); + await mockStream.closeWrite(options); }, closeRead: async () => { - closeSource(originalSource, log) - mockStream.timeline.closeRead = Date.now() + closeSource(originalSource, log); + mockStream.timeline.closeRead = Date.now(); if (mockStream.timeline.closeWrite != null) { - mockStream.timeline.close = Date.now() + mockStream.timeline.close = Date.now(); } }, closeWrite: async () => { - abortSinkController.abort() - mockStream.timeline.closeWrite = Date.now() + abortSinkController.abort(); + mockStream.timeline.closeWrite = Date.now(); if (mockStream.timeline.closeRead != null) { - mockStream.timeline.close = Date.now() + mockStream.timeline.close = Date.now(); } }, abort: () => { - closeSource(originalSource, log) - mockStream.timeline.closeWrite = Date.now() - mockStream.timeline.closeRead = Date.now() - mockStream.timeline.close = Date.now() + closeSource(originalSource, log); + mockStream.timeline.closeWrite = Date.now(); + mockStream.timeline.closeRead = Date.now(); + mockStream.timeline.close = Date.now(); }, - direction: 'outbound', - protocol: '/foo/1.0.0', + direction: "outbound", + protocol: "/foo/1.0.0", timeline: { - open: Date.now() + open: Date.now(), }, metadata: {}, id: `stream-${Date.now()}`, - status: 'open', - readStatus: 'ready', - writeStatus: 'ready', - log: logger('mock-stream'), - ...init - } - - return mockStream + status: "open", + readStatus: "ready", + writeStatus: "ready", + log: logger("mock-stream"), + ...init, + }; + + return mockStream; } export interface StreamPairInit { - duplex: Duplex, Source, Promise> - init?: StreamInit + duplex: Duplex< + AsyncGenerator, + Source, + Promise + >; + init?: StreamInit; } -export function streamPair (a: StreamPairInit, b: StreamPairInit, init: StreamInit = {}): [Stream, Stream] { +export function streamPair( + a: StreamPairInit, + b: StreamPairInit, + init: StreamInit = {} +): [Stream, Stream] { return [ mockStream(a.duplex, { - direction: 'outbound', + direction: "outbound", ...init, - ...(a.init ?? {}) + ...(a.init ?? {}), }), mockStream(b.duplex, { - direction: 'inbound', + direction: "inbound", ...init, - ...(b.init ?? {}) - }) - ] + ...(b.init ?? {}), + }), + ]; } export interface Peer { - peerId: PeerId - registrar: Registrar + peerId: PeerId; + registrar: Registrar; } -export function multiaddrConnectionPair (a: { peerId: PeerId, registrar: Registrar }, b: { peerId: PeerId, registrar: Registrar }): [ MultiaddrConnection, MultiaddrConnection ] { - const [peerBtoPeerA, peerAtoPeerB] = duplexPair() +export function multiaddrConnectionPair( + a: { peerId: PeerId; registrar: Registrar }, + b: { peerId: PeerId; registrar: Registrar } +): [MultiaddrConnection, MultiaddrConnection] { + const [peerBtoPeerA, peerAtoPeerB] = duplexPair< + Uint8Array | Uint8ArrayList + >(); return [ mockMultiaddrConnection(peerAtoPeerB, b.peerId), - mockMultiaddrConnection(peerBtoPeerA, a.peerId) - ] + mockMultiaddrConnection(peerBtoPeerA, a.peerId), + ]; } -export function connectionPair (a: { peerId: PeerId, registrar: Registrar }, b: { peerId: PeerId, registrar: Registrar }): [ Connection, Connection ] { - const [peerBtoPeerA, peerAtoPeerB] = multiaddrConnectionPair(a, b) +export function connectionPair( + a: { peerId: PeerId; registrar: Registrar }, + b: { peerId: PeerId; registrar: Registrar } +): [Connection, Connection] { + const [peerBtoPeerA, peerAtoPeerB] = multiaddrConnectionPair(a, b); return [ mockConnection(peerBtoPeerA, { - registrar: a.registrar + registrar: a.registrar, }), mockConnection(peerAtoPeerB, { - registrar: b.registrar - }) - ] + registrar: b.registrar, + }), + ]; } diff --git a/packages/kad-dht/src/query/manager.ts b/packages/kad-dht/src/query/manager.ts index d231a01669..8892633f52 100644 --- a/packages/kad-dht/src/query/manager.ts +++ b/packages/kad-dht/src/query/manager.ts @@ -1,197 +1,220 @@ -import { createScalableCuckooFilter } from '@libp2p/utils/filters' -import { anySignal } from 'any-signal' -import merge from 'it-merge' -import { setMaxListeners } from 'main-event' -import { pEvent } from 'p-event' -import { raceSignal } from 'race-signal' -import { toString as uint8ArrayToString } from 'uint8arrays/to-string' -import { - ALPHA, K, DEFAULT_QUERY_TIMEOUT -} from '../constants.js' -import { convertBuffer } from '../utils.js' -import { queryPath } from './query-path.js' -import type { QueryFunc } from './types.js' -import type { QueryEvent } from '../index.js' -import type { RoutingTable } from '../routing-table/index.js' -import type { ComponentLogger, Metrics, PeerId, RoutingOptions, Startable } from '@libp2p/interface' -import type { ConnectionManager } from '@libp2p/interface-internal' -import type { DeferredPromise } from 'p-defer' +import { createScalableCuckooFilter } from "@libp2p/utils/filters"; +import { anySignal } from "any-signal"; +import merge from "it-merge"; +import { setMaxListeners } from "main-event"; +import { pEvent } from "p-event"; +import { raceSignal } from "race-signal"; +import { toString as uint8ArrayToString } from "uint8arrays/to-string"; +import { ALPHA, K, DEFAULT_QUERY_TIMEOUT } from "../constants.js"; +import { convertBuffer } from "../utils.js"; +import { queryPath } from "./query-path.js"; +import type { QueryFunc } from "./types.js"; +import type { QueryEvent } from "../index.js"; +import type { RoutingTable } from "../routing-table/index.js"; +import type { + ComponentLogger, + Metrics, + PeerId, + RoutingOptions, + Startable, +} from "@libp2p/interface"; +import type { ConnectionManager } from "@libp2p/interface-internal"; +import type { DeferredPromise } from "p-defer"; export interface CleanUpEvents { - cleanup: CustomEvent + cleanup: CustomEvent; } export interface QueryManagerInit { - logPrefix: string - metricsPrefix: string - disjointPaths?: number - alpha?: number - initialQuerySelfHasRun: DeferredPromise - allowQueryWithZeroPeers?: boolean - routingTable: RoutingTable + logPrefix: string; + metricsPrefix: string; + disjointPaths?: number; + alpha?: number; + initialQuerySelfHasRun: DeferredPromise; + allowQueryWithZeroPeers?: boolean; + routingTable: RoutingTable; } export interface QueryManagerComponents { - peerId: PeerId - metrics?: Metrics - logger: ComponentLogger - connectionManager: ConnectionManager + peerId: PeerId; + metrics?: Metrics; + logger: ComponentLogger; + connectionManager: ConnectionManager; } export interface QueryOptions extends RoutingOptions { - isSelfQuery?: boolean + isSelfQuery?: boolean; } /** * Keeps track of all running queries */ export class QueryManager implements Startable { - public disjointPaths: number - private readonly alpha: number - private shutDownController: AbortController - private running: boolean - private readonly logger: ComponentLogger - private readonly peerId: PeerId - private readonly connectionManager: ConnectionManager - private readonly routingTable: RoutingTable - private initialQuerySelfHasRun?: DeferredPromise - private readonly logPrefix: string - private readonly allowQueryWithZeroPeers: boolean - - constructor (components: QueryManagerComponents, init: QueryManagerInit) { - this.logPrefix = init.logPrefix - this.disjointPaths = init.disjointPaths ?? K - this.alpha = init.alpha ?? ALPHA - this.initialQuerySelfHasRun = init.initialQuerySelfHasRun - this.routingTable = init.routingTable - this.logger = components.logger - this.peerId = components.peerId - this.connectionManager = components.connectionManager - this.allowQueryWithZeroPeers = init.allowQueryWithZeroPeers ?? false + public disjointPaths: number; + private readonly alpha: number; + private shutDownController: AbortController; + private running: boolean; + private readonly logger: ComponentLogger; + private readonly peerId: PeerId; + private readonly connectionManager: ConnectionManager; + private readonly routingTable: RoutingTable; + private initialQuerySelfHasRun?: DeferredPromise; + private readonly logPrefix: string; + private readonly allowQueryWithZeroPeers: boolean; + + constructor(components: QueryManagerComponents, init: QueryManagerInit) { + this.logPrefix = init.logPrefix; + this.disjointPaths = init.disjointPaths ?? K; + this.alpha = init.alpha ?? ALPHA; + this.initialQuerySelfHasRun = init.initialQuerySelfHasRun; + this.routingTable = init.routingTable; + this.logger = components.logger; + this.peerId = components.peerId; + this.connectionManager = components.connectionManager; + this.allowQueryWithZeroPeers = init.allowQueryWithZeroPeers ?? false; // allow us to stop queries on shut down - this.shutDownController = new AbortController() + this.shutDownController = new AbortController(); // make sure we don't make a lot of noise in the logs - setMaxListeners(Infinity, this.shutDownController.signal) + setMaxListeners(Infinity, this.shutDownController.signal); - this.running = false + this.running = false; } - isStarted (): boolean { - return this.running + isStarted(): boolean { + return this.running; } /** * Starts the query manager */ - async start (): Promise { + async start(): Promise { if (this.running) { - return + return; } - this.running = true + this.running = true; // allow us to stop queries on shut down - this.shutDownController = new AbortController() + this.shutDownController = new AbortController(); // make sure we don't make a lot of noise in the logs - setMaxListeners(Infinity, this.shutDownController.signal) + setMaxListeners(Infinity, this.shutDownController.signal); } /** * Stops all queries */ - async stop (): Promise { - this.running = false + async stop(): Promise { + this.running = false; - this.shutDownController.abort() + this.shutDownController.abort(); } - async * run (key: Uint8Array, queryFunc: QueryFunc, options: QueryOptions = {}): AsyncGenerator { + async *run( + key: Uint8Array, + queryFunc: QueryFunc, + options: QueryOptions = {} + ): AsyncGenerator { if (!this.running) { - throw new Error('QueryManager not started') + throw new Error("QueryManager not started"); } if (options.signal == null) { // don't let queries run forever - const signal = AbortSignal.timeout(DEFAULT_QUERY_TIMEOUT) + const signal = AbortSignal.timeout(DEFAULT_QUERY_TIMEOUT); // this signal will get listened to for network requests, etc // so make sure we don't make a lot of noise in the logs - setMaxListeners(Infinity, signal) + setMaxListeners(Infinity, signal); options = { ...options, - signal - } + signal, + }; } // if the user breaks out of a for..await of loop iterating over query // results we need to cancel any in-flight network requests - const queryEarlyExitController = new AbortController() + const queryEarlyExitController = new AbortController(); const signal = anySignal([ this.shutDownController.signal, queryEarlyExitController.signal, - options.signal - ]) + options.signal, + ]); // this signal will get listened to for every invocation of queryFunc // so make sure we don't make a lot of noise in the logs - setMaxListeners(Infinity, signal, queryEarlyExitController.signal) + setMaxListeners(Infinity, signal, queryEarlyExitController.signal); - const log = this.logger.forComponent(`${this.logPrefix}:query:` + uint8ArrayToString(key, 'base58btc')) + const log = this.logger.forComponent( + `${this.logPrefix}:query:` + uint8ArrayToString(key, "base58btc") + ); // query a subset of peers up to `kBucketSize / 2` in length - let queryFinished = false + let queryFinished = false; try { if (this.routingTable.size === 0 && !this.allowQueryWithZeroPeers) { - log('routing table was empty, waiting for some peers before running%s query', options.isSelfQuery === true ? ' self' : '') + log( + "routing table was empty, waiting for some peers before running%s query", + options.isSelfQuery === true ? " self" : "" + ); // wait to discover at least one DHT peer that isn't us - await pEvent(this.routingTable, 'peer:add', { + await pEvent(this.routingTable, "peer:add", { signal, - filter: (event) => !this.peerId.equals(event.detail) - }) - log('routing table has peers, continuing with%s query', options.isSelfQuery === true ? ' self' : '') + filter: (event) => !this.peerId.equals(event.detail), + }); + log( + "routing table has peers, continuing with%s query", + options.isSelfQuery === true ? " self" : "" + ); } if (options.isSelfQuery !== true && this.initialQuerySelfHasRun != null) { - log('waiting for initial self query before continuing') + log("waiting for initial self query before continuing"); - await raceSignal(this.initialQuerySelfHasRun.promise, signal) + await raceSignal(this.initialQuerySelfHasRun.promise, signal); - this.initialQuerySelfHasRun = undefined + this.initialQuerySelfHasRun = undefined; } - log('query:start') + log("query:start"); const id = await convertBuffer(key, { - signal - }) - const peers = this.routingTable.closestPeers(id, this.routingTable.kBucketSize) + signal, + }); + const peers = this.routingTable.closestPeers( + id, + this.routingTable.kBucketSize + ); // split peers into d buckets evenly(ish) - const peersToQuery = peers.sort(() => { - if (Math.random() > 0.5) { - return 1 - } + const peersToQuery = peers + .sort(() => { + if (Math.random() > 0.5) { + return 1; + } - return -1 - }) - .reduce((acc: PeerId[][], curr, index) => { - acc[index % this.disjointPaths].push(curr) + return -1; + }) + .reduce( + (acc: PeerId[][], curr, index) => { + acc[index % this.disjointPaths].push(curr); - return acc - }, new Array(this.disjointPaths).fill(0).map(() => [])) - .filter(peers => peers.length > 0) + return acc; + }, + new Array(this.disjointPaths).fill(0).map(() => []) + ) + .filter((peers) => peers.length > 0); if (peers.length === 0) { - log.error('running query with no peers') - return + log.error("running query with no peers"); + return; } // make sure we don't get trapped in a loop - const peersSeen = createScalableCuckooFilter(1024) + const peersSeen = createScalableCuckooFilter(1024); // Create query paths from the starting peers const paths = peersToQuery.map((peer, index) => { @@ -208,50 +231,52 @@ export class QueryManager implements Startable { log, peersSeen, onProgress: options.onProgress, - connectionManager: this.connectionManager - }) - }) + connectionManager: this.connectionManager, + }); + }); // Execute the query along each disjoint path and yield their results as they become available for await (const event of merge(...paths)) { - if (event.name === 'QUERY_ERROR') { - log.error('query error', event.error) + if (event.name === "QUERY_ERROR") { + log.error("query error - %e", event.error); } - if (event.name === 'PEER_RESPONSE') { + if (event.name === "PEER_RESPONSE") { for (const peer of [...event.closer, ...event.providers]) { // eslint-disable-next-line max-depth - if (!(await this.connectionManager.isDialable(peer.multiaddrs, { - signal - }))) { - continue + if ( + !(await this.connectionManager.isDialable(peer.multiaddrs, { + signal, + })) + ) { + continue; } await this.routingTable.add(peer.id, { - signal - }) + signal, + }); } } - signal.throwIfAborted() - yield event + signal.throwIfAborted(); + yield event; } - queryFinished = true + queryFinished = true; } catch (err) { if (this.running) { // ignore errors thrown during shut down - throw err + throw err; } } finally { if (!queryFinished) { - log('query exited early') - queryEarlyExitController.abort() + log("query exited early"); + queryEarlyExitController.abort(); } - signal.clear() + signal.clear(); - log('query finished') + log("query finished"); } } } diff --git a/packages/transport-webrtc/src/private-to-private/initiate-connection.ts b/packages/transport-webrtc/src/private-to-private/initiate-connection.ts index 98fa827f68..892751a6bf 100644 --- a/packages/transport-webrtc/src/private-to-private/initiate-connection.ts +++ b/packages/transport-webrtc/src/private-to-private/initiate-connection.ts @@ -1,97 +1,127 @@ -import { InvalidParametersError } from '@libp2p/interface' -import { peerIdFromString } from '@libp2p/peer-id' -import { pbStream } from 'it-protobuf-stream' -import { CustomProgressEvent } from 'progress-events' -import { SIGNALING_PROTOCOL } from '../constants.js' -import { SDPHandshakeFailedError } from '../error.js' -import { DataChannelMuxerFactory } from '../muxer.js' -import { RTCPeerConnection, RTCSessionDescription } from '../webrtc/index.js' -import { Message } from './pb/message.js' -import { splitAddr } from './transport.js' -import { readCandidatesUntilConnected } from './util.js' -import type { WebRTCDialEvents, WebRTCTransportMetrics } from './transport.js' -import type { DataChannelOptions } from '../index.js' -import type { LoggerOptions, Connection, ComponentLogger, IncomingStreamData } from '@libp2p/interface' -import type { ConnectionManager, TransportManager } from '@libp2p/interface-internal' -import type { Multiaddr } from '@multiformats/multiaddr' -import type { ProgressOptions } from 'progress-events' +import { InvalidParametersError } from "@libp2p/interface"; +import { peerIdFromString } from "@libp2p/peer-id"; +import { pbStream } from "it-protobuf-stream"; +import { CustomProgressEvent } from "progress-events"; +import { SIGNALING_PROTOCOL } from "../constants.js"; +import { SDPHandshakeFailedError } from "../error.js"; +import { DataChannelMuxerFactory } from "../muxer.js"; +import { RTCPeerConnection, RTCSessionDescription } from "../webrtc/index.js"; +import { Message } from "./pb/message.js"; +import { splitAddr } from "./transport.js"; +import { readCandidatesUntilConnected } from "./util.js"; +import type { WebRTCDialEvents, WebRTCTransportMetrics } from "./transport.js"; +import type { DataChannelOptions } from "../index.js"; +import type { + LoggerOptions, + Connection, + ComponentLogger, + IncomingStreamData, +} from "@libp2p/interface"; +import type { + ConnectionManager, + TransportManager, +} from "@libp2p/interface-internal"; +import type { Multiaddr } from "@multiformats/multiaddr"; +import type { ProgressOptions } from "progress-events"; export interface IncomingStreamOpts extends IncomingStreamData { - rtcConfiguration?: RTCConfiguration - dataChannelOptions?: Partial - signal: AbortSignal + rtcConfiguration?: RTCConfiguration; + dataChannelOptions?: Partial; + signal: AbortSignal; } -export interface ConnectOptions extends LoggerOptions, ProgressOptions { - rtcConfiguration?: RTCConfiguration - dataChannel?: DataChannelOptions - multiaddr: Multiaddr - connectionManager: ConnectionManager - transportManager: TransportManager - dataChannelOptions?: Partial - signal?: AbortSignal - metrics?: WebRTCTransportMetrics - logger: ComponentLogger +export interface ConnectOptions + extends LoggerOptions, + ProgressOptions { + rtcConfiguration?: RTCConfiguration; + dataChannel?: DataChannelOptions; + multiaddr: Multiaddr; + connectionManager: ConnectionManager; + transportManager: TransportManager; + dataChannelOptions?: Partial; + signal?: AbortSignal; + metrics?: WebRTCTransportMetrics; + logger: ComponentLogger; } -export async function initiateConnection ({ rtcConfiguration, dataChannel, signal, metrics, multiaddr: ma, connectionManager, transportManager, log, logger, onProgress }: ConnectOptions): Promise<{ remoteAddress: Multiaddr, peerConnection: RTCPeerConnection, muxerFactory: DataChannelMuxerFactory }> { - const { baseAddr } = splitAddr(ma) - - metrics?.dialerEvents.increment({ open: true }) - - log.trace('dialing base address: %a', baseAddr) - - const relayPeer = baseAddr.getPeerId() +export async function initiateConnection({ + rtcConfiguration, + dataChannel, + signal, + metrics, + multiaddr: ma, + connectionManager, + transportManager, + log, + logger, + onProgress, +}: ConnectOptions): Promise<{ + remoteAddress: Multiaddr; + peerConnection: RTCPeerConnection; + muxerFactory: DataChannelMuxerFactory; +}> { + const { baseAddr } = splitAddr(ma); + + metrics?.dialerEvents.increment({ open: true }); + + log.trace("dialing base address: %a", baseAddr); + + const relayPeer = baseAddr.getPeerId(); if (relayPeer == null) { - throw new InvalidParametersError('Relay peer was missing') + throw new InvalidParametersError("Relay peer was missing"); } - const connections = connectionManager.getConnections(peerIdFromString(relayPeer)) - let connection: Connection - let shouldCloseConnection = false + const connections = connectionManager.getConnections( + peerIdFromString(relayPeer) + ); + let connection: Connection; + let shouldCloseConnection = false; if (connections.length === 0) { - onProgress?.(new CustomProgressEvent('webrtc:dial-relay')) + onProgress?.(new CustomProgressEvent("webrtc:dial-relay")); // use the transport manager to open a connection. Initiating a WebRTC // connection takes place in the context of a dial - if we use the // connection manager instead we can end up joining our own dial context connection = await transportManager.dial(baseAddr, { signal, - onProgress - }) + onProgress, + }); // this connection is unmanaged by the connection manager so we should // close it when we are done - shouldCloseConnection = true + shouldCloseConnection = true; } else { - onProgress?.(new CustomProgressEvent('webrtc:reuse-relay-connection')) + onProgress?.(new CustomProgressEvent("webrtc:reuse-relay-connection")); - connection = connections[0] + connection = connections[0]; } try { - onProgress?.(new CustomProgressEvent('webrtc:open-signaling-stream')) + onProgress?.(new CustomProgressEvent("webrtc:open-signaling-stream")); const stream = await connection.newStream(SIGNALING_PROTOCOL, { signal, - runOnLimitedConnection: true - }) - - const messageStream = pbStream(stream).pb(Message) - const peerConnection = new RTCPeerConnection(rtcConfiguration) - const muxerFactory = new DataChannelMuxerFactory({ - logger - }, { - peerConnection, - dataChannelOptions: dataChannel - }) + runOnLimitedConnection: true, + }); + + const messageStream = pbStream(stream).pb(Message); + const peerConnection = new RTCPeerConnection(rtcConfiguration); + const muxerFactory = new DataChannelMuxerFactory( + { + logger, + }, + { + peerConnection, + dataChannelOptions: dataChannel, + } + ); try { // we create the channel so that the RTCPeerConnection has a component for // which to collect candidates. The label is not relevant to connection // initiation but can be useful for debugging - const channel = peerConnection.createDataChannel('init') + const channel = peerConnection.createDataChannel("init"); // setup callback to write ICE candidates to the remote peer peerConnection.onicecandidate = ({ candidate }) => { @@ -99,103 +129,113 @@ export async function initiateConnection ({ rtcConfiguration, dataChannel, signa // means end-of-candidates for this generation, otherwise this should // be a valid candidate object // see - https://www.w3.org/TR/webrtc/#rtcpeerconnectioniceevent - const data = JSON.stringify(candidate?.toJSON() ?? null) - - log.trace('initiator sending ICE candidate %o', candidate) - - void messageStream.write({ - type: Message.Type.ICE_CANDIDATE, - data - }, { - signal - }) - .catch(err => { - log.error('error sending ICE candidate', err) - }) - } + const data = JSON.stringify(candidate?.toJSON() ?? null); + + log.trace("initiator sending ICE candidate %o", candidate); + + void messageStream + .write( + { + type: Message.Type.ICE_CANDIDATE, + data, + }, + { + signal, + } + ) + .catch((err) => { + log.error("error sending ICE candidate", err); + }); + }; peerConnection.onicecandidateerror = (event) => { - log.error('initiator ICE candidate error', event) - } + log.error("initiator ICE candidate error", event); + }; // create an offer - const offerSdp = await peerConnection.createOffer().catch(err => { - log.error('could not execute createOffer', err) - throw new SDPHandshakeFailedError('Failed to set createOffer') - }) + const offerSdp = await peerConnection.createOffer().catch((err) => { + log.error("could not execute createOffer - %e", err); + throw new SDPHandshakeFailedError("Failed to set createOffer"); + }); - log.trace('initiator send SDP offer %s', offerSdp.sdp) + log.trace("initiator send SDP offer %s", offerSdp.sdp); - onProgress?.(new CustomProgressEvent('webrtc:send-sdp-offer')) + onProgress?.(new CustomProgressEvent("webrtc:send-sdp-offer")); // write the offer to the stream - await messageStream.write({ type: Message.Type.SDP_OFFER, data: offerSdp.sdp }, { - signal - }) + await messageStream.write( + { type: Message.Type.SDP_OFFER, data: offerSdp.sdp }, + { + signal, + } + ); // set offer as local description - await peerConnection.setLocalDescription(offerSdp).catch(err => { - log.error('could not execute setLocalDescription', err) - throw new SDPHandshakeFailedError('Failed to set localDescription') - }) + await peerConnection.setLocalDescription(offerSdp).catch((err) => { + log.error("could not execute setLocalDescription - %e", err); + throw new SDPHandshakeFailedError("Failed to set localDescription"); + }); - onProgress?.(new CustomProgressEvent('webrtc:read-sdp-answer')) + onProgress?.(new CustomProgressEvent("webrtc:read-sdp-answer")); - log.trace('initiator read SDP answer') + log.trace("initiator read SDP answer"); // read answer const answerMessage = await messageStream.read({ - signal - }) + signal, + }); if (answerMessage.type !== Message.Type.SDP_ANSWER) { - throw new SDPHandshakeFailedError('Remote should send an SDP answer') + throw new SDPHandshakeFailedError("Remote should send an SDP answer"); } - log.trace('initiator received SDP answer %s', answerMessage.data) + log.trace("initiator received SDP answer %s", answerMessage.data); - const answerSdp = new RTCSessionDescription({ type: 'answer', sdp: answerMessage.data }) - await peerConnection.setRemoteDescription(answerSdp).catch(err => { - log.error('could not execute setRemoteDescription', err) - throw new SDPHandshakeFailedError('Failed to set remoteDescription') - }) + const answerSdp = new RTCSessionDescription({ + type: "answer", + sdp: answerMessage.data, + }); + await peerConnection.setRemoteDescription(answerSdp).catch((err) => { + log.error("could not execute setRemoteDescription - %e", err); + throw new SDPHandshakeFailedError("Failed to set remoteDescription"); + }); - log.trace('initiator read candidates until connected') + log.trace("initiator read candidates until connected"); - onProgress?.(new CustomProgressEvent('webrtc:read-ice-candidates')) + onProgress?.(new CustomProgressEvent("webrtc:read-ice-candidates")); await readCandidatesUntilConnected(peerConnection, messageStream, { - direction: 'initiator', + direction: "initiator", signal, log, - onProgress - }) + onProgress, + }); - log.trace('initiator connected, closing init channel') - channel.close() + log.trace("initiator connected, closing init channel"); + channel.close(); - onProgress?.(new CustomProgressEvent('webrtc:close-signaling-stream')) + onProgress?.(new CustomProgressEvent("webrtc:close-signaling-stream")); - log.trace('closing signaling channel') + log.trace("closing signaling channel"); await stream.close({ - signal - }) + signal, + }); - log.trace('initiator connected to remote address %s', ma) + log.trace("initiator connected to remote address %s", ma); return { remoteAddress: ma, peerConnection, - muxerFactory - } + muxerFactory, + }; } catch (err: any) { - log.error('outgoing signaling error', err) + log.error("outgoing signaling error - %e", err); - peerConnection.close() - stream.abort(err) - throw err + peerConnection.close(); + stream.abort(err); + throw err; } finally { - peerConnection.onicecandidate = null - peerConnection.onicecandidateerror = null + peerConnection.onicecandidate = null; + peerConnection.onicecandidateerror = null; } } finally { // if we had to open a connection to perform the SDP handshake @@ -203,10 +243,10 @@ export async function initiateConnection ({ rtcConfiguration, dataChannel, signa if (shouldCloseConnection) { try { await connection.close({ - signal - }) + signal, + }); } catch (err: any) { - connection.abort(err) + connection.abort(err); } } } diff --git a/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts b/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts index 34a31da8ed..6e56a78a92 100644 --- a/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts +++ b/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts @@ -1,23 +1,29 @@ -import { multiaddr } from '@multiformats/multiaddr' -import { pbStream } from 'it-protobuf-stream' -import { SDPHandshakeFailedError } from '../error.js' -import { RTCSessionDescription } from '../webrtc/index.js' -import { Message } from './pb/message.js' -import { getConnectionState, readCandidatesUntilConnected } from './util.js' -import type { RTCPeerConnection } from '../webrtc/index.js' -import type { Logger, IncomingStreamData } from '@libp2p/interface' -import type { Multiaddr } from '@multiformats/multiaddr' +import { multiaddr } from "@multiformats/multiaddr"; +import { pbStream } from "it-protobuf-stream"; +import { SDPHandshakeFailedError } from "../error.js"; +import { RTCSessionDescription } from "../webrtc/index.js"; +import { Message } from "./pb/message.js"; +import { getConnectionState, readCandidatesUntilConnected } from "./util.js"; +import type { RTCPeerConnection } from "../webrtc/index.js"; +import type { Logger, IncomingStreamData } from "@libp2p/interface"; +import type { Multiaddr } from "@multiformats/multiaddr"; export interface IncomingStreamOpts extends IncomingStreamData { - peerConnection: RTCPeerConnection - signal: AbortSignal - log: Logger + peerConnection: RTCPeerConnection; + signal: AbortSignal; + log: Logger; } -export async function handleIncomingStream ({ peerConnection, stream, signal, connection, log }: IncomingStreamOpts): Promise<{ remoteAddress: Multiaddr }> { - log.trace('new inbound signaling stream') +export async function handleIncomingStream({ + peerConnection, + stream, + signal, + connection, + log, +}: IncomingStreamOpts): Promise<{ remoteAddress: Multiaddr }> { + log.trace("new inbound signaling stream"); - const messageStream = pbStream(stream).pb(Message) + const messageStream = pbStream(stream).pb(Message); try { // candidate callbacks @@ -26,84 +32,105 @@ export async function handleIncomingStream ({ peerConnection, stream, signal, co // means end-of-candidates for this generation, otherwise this should // be a valid candidate object // see - https://www.w3.org/TR/webrtc/#rtcpeerconnectioniceevent - const data = JSON.stringify(candidate?.toJSON() ?? null) - - log.trace('recipient sending ICE candidate %s', data) - - messageStream.write({ - type: Message.Type.ICE_CANDIDATE, - data - }, { - signal - }) - .catch(err => { - log.error('error sending ICE candidate', err) - }) - } - - log.trace('recipient read SDP offer') + const data = JSON.stringify(candidate?.toJSON() ?? null); + + log.trace("recipient sending ICE candidate %s", data); + + messageStream + .write( + { + type: Message.Type.ICE_CANDIDATE, + data, + }, + { + signal, + } + ) + .catch((err) => { + log.error("error sending ICE candidate - %e", err); + }); + }; + + log.trace("recipient read SDP offer"); // read an SDP offer const pbOffer = await messageStream.read({ - signal - }) + signal, + }); if (pbOffer.type !== Message.Type.SDP_OFFER) { - throw new SDPHandshakeFailedError(`expected message type SDP_OFFER, received: ${pbOffer.type ?? 'undefined'} `) + throw new SDPHandshakeFailedError( + `expected message type SDP_OFFER, received: ${ + pbOffer.type ?? "undefined" + } ` + ); } - log.trace('recipient received SDP offer %s', pbOffer.data) + log.trace("recipient received SDP offer %s", pbOffer.data); const offer = new RTCSessionDescription({ - type: 'offer', - sdp: pbOffer.data - }) + type: "offer", + sdp: pbOffer.data, + }); - await peerConnection.setRemoteDescription(offer).catch(err => { - log.error('could not execute setRemoteDescription', err) - throw new SDPHandshakeFailedError('Failed to set remoteDescription') - }) + await peerConnection.setRemoteDescription(offer).catch((err) => { + log.error("could not execute setRemoteDescription - %e", err); + throw new SDPHandshakeFailedError("Failed to set remoteDescription"); + }); // create and write an SDP answer - const answer = await peerConnection.createAnswer().catch(err => { - log.error('could not execute createAnswer', err) - throw new SDPHandshakeFailedError('Failed to create answer') - }) + const answer = await peerConnection.createAnswer().catch((err) => { + log.error("could not execute createAnswer - %e", err); + throw new SDPHandshakeFailedError("Failed to create answer"); + }); - log.trace('recipient send SDP answer %s', answer.sdp) + log.trace("recipient send SDP answer %s", answer.sdp); // write the answer to the remote - await messageStream.write({ type: Message.Type.SDP_ANSWER, data: answer.sdp }, { - signal - }) + await messageStream.write( + { type: Message.Type.SDP_ANSWER, data: answer.sdp }, + { + signal, + } + ); - await peerConnection.setLocalDescription(answer).catch(err => { - log.error('could not execute setLocalDescription', err) - throw new SDPHandshakeFailedError('Failed to set localDescription') - }) + await peerConnection.setLocalDescription(answer).catch((err) => { + log.error("could not execute setLocalDescription - %e", err); + throw new SDPHandshakeFailedError("Failed to set localDescription"); + }); - log.trace('recipient read candidates until connected') + log.trace("recipient read candidates until connected"); // wait until candidates are connected await readCandidatesUntilConnected(peerConnection, messageStream, { - direction: 'recipient', + direction: "recipient", signal, - log - }) + log, + }); } catch (err: any) { - if (getConnectionState(peerConnection) !== 'connected') { - log.error('error while handling signaling stream from peer %a', connection.remoteAddr, err) - - peerConnection.close() - throw err + if (getConnectionState(peerConnection) !== "connected") { + log.error( + "error while handling signaling stream from peer %a - %e", + connection.remoteAddr, + err + ); + + peerConnection.close(); + throw err; } else { - log('error while handling signaling stream from peer %a, ignoring as the RTCPeerConnection is already connected', connection.remoteAddr, err) + log( + "error while handling signaling stream from peer %a, ignoring as the RTCPeerConnection is already connected - %e", + connection.remoteAddr, + err + ); } } - const remoteAddress = multiaddr(`/webrtc/p2p/${connection.remoteAddr.getPeerId()}`) + const remoteAddress = multiaddr( + `/webrtc/p2p/${connection.remoteAddr.getPeerId()}` + ); - log.trace('recipient connected to remote address %s', remoteAddress) + log.trace("recipient connected to remote address %s", remoteAddress); - return { remoteAddress } + return { remoteAddress }; } diff --git a/packages/transport-webtransport/src/muxer.ts b/packages/transport-webtransport/src/muxer.ts index a20eb0bff8..02c1104c9f 100644 --- a/packages/transport-webtransport/src/muxer.ts +++ b/packages/transport-webtransport/src/muxer.ts @@ -1,88 +1,114 @@ -import { webtransportBiDiStreamToStream } from './stream.js' -import { inertDuplex } from './utils/inert-duplex.js' -import type WebTransport from './webtransport.js' -import type { ComponentLogger, Stream, StreamMuxer, StreamMuxerFactory, StreamMuxerInit } from '@libp2p/interface' +import { webtransportBiDiStreamToStream } from "./stream.js"; +import { inertDuplex } from "./utils/inert-duplex.js"; +import type WebTransport from "./webtransport.js"; +import type { + ComponentLogger, + Stream, + StreamMuxer, + StreamMuxerFactory, + StreamMuxerInit, +} from "@libp2p/interface"; export interface WebTransportMuxerInit { - maxInboundStreams: number + maxInboundStreams: number; } -export function webtransportMuxer (wt: Pick, reader: ReadableStreamDefaultReader, logger: ComponentLogger, config: WebTransportMuxerInit): StreamMuxerFactory { - let streamIDCounter = 0 - const log = logger.forComponent('libp2p:webtransport:muxer') +export function webtransportMuxer( + wt: Pick, + reader: ReadableStreamDefaultReader, + logger: ComponentLogger, + config: WebTransportMuxerInit +): StreamMuxerFactory { + let streamIDCounter = 0; + const log = logger.forComponent("libp2p:webtransport:muxer"); return { - protocol: 'webtransport', + protocol: "webtransport", createStreamMuxer: (init?: StreamMuxerInit): StreamMuxer => { // !TODO handle abort signal when WebTransport supports this. - if (typeof init === 'function') { + if (typeof init === "function") { // The api docs say that init may be a function - init = { onIncomingStream: init } + init = { onIncomingStream: init }; } - const activeStreams: Stream[] = [] + const activeStreams: Stream[] = []; Promise.resolve() .then(async () => { //! TODO unclear how to add backpressure here? while (true) { - const { done, value: wtStream } = await reader.read() + const { done, value: wtStream } = await reader.read(); if (done) { - break + break; } if (activeStreams.length >= config.maxInboundStreams) { - log(`too many inbound streams open - ${activeStreams.length}/${config.maxInboundStreams}, closing new incoming stream`) + log( + `too many inbound streams open - ${activeStreams.length}/${config.maxInboundStreams}, closing new incoming stream` + ); // We've reached our limit, close this stream. wtStream.writable.close().catch((err: Error) => { - log.error(`failed to close inbound stream that crossed our maxInboundStream limit: ${err.message}`) - }) + log.error( + "failed to close inbound stream that crossed our maxInboundStream limit - %e", + err.message + ); + }); wtStream.readable.cancel().catch((err: Error) => { - log.error(`failed to close inbound stream that crossed our maxInboundStream limit: ${err.message}`) - }) + log.error( + "failed to close inbound stream that crossed our maxInboundStream limit - %e", + err.message + ); + }); } else { const stream = await webtransportBiDiStreamToStream( wtStream, String(streamIDCounter++), - 'inbound', + "inbound", activeStreams, init?.onStreamEnd, logger - ) - activeStreams.push(stream) - init?.onIncomingStream?.(stream) + ); + activeStreams.push(stream); + init?.onIncomingStream?.(stream); } } }) - .catch(err => { - log.error('could not create a new stream', err) - }) + .catch((err) => { + log.error("could not create a new stream - %e", err); + }); const muxer: StreamMuxer = { - protocol: 'webtransport', + protocol: "webtransport", streams: activeStreams, newStream: async (name?: string): Promise => { - log('new outgoing stream', name) - - const wtStream = await wt.createBidirectionalStream() - const stream = await webtransportBiDiStreamToStream(wtStream, String(streamIDCounter++), init?.direction ?? 'outbound', activeStreams, init?.onStreamEnd, logger) - activeStreams.push(stream) - - return stream + log("new outgoing stream", name); + + const wtStream = await wt.createBidirectionalStream(); + const stream = await webtransportBiDiStreamToStream( + wtStream, + String(streamIDCounter++), + init?.direction ?? "outbound", + activeStreams, + init?.onStreamEnd, + logger + ); + activeStreams.push(stream); + + return stream; }, /** * Close all tracked streams and stop the muxer */ close: async () => { - log('closing webtransport muxer gracefully') + log("closing webtransport muxer gracefully"); try { - wt.close() + wt.close(); } catch (err: any) { - muxer.abort(err) + muxer.abort(err); } }, @@ -90,20 +116,20 @@ export function webtransportMuxer (wt: Pick { - log('closing webtransport muxer with err:', err) + log("closing webtransport muxer with err:", err); try { - wt.close() + wt.close(); } catch (err: any) { - log.error('webtransport session threw error during close', err) + log.error("webtransport session threw error during close", err); } }, // This stream muxer is webtransport native. Therefore it doesn't plug in with any other duplex. - ...inertDuplex() - } + ...inertDuplex(), + }; - return muxer - } - } + return muxer; + }, + }; } From 49bbfaf5f55cc5c6cd26e86a8fd663568f788dee Mon Sep 17 00:00:00 2001 From: Suchitra Swain Date: Wed, 4 Jun 2025 13:25:35 +0200 Subject: [PATCH 02/15] formate revert --- packages/integration-tests/test/interop.ts | 118 +++++++++--------- .../src/mocks/connection.ts | 86 ++++++------- packages/kad-dht/src/query/manager.ts | 62 ++++----- .../private-to-private/initiate-connection.ts | 94 +++++++------- .../signaling-stream-handler.ts | 58 ++++----- packages/transport-webtransport/src/muxer.ts | 36 +++--- 6 files changed, 227 insertions(+), 227 deletions(-) diff --git a/packages/integration-tests/test/interop.ts b/packages/integration-tests/test/interop.ts index 724e0e6cee..47aebc03d2 100644 --- a/packages/integration-tests/test/interop.ts +++ b/packages/integration-tests/test/interop.ts @@ -1,35 +1,35 @@ -import fs from "fs"; -import { gossipsub } from "@chainsafe/libp2p-gossipsub"; -import { noise } from "@chainsafe/libp2p-noise"; -import { yamux } from "@chainsafe/libp2p-yamux"; +import fs from 'fs'; +import { gossipsub } from '@chainsafe/libp2p-gossipsub'; +import { noise } from '@chainsafe/libp2p-noise'; +import { yamux } from '@chainsafe/libp2p-yamux'; import { circuitRelayServer, circuitRelayTransport, -} from "@libp2p/circuit-relay-v2"; -import { privateKeyFromProtobuf } from "@libp2p/crypto/keys"; -import { createClient } from "@libp2p/daemon-client"; -import { createServer } from "@libp2p/daemon-server"; -import { floodsub } from "@libp2p/floodsub"; -import { identify } from "@libp2p/identify"; -import { UnsupportedError, interopTests } from "@libp2p/interop"; -import { kadDHT, passthroughMapper } from "@libp2p/kad-dht"; -import { logger } from "@libp2p/logger"; -import { mplex } from "@libp2p/mplex"; -import { ping } from "@libp2p/ping"; -import { plaintext } from "@libp2p/plaintext"; -import { tcp } from "@libp2p/tcp"; -import { tls } from "@libp2p/tls"; -import { webRTCDirect } from "@libp2p/webrtc"; -import { multiaddr } from "@multiformats/multiaddr"; -import { execa } from "execa"; -import { path as p2pd } from "go-libp2p"; -import { createLibp2p } from "libp2p"; -import pDefer from "p-defer"; -import type { Identify } from "@libp2p/identify"; -import type { ServiceMap, PrivateKey } from "@libp2p/interface"; -import type { SpawnOptions, Daemon, DaemonFactory } from "@libp2p/interop"; -import type { PingService } from "@libp2p/ping"; -import type { Libp2pOptions, ServiceFactoryMap } from "libp2p"; +} from '@libp2p/circuit-relay-v2'; +import { privateKeyFromProtobuf } from '@libp2p/crypto/keys'; +import { createClient } from '@libp2p/daemon-client'; +import { createServer } from '@libp2p/daemon-server'; +import { floodsub } from '@libp2p/floodsub'; +import { identify } from '@libp2p/identify'; +import { UnsupportedError, interopTests } from '@libp2p/interop'; +import { kadDHT, passthroughMapper } from '@libp2p/kad-dht'; +import { logger } from '@libp2p/logger'; +import { mplex } from '@libp2p/mplex'; +import { ping } from '@libp2p/ping'; +import { plaintext } from '@libp2p/plaintext'; +import { tcp } from '@libp2p/tcp'; +import { tls } from '@libp2p/tls'; +import { webRTCDirect } from '@libp2p/webrtc'; +import { multiaddr } from '@multiformats/multiaddr'; +import { execa } from 'execa'; +import { path as p2pd } from 'go-libp2p'; +import { createLibp2p } from 'libp2p'; +import pDefer from 'p-defer'; +import type { Identify } from '@libp2p/identify'; +import type { ServiceMap, PrivateKey } from '@libp2p/interface'; +import type { SpawnOptions, Daemon, DaemonFactory } from '@libp2p/interop'; +import type { PingService } from '@libp2p/ping'; +import type { Libp2pOptions, ServiceFactoryMap } from 'libp2p'; /** * @packageDocumentation @@ -50,14 +50,14 @@ async function createGoPeer(options: SpawnOptions): Promise { const opts = [`-listen=${apiAddr.toString()}`]; if (options.noListen === true) { - opts.push("-noListenAddrs"); + opts.push('-noListenAddrs'); } else { - if (options.transport == null || options.transport === "tcp") { - opts.push("-hostAddrs=/ip4/127.0.0.1/tcp/0"); - } else if (options.transport === "webtransport") { - opts.push("-hostAddrs=/ip4/127.0.0.1/udp/0/quic-v1/webtransport"); - } else if (options.transport === "webrtc-direct") { - opts.push("-hostAddrs=/ip4/127.0.0.1/udp/0/webrtc-direct"); + if (options.transport == null || options.transport === 'tcp') { + opts.push('-hostAddrs=/ip4/127.0.0.1/tcp/0'); + } else if (options.transport === 'webtransport') { + opts.push('-hostAddrs=/ip4/127.0.0.1/udp/0/quic-v1/webtransport'); + } else if (options.transport === 'webrtc-direct') { + opts.push('-hostAddrs=/ip4/127.0.0.1/udp/0/webrtc-direct'); } else { throw new UnsupportedError(); } @@ -68,15 +68,15 @@ async function createGoPeer(options: SpawnOptions): Promise { } if (options.dht === true) { - opts.push("-dhtServer"); + opts.push('-dhtServer'); } if (options.relay === true) { - opts.push("-relay"); + opts.push('-relay'); } if (options.pubsub === true) { - opts.push("-pubsub"); + opts.push('-pubsub'); } if (options.pubsubRouter != null) { @@ -87,31 +87,31 @@ async function createGoPeer(options: SpawnOptions): Promise { opts.push(`-id=${options.key}`); } - if (options.muxer === "mplex") { - opts.push("-muxer=mplex"); + if (options.muxer === 'mplex') { + opts.push('-muxer=mplex'); } else { - opts.push("-muxer=yamux"); + opts.push('-muxer=yamux'); } const deferred = pDefer(); const proc = execa(p2pd(), opts, { env: { - GOLOG_LOG_LEVEL: "debug", + GOLOG_LOG_LEVEL: 'debug', }, }); - proc.stdout?.on("data", (buf: Buffer) => { + proc.stdout?.on('data', (buf: Buffer) => { const str = buf.toString(); log(str); // daemon has started - if (str.includes("Control socket:")) { + if (str.includes('Control socket:')) { deferred.resolve(); } }); - proc.stderr?.on("data", (buf) => { - log.error("interop main error - %e", buf.toString()); + proc.stderr?.on('data', (buf) => { + log.error('interop main error - %e', buf.toString()); }); await deferred.promise; @@ -143,16 +143,16 @@ async function createJsPeer(options: SpawnOptions): Promise { }; if (options.noListen !== true) { - if (options.transport == null || options.transport === "tcp") { - opts.addresses?.listen?.push("/ip4/127.0.0.1/tcp/0"); - } else if (options.transport === "webrtc-direct") { - opts.addresses?.listen?.push("/ip4/127.0.0.1/udp/0/webrtc-direct"); + if (options.transport == null || options.transport === 'tcp') { + opts.addresses?.listen?.push('/ip4/127.0.0.1/tcp/0'); + } else if (options.transport === 'webrtc-direct') { + opts.addresses?.listen?.push('/ip4/127.0.0.1/udp/0/webrtc-direct'); } else { throw new UnsupportedError(); } } - if (options.transport === "webtransport") { + if (options.transport === 'webtransport') { throw new UnsupportedError(); } @@ -163,22 +163,22 @@ async function createJsPeer(options: SpawnOptions): Promise { ping: ping(), }; - if (options.encryption === "tls") { + if (options.encryption === 'tls') { opts.connectionEncrypters?.push(tls()); - } else if (options.encryption === "plaintext") { + } else if (options.encryption === 'plaintext') { opts.connectionEncrypters?.push(plaintext()); } else { opts.connectionEncrypters?.push(noise()); } - if (options.muxer === "mplex") { + if (options.muxer === 'mplex') { opts.streamMuxers?.push(mplex()); } else { opts.streamMuxers?.push(yamux()); } if (options.pubsub === true) { - if (options.pubsubRouter === "floodsub") { + if (options.pubsubRouter === 'floodsub') { services.pubsub = floodsub(); } else { services.pubsub = gossipsub(); @@ -191,7 +191,7 @@ async function createJsPeer(options: SpawnOptions): Promise { if (options.dht === true) { services.dht = kadDHT({ - protocol: "/ipfs/kad/1.0.0", + protocol: '/ipfs/kad/1.0.0', peerInfoMapper: passthroughMapper, clientMode: false, }); @@ -202,7 +202,7 @@ async function createJsPeer(options: SpawnOptions): Promise { services, }); - const server = createServer(multiaddr("/ip4/127.0.0.1/tcp/0"), node); + const server = createServer(multiaddr('/ip4/127.0.0.1/tcp/0'), node); await server.start(); return { @@ -217,7 +217,7 @@ async function createJsPeer(options: SpawnOptions): Promise { async function main(): Promise { const factory: DaemonFactory = { async spawn(options: SpawnOptions) { - if (options.type === "go") { + if (options.type === 'go') { return createGoPeer(options); } diff --git a/packages/interface-compliance-tests/src/mocks/connection.ts b/packages/interface-compliance-tests/src/mocks/connection.ts index b89c348481..e78776e1d2 100644 --- a/packages/interface-compliance-tests/src/mocks/connection.ts +++ b/packages/interface-compliance-tests/src/mocks/connection.ts @@ -1,14 +1,14 @@ -import { ConnectionClosedError } from "@libp2p/interface"; -import { defaultLogger, logger } from "@libp2p/logger"; -import * as mss from "@libp2p/multistream-select"; -import { peerIdFromString } from "@libp2p/peer-id"; -import { closeSource } from "@libp2p/utils/close-source"; -import { duplexPair } from "it-pair/duplex"; -import { pipe } from "it-pipe"; -import { Uint8ArrayList } from "uint8arraylist"; -import { mockMultiaddrConnection } from "./multiaddr-connection.js"; -import { mockMuxer } from "./muxer.js"; -import { mockRegistrar } from "./registrar.js"; +import { ConnectionClosedError } from '@libp2p/interface'; +import { defaultLogger, logger } from '@libp2p/logger'; +import * as mss from '@libp2p/multistream-select'; +import { peerIdFromString } from '@libp2p/peer-id'; +import { closeSource } from '@libp2p/utils/close-source'; +import { duplexPair } from 'it-pair/duplex'; +import { pipe } from 'it-pipe'; +import { Uint8ArrayList } from 'uint8arraylist'; +import { mockMultiaddrConnection } from './multiaddr-connection.js'; +import { mockMuxer } from './muxer.js'; +import { mockRegistrar } from './registrar.js'; import type { AbortOptions, ComponentLogger, @@ -24,10 +24,10 @@ import type { StreamMuxerFactory, NewStreamOptions, ConnectionLimits, -} from "@libp2p/interface"; -import type { Registrar } from "@libp2p/interface-internal"; -import type { Multiaddr } from "@multiformats/multiaddr"; -import type { Duplex, Source } from "it-stream-types"; +} from '@libp2p/interface'; +import type { Registrar } from '@libp2p/interface-internal'; +import type { Multiaddr } from '@multiformats/multiaddr'; +import type { Duplex, Source } from 'it-stream-types'; export interface MockConnectionOptions { direction?: Direction; @@ -70,11 +70,11 @@ class MockConnection implements Connection { this.remoteAddr = remoteAddr; this.remotePeer = remotePeer; this.direction = direction; - this.status = "open"; + this.status = 'open'; this.direction = direction; this.timeline = maConn.timeline; - this.multiplexer = "test-multiplexer"; - this.encryption = "yes-yes-very-secure"; + this.multiplexer = 'test-multiplexer'; + this.encryption = 'yes-yes-very-secure'; this.streams = []; this.tags = []; this.muxer = muxer; @@ -92,12 +92,12 @@ class MockConnection implements Connection { } if (protocols.length === 0) { - throw new Error("protocols must have a length"); + throw new Error('protocols must have a length'); } - if (this.status !== "open") { + if (this.status !== 'open') { throw new ConnectionClosedError( - "connection must be open to create streams" + 'connection must be open to create streams' ); } @@ -107,11 +107,11 @@ class MockConnection implements Connection { const stream = await this.muxer.newStream(id); const result = await mss.select(stream, protocols, { ...options, - log: this.logger.forComponent("libp2p:mock-connection:stream:mss:select"), + log: this.logger.forComponent('libp2p:mock-connection:stream:mss:select'), }); stream.protocol = result.protocol; - stream.direction = "outbound"; + stream.direction = 'outbound'; stream.sink = result.stream.sink; stream.source = result.stream.source; @@ -121,20 +121,20 @@ class MockConnection implements Connection { } async close(options?: AbortOptions): Promise { - this.status = "closing"; + this.status = 'closing'; await Promise.all(this.streams.map(async (s) => s.close(options))); await this.maConn.close(); - this.status = "closed"; + this.status = 'closed'; this.timeline.close = Date.now(); } abort(err: Error): void { - this.status = "closing"; + this.status = 'closing'; this.streams.forEach((s) => { s.abort(err); }); this.maConn.abort(err); - this.status = "closed"; + this.status = 'closed'; this.timeline.close = Date.now(); } } @@ -146,18 +146,18 @@ export function mockConnection( const remoteAddr = maConn.remoteAddr; const remotePeerIdStr = remoteAddr.getPeerId() ?? - "12D3KooWCrhmFM1BCPGBkNzbPfDk4cjYmtAYSpZwUBC69Qg2kZyq"; + '12D3KooWCrhmFM1BCPGBkNzbPfDk4cjYmtAYSpZwUBC69Qg2kZyq'; const logger = opts.logger ?? defaultLogger(); if (remotePeerIdStr == null) { - throw new Error("Remote multiaddr must contain a peer id"); + throw new Error('Remote multiaddr must contain a peer id'); } const remotePeer = peerIdFromString(remotePeerIdStr); - const direction = opts.direction ?? "inbound"; + const direction = opts.direction ?? 'inbound'; const registrar = opts.registrar ?? mockRegistrar(); const muxerFactory = opts.muxerFactory ?? mockMuxer(); - const log = logger.forComponent("libp2p:mock-muxer"); + const log = logger.forComponent('libp2p:mock-muxer'); const muxer = muxerFactory.createStreamMuxer({ direction, @@ -168,7 +168,7 @@ export function mockConnection( log, }) .then(({ stream, protocol }) => { - log("%s: incoming stream opened on %s", direction, protocol); + log('%s: incoming stream opened on %s', direction, protocol); muxedStream.protocol = protocol; muxedStream.sink = stream.sink; muxedStream.source = stream.source; @@ -179,10 +179,10 @@ export function mockConnection( handler({ connection, stream: muxedStream }); }) .catch((err) => { - log.error("incoming stream handler error - %e", err); + log.error('incoming stream handler error - %e', err); }); } catch (err: any) { - log.error("error handling incoming stream - %e", err); + log.error('error handling incoming stream - %e', err); } }, onStreamEnd: (muxedStream) => { @@ -243,7 +243,7 @@ export function mockStream( const abortSinkController = new AbortController(); const originalSink = stream.sink.bind(stream); stream.sink = async (source) => { - abortSinkController.signal.addEventListener("abort", () => { + abortSinkController.signal.addEventListener('abort', () => { closeSource(source, log); }); @@ -278,17 +278,17 @@ export function mockStream( mockStream.timeline.closeRead = Date.now(); mockStream.timeline.close = Date.now(); }, - direction: "outbound", - protocol: "/foo/1.0.0", + direction: 'outbound', + protocol: '/foo/1.0.0', timeline: { open: Date.now(), }, metadata: {}, id: `stream-${Date.now()}`, - status: "open", - readStatus: "ready", - writeStatus: "ready", - log: logger("mock-stream"), + status: 'open', + readStatus: 'ready', + writeStatus: 'ready', + log: logger('mock-stream'), ...init, }; @@ -311,12 +311,12 @@ export function streamPair( ): [Stream, Stream] { return [ mockStream(a.duplex, { - direction: "outbound", + direction: 'outbound', ...init, ...(a.init ?? {}), }), mockStream(b.duplex, { - direction: "inbound", + direction: 'inbound', ...init, ...(b.init ?? {}), }), diff --git a/packages/kad-dht/src/query/manager.ts b/packages/kad-dht/src/query/manager.ts index 8892633f52..0313b20141 100644 --- a/packages/kad-dht/src/query/manager.ts +++ b/packages/kad-dht/src/query/manager.ts @@ -1,25 +1,25 @@ -import { createScalableCuckooFilter } from "@libp2p/utils/filters"; -import { anySignal } from "any-signal"; -import merge from "it-merge"; -import { setMaxListeners } from "main-event"; -import { pEvent } from "p-event"; -import { raceSignal } from "race-signal"; -import { toString as uint8ArrayToString } from "uint8arrays/to-string"; -import { ALPHA, K, DEFAULT_QUERY_TIMEOUT } from "../constants.js"; -import { convertBuffer } from "../utils.js"; -import { queryPath } from "./query-path.js"; -import type { QueryFunc } from "./types.js"; -import type { QueryEvent } from "../index.js"; -import type { RoutingTable } from "../routing-table/index.js"; +import { createScalableCuckooFilter } from '@libp2p/utils/filters'; +import { anySignal } from 'any-signal'; +import merge from 'it-merge'; +import { setMaxListeners } from 'main-event'; +import { pEvent } from 'p-event'; +import { raceSignal } from 'race-signal'; +import { toString as uint8ArrayToString } from 'uint8arrays/to-string'; +import { ALPHA, K, DEFAULT_QUERY_TIMEOUT } from '../constants.js'; +import { convertBuffer } from '../utils.js'; +import { queryPath } from './query-path.js'; +import type { QueryFunc } from './types.js'; +import type { QueryEvent } from '../index.js'; +import type { RoutingTable } from '../routing-table/index.js'; import type { ComponentLogger, Metrics, PeerId, RoutingOptions, Startable, -} from "@libp2p/interface"; -import type { ConnectionManager } from "@libp2p/interface-internal"; -import type { DeferredPromise } from "p-defer"; +} from '@libp2p/interface'; +import type { ConnectionManager } from '@libp2p/interface-internal'; +import type { DeferredPromise } from 'p-defer'; export interface CleanUpEvents { cleanup: CustomEvent; @@ -116,7 +116,7 @@ export class QueryManager implements Startable { options: QueryOptions = {} ): AsyncGenerator { if (!this.running) { - throw new Error("QueryManager not started"); + throw new Error('QueryManager not started'); } if (options.signal == null) { @@ -148,7 +148,7 @@ export class QueryManager implements Startable { setMaxListeners(Infinity, signal, queryEarlyExitController.signal); const log = this.logger.forComponent( - `${this.logPrefix}:query:` + uint8ArrayToString(key, "base58btc") + `${this.logPrefix}:query:` + uint8ArrayToString(key, 'base58btc') ); // query a subset of peers up to `kBucketSize / 2` in length @@ -157,29 +157,29 @@ export class QueryManager implements Startable { try { if (this.routingTable.size === 0 && !this.allowQueryWithZeroPeers) { log( - "routing table was empty, waiting for some peers before running%s query", - options.isSelfQuery === true ? " self" : "" + 'routing table was empty, waiting for some peers before running%s query', + options.isSelfQuery === true ? ' self' : '' ); // wait to discover at least one DHT peer that isn't us - await pEvent(this.routingTable, "peer:add", { + await pEvent(this.routingTable, 'peer:add', { signal, filter: (event) => !this.peerId.equals(event.detail), }); log( - "routing table has peers, continuing with%s query", - options.isSelfQuery === true ? " self" : "" + 'routing table has peers, continuing with%s query', + options.isSelfQuery === true ? ' self' : '' ); } if (options.isSelfQuery !== true && this.initialQuerySelfHasRun != null) { - log("waiting for initial self query before continuing"); + log('waiting for initial self query before continuing'); await raceSignal(this.initialQuerySelfHasRun.promise, signal); this.initialQuerySelfHasRun = undefined; } - log("query:start"); + log('query:start'); const id = await convertBuffer(key, { signal, @@ -209,7 +209,7 @@ export class QueryManager implements Startable { .filter((peers) => peers.length > 0); if (peers.length === 0) { - log.error("running query with no peers"); + log.error('running query with no peers'); return; } @@ -237,11 +237,11 @@ export class QueryManager implements Startable { // Execute the query along each disjoint path and yield their results as they become available for await (const event of merge(...paths)) { - if (event.name === "QUERY_ERROR") { - log.error("query error - %e", event.error); + if (event.name === 'QUERY_ERROR') { + log.error('query error - %e', event.error); } - if (event.name === "PEER_RESPONSE") { + if (event.name === 'PEER_RESPONSE') { for (const peer of [...event.closer, ...event.providers]) { // eslint-disable-next-line max-depth if ( @@ -270,13 +270,13 @@ export class QueryManager implements Startable { } } finally { if (!queryFinished) { - log("query exited early"); + log('query exited early'); queryEarlyExitController.abort(); } signal.clear(); - log("query finished"); + log('query finished'); } } } diff --git a/packages/transport-webrtc/src/private-to-private/initiate-connection.ts b/packages/transport-webrtc/src/private-to-private/initiate-connection.ts index 892751a6bf..8268fb7187 100644 --- a/packages/transport-webrtc/src/private-to-private/initiate-connection.ts +++ b/packages/transport-webrtc/src/private-to-private/initiate-connection.ts @@ -1,28 +1,28 @@ -import { InvalidParametersError } from "@libp2p/interface"; -import { peerIdFromString } from "@libp2p/peer-id"; -import { pbStream } from "it-protobuf-stream"; -import { CustomProgressEvent } from "progress-events"; -import { SIGNALING_PROTOCOL } from "../constants.js"; -import { SDPHandshakeFailedError } from "../error.js"; -import { DataChannelMuxerFactory } from "../muxer.js"; -import { RTCPeerConnection, RTCSessionDescription } from "../webrtc/index.js"; -import { Message } from "./pb/message.js"; -import { splitAddr } from "./transport.js"; -import { readCandidatesUntilConnected } from "./util.js"; -import type { WebRTCDialEvents, WebRTCTransportMetrics } from "./transport.js"; -import type { DataChannelOptions } from "../index.js"; +import { InvalidParametersError } from '@libp2p/interface'; +import { peerIdFromString } from '@libp2p/peer-id'; +import { pbStream } from 'it-protobuf-stream'; +import { CustomProgressEvent } from 'progress-events'; +import { SIGNALING_PROTOCOL } from '../constants.js'; +import { SDPHandshakeFailedError } from '../error.js'; +import { DataChannelMuxerFactory } from '../muxer.js'; +import { RTCPeerConnection, RTCSessionDescription } from '../webrtc/index.js'; +import { Message } from './pb/message.js'; +import { splitAddr } from './transport.js'; +import { readCandidatesUntilConnected } from './util.js'; +import type { WebRTCDialEvents, WebRTCTransportMetrics } from './transport.js'; +import type { DataChannelOptions } from '../index.js'; import type { LoggerOptions, Connection, ComponentLogger, IncomingStreamData, -} from "@libp2p/interface"; +} from '@libp2p/interface'; import type { ConnectionManager, TransportManager, -} from "@libp2p/interface-internal"; -import type { Multiaddr } from "@multiformats/multiaddr"; -import type { ProgressOptions } from "progress-events"; +} from '@libp2p/interface-internal'; +import type { Multiaddr } from '@multiformats/multiaddr'; +import type { ProgressOptions } from 'progress-events'; export interface IncomingStreamOpts extends IncomingStreamData { rtcConfiguration?: RTCConfiguration; @@ -64,12 +64,12 @@ export async function initiateConnection({ metrics?.dialerEvents.increment({ open: true }); - log.trace("dialing base address: %a", baseAddr); + log.trace('dialing base address: %a', baseAddr); const relayPeer = baseAddr.getPeerId(); if (relayPeer == null) { - throw new InvalidParametersError("Relay peer was missing"); + throw new InvalidParametersError('Relay peer was missing'); } const connections = connectionManager.getConnections( @@ -79,7 +79,7 @@ export async function initiateConnection({ let shouldCloseConnection = false; if (connections.length === 0) { - onProgress?.(new CustomProgressEvent("webrtc:dial-relay")); + onProgress?.(new CustomProgressEvent('webrtc:dial-relay')); // use the transport manager to open a connection. Initiating a WebRTC // connection takes place in the context of a dial - if we use the @@ -92,13 +92,13 @@ export async function initiateConnection({ // close it when we are done shouldCloseConnection = true; } else { - onProgress?.(new CustomProgressEvent("webrtc:reuse-relay-connection")); + onProgress?.(new CustomProgressEvent('webrtc:reuse-relay-connection')); connection = connections[0]; } try { - onProgress?.(new CustomProgressEvent("webrtc:open-signaling-stream")); + onProgress?.(new CustomProgressEvent('webrtc:open-signaling-stream')); const stream = await connection.newStream(SIGNALING_PROTOCOL, { signal, @@ -121,7 +121,7 @@ export async function initiateConnection({ // we create the channel so that the RTCPeerConnection has a component for // which to collect candidates. The label is not relevant to connection // initiation but can be useful for debugging - const channel = peerConnection.createDataChannel("init"); + const channel = peerConnection.createDataChannel('init'); // setup callback to write ICE candidates to the remote peer peerConnection.onicecandidate = ({ candidate }) => { @@ -131,7 +131,7 @@ export async function initiateConnection({ // see - https://www.w3.org/TR/webrtc/#rtcpeerconnectioniceevent const data = JSON.stringify(candidate?.toJSON() ?? null); - log.trace("initiator sending ICE candidate %o", candidate); + log.trace('initiator sending ICE candidate %o', candidate); void messageStream .write( @@ -144,22 +144,22 @@ export async function initiateConnection({ } ) .catch((err) => { - log.error("error sending ICE candidate", err); + log.error('error sending ICE candidate', err); }); }; peerConnection.onicecandidateerror = (event) => { - log.error("initiator ICE candidate error", event); + log.error('initiator ICE candidate error', event); }; // create an offer const offerSdp = await peerConnection.createOffer().catch((err) => { - log.error("could not execute createOffer - %e", err); - throw new SDPHandshakeFailedError("Failed to set createOffer"); + log.error('could not execute createOffer - %e', err); + throw new SDPHandshakeFailedError('Failed to set createOffer'); }); - log.trace("initiator send SDP offer %s", offerSdp.sdp); + log.trace('initiator send SDP offer %s', offerSdp.sdp); - onProgress?.(new CustomProgressEvent("webrtc:send-sdp-offer")); + onProgress?.(new CustomProgressEvent('webrtc:send-sdp-offer')); // write the offer to the stream await messageStream.write( @@ -171,13 +171,13 @@ export async function initiateConnection({ // set offer as local description await peerConnection.setLocalDescription(offerSdp).catch((err) => { - log.error("could not execute setLocalDescription - %e", err); - throw new SDPHandshakeFailedError("Failed to set localDescription"); + log.error('could not execute setLocalDescription - %e', err); + throw new SDPHandshakeFailedError('Failed to set localDescription'); }); - onProgress?.(new CustomProgressEvent("webrtc:read-sdp-answer")); + onProgress?.(new CustomProgressEvent('webrtc:read-sdp-answer')); - log.trace("initiator read SDP answer"); + log.trace('initiator read SDP answer'); // read answer const answerMessage = await messageStream.read({ @@ -185,42 +185,42 @@ export async function initiateConnection({ }); if (answerMessage.type !== Message.Type.SDP_ANSWER) { - throw new SDPHandshakeFailedError("Remote should send an SDP answer"); + throw new SDPHandshakeFailedError('Remote should send an SDP answer'); } - log.trace("initiator received SDP answer %s", answerMessage.data); + log.trace('initiator received SDP answer %s', answerMessage.data); const answerSdp = new RTCSessionDescription({ - type: "answer", + type: 'answer', sdp: answerMessage.data, }); await peerConnection.setRemoteDescription(answerSdp).catch((err) => { - log.error("could not execute setRemoteDescription - %e", err); - throw new SDPHandshakeFailedError("Failed to set remoteDescription"); + log.error('could not execute setRemoteDescription - %e', err); + throw new SDPHandshakeFailedError('Failed to set remoteDescription'); }); - log.trace("initiator read candidates until connected"); + log.trace('initiator read candidates until connected'); - onProgress?.(new CustomProgressEvent("webrtc:read-ice-candidates")); + onProgress?.(new CustomProgressEvent('webrtc:read-ice-candidates')); await readCandidatesUntilConnected(peerConnection, messageStream, { - direction: "initiator", + direction: 'initiator', signal, log, onProgress, }); - log.trace("initiator connected, closing init channel"); + log.trace('initiator connected, closing init channel'); channel.close(); - onProgress?.(new CustomProgressEvent("webrtc:close-signaling-stream")); + onProgress?.(new CustomProgressEvent('webrtc:close-signaling-stream')); - log.trace("closing signaling channel"); + log.trace('closing signaling channel'); await stream.close({ signal, }); - log.trace("initiator connected to remote address %s", ma); + log.trace('initiator connected to remote address %s', ma); return { remoteAddress: ma, @@ -228,7 +228,7 @@ export async function initiateConnection({ muxerFactory, }; } catch (err: any) { - log.error("outgoing signaling error - %e", err); + log.error('outgoing signaling error - %e', err); peerConnection.close(); stream.abort(err); diff --git a/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts b/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts index 6e56a78a92..a8081bf28f 100644 --- a/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts +++ b/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts @@ -1,12 +1,12 @@ -import { multiaddr } from "@multiformats/multiaddr"; -import { pbStream } from "it-protobuf-stream"; -import { SDPHandshakeFailedError } from "../error.js"; -import { RTCSessionDescription } from "../webrtc/index.js"; -import { Message } from "./pb/message.js"; -import { getConnectionState, readCandidatesUntilConnected } from "./util.js"; -import type { RTCPeerConnection } from "../webrtc/index.js"; -import type { Logger, IncomingStreamData } from "@libp2p/interface"; -import type { Multiaddr } from "@multiformats/multiaddr"; +import { multiaddr } from '@multiformats/multiaddr'; +import { pbStream } from 'it-protobuf-stream'; +import { SDPHandshakeFailedError } from '../error.js'; +import { RTCSessionDescription } from '../webrtc/index.js'; +import { Message } from './pb/message.js'; +import { getConnectionState, readCandidatesUntilConnected } from './util.js'; +import type { RTCPeerConnection } from '../webrtc/index.js'; +import type { Logger, IncomingStreamData } from '@libp2p/interface'; +import type { Multiaddr } from '@multiformats/multiaddr'; export interface IncomingStreamOpts extends IncomingStreamData { peerConnection: RTCPeerConnection; @@ -21,7 +21,7 @@ export async function handleIncomingStream({ connection, log, }: IncomingStreamOpts): Promise<{ remoteAddress: Multiaddr }> { - log.trace("new inbound signaling stream"); + log.trace('new inbound signaling stream'); const messageStream = pbStream(stream).pb(Message); @@ -34,7 +34,7 @@ export async function handleIncomingStream({ // see - https://www.w3.org/TR/webrtc/#rtcpeerconnectioniceevent const data = JSON.stringify(candidate?.toJSON() ?? null); - log.trace("recipient sending ICE candidate %s", data); + log.trace('recipient sending ICE candidate %s', data); messageStream .write( @@ -47,11 +47,11 @@ export async function handleIncomingStream({ } ) .catch((err) => { - log.error("error sending ICE candidate - %e", err); + log.error('error sending ICE candidate - %e', err); }); }; - log.trace("recipient read SDP offer"); + log.trace('recipient read SDP offer'); // read an SDP offer const pbOffer = await messageStream.read({ @@ -61,30 +61,30 @@ export async function handleIncomingStream({ if (pbOffer.type !== Message.Type.SDP_OFFER) { throw new SDPHandshakeFailedError( `expected message type SDP_OFFER, received: ${ - pbOffer.type ?? "undefined" + pbOffer.type ?? 'undefined' } ` ); } - log.trace("recipient received SDP offer %s", pbOffer.data); + log.trace('recipient received SDP offer %s', pbOffer.data); const offer = new RTCSessionDescription({ - type: "offer", + type: 'offer', sdp: pbOffer.data, }); await peerConnection.setRemoteDescription(offer).catch((err) => { - log.error("could not execute setRemoteDescription - %e", err); - throw new SDPHandshakeFailedError("Failed to set remoteDescription"); + log.error('could not execute setRemoteDescription - %e', err); + throw new SDPHandshakeFailedError('Failed to set remoteDescription'); }); // create and write an SDP answer const answer = await peerConnection.createAnswer().catch((err) => { - log.error("could not execute createAnswer - %e", err); - throw new SDPHandshakeFailedError("Failed to create answer"); + log.error('could not execute createAnswer - %e', err); + throw new SDPHandshakeFailedError('Failed to create answer'); }); - log.trace("recipient send SDP answer %s", answer.sdp); + log.trace('recipient send SDP answer %s', answer.sdp); // write the answer to the remote await messageStream.write( @@ -95,22 +95,22 @@ export async function handleIncomingStream({ ); await peerConnection.setLocalDescription(answer).catch((err) => { - log.error("could not execute setLocalDescription - %e", err); - throw new SDPHandshakeFailedError("Failed to set localDescription"); + log.error('could not execute setLocalDescription - %e', err); + throw new SDPHandshakeFailedError('Failed to set localDescription'); }); - log.trace("recipient read candidates until connected"); + log.trace('recipient read candidates until connected'); // wait until candidates are connected await readCandidatesUntilConnected(peerConnection, messageStream, { - direction: "recipient", + direction: 'recipient', signal, log, }); } catch (err: any) { - if (getConnectionState(peerConnection) !== "connected") { + if (getConnectionState(peerConnection) !== 'connected') { log.error( - "error while handling signaling stream from peer %a - %e", + 'error while handling signaling stream from peer %a - %e', connection.remoteAddr, err ); @@ -119,7 +119,7 @@ export async function handleIncomingStream({ throw err; } else { log( - "error while handling signaling stream from peer %a, ignoring as the RTCPeerConnection is already connected - %e", + 'error while handling signaling stream from peer %a, ignoring as the RTCPeerConnection is already connected - %e', connection.remoteAddr, err ); @@ -130,7 +130,7 @@ export async function handleIncomingStream({ `/webrtc/p2p/${connection.remoteAddr.getPeerId()}` ); - log.trace("recipient connected to remote address %s", remoteAddress); + log.trace('recipient connected to remote address %s', remoteAddress); return { remoteAddress }; } diff --git a/packages/transport-webtransport/src/muxer.ts b/packages/transport-webtransport/src/muxer.ts index 02c1104c9f..61f4910f4b 100644 --- a/packages/transport-webtransport/src/muxer.ts +++ b/packages/transport-webtransport/src/muxer.ts @@ -1,33 +1,33 @@ -import { webtransportBiDiStreamToStream } from "./stream.js"; -import { inertDuplex } from "./utils/inert-duplex.js"; -import type WebTransport from "./webtransport.js"; +import { webtransportBiDiStreamToStream } from './stream.js'; +import { inertDuplex } from './utils/inert-duplex.js'; +import type WebTransport from './webtransport.js'; import type { ComponentLogger, Stream, StreamMuxer, StreamMuxerFactory, StreamMuxerInit, -} from "@libp2p/interface"; +} from '@libp2p/interface'; export interface WebTransportMuxerInit { maxInboundStreams: number; } export function webtransportMuxer( - wt: Pick, + wt: Pick, reader: ReadableStreamDefaultReader, logger: ComponentLogger, config: WebTransportMuxerInit ): StreamMuxerFactory { let streamIDCounter = 0; - const log = logger.forComponent("libp2p:webtransport:muxer"); + const log = logger.forComponent('libp2p:webtransport:muxer'); return { - protocol: "webtransport", + protocol: 'webtransport', createStreamMuxer: (init?: StreamMuxerInit): StreamMuxer => { // !TODO handle abort signal when WebTransport supports this. - if (typeof init === "function") { + if (typeof init === 'function') { // The api docs say that init may be a function init = { onIncomingStream: init }; } @@ -51,13 +51,13 @@ export function webtransportMuxer( // We've reached our limit, close this stream. wtStream.writable.close().catch((err: Error) => { log.error( - "failed to close inbound stream that crossed our maxInboundStream limit - %e", + 'failed to close inbound stream that crossed our maxInboundStream limit - %e', err.message ); }); wtStream.readable.cancel().catch((err: Error) => { log.error( - "failed to close inbound stream that crossed our maxInboundStream limit - %e", + 'failed to close inbound stream that crossed our maxInboundStream limit - %e', err.message ); }); @@ -65,7 +65,7 @@ export function webtransportMuxer( const stream = await webtransportBiDiStreamToStream( wtStream, String(streamIDCounter++), - "inbound", + 'inbound', activeStreams, init?.onStreamEnd, logger @@ -76,20 +76,20 @@ export function webtransportMuxer( } }) .catch((err) => { - log.error("could not create a new stream - %e", err); + log.error('could not create a new stream - %e', err); }); const muxer: StreamMuxer = { - protocol: "webtransport", + protocol: 'webtransport', streams: activeStreams, newStream: async (name?: string): Promise => { - log("new outgoing stream", name); + log('new outgoing stream', name); const wtStream = await wt.createBidirectionalStream(); const stream = await webtransportBiDiStreamToStream( wtStream, String(streamIDCounter++), - init?.direction ?? "outbound", + init?.direction ?? 'outbound', activeStreams, init?.onStreamEnd, logger @@ -103,7 +103,7 @@ export function webtransportMuxer( * Close all tracked streams and stop the muxer */ close: async () => { - log("closing webtransport muxer gracefully"); + log('closing webtransport muxer gracefully'); try { wt.close(); @@ -116,12 +116,12 @@ export function webtransportMuxer( * Abort all tracked streams and stop the muxer */ abort: (err: Error) => { - log("closing webtransport muxer with err:", err); + log('closing webtransport muxer with err:', err); try { wt.close(); } catch (err: any) { - log.error("webtransport session threw error during close", err); + log.error('webtransport session threw error during close', err); } }, From 15b8e8988a71aea6b96a0b20936cf5df053ef95e Mon Sep 17 00:00:00 2001 From: Suchitra Swain Date: Wed, 4 Jun 2025 13:26:49 +0200 Subject: [PATCH 03/15] package.json reverted --- package.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/package.json b/package.json index 44620acedc..63f09d20e9 100644 --- a/package.json +++ b/package.json @@ -46,8 +46,5 @@ "doc", "interop", "packages/*" - ], - "dependencies": { - "@libp2p/interface": "^2.10.3" - } + ] } From 0bf370131c592e209e0830267014a72ffe9c11c3 Mon Sep 17 00:00:00 2001 From: Suchitra Swain Date: Wed, 4 Jun 2025 13:28:36 +0200 Subject: [PATCH 04/15] formate revert --- packages/integration-tests/test/interop.ts | 178 +++++------ .../src/mocks/connection.ts | 296 +++++++++--------- packages/kad-dht/src/query/manager.ts | 196 ++++++------ .../private-to-private/initiate-connection.ts | 188 +++++------ .../signaling-stream-handler.ts | 88 +++--- packages/transport-webtransport/src/muxer.ts | 70 ++--- 6 files changed, 508 insertions(+), 508 deletions(-) diff --git a/packages/integration-tests/test/interop.ts b/packages/integration-tests/test/interop.ts index 47aebc03d2..789c7e253a 100644 --- a/packages/integration-tests/test/interop.ts +++ b/packages/integration-tests/test/interop.ts @@ -1,35 +1,35 @@ -import fs from 'fs'; -import { gossipsub } from '@chainsafe/libp2p-gossipsub'; -import { noise } from '@chainsafe/libp2p-noise'; -import { yamux } from '@chainsafe/libp2p-yamux'; +import fs from 'fs' +import { gossipsub } from '@chainsafe/libp2p-gossipsub' +import { noise } from '@chainsafe/libp2p-noise' +import { yamux } from '@chainsafe/libp2p-yamux' import { circuitRelayServer, circuitRelayTransport, -} from '@libp2p/circuit-relay-v2'; -import { privateKeyFromProtobuf } from '@libp2p/crypto/keys'; -import { createClient } from '@libp2p/daemon-client'; -import { createServer } from '@libp2p/daemon-server'; -import { floodsub } from '@libp2p/floodsub'; -import { identify } from '@libp2p/identify'; -import { UnsupportedError, interopTests } from '@libp2p/interop'; -import { kadDHT, passthroughMapper } from '@libp2p/kad-dht'; -import { logger } from '@libp2p/logger'; -import { mplex } from '@libp2p/mplex'; -import { ping } from '@libp2p/ping'; -import { plaintext } from '@libp2p/plaintext'; -import { tcp } from '@libp2p/tcp'; -import { tls } from '@libp2p/tls'; -import { webRTCDirect } from '@libp2p/webrtc'; -import { multiaddr } from '@multiformats/multiaddr'; -import { execa } from 'execa'; -import { path as p2pd } from 'go-libp2p'; -import { createLibp2p } from 'libp2p'; -import pDefer from 'p-defer'; -import type { Identify } from '@libp2p/identify'; -import type { ServiceMap, PrivateKey } from '@libp2p/interface'; -import type { SpawnOptions, Daemon, DaemonFactory } from '@libp2p/interop'; -import type { PingService } from '@libp2p/ping'; -import type { Libp2pOptions, ServiceFactoryMap } from 'libp2p'; +} from '@libp2p/circuit-relay-v2' +import { privateKeyFromProtobuf } from '@libp2p/crypto/keys' +import { createClient } from '@libp2p/daemon-client' +import { createServer } from '@libp2p/daemon-server' +import { floodsub } from '@libp2p/floodsub' +import { identify } from '@libp2p/identify' +import { UnsupportedError, interopTests } from '@libp2p/interop' +import { kadDHT, passthroughMapper } from '@libp2p/kad-dht' +import { logger } from '@libp2p/logger' +import { mplex } from '@libp2p/mplex' +import { ping } from '@libp2p/ping' +import { plaintext } from '@libp2p/plaintext' +import { tcp } from '@libp2p/tcp' +import { tls } from '@libp2p/tls' +import { webRTCDirect } from '@libp2p/webrtc' +import { multiaddr } from '@multiformats/multiaddr' +import { execa } from 'execa' +import { path as p2pd } from 'go-libp2p' +import { createLibp2p } from 'libp2p' +import pDefer from 'p-defer' +import type { Identify } from '@libp2p/identify' +import type { ServiceMap, PrivateKey } from '@libp2p/interface' +import type { SpawnOptions, Daemon, DaemonFactory } from '@libp2p/interop' +import type { PingService } from '@libp2p/ping' +import type { Libp2pOptions, ServiceFactoryMap } from 'libp2p' /** * @packageDocumentation @@ -42,94 +42,94 @@ import type { Libp2pOptions, ServiceFactoryMap } from 'libp2p'; */ async function createGoPeer(options: SpawnOptions): Promise { - const controlPort = Math.floor(Math.random() * (50000 - 10000 + 1)) + 10000; - const apiAddr = multiaddr(`/ip4/127.0.0.1/tcp/${controlPort}`); + const controlPort = Math.floor(Math.random() * (50000 - 10000 + 1)) + 10000 + const apiAddr = multiaddr(`/ip4/127.0.0.1/tcp/${controlPort}`) - const log = logger(`go-libp2p:${controlPort}`); + const log = logger(`go-libp2p:${controlPort}`) - const opts = [`-listen=${apiAddr.toString()}`]; + const opts = [`-listen=${apiAddr.toString()}`] if (options.noListen === true) { - opts.push('-noListenAddrs'); + opts.push('-noListenAddrs') } else { if (options.transport == null || options.transport === 'tcp') { - opts.push('-hostAddrs=/ip4/127.0.0.1/tcp/0'); + opts.push('-hostAddrs=/ip4/127.0.0.1/tcp/0') } else if (options.transport === 'webtransport') { - opts.push('-hostAddrs=/ip4/127.0.0.1/udp/0/quic-v1/webtransport'); + opts.push('-hostAddrs=/ip4/127.0.0.1/udp/0/quic-v1/webtransport') } else if (options.transport === 'webrtc-direct') { - opts.push('-hostAddrs=/ip4/127.0.0.1/udp/0/webrtc-direct'); + opts.push('-hostAddrs=/ip4/127.0.0.1/udp/0/webrtc-direct') } else { - throw new UnsupportedError(); + throw new UnsupportedError() } } if (options.encryption != null) { - opts.push(`-${options.encryption}=true`); + opts.push(`-${options.encryption}=true`) } if (options.dht === true) { - opts.push('-dhtServer'); + opts.push('-dhtServer') } if (options.relay === true) { - opts.push('-relay'); + opts.push('-relay') } if (options.pubsub === true) { - opts.push('-pubsub'); + opts.push('-pubsub') } if (options.pubsubRouter != null) { - opts.push(`-pubsubRouter=${options.pubsubRouter}`); + opts.push(`-pubsubRouter=${options.pubsubRouter}`) } if (options.key != null) { - opts.push(`-id=${options.key}`); + opts.push(`-id=${options.key}`) } if (options.muxer === 'mplex') { - opts.push('-muxer=mplex'); + opts.push('-muxer=mplex') } else { - opts.push('-muxer=yamux'); + opts.push('-muxer=yamux') } - const deferred = pDefer(); + const deferred = pDefer() const proc = execa(p2pd(), opts, { env: { GOLOG_LOG_LEVEL: 'debug', }, - }); + }) proc.stdout?.on('data', (buf: Buffer) => { - const str = buf.toString(); - log(str); + const str = buf.toString() + log(str) // daemon has started if (str.includes('Control socket:')) { - deferred.resolve(); + deferred.resolve() } - }); + }) proc.stderr?.on('data', (buf) => { - log.error('interop main error - %e', buf.toString()); - }); + log.error('interop main error - %e', buf.toString()) + }) - await deferred.promise; + await deferred.promise return { client: createClient(apiAddr), stop: async () => { - proc.kill(); + proc.kill() }, - }; + } } async function createJsPeer(options: SpawnOptions): Promise { - let privateKey: PrivateKey | undefined; + let privateKey: PrivateKey | undefined if (options.key != null) { - const keyFile = fs.readFileSync(options.key); - privateKey = privateKeyFromProtobuf(keyFile); + const keyFile = fs.readFileSync(options.key) + privateKey = privateKeyFromProtobuf(keyFile) } const opts: Libp2pOptions = { @@ -140,53 +140,53 @@ async function createJsPeer(options: SpawnOptions): Promise { transports: [tcp(), circuitRelayTransport(), webRTCDirect()], streamMuxers: [], connectionEncrypters: [], - }; + } if (options.noListen !== true) { if (options.transport == null || options.transport === 'tcp') { - opts.addresses?.listen?.push('/ip4/127.0.0.1/tcp/0'); + opts.addresses?.listen?.push('/ip4/127.0.0.1/tcp/0') } else if (options.transport === 'webrtc-direct') { - opts.addresses?.listen?.push('/ip4/127.0.0.1/udp/0/webrtc-direct'); + opts.addresses?.listen?.push('/ip4/127.0.0.1/udp/0/webrtc-direct') } else { - throw new UnsupportedError(); + throw new UnsupportedError() } } if (options.transport === 'webtransport') { - throw new UnsupportedError(); + throw new UnsupportedError() } const services: ServiceFactoryMap< - { identify: Identify; ping: PingService } & Record + { identify: Identify ping: PingService } & Record > = { identify: identify(), ping: ping(), - }; + } if (options.encryption === 'tls') { - opts.connectionEncrypters?.push(tls()); + opts.connectionEncrypters?.push(tls()) } else if (options.encryption === 'plaintext') { - opts.connectionEncrypters?.push(plaintext()); + opts.connectionEncrypters?.push(plaintext()) } else { - opts.connectionEncrypters?.push(noise()); + opts.connectionEncrypters?.push(noise()) } if (options.muxer === 'mplex') { - opts.streamMuxers?.push(mplex()); + opts.streamMuxers?.push(mplex()) } else { - opts.streamMuxers?.push(yamux()); + opts.streamMuxers?.push(yamux()) } if (options.pubsub === true) { if (options.pubsubRouter === 'floodsub') { - services.pubsub = floodsub(); + services.pubsub = floodsub() } else { - services.pubsub = gossipsub(); + services.pubsub = gossipsub() } } if (options.relay === true) { - services.relay = circuitRelayServer(); + services.relay = circuitRelayServer() } if (options.dht === true) { @@ -194,41 +194,41 @@ async function createJsPeer(options: SpawnOptions): Promise { protocol: '/ipfs/kad/1.0.0', peerInfoMapper: passthroughMapper, clientMode: false, - }); + }) } const node: any = await createLibp2p({ ...opts, services, - }); + }) - const server = createServer(multiaddr('/ip4/127.0.0.1/tcp/0'), node); - await server.start(); + const server = createServer(multiaddr('/ip4/127.0.0.1/tcp/0'), node) + await server.start() return { client: createClient(server.getMultiaddr()), stop: async () => { - await server.stop(); - await node.stop(); + await server.stop() + await node.stop() }, - }; + } } async function main(): Promise { const factory: DaemonFactory = { async spawn(options: SpawnOptions) { if (options.type === 'go') { - return createGoPeer(options); + return createGoPeer(options) } - return createJsPeer(options); + return createJsPeer(options) }, - }; + } - await interopTests(factory); + await interopTests(factory) } main().catch((err) => { - console.error(err); // eslint-disable-line no-console - process.exit(1); -}); + console.error(err) // eslint-disable-line no-console + process.exit(1) +}) diff --git a/packages/interface-compliance-tests/src/mocks/connection.ts b/packages/interface-compliance-tests/src/mocks/connection.ts index e78776e1d2..e57a91122d 100644 --- a/packages/interface-compliance-tests/src/mocks/connection.ts +++ b/packages/interface-compliance-tests/src/mocks/connection.ts @@ -1,14 +1,14 @@ -import { ConnectionClosedError } from '@libp2p/interface'; -import { defaultLogger, logger } from '@libp2p/logger'; -import * as mss from '@libp2p/multistream-select'; -import { peerIdFromString } from '@libp2p/peer-id'; -import { closeSource } from '@libp2p/utils/close-source'; -import { duplexPair } from 'it-pair/duplex'; -import { pipe } from 'it-pipe'; -import { Uint8ArrayList } from 'uint8arraylist'; -import { mockMultiaddrConnection } from './multiaddr-connection.js'; -import { mockMuxer } from './muxer.js'; -import { mockRegistrar } from './registrar.js'; +import { ConnectionClosedError } from '@libp2p/interface' +import { defaultLogger, logger } from '@libp2p/logger' +import * as mss from '@libp2p/multistream-select' +import { peerIdFromString } from '@libp2p/peer-id' +import { closeSource } from '@libp2p/utils/close-source' +import { duplexPair } from 'it-pair/duplex' +import { pipe } from 'it-pipe' +import { Uint8ArrayList } from 'uint8arraylist' +import { mockMultiaddrConnection } from './multiaddr-connection.js' +import { mockMuxer } from './muxer.js' +import { mockRegistrar } from './registrar.js' import type { AbortOptions, ComponentLogger, @@ -24,63 +24,63 @@ import type { StreamMuxerFactory, NewStreamOptions, ConnectionLimits, -} from '@libp2p/interface'; -import type { Registrar } from '@libp2p/interface-internal'; -import type { Multiaddr } from '@multiformats/multiaddr'; -import type { Duplex, Source } from 'it-stream-types'; +} from '@libp2p/interface' +import type { Registrar } from '@libp2p/interface-internal' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { Duplex, Source } from 'it-stream-types' export interface MockConnectionOptions { - direction?: Direction; - registrar?: Registrar; - muxerFactory?: StreamMuxerFactory; - logger?: ComponentLogger; + direction?: Direction + registrar?: Registrar + muxerFactory?: StreamMuxerFactory + logger?: ComponentLogger } interface MockConnectionInit { - remoteAddr: Multiaddr; - remotePeer: PeerId; - direction: Direction; - maConn: MultiaddrConnection; - muxer: StreamMuxer; - logger: ComponentLogger; + remoteAddr: Multiaddr + remotePeer: PeerId + direction: Direction + maConn: MultiaddrConnection + muxer: StreamMuxer + logger: ComponentLogger } class MockConnection implements Connection { - public id: string; - public remoteAddr: Multiaddr; - public remotePeer: PeerId; - public direction: Direction; - public timeline: ConnectionTimeline; - public multiplexer?: string; - public encryption?: string; - public status: ConnectionStatus; - public streams: Stream[]; - public tags: string[]; - public limits?: ConnectionLimits; - public log: Logger; - - private readonly muxer: StreamMuxer; - private readonly maConn: MultiaddrConnection; - private readonly logger: ComponentLogger; + public id: string + public remoteAddr: Multiaddr + public remotePeer: PeerId + public direction: Direction + public timeline: ConnectionTimeline + public multiplexer?: string + public encryption?: string + public status: ConnectionStatus + public streams: Stream[] + public tags: string[] + public limits?: ConnectionLimits + public log: Logger + + private readonly muxer: StreamMuxer + private readonly maConn: MultiaddrConnection + private readonly logger: ComponentLogger constructor(init: MockConnectionInit) { - const { remoteAddr, remotePeer, direction, maConn, muxer, logger } = init; - - this.id = `mock-connection-${Math.random()}`; - this.remoteAddr = remoteAddr; - this.remotePeer = remotePeer; - this.direction = direction; - this.status = 'open'; - this.direction = direction; - this.timeline = maConn.timeline; - this.multiplexer = 'test-multiplexer'; - this.encryption = 'yes-yes-very-secure'; - this.streams = []; - this.tags = []; - this.muxer = muxer; - this.maConn = maConn; - this.logger = logger; - this.log = logger.forComponent(this.id); + const { remoteAddr, remotePeer, direction, maConn, muxer, logger } = init + + this.id = `mock-connection-${Math.random()}` + this.remoteAddr = remoteAddr + this.remotePeer = remotePeer + this.direction = direction + this.status = 'open' + this.direction = direction + this.timeline = maConn.timeline + this.multiplexer = 'test-multiplexer' + this.encryption = 'yes-yes-very-secure' + this.streams = [] + this.tags = [] + this.muxer = muxer + this.maConn = maConn + this.logger = logger + this.log = logger.forComponent(this.id) } async newStream( @@ -88,54 +88,54 @@ class MockConnection implements Connection { options?: NewStreamOptions ): Promise { if (!Array.isArray(protocols)) { - protocols = [protocols]; + protocols = [protocols] } if (protocols.length === 0) { - throw new Error('protocols must have a length'); + throw new Error('protocols must have a length') } if (this.status !== 'open') { throw new ConnectionClosedError( 'connection must be open to create streams' - ); + ) } - options?.signal?.throwIfAborted(); + options?.signal?.throwIfAborted() - const id = `${Math.random()}`; - const stream = await this.muxer.newStream(id); + const id = `${Math.random()}` + const stream = await this.muxer.newStream(id) const result = await mss.select(stream, protocols, { ...options, log: this.logger.forComponent('libp2p:mock-connection:stream:mss:select'), - }); + }) - stream.protocol = result.protocol; - stream.direction = 'outbound'; - stream.sink = result.stream.sink; - stream.source = result.stream.source; + stream.protocol = result.protocol + stream.direction = 'outbound' + stream.sink = result.stream.sink + stream.source = result.stream.source - this.streams.push(stream); + this.streams.push(stream) - return stream; + return stream } async close(options?: AbortOptions): Promise { - this.status = 'closing'; - await Promise.all(this.streams.map(async (s) => s.close(options))); - await this.maConn.close(); - this.status = 'closed'; - this.timeline.close = Date.now(); + this.status = 'closing' + await Promise.all(this.streams.map(async (s) => s.close(options))) + await this.maConn.close() + this.status = 'closed' + this.timeline.close = Date.now() } abort(err: Error): void { - this.status = 'closing'; + this.status = 'closing' this.streams.forEach((s) => { - s.abort(err); - }); - this.maConn.abort(err); - this.status = 'closed'; - this.timeline.close = Date.now(); + s.abort(err) + }) + this.maConn.abort(err) + this.status = 'closed' + this.timeline.close = Date.now() } } @@ -143,21 +143,21 @@ export function mockConnection( maConn: MultiaddrConnection, opts: MockConnectionOptions = {} ): Connection { - const remoteAddr = maConn.remoteAddr; + const remoteAddr = maConn.remoteAddr const remotePeerIdStr = remoteAddr.getPeerId() ?? - '12D3KooWCrhmFM1BCPGBkNzbPfDk4cjYmtAYSpZwUBC69Qg2kZyq'; - const logger = opts.logger ?? defaultLogger(); + '12D3KooWCrhmFM1BCPGBkNzbPfDk4cjYmtAYSpZwUBC69Qg2kZyq' + const logger = opts.logger ?? defaultLogger() if (remotePeerIdStr == null) { - throw new Error('Remote multiaddr must contain a peer id'); + 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 log = logger.forComponent('libp2p:mock-muxer'); + const remotePeer = peerIdFromString(remotePeerIdStr) + const direction = opts.direction ?? 'inbound' + const registrar = opts.registrar ?? mockRegistrar() + const muxerFactory = opts.muxerFactory ?? mockMuxer() + const log = logger.forComponent('libp2p:mock-muxer') const muxer = muxerFactory.createStreamMuxer({ direction, @@ -168,31 +168,31 @@ export function mockConnection( log, }) .then(({ stream, protocol }) => { - log('%s: incoming stream opened on %s', direction, protocol); - muxedStream.protocol = protocol; - muxedStream.sink = stream.sink; - muxedStream.source = stream.source; + log('%s: incoming stream opened on %s', direction, protocol) + muxedStream.protocol = protocol + muxedStream.sink = stream.sink + muxedStream.source = stream.source - connection.streams.push(muxedStream); - const { handler } = registrar.getHandler(protocol); + connection.streams.push(muxedStream) + const { handler } = registrar.getHandler(protocol) - handler({ connection, stream: muxedStream }); + handler({ connection, stream: muxedStream }) }) .catch((err) => { - log.error('incoming stream handler error - %e', err); - }); + log.error('incoming stream handler error - %e', err) + }) } catch (err: any) { - log.error('error handling incoming stream - %e', err); + log.error('error handling incoming stream - %e', err) } }, onStreamEnd: (muxedStream) => { connection.streams = connection.streams.filter( (stream) => stream.id !== muxedStream.id - ); + ) }, - }); + }) - void pipe(maConn, muxer, maConn); + void pipe(maConn, muxer, maConn) const connection = new MockConnection({ remoteAddr, @@ -201,15 +201,15 @@ export function mockConnection( maConn, muxer, logger, - }); + }) - return connection; + return connection } export interface StreamInit { - direction?: Direction; - protocol?: string; - id?: string; + direction?: Direction + protocol?: string + id?: string } export function mockStream( @@ -220,12 +220,12 @@ export function mockStream( >, init: StreamInit = {} ): Stream { - const id = `stream-${Date.now()}`; - const log = logger(`libp2p:mock-stream:${id}`); + const id = `stream-${Date.now()}` + const log = logger(`libp2p:mock-stream:${id}`) // ensure stream output is `Uint8ArrayList` as it would be from an actual // Stream where everything is length-varint encoded - const originalSource = stream.source; + const originalSource = stream.source stream.source = (async function* (): AsyncGenerator< Uint8ArrayList, any, @@ -233,50 +233,50 @@ export function mockStream( > { for await (const buf of originalSource) { if (buf instanceof Uint8Array) { - yield new Uint8ArrayList(buf); + yield new Uint8ArrayList(buf) } else { - yield buf; + yield buf } } - })(); + })() - const abortSinkController = new AbortController(); - const originalSink = stream.sink.bind(stream); + const abortSinkController = new AbortController() + const originalSink = stream.sink.bind(stream) stream.sink = async (source) => { abortSinkController.signal.addEventListener('abort', () => { - closeSource(source, log); - }); + closeSource(source, log) + }) - await originalSink(source); - }; + await originalSink(source) + } const mockStream: Stream = { ...stream, close: async (options) => { - await mockStream.closeRead(options); - await mockStream.closeWrite(options); + await mockStream.closeRead(options) + await mockStream.closeWrite(options) }, closeRead: async () => { - closeSource(originalSource, log); - mockStream.timeline.closeRead = Date.now(); + closeSource(originalSource, log) + mockStream.timeline.closeRead = Date.now() if (mockStream.timeline.closeWrite != null) { - mockStream.timeline.close = Date.now(); + mockStream.timeline.close = Date.now() } }, closeWrite: async () => { - abortSinkController.abort(); - mockStream.timeline.closeWrite = Date.now(); + abortSinkController.abort() + mockStream.timeline.closeWrite = Date.now() if (mockStream.timeline.closeRead != null) { - mockStream.timeline.close = Date.now(); + mockStream.timeline.close = Date.now() } }, abort: () => { - closeSource(originalSource, log); - mockStream.timeline.closeWrite = Date.now(); - mockStream.timeline.closeRead = Date.now(); - mockStream.timeline.close = Date.now(); + closeSource(originalSource, log) + mockStream.timeline.closeWrite = Date.now() + mockStream.timeline.closeRead = Date.now() + mockStream.timeline.close = Date.now() }, direction: 'outbound', protocol: '/foo/1.0.0', @@ -290,9 +290,9 @@ export function mockStream( writeStatus: 'ready', log: logger('mock-stream'), ...init, - }; + } - return mockStream; + return mockStream } export interface StreamPairInit { @@ -300,8 +300,8 @@ export interface StreamPairInit { AsyncGenerator, Source, Promise - >; - init?: StreamInit; + > + init?: StreamInit } export function streamPair( @@ -320,33 +320,33 @@ export function streamPair( ...init, ...(b.init ?? {}), }), - ]; + ] } export interface Peer { - peerId: PeerId; - registrar: Registrar; + peerId: PeerId + registrar: Registrar } export function multiaddrConnectionPair( - a: { peerId: PeerId; registrar: Registrar }, - b: { peerId: PeerId; registrar: Registrar } + a: { peerId: PeerId registrar: Registrar }, + b: { peerId: PeerId registrar: Registrar } ): [MultiaddrConnection, MultiaddrConnection] { const [peerBtoPeerA, peerAtoPeerB] = duplexPair< Uint8Array | Uint8ArrayList - >(); + >() return [ mockMultiaddrConnection(peerAtoPeerB, b.peerId), mockMultiaddrConnection(peerBtoPeerA, a.peerId), - ]; + ] } export function connectionPair( - a: { peerId: PeerId; registrar: Registrar }, - b: { peerId: PeerId; registrar: Registrar } + a: { peerId: PeerId registrar: Registrar }, + b: { peerId: PeerId registrar: Registrar } ): [Connection, Connection] { - const [peerBtoPeerA, peerAtoPeerB] = multiaddrConnectionPair(a, b); + const [peerBtoPeerA, peerAtoPeerB] = multiaddrConnectionPair(a, b) return [ mockConnection(peerBtoPeerA, { @@ -355,5 +355,5 @@ export function connectionPair( mockConnection(peerAtoPeerB, { registrar: b.registrar, }), - ]; + ] } diff --git a/packages/kad-dht/src/query/manager.ts b/packages/kad-dht/src/query/manager.ts index 0313b20141..b3ef928847 100644 --- a/packages/kad-dht/src/query/manager.ts +++ b/packages/kad-dht/src/query/manager.ts @@ -1,88 +1,88 @@ -import { createScalableCuckooFilter } from '@libp2p/utils/filters'; -import { anySignal } from 'any-signal'; -import merge from 'it-merge'; -import { setMaxListeners } from 'main-event'; -import { pEvent } from 'p-event'; -import { raceSignal } from 'race-signal'; -import { toString as uint8ArrayToString } from 'uint8arrays/to-string'; -import { ALPHA, K, DEFAULT_QUERY_TIMEOUT } from '../constants.js'; -import { convertBuffer } from '../utils.js'; -import { queryPath } from './query-path.js'; -import type { QueryFunc } from './types.js'; -import type { QueryEvent } from '../index.js'; -import type { RoutingTable } from '../routing-table/index.js'; +import { createScalableCuckooFilter } from '@libp2p/utils/filters' +import { anySignal } from 'any-signal' +import merge from 'it-merge' +import { setMaxListeners } from 'main-event' +import { pEvent } from 'p-event' +import { raceSignal } from 'race-signal' +import { toString as uint8ArrayToString } from 'uint8arrays/to-string' +import { ALPHA, K, DEFAULT_QUERY_TIMEOUT } from '../constants.js' +import { convertBuffer } from '../utils.js' +import { queryPath } from './query-path.js' +import type { QueryFunc } from './types.js' +import type { QueryEvent } from '../index.js' +import type { RoutingTable } from '../routing-table/index.js' import type { ComponentLogger, Metrics, PeerId, RoutingOptions, Startable, -} from '@libp2p/interface'; -import type { ConnectionManager } from '@libp2p/interface-internal'; -import type { DeferredPromise } from 'p-defer'; +} from '@libp2p/interface' +import type { ConnectionManager } from '@libp2p/interface-internal' +import type { DeferredPromise } from 'p-defer' export interface CleanUpEvents { - cleanup: CustomEvent; + cleanup: CustomEvent } export interface QueryManagerInit { - logPrefix: string; - metricsPrefix: string; - disjointPaths?: number; - alpha?: number; - initialQuerySelfHasRun: DeferredPromise; - allowQueryWithZeroPeers?: boolean; - routingTable: RoutingTable; + logPrefix: string + metricsPrefix: string + disjointPaths?: number + alpha?: number + initialQuerySelfHasRun: DeferredPromise + allowQueryWithZeroPeers?: boolean + routingTable: RoutingTable } export interface QueryManagerComponents { - peerId: PeerId; - metrics?: Metrics; - logger: ComponentLogger; - connectionManager: ConnectionManager; + peerId: PeerId + metrics?: Metrics + logger: ComponentLogger + connectionManager: ConnectionManager } export interface QueryOptions extends RoutingOptions { - isSelfQuery?: boolean; + isSelfQuery?: boolean } /** * Keeps track of all running queries */ export class QueryManager implements Startable { - public disjointPaths: number; - private readonly alpha: number; - private shutDownController: AbortController; - private running: boolean; - private readonly logger: ComponentLogger; - private readonly peerId: PeerId; - private readonly connectionManager: ConnectionManager; - private readonly routingTable: RoutingTable; - private initialQuerySelfHasRun?: DeferredPromise; - private readonly logPrefix: string; - private readonly allowQueryWithZeroPeers: boolean; + public disjointPaths: number + private readonly alpha: number + private shutDownController: AbortController + private running: boolean + private readonly logger: ComponentLogger + private readonly peerId: PeerId + private readonly connectionManager: ConnectionManager + private readonly routingTable: RoutingTable + private initialQuerySelfHasRun?: DeferredPromise + private readonly logPrefix: string + private readonly allowQueryWithZeroPeers: boolean constructor(components: QueryManagerComponents, init: QueryManagerInit) { - this.logPrefix = init.logPrefix; - this.disjointPaths = init.disjointPaths ?? K; - this.alpha = init.alpha ?? ALPHA; - this.initialQuerySelfHasRun = init.initialQuerySelfHasRun; - this.routingTable = init.routingTable; - this.logger = components.logger; - this.peerId = components.peerId; - this.connectionManager = components.connectionManager; - this.allowQueryWithZeroPeers = init.allowQueryWithZeroPeers ?? false; + this.logPrefix = init.logPrefix + this.disjointPaths = init.disjointPaths ?? K + this.alpha = init.alpha ?? ALPHA + this.initialQuerySelfHasRun = init.initialQuerySelfHasRun + this.routingTable = init.routingTable + this.logger = components.logger + this.peerId = components.peerId + this.connectionManager = components.connectionManager + this.allowQueryWithZeroPeers = init.allowQueryWithZeroPeers ?? false // allow us to stop queries on shut down - this.shutDownController = new AbortController(); + this.shutDownController = new AbortController() // make sure we don't make a lot of noise in the logs - setMaxListeners(Infinity, this.shutDownController.signal); + setMaxListeners(Infinity, this.shutDownController.signal) - this.running = false; + this.running = false } isStarted(): boolean { - return this.running; + return this.running } /** @@ -90,24 +90,24 @@ export class QueryManager implements Startable { */ async start(): Promise { if (this.running) { - return; + return } - this.running = true; + this.running = true // allow us to stop queries on shut down - this.shutDownController = new AbortController(); + this.shutDownController = new AbortController() // make sure we don't make a lot of noise in the logs - setMaxListeners(Infinity, this.shutDownController.signal); + setMaxListeners(Infinity, this.shutDownController.signal) } /** * Stops all queries */ async stop(): Promise { - this.running = false; + this.running = false - this.shutDownController.abort(); + this.shutDownController.abort() } async *run( @@ -116,105 +116,105 @@ export class QueryManager implements Startable { options: QueryOptions = {} ): AsyncGenerator { if (!this.running) { - throw new Error('QueryManager not started'); + throw new Error('QueryManager not started') } if (options.signal == null) { // don't let queries run forever - const signal = AbortSignal.timeout(DEFAULT_QUERY_TIMEOUT); + const signal = AbortSignal.timeout(DEFAULT_QUERY_TIMEOUT) // this signal will get listened to for network requests, etc // so make sure we don't make a lot of noise in the logs - setMaxListeners(Infinity, signal); + setMaxListeners(Infinity, signal) options = { ...options, signal, - }; + } } // if the user breaks out of a for..await of loop iterating over query // results we need to cancel any in-flight network requests - const queryEarlyExitController = new AbortController(); + const queryEarlyExitController = new AbortController() const signal = anySignal([ this.shutDownController.signal, queryEarlyExitController.signal, options.signal, - ]); + ]) // this signal will get listened to for every invocation of queryFunc // so make sure we don't make a lot of noise in the logs - setMaxListeners(Infinity, signal, queryEarlyExitController.signal); + setMaxListeners(Infinity, signal, queryEarlyExitController.signal) const log = this.logger.forComponent( `${this.logPrefix}:query:` + uint8ArrayToString(key, 'base58btc') - ); + ) // query a subset of peers up to `kBucketSize / 2` in length - let queryFinished = false; + let queryFinished = false try { if (this.routingTable.size === 0 && !this.allowQueryWithZeroPeers) { log( 'routing table was empty, waiting for some peers before running%s query', options.isSelfQuery === true ? ' self' : '' - ); + ) // wait to discover at least one DHT peer that isn't us await pEvent(this.routingTable, 'peer:add', { signal, filter: (event) => !this.peerId.equals(event.detail), - }); + }) log( 'routing table has peers, continuing with%s query', options.isSelfQuery === true ? ' self' : '' - ); + ) } if (options.isSelfQuery !== true && this.initialQuerySelfHasRun != null) { - log('waiting for initial self query before continuing'); + log('waiting for initial self query before continuing') - await raceSignal(this.initialQuerySelfHasRun.promise, signal); + await raceSignal(this.initialQuerySelfHasRun.promise, signal) - this.initialQuerySelfHasRun = undefined; + this.initialQuerySelfHasRun = undefined } - log('query:start'); + log('query:start') const id = await convertBuffer(key, { signal, - }); + }) const peers = this.routingTable.closestPeers( id, this.routingTable.kBucketSize - ); + ) // split peers into d buckets evenly(ish) const peersToQuery = peers .sort(() => { if (Math.random() > 0.5) { - return 1; + return 1 } - return -1; + return -1 }) .reduce( (acc: PeerId[][], curr, index) => { - acc[index % this.disjointPaths].push(curr); + acc[index % this.disjointPaths].push(curr) - return acc; + return acc }, new Array(this.disjointPaths).fill(0).map(() => []) ) - .filter((peers) => peers.length > 0); + .filter((peers) => peers.length > 0) if (peers.length === 0) { - log.error('running query with no peers'); - return; + log.error('running query with no peers') + return } // make sure we don't get trapped in a loop - const peersSeen = createScalableCuckooFilter(1024); + const peersSeen = createScalableCuckooFilter(1024) // Create query paths from the starting peers const paths = peersToQuery.map((peer, index) => { @@ -232,13 +232,13 @@ export class QueryManager implements Startable { peersSeen, onProgress: options.onProgress, connectionManager: this.connectionManager, - }); - }); + }) + }) // Execute the query along each disjoint path and yield their results as they become available for await (const event of merge(...paths)) { if (event.name === 'QUERY_ERROR') { - log.error('query error - %e', event.error); + log.error('query error - %e', event.error) } if (event.name === 'PEER_RESPONSE') { @@ -249,34 +249,34 @@ export class QueryManager implements Startable { signal, })) ) { - continue; + continue } await this.routingTable.add(peer.id, { signal, - }); + }) } } - signal.throwIfAborted(); - yield event; + signal.throwIfAborted() + yield event } - queryFinished = true; + queryFinished = true } catch (err) { if (this.running) { // ignore errors thrown during shut down - throw err; + throw err } } finally { if (!queryFinished) { - log('query exited early'); - queryEarlyExitController.abort(); + log('query exited early') + queryEarlyExitController.abort() } - signal.clear(); + signal.clear() - log('query finished'); + log('query finished') } } } diff --git a/packages/transport-webrtc/src/private-to-private/initiate-connection.ts b/packages/transport-webrtc/src/private-to-private/initiate-connection.ts index 8268fb7187..47d8f20376 100644 --- a/packages/transport-webrtc/src/private-to-private/initiate-connection.ts +++ b/packages/transport-webrtc/src/private-to-private/initiate-connection.ts @@ -1,47 +1,47 @@ -import { InvalidParametersError } from '@libp2p/interface'; -import { peerIdFromString } from '@libp2p/peer-id'; -import { pbStream } from 'it-protobuf-stream'; -import { CustomProgressEvent } from 'progress-events'; -import { SIGNALING_PROTOCOL } from '../constants.js'; -import { SDPHandshakeFailedError } from '../error.js'; -import { DataChannelMuxerFactory } from '../muxer.js'; -import { RTCPeerConnection, RTCSessionDescription } from '../webrtc/index.js'; -import { Message } from './pb/message.js'; -import { splitAddr } from './transport.js'; -import { readCandidatesUntilConnected } from './util.js'; -import type { WebRTCDialEvents, WebRTCTransportMetrics } from './transport.js'; -import type { DataChannelOptions } from '../index.js'; +import { InvalidParametersError } from '@libp2p/interface' +import { peerIdFromString } from '@libp2p/peer-id' +import { pbStream } from 'it-protobuf-stream' +import { CustomProgressEvent } from 'progress-events' +import { SIGNALING_PROTOCOL } from '../constants.js' +import { SDPHandshakeFailedError } from '../error.js' +import { DataChannelMuxerFactory } from '../muxer.js' +import { RTCPeerConnection, RTCSessionDescription } from '../webrtc/index.js' +import { Message } from './pb/message.js' +import { splitAddr } from './transport.js' +import { readCandidatesUntilConnected } from './util.js' +import type { WebRTCDialEvents, WebRTCTransportMetrics } from './transport.js' +import type { DataChannelOptions } from '../index.js' import type { LoggerOptions, Connection, ComponentLogger, IncomingStreamData, -} from '@libp2p/interface'; +} from '@libp2p/interface' import type { ConnectionManager, TransportManager, -} from '@libp2p/interface-internal'; -import type { Multiaddr } from '@multiformats/multiaddr'; -import type { ProgressOptions } from 'progress-events'; +} from '@libp2p/interface-internal' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { ProgressOptions } from 'progress-events' export interface IncomingStreamOpts extends IncomingStreamData { - rtcConfiguration?: RTCConfiguration; - dataChannelOptions?: Partial; - signal: AbortSignal; + rtcConfiguration?: RTCConfiguration + dataChannelOptions?: Partial + signal: AbortSignal } export interface ConnectOptions extends LoggerOptions, ProgressOptions { - rtcConfiguration?: RTCConfiguration; - dataChannel?: DataChannelOptions; - multiaddr: Multiaddr; - connectionManager: ConnectionManager; - transportManager: TransportManager; - dataChannelOptions?: Partial; - signal?: AbortSignal; - metrics?: WebRTCTransportMetrics; - logger: ComponentLogger; + rtcConfiguration?: RTCConfiguration + dataChannel?: DataChannelOptions + multiaddr: Multiaddr + connectionManager: ConnectionManager + transportManager: TransportManager + dataChannelOptions?: Partial + signal?: AbortSignal + metrics?: WebRTCTransportMetrics + logger: ComponentLogger } export async function initiateConnection({ @@ -56,30 +56,30 @@ export async function initiateConnection({ logger, onProgress, }: ConnectOptions): Promise<{ - remoteAddress: Multiaddr; - peerConnection: RTCPeerConnection; - muxerFactory: DataChannelMuxerFactory; + remoteAddress: Multiaddr + peerConnection: RTCPeerConnection + muxerFactory: DataChannelMuxerFactory }> { - const { baseAddr } = splitAddr(ma); + const { baseAddr } = splitAddr(ma) - metrics?.dialerEvents.increment({ open: true }); + metrics?.dialerEvents.increment({ open: true }) - log.trace('dialing base address: %a', baseAddr); + log.trace('dialing base address: %a', baseAddr) - const relayPeer = baseAddr.getPeerId(); + const relayPeer = baseAddr.getPeerId() if (relayPeer == null) { - throw new InvalidParametersError('Relay peer was missing'); + throw new InvalidParametersError('Relay peer was missing') } const connections = connectionManager.getConnections( peerIdFromString(relayPeer) - ); - let connection: Connection; - let shouldCloseConnection = false; + ) + let connection: Connection + let shouldCloseConnection = false if (connections.length === 0) { - onProgress?.(new CustomProgressEvent('webrtc:dial-relay')); + onProgress?.(new CustomProgressEvent('webrtc:dial-relay')) // use the transport manager to open a connection. Initiating a WebRTC // connection takes place in the context of a dial - if we use the @@ -87,26 +87,26 @@ export async function initiateConnection({ connection = await transportManager.dial(baseAddr, { signal, onProgress, - }); + }) // this connection is unmanaged by the connection manager so we should // close it when we are done - shouldCloseConnection = true; + shouldCloseConnection = true } else { - onProgress?.(new CustomProgressEvent('webrtc:reuse-relay-connection')); + onProgress?.(new CustomProgressEvent('webrtc:reuse-relay-connection')) - connection = connections[0]; + connection = connections[0] } try { - onProgress?.(new CustomProgressEvent('webrtc:open-signaling-stream')); + onProgress?.(new CustomProgressEvent('webrtc:open-signaling-stream')) const stream = await connection.newStream(SIGNALING_PROTOCOL, { signal, runOnLimitedConnection: true, - }); + }) - const messageStream = pbStream(stream).pb(Message); - const peerConnection = new RTCPeerConnection(rtcConfiguration); + const messageStream = pbStream(stream).pb(Message) + const peerConnection = new RTCPeerConnection(rtcConfiguration) const muxerFactory = new DataChannelMuxerFactory( { logger, @@ -115,13 +115,13 @@ export async function initiateConnection({ peerConnection, dataChannelOptions: dataChannel, } - ); + ) try { // we create the channel so that the RTCPeerConnection has a component for // which to collect candidates. The label is not relevant to connection // initiation but can be useful for debugging - const channel = peerConnection.createDataChannel('init'); + const channel = peerConnection.createDataChannel('init') // setup callback to write ICE candidates to the remote peer peerConnection.onicecandidate = ({ candidate }) => { @@ -129,9 +129,9 @@ export async function initiateConnection({ // means end-of-candidates for this generation, otherwise this should // be a valid candidate object // see - https://www.w3.org/TR/webrtc/#rtcpeerconnectioniceevent - const data = JSON.stringify(candidate?.toJSON() ?? null); + const data = JSON.stringify(candidate?.toJSON() ?? null) - log.trace('initiator sending ICE candidate %o', candidate); + log.trace('initiator sending ICE candidate %o', candidate) void messageStream .write( @@ -144,22 +144,22 @@ export async function initiateConnection({ } ) .catch((err) => { - log.error('error sending ICE candidate', err); - }); - }; + log.error('error sending ICE candidate', err) + }) + } peerConnection.onicecandidateerror = (event) => { - log.error('initiator ICE candidate error', event); - }; + log.error('initiator ICE candidate error', event) + } // create an offer const offerSdp = await peerConnection.createOffer().catch((err) => { - log.error('could not execute createOffer - %e', err); - throw new SDPHandshakeFailedError('Failed to set createOffer'); - }); + log.error('could not execute createOffer - %e', err) + throw new SDPHandshakeFailedError('Failed to set createOffer') + }) - log.trace('initiator send SDP offer %s', offerSdp.sdp); + log.trace('initiator send SDP offer %s', offerSdp.sdp) - onProgress?.(new CustomProgressEvent('webrtc:send-sdp-offer')); + onProgress?.(new CustomProgressEvent('webrtc:send-sdp-offer')) // write the offer to the stream await messageStream.write( @@ -167,75 +167,75 @@ export async function initiateConnection({ { signal, } - ); + ) // set offer as local description await peerConnection.setLocalDescription(offerSdp).catch((err) => { - log.error('could not execute setLocalDescription - %e', err); - throw new SDPHandshakeFailedError('Failed to set localDescription'); - }); + log.error('could not execute setLocalDescription - %e', err) + throw new SDPHandshakeFailedError('Failed to set localDescription') + }) - onProgress?.(new CustomProgressEvent('webrtc:read-sdp-answer')); + onProgress?.(new CustomProgressEvent('webrtc:read-sdp-answer')) - log.trace('initiator read SDP answer'); + log.trace('initiator read SDP answer') // read answer const answerMessage = await messageStream.read({ signal, - }); + }) if (answerMessage.type !== Message.Type.SDP_ANSWER) { - throw new SDPHandshakeFailedError('Remote should send an SDP answer'); + throw new SDPHandshakeFailedError('Remote should send an SDP answer') } - log.trace('initiator received SDP answer %s', answerMessage.data); + log.trace('initiator received SDP answer %s', answerMessage.data) const answerSdp = new RTCSessionDescription({ type: 'answer', sdp: answerMessage.data, - }); + }) await peerConnection.setRemoteDescription(answerSdp).catch((err) => { - log.error('could not execute setRemoteDescription - %e', err); - throw new SDPHandshakeFailedError('Failed to set remoteDescription'); - }); + log.error('could not execute setRemoteDescription - %e', err) + throw new SDPHandshakeFailedError('Failed to set remoteDescription') + }) - log.trace('initiator read candidates until connected'); + log.trace('initiator read candidates until connected') - onProgress?.(new CustomProgressEvent('webrtc:read-ice-candidates')); + onProgress?.(new CustomProgressEvent('webrtc:read-ice-candidates')) await readCandidatesUntilConnected(peerConnection, messageStream, { direction: 'initiator', signal, log, onProgress, - }); + }) - log.trace('initiator connected, closing init channel'); - channel.close(); + log.trace('initiator connected, closing init channel') + channel.close() - onProgress?.(new CustomProgressEvent('webrtc:close-signaling-stream')); + onProgress?.(new CustomProgressEvent('webrtc:close-signaling-stream')) - log.trace('closing signaling channel'); + log.trace('closing signaling channel') await stream.close({ signal, - }); + }) - log.trace('initiator connected to remote address %s', ma); + log.trace('initiator connected to remote address %s', ma) return { remoteAddress: ma, peerConnection, muxerFactory, - }; + } } catch (err: any) { - log.error('outgoing signaling error - %e', err); + log.error('outgoing signaling error - %e', err) - peerConnection.close(); - stream.abort(err); - throw err; + peerConnection.close() + stream.abort(err) + throw err } finally { - peerConnection.onicecandidate = null; - peerConnection.onicecandidateerror = null; + peerConnection.onicecandidate = null + peerConnection.onicecandidateerror = null } } finally { // if we had to open a connection to perform the SDP handshake @@ -244,9 +244,9 @@ export async function initiateConnection({ try { await connection.close({ signal, - }); + }) } catch (err: any) { - connection.abort(err); + connection.abort(err) } } } diff --git a/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts b/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts index a8081bf28f..a00441f6e7 100644 --- a/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts +++ b/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts @@ -1,17 +1,17 @@ -import { multiaddr } from '@multiformats/multiaddr'; -import { pbStream } from 'it-protobuf-stream'; -import { SDPHandshakeFailedError } from '../error.js'; -import { RTCSessionDescription } from '../webrtc/index.js'; -import { Message } from './pb/message.js'; -import { getConnectionState, readCandidatesUntilConnected } from './util.js'; -import type { RTCPeerConnection } from '../webrtc/index.js'; -import type { Logger, IncomingStreamData } from '@libp2p/interface'; -import type { Multiaddr } from '@multiformats/multiaddr'; +import { multiaddr } from '@multiformats/multiaddr' +import { pbStream } from 'it-protobuf-stream' +import { SDPHandshakeFailedError } from '../error.js' +import { RTCSessionDescription } from '../webrtc/index.js' +import { Message } from './pb/message.js' +import { getConnectionState, readCandidatesUntilConnected } from './util.js' +import type { RTCPeerConnection } from '../webrtc/index.js' +import type { Logger, IncomingStreamData } from '@libp2p/interface' +import type { Multiaddr } from '@multiformats/multiaddr' export interface IncomingStreamOpts extends IncomingStreamData { - peerConnection: RTCPeerConnection; - signal: AbortSignal; - log: Logger; + peerConnection: RTCPeerConnection + signal: AbortSignal + log: Logger } export async function handleIncomingStream({ @@ -21,9 +21,9 @@ export async function handleIncomingStream({ connection, log, }: IncomingStreamOpts): Promise<{ remoteAddress: Multiaddr }> { - log.trace('new inbound signaling stream'); + log.trace('new inbound signaling stream') - const messageStream = pbStream(stream).pb(Message); + const messageStream = pbStream(stream).pb(Message) try { // candidate callbacks @@ -32,9 +32,9 @@ export async function handleIncomingStream({ // means end-of-candidates for this generation, otherwise this should // be a valid candidate object // see - https://www.w3.org/TR/webrtc/#rtcpeerconnectioniceevent - const data = JSON.stringify(candidate?.toJSON() ?? null); + const data = JSON.stringify(candidate?.toJSON() ?? null) - log.trace('recipient sending ICE candidate %s', data); + log.trace('recipient sending ICE candidate %s', data) messageStream .write( @@ -47,44 +47,44 @@ export async function handleIncomingStream({ } ) .catch((err) => { - log.error('error sending ICE candidate - %e', err); - }); - }; + log.error('error sending ICE candidate - %e', err) + }) + } - log.trace('recipient read SDP offer'); + log.trace('recipient read SDP offer') // read an SDP offer const pbOffer = await messageStream.read({ signal, - }); + }) if (pbOffer.type !== Message.Type.SDP_OFFER) { throw new SDPHandshakeFailedError( `expected message type SDP_OFFER, received: ${ pbOffer.type ?? 'undefined' } ` - ); + ) } - log.trace('recipient received SDP offer %s', pbOffer.data); + log.trace('recipient received SDP offer %s', pbOffer.data) const offer = new RTCSessionDescription({ type: 'offer', sdp: pbOffer.data, - }); + }) await peerConnection.setRemoteDescription(offer).catch((err) => { - log.error('could not execute setRemoteDescription - %e', err); - throw new SDPHandshakeFailedError('Failed to set remoteDescription'); - }); + log.error('could not execute setRemoteDescription - %e', err) + throw new SDPHandshakeFailedError('Failed to set remoteDescription') + }) // create and write an SDP answer const answer = await peerConnection.createAnswer().catch((err) => { - log.error('could not execute createAnswer - %e', err); - throw new SDPHandshakeFailedError('Failed to create answer'); - }); + log.error('could not execute createAnswer - %e', err) + throw new SDPHandshakeFailedError('Failed to create answer') + }) - log.trace('recipient send SDP answer %s', answer.sdp); + log.trace('recipient send SDP answer %s', answer.sdp) // write the answer to the remote await messageStream.write( @@ -92,45 +92,45 @@ export async function handleIncomingStream({ { signal, } - ); + ) await peerConnection.setLocalDescription(answer).catch((err) => { - log.error('could not execute setLocalDescription - %e', err); - throw new SDPHandshakeFailedError('Failed to set localDescription'); - }); + log.error('could not execute setLocalDescription - %e', err) + throw new SDPHandshakeFailedError('Failed to set localDescription') + }) - log.trace('recipient read candidates until connected'); + log.trace('recipient read candidates until connected') // wait until candidates are connected await readCandidatesUntilConnected(peerConnection, messageStream, { direction: 'recipient', signal, log, - }); + }) } catch (err: any) { if (getConnectionState(peerConnection) !== 'connected') { log.error( 'error while handling signaling stream from peer %a - %e', connection.remoteAddr, err - ); + ) - peerConnection.close(); - throw err; + peerConnection.close() + throw err } else { log( 'error while handling signaling stream from peer %a, ignoring as the RTCPeerConnection is already connected - %e', connection.remoteAddr, err - ); + ) } } const remoteAddress = multiaddr( `/webrtc/p2p/${connection.remoteAddr.getPeerId()}` - ); + ) - log.trace('recipient connected to remote address %s', remoteAddress); + log.trace('recipient connected to remote address %s', remoteAddress) - return { remoteAddress }; + return { remoteAddress } } diff --git a/packages/transport-webtransport/src/muxer.ts b/packages/transport-webtransport/src/muxer.ts index 61f4910f4b..54614f5ae1 100644 --- a/packages/transport-webtransport/src/muxer.ts +++ b/packages/transport-webtransport/src/muxer.ts @@ -1,16 +1,16 @@ -import { webtransportBiDiStreamToStream } from './stream.js'; -import { inertDuplex } from './utils/inert-duplex.js'; -import type WebTransport from './webtransport.js'; +import { webtransportBiDiStreamToStream } from './stream.js' +import { inertDuplex } from './utils/inert-duplex.js' +import type WebTransport from './webtransport.js' import type { ComponentLogger, Stream, StreamMuxer, StreamMuxerFactory, StreamMuxerInit, -} from '@libp2p/interface'; +} from '@libp2p/interface' export interface WebTransportMuxerInit { - maxInboundStreams: number; + maxInboundStreams: number } export function webtransportMuxer( @@ -19,8 +19,8 @@ export function webtransportMuxer( logger: ComponentLogger, config: WebTransportMuxerInit ): StreamMuxerFactory { - let streamIDCounter = 0; - const log = logger.forComponent('libp2p:webtransport:muxer'); + let streamIDCounter = 0 + const log = logger.forComponent('libp2p:webtransport:muxer') return { protocol: 'webtransport', @@ -29,38 +29,38 @@ export function webtransportMuxer( if (typeof init === 'function') { // The api docs say that init may be a function - init = { onIncomingStream: init }; + init = { onIncomingStream: init } } - const activeStreams: Stream[] = []; + const activeStreams: Stream[] = [] Promise.resolve() .then(async () => { //! TODO unclear how to add backpressure here? while (true) { - const { done, value: wtStream } = await reader.read(); + const { done, value: wtStream } = await reader.read() if (done) { - break; + break } if (activeStreams.length >= config.maxInboundStreams) { log( `too many inbound streams open - ${activeStreams.length}/${config.maxInboundStreams}, closing new incoming stream` - ); + ) // We've reached our limit, close this stream. wtStream.writable.close().catch((err: Error) => { log.error( 'failed to close inbound stream that crossed our maxInboundStream limit - %e', err.message - ); - }); + ) + }) wtStream.readable.cancel().catch((err: Error) => { log.error( 'failed to close inbound stream that crossed our maxInboundStream limit - %e', err.message - ); - }); + ) + }) } else { const stream = await webtransportBiDiStreamToStream( wtStream, @@ -69,23 +69,23 @@ export function webtransportMuxer( activeStreams, init?.onStreamEnd, logger - ); - activeStreams.push(stream); - init?.onIncomingStream?.(stream); + ) + activeStreams.push(stream) + init?.onIncomingStream?.(stream) } } }) .catch((err) => { - log.error('could not create a new stream - %e', err); - }); + log.error('could not create a new stream - %e', err) + }) const muxer: StreamMuxer = { protocol: 'webtransport', streams: activeStreams, newStream: async (name?: string): Promise => { - log('new outgoing stream', name); + log('new outgoing stream', name) - const wtStream = await wt.createBidirectionalStream(); + const wtStream = await wt.createBidirectionalStream() const stream = await webtransportBiDiStreamToStream( wtStream, String(streamIDCounter++), @@ -93,22 +93,22 @@ export function webtransportMuxer( activeStreams, init?.onStreamEnd, logger - ); - activeStreams.push(stream); + ) + activeStreams.push(stream) - return stream; + return stream }, /** * Close all tracked streams and stop the muxer */ close: async () => { - log('closing webtransport muxer gracefully'); + log('closing webtransport muxer gracefully') try { - wt.close(); + wt.close() } catch (err: any) { - muxer.abort(err); + muxer.abort(err) } }, @@ -116,20 +116,20 @@ export function webtransportMuxer( * Abort all tracked streams and stop the muxer */ abort: (err: Error) => { - log('closing webtransport muxer with err:', err); + log('closing webtransport muxer with err:', err) try { - wt.close(); + wt.close() } catch (err: any) { - log.error('webtransport session threw error during close', err); + log.error('webtransport session threw error during close', err) } }, // This stream muxer is webtransport native. Therefore it doesn't plug in with any other duplex. ...inertDuplex(), - }; + } - return muxer; + return muxer }, - }; + } } From 7290a49899925e486f995f66dcfbe3cb550a5a45 Mon Sep 17 00:00:00 2001 From: Suchitra Swain Date: Wed, 4 Jun 2025 13:37:26 +0200 Subject: [PATCH 05/15] formatiing reverted --- .../private-to-private/initiate-connection.ts | 68 ++++++------------- .../signaling-stream-handler.ts | 8 +-- packages/transport-webtransport/src/muxer.ts | 12 +--- 3 files changed, 23 insertions(+), 65 deletions(-) diff --git a/packages/transport-webrtc/src/private-to-private/initiate-connection.ts b/packages/transport-webrtc/src/private-to-private/initiate-connection.ts index 47d8f20376..107441954d 100644 --- a/packages/transport-webrtc/src/private-to-private/initiate-connection.ts +++ b/packages/transport-webrtc/src/private-to-private/initiate-connection.ts @@ -11,16 +11,8 @@ import { splitAddr } from './transport.js' import { readCandidatesUntilConnected } from './util.js' import type { WebRTCDialEvents, WebRTCTransportMetrics } from './transport.js' import type { DataChannelOptions } from '../index.js' -import type { - LoggerOptions, - Connection, - ComponentLogger, - IncomingStreamData, -} from '@libp2p/interface' -import type { - ConnectionManager, - TransportManager, -} from '@libp2p/interface-internal' +import type { LoggerOptions, Connection, ComponentLogger, IncomingStreamData } from '@libp2p/interface' +import type { ConnectionManager, TransportManager } from '@libp2p/interface-internal' import type { Multiaddr } from '@multiformats/multiaddr' import type { ProgressOptions } from 'progress-events' @@ -30,9 +22,7 @@ export interface IncomingStreamOpts extends IncomingStreamData { signal: AbortSignal } -export interface ConnectOptions - extends LoggerOptions, - ProgressOptions { +export interface ConnectOptions extends LoggerOptions, ProgressOptions { rtcConfiguration?: RTCConfiguration dataChannel?: DataChannelOptions multiaddr: Multiaddr @@ -44,22 +34,7 @@ export interface ConnectOptions logger: ComponentLogger } -export async function initiateConnection({ - rtcConfiguration, - dataChannel, - signal, - metrics, - multiaddr: ma, - connectionManager, - transportManager, - log, - logger, - onProgress, -}: ConnectOptions): Promise<{ - remoteAddress: Multiaddr - peerConnection: RTCPeerConnection - muxerFactory: DataChannelMuxerFactory -}> { +export async function initiateConnection ({ rtcConfiguration, dataChannel, signal, metrics, multiaddr: ma, connectionManager, transportManager, log, logger, onProgress }: ConnectOptions): Promise<{ remoteAddress: Multiaddr, peerConnection: RTCPeerConnection, muxerFactory: DataChannelMuxerFactory }> { const { baseAddr } = splitAddr(ma) metrics?.dialerEvents.increment({ open: true }) @@ -72,9 +47,7 @@ export async function initiateConnection({ throw new InvalidParametersError('Relay peer was missing') } - const connections = connectionManager.getConnections( - peerIdFromString(relayPeer) - ) + const connections = connectionManager.getConnections(peerIdFromString(relayPeer)) let connection: Connection let shouldCloseConnection = false @@ -86,7 +59,7 @@ export async function initiateConnection({ // connection manager instead we can end up joining our own dial context connection = await transportManager.dial(baseAddr, { signal, - onProgress, + onProgress }) // this connection is unmanaged by the connection manager so we should // close it when we are done @@ -102,18 +75,18 @@ export async function initiateConnection({ const stream = await connection.newStream(SIGNALING_PROTOCOL, { signal, - runOnLimitedConnection: true, + runOnLimitedConnection: true }) const messageStream = pbStream(stream).pb(Message) const peerConnection = new RTCPeerConnection(rtcConfiguration) const muxerFactory = new DataChannelMuxerFactory( { - logger, + logger }, { peerConnection, - dataChannelOptions: dataChannel, + dataChannelOptions: dataChannel } ) @@ -137,10 +110,10 @@ export async function initiateConnection({ .write( { type: Message.Type.ICE_CANDIDATE, - data, + data }, { - signal, + signal } ) .catch((err) => { @@ -162,12 +135,9 @@ export async function initiateConnection({ onProgress?.(new CustomProgressEvent('webrtc:send-sdp-offer')) // write the offer to the stream - await messageStream.write( - { type: Message.Type.SDP_OFFER, data: offerSdp.sdp }, - { - signal, - } - ) + await messageStream.write({ type: Message.Type.SDP_OFFER, data: offerSdp.sdp }, { + signal + }) // set offer as local description await peerConnection.setLocalDescription(offerSdp).catch((err) => { @@ -181,7 +151,7 @@ export async function initiateConnection({ // read answer const answerMessage = await messageStream.read({ - signal, + signal }) if (answerMessage.type !== Message.Type.SDP_ANSWER) { @@ -207,7 +177,7 @@ export async function initiateConnection({ direction: 'initiator', signal, log, - onProgress, + onProgress }) log.trace('initiator connected, closing init channel') @@ -217,7 +187,7 @@ export async function initiateConnection({ log.trace('closing signaling channel') await stream.close({ - signal, + signal }) log.trace('initiator connected to remote address %s', ma) @@ -225,7 +195,7 @@ export async function initiateConnection({ return { remoteAddress: ma, peerConnection, - muxerFactory, + muxerFactory } } catch (err: any) { log.error('outgoing signaling error - %e', err) @@ -243,7 +213,7 @@ export async function initiateConnection({ if (shouldCloseConnection) { try { await connection.close({ - signal, + signal }) } catch (err: any) { connection.abort(err) diff --git a/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts b/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts index a00441f6e7..1c75cc3aff 100644 --- a/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts +++ b/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts @@ -14,13 +14,7 @@ export interface IncomingStreamOpts extends IncomingStreamData { log: Logger } -export async function handleIncomingStream({ - peerConnection, - stream, - signal, - connection, - log, -}: IncomingStreamOpts): Promise<{ remoteAddress: Multiaddr }> { +export async function handleIncomingStream ({ peerConnection, stream, signal, connection, log }: IncomingStreamOpts): Promise<{ remoteAddress: Multiaddr }> { log.trace('new inbound signaling stream') const messageStream = pbStream(stream).pb(Message) diff --git a/packages/transport-webtransport/src/muxer.ts b/packages/transport-webtransport/src/muxer.ts index 54614f5ae1..0b060fe90f 100644 --- a/packages/transport-webtransport/src/muxer.ts +++ b/packages/transport-webtransport/src/muxer.ts @@ -1,13 +1,7 @@ import { webtransportBiDiStreamToStream } from './stream.js' import { inertDuplex } from './utils/inert-duplex.js' import type WebTransport from './webtransport.js' -import type { - ComponentLogger, - Stream, - StreamMuxer, - StreamMuxerFactory, - StreamMuxerInit, -} from '@libp2p/interface' +import type { ComponentLogger, Stream, StreamMuxer, StreamMuxerFactory, StreamMuxerInit } from '@libp2p/interface' export interface WebTransportMuxerInit { maxInboundStreams: number @@ -126,10 +120,10 @@ export function webtransportMuxer( }, // This stream muxer is webtransport native. Therefore it doesn't plug in with any other duplex. - ...inertDuplex(), + ...inertDuplex() } return muxer - }, + } } } From 4a9fa3a9d2ee8f6396191fb4eb7e1f3333145c58 Mon Sep 17 00:00:00 2001 From: Suchitra Swain Date: Wed, 4 Jun 2025 13:41:54 +0200 Subject: [PATCH 06/15] interop formate fix --- packages/integration-tests/test/interop.ts | 38 ++++++++++------------ 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/packages/integration-tests/test/interop.ts b/packages/integration-tests/test/interop.ts index 789c7e253a..ee0b05e28f 100644 --- a/packages/integration-tests/test/interop.ts +++ b/packages/integration-tests/test/interop.ts @@ -2,10 +2,7 @@ import fs from 'fs' import { gossipsub } from '@chainsafe/libp2p-gossipsub' import { noise } from '@chainsafe/libp2p-noise' import { yamux } from '@chainsafe/libp2p-yamux' -import { - circuitRelayServer, - circuitRelayTransport, -} from '@libp2p/circuit-relay-v2' +import { circuitRelayServer, circuitRelayTransport } from '@libp2p/circuit-relay-v2' import { privateKeyFromProtobuf } from '@libp2p/crypto/keys' import { createClient } from '@libp2p/daemon-client' import { createServer } from '@libp2p/daemon-server' @@ -41,14 +38,15 @@ import type { Libp2pOptions, ServiceFactoryMap } from 'libp2p' * ``` */ -async function createGoPeer(options: SpawnOptions): Promise { +async function createGoPeer (options: SpawnOptions): Promise { const controlPort = Math.floor(Math.random() * (50000 - 10000 + 1)) + 10000 const apiAddr = multiaddr(`/ip4/127.0.0.1/tcp/${controlPort}`) const log = logger(`go-libp2p:${controlPort}`) - const opts = [`-listen=${apiAddr.toString()}`] - + const opts = [ + `-listen=${apiAddr.toString()}` + ] if (options.noListen === true) { opts.push('-noListenAddrs') } else { @@ -96,8 +94,8 @@ async function createGoPeer(options: SpawnOptions): Promise { const deferred = pDefer() const proc = execa(p2pd(), opts, { env: { - GOLOG_LOG_LEVEL: 'debug', - }, + GOLOG_LOG_LEVEL: 'debug' + } }) proc.stdout?.on('data', (buf: Buffer) => { @@ -120,11 +118,11 @@ async function createGoPeer(options: SpawnOptions): Promise { client: createClient(apiAddr), stop: async () => { proc.kill() - }, + } } } -async function createJsPeer(options: SpawnOptions): Promise { +async function createJsPeer (options: SpawnOptions): Promise { let privateKey: PrivateKey | undefined if (options.key != null) { @@ -139,7 +137,7 @@ async function createJsPeer(options: SpawnOptions): Promise { }, transports: [tcp(), circuitRelayTransport(), webRTCDirect()], streamMuxers: [], - connectionEncrypters: [], + connectionEncrypters: [] } if (options.noListen !== true) { @@ -156,11 +154,9 @@ async function createJsPeer(options: SpawnOptions): Promise { throw new UnsupportedError() } - const services: ServiceFactoryMap< - { identify: Identify ping: PingService } & Record - > = { + const services: ServiceFactoryMap<{ identify: Identify, ping: PingService } & Record> = { identify: identify(), - ping: ping(), + ping: ping() } if (options.encryption === 'tls') { @@ -193,7 +189,7 @@ async function createJsPeer(options: SpawnOptions): Promise { services.dht = kadDHT({ protocol: '/ipfs/kad/1.0.0', peerInfoMapper: passthroughMapper, - clientMode: false, + clientMode: false }) } @@ -214,21 +210,21 @@ async function createJsPeer(options: SpawnOptions): Promise { } } -async function main(): Promise { +async function main (): Promise { const factory: DaemonFactory = { - async spawn(options: SpawnOptions) { + async spawn (options: SpawnOptions) { if (options.type === 'go') { return createGoPeer(options) } return createJsPeer(options) - }, + } } await interopTests(factory) } -main().catch((err) => { +main().catch(err => { console.error(err) // eslint-disable-line no-console process.exit(1) }) From 70b7ca27496c54d70f9a2e6d522a4b908bc472a3 Mon Sep 17 00:00:00 2001 From: Suchitra Swain Date: Wed, 4 Jun 2025 13:52:55 +0200 Subject: [PATCH 07/15] connection.ts fixed --- packages/integration-tests/test/interop.ts | 12 ++-- .../src/mocks/connection.ts | 57 ++++++------------- 2 files changed, 24 insertions(+), 45 deletions(-) diff --git a/packages/integration-tests/test/interop.ts b/packages/integration-tests/test/interop.ts index ee0b05e28f..e71a2f37b7 100644 --- a/packages/integration-tests/test/interop.ts +++ b/packages/integration-tests/test/interop.ts @@ -133,9 +133,13 @@ async function createJsPeer (options: SpawnOptions): Promise { const opts: Libp2pOptions = { privateKey, addresses: { - listen: [], + listen: [] }, - transports: [tcp(), circuitRelayTransport(), webRTCDirect()], + transports: [ + tcp(), + circuitRelayTransport(), + webRTCDirect() + ], streamMuxers: [], connectionEncrypters: [] } @@ -195,7 +199,7 @@ async function createJsPeer (options: SpawnOptions): Promise { const node: any = await createLibp2p({ ...opts, - services, + services }) const server = createServer(multiaddr('/ip4/127.0.0.1/tcp/0'), node) @@ -206,7 +210,7 @@ async function createJsPeer (options: SpawnOptions): Promise { stop: async () => { await server.stop() await node.stop() - }, + } } } diff --git a/packages/interface-compliance-tests/src/mocks/connection.ts b/packages/interface-compliance-tests/src/mocks/connection.ts index e57a91122d..7abe0aaf59 100644 --- a/packages/interface-compliance-tests/src/mocks/connection.ts +++ b/packages/interface-compliance-tests/src/mocks/connection.ts @@ -9,22 +9,7 @@ import { Uint8ArrayList } from 'uint8arraylist' import { mockMultiaddrConnection } from './multiaddr-connection.js' import { mockMuxer } from './muxer.js' import { mockRegistrar } from './registrar.js' -import type { - AbortOptions, - ComponentLogger, - Logger, - MultiaddrConnection, - Connection, - Stream, - Direction, - ConnectionTimeline, - ConnectionStatus, - PeerId, - StreamMuxer, - StreamMuxerFactory, - NewStreamOptions, - ConnectionLimits, -} from '@libp2p/interface' +import type { AbortOptions, ComponentLogger, Logger, MultiaddrConnection, Connection, Stream, Direction, ConnectionTimeline, ConnectionStatus, PeerId, StreamMuxer, StreamMuxerFactory, NewStreamOptions, ConnectionLimits } from '@libp2p/interface' import type { Registrar } from '@libp2p/interface-internal' import type { Multiaddr } from '@multiformats/multiaddr' import type { Duplex, Source } from 'it-stream-types' @@ -63,7 +48,7 @@ class MockConnection implements Connection { private readonly maConn: MultiaddrConnection private readonly logger: ComponentLogger - constructor(init: MockConnectionInit) { + constructor (init: MockConnectionInit) { const { remoteAddr, remotePeer, direction, maConn, muxer, logger } = init this.id = `mock-connection-${Math.random()}` @@ -83,10 +68,7 @@ class MockConnection implements Connection { this.log = logger.forComponent(this.id) } - async newStream( - protocols: string | string[], - options?: NewStreamOptions - ): Promise { + async newStream (protocols: string | string[], options?: NewStreamOptions): Promise { if (!Array.isArray(protocols)) { protocols = [protocols] } @@ -96,9 +78,7 @@ class MockConnection implements Connection { } if (this.status !== 'open') { - throw new ConnectionClosedError( - 'connection must be open to create streams' - ) + throw new ConnectionClosedError('connection must be open to create streams') } options?.signal?.throwIfAborted() @@ -107,7 +87,7 @@ class MockConnection implements Connection { const stream = await this.muxer.newStream(id) const result = await mss.select(stream, protocols, { ...options, - log: this.logger.forComponent('libp2p:mock-connection:stream:mss:select'), + log: this.logger.forComponent('libp2p:mock-connection:stream:mss:select') }) stream.protocol = result.protocol @@ -120,17 +100,19 @@ class MockConnection implements Connection { return stream } - async close(options?: AbortOptions): Promise { + async close (options?: AbortOptions): Promise { this.status = 'closing' - await Promise.all(this.streams.map(async (s) => s.close(options))) + await Promise.all( + this.streams.map(async s => s.close(options)) + ) await this.maConn.close() this.status = 'closed' this.timeline.close = Date.now() } - abort(err: Error): void { + abort (err: Error): void { this.status = 'closing' - this.streams.forEach((s) => { + this.streams.forEach(s => { s.abort(err) }) this.maConn.abort(err) @@ -139,14 +121,9 @@ class MockConnection implements Connection { } } -export function mockConnection( - maConn: MultiaddrConnection, - opts: MockConnectionOptions = {} -): Connection { +export function mockConnection (maConn: MultiaddrConnection, opts: MockConnectionOptions = {}): Connection { const remoteAddr = maConn.remoteAddr - const remotePeerIdStr = - remoteAddr.getPeerId() ?? - '12D3KooWCrhmFM1BCPGBkNzbPfDk4cjYmtAYSpZwUBC69Qg2kZyq' + const remotePeerIdStr = remoteAddr.getPeerId() ?? '12D3KooWCrhmFM1BCPGBkNzbPfDk4cjYmtAYSpZwUBC69Qg2kZyq' const logger = opts.logger ?? defaultLogger() if (remotePeerIdStr == null) { @@ -165,7 +142,7 @@ export function mockConnection( try { mss .handle(muxedStream, registrar.getProtocols(), { - log, + log }) .then(({ stream, protocol }) => { log('%s: incoming stream opened on %s', direction, protocol) @@ -186,10 +163,8 @@ export function mockConnection( } }, onStreamEnd: (muxedStream) => { - connection.streams = connection.streams.filter( - (stream) => stream.id !== muxedStream.id - ) - }, + connection.streams = connection.streams.filter(stream => stream.id !== muxedStream.id) + } }) void pipe(maConn, muxer, maConn) From 9967ca671b533b8d10cc4a4e7a93e091e9d7b63c Mon Sep 17 00:00:00 2001 From: Suchitra Swain Date: Wed, 4 Jun 2025 13:55:42 +0200 Subject: [PATCH 08/15] connection.ts fixed --- .../src/mocks/connection.ts | 63 ++++++------------- 1 file changed, 19 insertions(+), 44 deletions(-) diff --git a/packages/interface-compliance-tests/src/mocks/connection.ts b/packages/interface-compliance-tests/src/mocks/connection.ts index 7abe0aaf59..3e50b2a03f 100644 --- a/packages/interface-compliance-tests/src/mocks/connection.ts +++ b/packages/interface-compliance-tests/src/mocks/connection.ts @@ -167,7 +167,9 @@ export function mockConnection (maConn: MultiaddrConnection, opts: MockConnectio } }) - void pipe(maConn, muxer, maConn) + void pipe( + maConn, muxer, maConn + ) const connection = new MockConnection({ remoteAddr, @@ -175,7 +177,7 @@ export function mockConnection (maConn: MultiaddrConnection, opts: MockConnectio direction, maConn, muxer, - logger, + logger }) return connection @@ -187,25 +189,14 @@ export interface StreamInit { id?: string } -export function mockStream( - stream: Duplex< - AsyncGenerator, - Source, - Promise - >, - init: StreamInit = {} -): Stream { +export function mockStream (stream: Duplex, Source, Promise>, init: StreamInit = {}): Stream { const id = `stream-${Date.now()}` const log = logger(`libp2p:mock-stream:${id}`) // ensure stream output is `Uint8ArrayList` as it would be from an actual // Stream where everything is length-varint encoded const originalSource = stream.source - stream.source = (async function* (): AsyncGenerator< - Uint8ArrayList, - any, - unknown - > { + stream.source = (async function * (): AsyncGenerator { for await (const buf of originalSource) { if (buf instanceof Uint8Array) { yield new Uint8ArrayList(buf) @@ -256,7 +247,7 @@ export function mockStream( direction: 'outbound', protocol: '/foo/1.0.0', timeline: { - open: Date.now(), + open: Date.now() }, metadata: {}, id: `stream-${Date.now()}`, @@ -264,37 +255,29 @@ export function mockStream( readStatus: 'ready', writeStatus: 'ready', log: logger('mock-stream'), - ...init, + ...init } return mockStream } export interface StreamPairInit { - duplex: Duplex< - AsyncGenerator, - Source, - Promise - > + duplex: Duplex, Source, Promise> init?: StreamInit } -export function streamPair( - a: StreamPairInit, - b: StreamPairInit, - init: StreamInit = {} -): [Stream, Stream] { +export function streamPair (a: StreamPairInit, b: StreamPairInit, init: StreamInit = {}): [Stream, Stream] { return [ mockStream(a.duplex, { direction: 'outbound', ...init, - ...(a.init ?? {}), + ...(a.init ?? {}) }), mockStream(b.duplex, { direction: 'inbound', ...init, - ...(b.init ?? {}), - }), + ...(b.init ?? {}) + }) ] } @@ -303,32 +286,24 @@ export interface Peer { registrar: Registrar } -export function multiaddrConnectionPair( - a: { peerId: PeerId registrar: Registrar }, - b: { peerId: PeerId registrar: Registrar } -): [MultiaddrConnection, MultiaddrConnection] { - const [peerBtoPeerA, peerAtoPeerB] = duplexPair< - Uint8Array | Uint8ArrayList - >() +export function multiaddrConnectionPair (a: { peerId: PeerId, registrar: Registrar }, b: { peerId: PeerId, registrar: Registrar }): [ MultiaddrConnection, MultiaddrConnection ] { + const [peerBtoPeerA, peerAtoPeerB] = duplexPair() return [ mockMultiaddrConnection(peerAtoPeerB, b.peerId), - mockMultiaddrConnection(peerBtoPeerA, a.peerId), + mockMultiaddrConnection(peerBtoPeerA, a.peerId) ] } -export function connectionPair( - a: { peerId: PeerId registrar: Registrar }, - b: { peerId: PeerId registrar: Registrar } -): [Connection, Connection] { +export function connectionPair (a: { peerId: PeerId, registrar: Registrar }, b: { peerId: PeerId, registrar: Registrar }): [ Connection, Connection ] { const [peerBtoPeerA, peerAtoPeerB] = multiaddrConnectionPair(a, b) return [ mockConnection(peerBtoPeerA, { - registrar: a.registrar, + registrar: a.registrar }), mockConnection(peerAtoPeerB, { - registrar: b.registrar, + registrar: b.registrar }), ] } From 9f80d8cca6f05d0e8e3319998fc82debc7bc6ceb Mon Sep 17 00:00:00 2001 From: Suchitra Swain Date: Wed, 4 Jun 2025 14:00:17 +0200 Subject: [PATCH 09/15] manager fixed --- packages/kad-dht/src/query/manager.ts | 70 +++++++++------------------ 1 file changed, 24 insertions(+), 46 deletions(-) diff --git a/packages/kad-dht/src/query/manager.ts b/packages/kad-dht/src/query/manager.ts index b3ef928847..8e18c6dbb2 100644 --- a/packages/kad-dht/src/query/manager.ts +++ b/packages/kad-dht/src/query/manager.ts @@ -11,13 +11,7 @@ import { queryPath } from './query-path.js' import type { QueryFunc } from './types.js' import type { QueryEvent } from '../index.js' import type { RoutingTable } from '../routing-table/index.js' -import type { - ComponentLogger, - Metrics, - PeerId, - RoutingOptions, - Startable, -} from '@libp2p/interface' +import type { ComponentLogger, Metrics, PeerId, RoutingOptions, Startable } from '@libp2p/interface' import type { ConnectionManager } from '@libp2p/interface-internal' import type { DeferredPromise } from 'p-defer' @@ -62,7 +56,7 @@ export class QueryManager implements Startable { private readonly logPrefix: string private readonly allowQueryWithZeroPeers: boolean - constructor(components: QueryManagerComponents, init: QueryManagerInit) { + constructor (components: QueryManagerComponents, init: QueryManagerInit) { this.logPrefix = init.logPrefix this.disjointPaths = init.disjointPaths ?? K this.alpha = init.alpha ?? ALPHA @@ -81,14 +75,14 @@ export class QueryManager implements Startable { this.running = false } - isStarted(): boolean { + isStarted (): boolean { return this.running } /** * Starts the query manager */ - async start(): Promise { + async start (): Promise { if (this.running) { return } @@ -104,17 +98,13 @@ export class QueryManager implements Startable { /** * Stops all queries */ - async stop(): Promise { + async stop (): Promise { this.running = false this.shutDownController.abort() } - async *run( - key: Uint8Array, - queryFunc: QueryFunc, - options: QueryOptions = {} - ): AsyncGenerator { + async * run (key: Uint8Array, queryFunc: QueryFunc, options: QueryOptions = {}): AsyncGenerator { if (!this.running) { throw new Error('QueryManager not started') } @@ -129,7 +119,7 @@ export class QueryManager implements Startable { options = { ...options, - signal, + signal } } @@ -140,35 +130,27 @@ export class QueryManager implements Startable { const signal = anySignal([ this.shutDownController.signal, queryEarlyExitController.signal, - options.signal, + options.signal ]) // this signal will get listened to for every invocation of queryFunc // so make sure we don't make a lot of noise in the logs setMaxListeners(Infinity, signal, queryEarlyExitController.signal) - const log = this.logger.forComponent( - `${this.logPrefix}:query:` + uint8ArrayToString(key, 'base58btc') - ) + const log = this.logger.forComponent(`${this.logPrefix}:query:` + uint8ArrayToString(key, 'base58btc')) // query a subset of peers up to `kBucketSize / 2` in length let queryFinished = false try { if (this.routingTable.size === 0 && !this.allowQueryWithZeroPeers) { - log( - 'routing table was empty, waiting for some peers before running%s query', - options.isSelfQuery === true ? ' self' : '' - ) + log('routing table was empty, waiting for some peers before running%s query', options.isSelfQuery === true ? ' self' : '') // wait to discover at least one DHT peer that isn't us await pEvent(this.routingTable, 'peer:add', { signal, - filter: (event) => !this.peerId.equals(event.detail), + filter: (event) => !this.peerId.equals(event.detail) }) - log( - 'routing table has peers, continuing with%s query', - options.isSelfQuery === true ? ' self' : '' - ) + log('routing table has peers, continuing with%s query', options.isSelfQuery === true ? ' self' : '') } if (options.isSelfQuery !== true && this.initialQuerySelfHasRun != null) { @@ -182,7 +164,7 @@ export class QueryManager implements Startable { log('query:start') const id = await convertBuffer(key, { - signal, + signal }) const peers = this.routingTable.closestPeers( id, @@ -190,23 +172,19 @@ export class QueryManager implements Startable { ) // split peers into d buckets evenly(ish) - const peersToQuery = peers - .sort(() => { - if (Math.random() > 0.5) { - return 1 - } + const peersToQuery = peers.sort(() => { + if (Math.random() > 0.5) { + return 1 + } return -1 }) - .reduce( - (acc: PeerId[][], curr, index) => { - acc[index % this.disjointPaths].push(curr) + .reduce((acc: PeerId[][], curr, index) => { + acc[index % this.disjointPaths].push(curr) return acc - }, - new Array(this.disjointPaths).fill(0).map(() => []) - ) - .filter((peers) => peers.length > 0) + },new Array(this.disjointPaths).fill(0).map(() => [])) + .filter(peers => peers.length > 0) if (peers.length === 0) { log.error('running query with no peers') @@ -231,7 +209,7 @@ export class QueryManager implements Startable { log, peersSeen, onProgress: options.onProgress, - connectionManager: this.connectionManager, + connectionManager: this.connectionManager }) }) @@ -246,14 +224,14 @@ export class QueryManager implements Startable { // eslint-disable-next-line max-depth if ( !(await this.connectionManager.isDialable(peer.multiaddrs, { - signal, + signal })) ) { continue } await this.routingTable.add(peer.id, { - signal, + signal }) } } From aa8cb7ee98b016c9f2f92cba9e0bfa2f75d9170a Mon Sep 17 00:00:00 2001 From: Suchitra Swain Date: Wed, 4 Jun 2025 14:07:55 +0200 Subject: [PATCH 10/15] code reverted --- .../src/mocks/connection.ts | 5 +-- packages/kad-dht/src/query/manager.ts | 27 ++++++------ .../private-to-private/initiate-connection.ts | 33 ++++++-------- .../signaling-stream-handler.ts | 43 +++++++------------ packages/transport-webtransport/src/muxer.ts | 16 +------ 5 files changed, 44 insertions(+), 80 deletions(-) diff --git a/packages/interface-compliance-tests/src/mocks/connection.ts b/packages/interface-compliance-tests/src/mocks/connection.ts index 3e50b2a03f..61721fd5c2 100644 --- a/packages/interface-compliance-tests/src/mocks/connection.ts +++ b/packages/interface-compliance-tests/src/mocks/connection.ts @@ -140,8 +140,7 @@ export function mockConnection (maConn: MultiaddrConnection, opts: MockConnectio direction, onIncomingStream: (muxedStream) => { try { - mss - .handle(muxedStream, registrar.getProtocols(), { + mss.handle(muxedStream, registrar.getProtocols(), { log }) .then(({ stream, protocol }) => { @@ -304,6 +303,6 @@ export function connectionPair (a: { peerId: PeerId, registrar: Registrar }, b: }), mockConnection(peerAtoPeerB, { registrar: b.registrar - }), + }) ] } diff --git a/packages/kad-dht/src/query/manager.ts b/packages/kad-dht/src/query/manager.ts index 8e18c6dbb2..1b0f92c606 100644 --- a/packages/kad-dht/src/query/manager.ts +++ b/packages/kad-dht/src/query/manager.ts @@ -5,7 +5,9 @@ import { setMaxListeners } from 'main-event' import { pEvent } from 'p-event' import { raceSignal } from 'race-signal' import { toString as uint8ArrayToString } from 'uint8arrays/to-string' -import { ALPHA, K, DEFAULT_QUERY_TIMEOUT } from '../constants.js' +import { + ALPHA, K, DEFAULT_QUERY_TIMEOUT +} from '../constants.js' import { convertBuffer } from '../utils.js' import { queryPath } from './query-path.js' import type { QueryFunc } from './types.js' @@ -166,10 +168,7 @@ export class QueryManager implements Startable { const id = await convertBuffer(key, { signal }) - const peers = this.routingTable.closestPeers( - id, - this.routingTable.kBucketSize - ) + const peers = this.routingTable.closestPeers(id, this.routingTable.kBucketSize) // split peers into d buckets evenly(ish) const peersToQuery = peers.sort(() => { @@ -177,13 +176,13 @@ export class QueryManager implements Startable { return 1 } - return -1 - }) - .reduce((acc: PeerId[][], curr, index) => { + return -1 + }) + .reduce((acc: PeerId[][], curr, index) => { acc[index % this.disjointPaths].push(curr) - return acc - },new Array(this.disjointPaths).fill(0).map(() => [])) + return acc + },new Array(this.disjointPaths).fill(0).map(() => [])) .filter(peers => peers.length > 0) if (peers.length === 0) { @@ -222,11 +221,9 @@ export class QueryManager implements Startable { if (event.name === 'PEER_RESPONSE') { for (const peer of [...event.closer, ...event.providers]) { // eslint-disable-next-line max-depth - if ( - !(await this.connectionManager.isDialable(peer.multiaddrs, { - signal - })) - ) { + if (!(await this.connectionManager.isDialable(peer.multiaddrs, { + signal + }))) { continue } diff --git a/packages/transport-webrtc/src/private-to-private/initiate-connection.ts b/packages/transport-webrtc/src/private-to-private/initiate-connection.ts index 107441954d..dd88fd89f5 100644 --- a/packages/transport-webrtc/src/private-to-private/initiate-connection.ts +++ b/packages/transport-webrtc/src/private-to-private/initiate-connection.ts @@ -80,15 +80,12 @@ export async function initiateConnection ({ rtcConfiguration, dataChannel, signa const messageStream = pbStream(stream).pb(Message) const peerConnection = new RTCPeerConnection(rtcConfiguration) - const muxerFactory = new DataChannelMuxerFactory( - { - logger - }, - { - peerConnection, - dataChannelOptions: dataChannel - } - ) + const muxerFactory = new DataChannelMuxerFactory({ + logger + }, { + peerConnection, + dataChannelOptions: dataChannel + }) try { // we create the channel so that the RTCPeerConnection has a component for @@ -106,17 +103,13 @@ export async function initiateConnection ({ rtcConfiguration, dataChannel, signa log.trace('initiator sending ICE candidate %o', candidate) - void messageStream - .write( - { - type: Message.Type.ICE_CANDIDATE, - data - }, - { - signal - } - ) - .catch((err) => { + void messageStream.write({ + type: Message.Type.ICE_CANDIDATE, + data + }, { + signal + }) + .catch(err => { log.error('error sending ICE candidate', err) }) } diff --git a/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts b/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts index 1c75cc3aff..52594aee5e 100644 --- a/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts +++ b/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts @@ -30,17 +30,13 @@ export async function handleIncomingStream ({ peerConnection, stream, signal, co log.trace('recipient sending ICE candidate %s', data) - messageStream - .write( - { - type: Message.Type.ICE_CANDIDATE, - data, - }, - { - signal, - } - ) - .catch((err) => { + messageStream.write({ + type: Message.Type.ICE_CANDIDATE, + data + }, { + signal + }) + .catch(err => { log.error('error sending ICE candidate - %e', err) }) } @@ -49,22 +45,18 @@ export async function handleIncomingStream ({ peerConnection, stream, signal, co // read an SDP offer const pbOffer = await messageStream.read({ - signal, + signal }) if (pbOffer.type !== Message.Type.SDP_OFFER) { - throw new SDPHandshakeFailedError( - `expected message type SDP_OFFER, received: ${ - pbOffer.type ?? 'undefined' - } ` - ) + throw new SDPHandshakeFailedError(`expected message type SDP_OFFER, received: ${pbOffer.type ?? 'undefined'} `) } log.trace('recipient received SDP offer %s', pbOffer.data) const offer = new RTCSessionDescription({ type: 'offer', - sdp: pbOffer.data, + sdp: pbOffer.data }) await peerConnection.setRemoteDescription(offer).catch((err) => { @@ -81,12 +73,9 @@ export async function handleIncomingStream ({ peerConnection, stream, signal, co log.trace('recipient send SDP answer %s', answer.sdp) // write the answer to the remote - await messageStream.write( - { type: Message.Type.SDP_ANSWER, data: answer.sdp }, - { - signal, - } - ) + await messageStream.write({ type: Message.Type.SDP_ANSWER, data: answer.sdp }, { + signal + }) await peerConnection.setLocalDescription(answer).catch((err) => { log.error('could not execute setLocalDescription - %e', err) @@ -99,7 +88,7 @@ export async function handleIncomingStream ({ peerConnection, stream, signal, co await readCandidatesUntilConnected(peerConnection, messageStream, { direction: 'recipient', signal, - log, + log }) } catch (err: any) { if (getConnectionState(peerConnection) !== 'connected') { @@ -120,9 +109,7 @@ export async function handleIncomingStream ({ peerConnection, stream, signal, co } } - const remoteAddress = multiaddr( - `/webrtc/p2p/${connection.remoteAddr.getPeerId()}` - ) + const remoteAddress = multiaddr(`/webrtc/p2p/${connection.remoteAddr.getPeerId()}`) log.trace('recipient connected to remote address %s', remoteAddress) diff --git a/packages/transport-webtransport/src/muxer.ts b/packages/transport-webtransport/src/muxer.ts index 0b060fe90f..2cd473faa4 100644 --- a/packages/transport-webtransport/src/muxer.ts +++ b/packages/transport-webtransport/src/muxer.ts @@ -7,12 +7,7 @@ export interface WebTransportMuxerInit { maxInboundStreams: number } -export function webtransportMuxer( - wt: Pick, - reader: ReadableStreamDefaultReader, - logger: ComponentLogger, - config: WebTransportMuxerInit -): StreamMuxerFactory { +export function webtransportMuxer (wt: Pick, reader: ReadableStreamDefaultReader, logger: ComponentLogger, config: WebTransportMuxerInit): StreamMuxerFactory { let streamIDCounter = 0 const log = logger.forComponent('libp2p:webtransport:muxer') @@ -80,14 +75,7 @@ export function webtransportMuxer( log('new outgoing stream', name) const wtStream = await wt.createBidirectionalStream() - const stream = await webtransportBiDiStreamToStream( - wtStream, - String(streamIDCounter++), - init?.direction ?? 'outbound', - activeStreams, - init?.onStreamEnd, - logger - ) + const stream = await webtransportBiDiStreamToStream(wtStream, String(streamIDCounter++), init?.direction ?? 'outbound', activeStreams, init?.onStreamEnd, logger) activeStreams.push(stream) return stream From 52059a1a0bd6a5281ab39637b27eb1811f92757f Mon Sep 17 00:00:00 2001 From: Suchitra Swain Date: Wed, 4 Jun 2025 15:45:57 +0200 Subject: [PATCH 11/15] unrelated changed fixed --- packages/integration-tests/test/interop.ts | 1 + .../src/mocks/connection.ts | 6 +++--- packages/kad-dht/src/query/manager.ts | 4 ++-- .../src/private-to-private/initiate-connection.ts | 11 ++++------- .../private-to-private/signaling-stream-handler.ts | 6 +++--- packages/transport-webtransport/src/muxer.ts | 6 ++---- 6 files changed, 15 insertions(+), 19 deletions(-) diff --git a/packages/integration-tests/test/interop.ts b/packages/integration-tests/test/interop.ts index e71a2f37b7..d943adf94f 100644 --- a/packages/integration-tests/test/interop.ts +++ b/packages/integration-tests/test/interop.ts @@ -47,6 +47,7 @@ async function createGoPeer (options: SpawnOptions): Promise { const opts = [ `-listen=${apiAddr.toString()}` ] + if (options.noListen === true) { opts.push('-noListenAddrs') } else { diff --git a/packages/interface-compliance-tests/src/mocks/connection.ts b/packages/interface-compliance-tests/src/mocks/connection.ts index 61721fd5c2..3676e9218d 100644 --- a/packages/interface-compliance-tests/src/mocks/connection.ts +++ b/packages/interface-compliance-tests/src/mocks/connection.ts @@ -141,8 +141,8 @@ export function mockConnection (maConn: MultiaddrConnection, opts: MockConnectio onIncomingStream: (muxedStream) => { try { mss.handle(muxedStream, registrar.getProtocols(), { - log - }) + log + }) .then(({ stream, protocol }) => { log('%s: incoming stream opened on %s', direction, protocol) muxedStream.protocol = protocol @@ -154,7 +154,7 @@ export function mockConnection (maConn: MultiaddrConnection, opts: MockConnectio handler({ connection, stream: muxedStream }) }) - .catch((err) => { + .catch(err => { log.error('incoming stream handler error - %e', err) }) } catch (err: any) { diff --git a/packages/kad-dht/src/query/manager.ts b/packages/kad-dht/src/query/manager.ts index 1b0f92c606..775fc30a35 100644 --- a/packages/kad-dht/src/query/manager.ts +++ b/packages/kad-dht/src/query/manager.ts @@ -168,7 +168,7 @@ export class QueryManager implements Startable { const id = await convertBuffer(key, { signal }) - const peers = this.routingTable.closestPeers(id, this.routingTable.kBucketSize) + const peers = this.routingTable.closestPeers(id, this.routingTable.kBucketSize) // split peers into d buckets evenly(ish) const peersToQuery = peers.sort(() => { @@ -182,7 +182,7 @@ export class QueryManager implements Startable { acc[index % this.disjointPaths].push(curr) return acc - },new Array(this.disjointPaths).fill(0).map(() => [])) + }, new Array(this.disjointPaths).fill(0).map(() => [])) .filter(peers => peers.length > 0) if (peers.length === 0) { diff --git a/packages/transport-webrtc/src/private-to-private/initiate-connection.ts b/packages/transport-webrtc/src/private-to-private/initiate-connection.ts index dd88fd89f5..cdbffe96d9 100644 --- a/packages/transport-webrtc/src/private-to-private/initiate-connection.ts +++ b/packages/transport-webrtc/src/private-to-private/initiate-connection.ts @@ -118,7 +118,7 @@ export async function initiateConnection ({ rtcConfiguration, dataChannel, signa } // create an offer - const offerSdp = await peerConnection.createOffer().catch((err) => { + const offerSdp = await peerConnection.createOffer().catch(err => { log.error('could not execute createOffer - %e', err) throw new SDPHandshakeFailedError('Failed to set createOffer') }) @@ -133,7 +133,7 @@ export async function initiateConnection ({ rtcConfiguration, dataChannel, signa }) // set offer as local description - await peerConnection.setLocalDescription(offerSdp).catch((err) => { + await peerConnection.setLocalDescription(offerSdp).catch(err => { log.error('could not execute setLocalDescription - %e', err) throw new SDPHandshakeFailedError('Failed to set localDescription') }) @@ -153,11 +153,8 @@ export async function initiateConnection ({ rtcConfiguration, dataChannel, signa log.trace('initiator received SDP answer %s', answerMessage.data) - const answerSdp = new RTCSessionDescription({ - type: 'answer', - sdp: answerMessage.data, - }) - await peerConnection.setRemoteDescription(answerSdp).catch((err) => { + const answerSdp = new RTCSessionDescription({ type: 'answer', sdp: answerMessage.data }) + await peerConnection.setRemoteDescription(answerSdp).catch(err => { log.error('could not execute setRemoteDescription - %e', err) throw new SDPHandshakeFailedError('Failed to set remoteDescription') }) diff --git a/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts b/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts index 52594aee5e..c1fe627d64 100644 --- a/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts +++ b/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts @@ -59,13 +59,13 @@ export async function handleIncomingStream ({ peerConnection, stream, signal, co sdp: pbOffer.data }) - await peerConnection.setRemoteDescription(offer).catch((err) => { + await peerConnection.setRemoteDescription(offer).catch(err => { log.error('could not execute setRemoteDescription - %e', err) throw new SDPHandshakeFailedError('Failed to set remoteDescription') }) // create and write an SDP answer - const answer = await peerConnection.createAnswer().catch((err) => { + const answer = await peerConnection.createAnswer().catch(err => { log.error('could not execute createAnswer - %e', err) throw new SDPHandshakeFailedError('Failed to create answer') }) @@ -77,7 +77,7 @@ export async function handleIncomingStream ({ peerConnection, stream, signal, co signal }) - await peerConnection.setLocalDescription(answer).catch((err) => { + await peerConnection.setLocalDescription(answer).catch(err => { log.error('could not execute setLocalDescription - %e', err) throw new SDPHandshakeFailedError('Failed to set localDescription') }) diff --git a/packages/transport-webtransport/src/muxer.ts b/packages/transport-webtransport/src/muxer.ts index 2cd473faa4..08f9eb60cd 100644 --- a/packages/transport-webtransport/src/muxer.ts +++ b/packages/transport-webtransport/src/muxer.ts @@ -34,9 +34,7 @@ export function webtransportMuxer (wt: Pick= config.maxInboundStreams) { - log( - `too many inbound streams open - ${activeStreams.length}/${config.maxInboundStreams}, closing new incoming stream` - ) + log(`too many inbound streams open - ${activeStreams.length}/${config.maxInboundStreams}, closing new incoming stream`) // We've reached our limit, close this stream. wtStream.writable.close().catch((err: Error) => { log.error( @@ -64,7 +62,7 @@ export function webtransportMuxer (wt: Pick { + .catch(err => { log.error('could not create a new stream - %e', err) }) From 9364f706f706c72deb72ac43e1586edf1d0894a3 Mon Sep 17 00:00:00 2001 From: Suchitra Swain Date: Wed, 4 Jun 2025 15:47:13 +0200 Subject: [PATCH 12/15] unrelated changed fixed --- packages/integration-tests/test/interop.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/integration-tests/test/interop.ts b/packages/integration-tests/test/interop.ts index d943adf94f..c2567f10f5 100644 --- a/packages/integration-tests/test/interop.ts +++ b/packages/integration-tests/test/interop.ts @@ -47,7 +47,7 @@ async function createGoPeer (options: SpawnOptions): Promise { const opts = [ `-listen=${apiAddr.toString()}` ] - + if (options.noListen === true) { opts.push('-noListenAddrs') } else { From e211278c04c8786d25497c6463e45e8ab150077e Mon Sep 17 00:00:00 2001 From: Suchitra Swain Date: Thu, 5 Jun 2025 10:23:19 +0200 Subject: [PATCH 13/15] spacing fixed --- packages/integration-tests/test/interop.ts | 2 +- .../src/private-to-private/initiate-connection.ts | 2 +- .../src/private-to-private/signaling-stream-handler.ts | 7 +------ 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/integration-tests/test/interop.ts b/packages/integration-tests/test/interop.ts index c2567f10f5..6e0e2c6438 100644 --- a/packages/integration-tests/test/interop.ts +++ b/packages/integration-tests/test/interop.ts @@ -110,7 +110,7 @@ async function createGoPeer (options: SpawnOptions): Promise { }) proc.stderr?.on('data', (buf) => { - log.error('interop main error - %e', buf.toString()) + log.error('interop main error - %s', buf.toString()) }) await deferred.promise diff --git a/packages/transport-webrtc/src/private-to-private/initiate-connection.ts b/packages/transport-webrtc/src/private-to-private/initiate-connection.ts index cdbffe96d9..adab2a423d 100644 --- a/packages/transport-webrtc/src/private-to-private/initiate-connection.ts +++ b/packages/transport-webrtc/src/private-to-private/initiate-connection.ts @@ -128,7 +128,7 @@ export async function initiateConnection ({ rtcConfiguration, dataChannel, signa onProgress?.(new CustomProgressEvent('webrtc:send-sdp-offer')) // write the offer to the stream - await messageStream.write({ type: Message.Type.SDP_OFFER, data: offerSdp.sdp }, { + await messageStream.write({ type: Message.Type.SDP_OFFER, data: offerSdp.sdp }, { signal }) diff --git a/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts b/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts index c1fe627d64..f2448d37d0 100644 --- a/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts +++ b/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts @@ -92,12 +92,7 @@ export async function handleIncomingStream ({ peerConnection, stream, signal, co }) } catch (err: any) { if (getConnectionState(peerConnection) !== 'connected') { - log.error( - 'error while handling signaling stream from peer %a - %e', - connection.remoteAddr, - err - ) - + log.error('error while handling signaling stream from peer %a', connection.remoteAddr, err) peerConnection.close() throw err } else { From 3ccee889e99b4c4866f517865390061e89cdfcbc Mon Sep 17 00:00:00 2001 From: Suchitra Swain Date: Tue, 17 Jun 2025 11:38:24 +0200 Subject: [PATCH 14/15] comment resolved --- packages/integration-tests/test/interop.ts | 2 +- .../src/private-to-private/signaling-stream-handler.ts | 6 +----- packages/transport-webtransport/src/muxer.ts | 10 ++-------- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/packages/integration-tests/test/interop.ts b/packages/integration-tests/test/interop.ts index 6e0e2c6438..f02c7271cc 100644 --- a/packages/integration-tests/test/interop.ts +++ b/packages/integration-tests/test/interop.ts @@ -110,7 +110,7 @@ async function createGoPeer (options: SpawnOptions): Promise { }) proc.stderr?.on('data', (buf) => { - log.error('interop main error - %s', buf.toString()) + log.error(buf.toString()) }) await deferred.promise diff --git a/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts b/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts index f2448d37d0..93b3bb4dff 100644 --- a/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts +++ b/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts @@ -96,11 +96,7 @@ export async function handleIncomingStream ({ peerConnection, stream, signal, co peerConnection.close() throw err } else { - log( - 'error while handling signaling stream from peer %a, ignoring as the RTCPeerConnection is already connected - %e', - connection.remoteAddr, - err - ) + log.error('error while handling signaling stream from peer %a', connection.remoteAddr, err) } } diff --git a/packages/transport-webtransport/src/muxer.ts b/packages/transport-webtransport/src/muxer.ts index 08f9eb60cd..078b8fc7b8 100644 --- a/packages/transport-webtransport/src/muxer.ts +++ b/packages/transport-webtransport/src/muxer.ts @@ -37,16 +37,10 @@ export function webtransportMuxer (wt: Pick { - log.error( - 'failed to close inbound stream that crossed our maxInboundStream limit - %e', - err.message - ) + log.error('failed to close inbound stream that crossed our maxInboundStream limit - %e', err) }) wtStream.readable.cancel().catch((err: Error) => { - log.error( - 'failed to close inbound stream that crossed our maxInboundStream limit - %e', - err.message - ) + log.error('failed to close inbound stream that crossed our maxInboundStream limit - %e', err) }) } else { const stream = await webtransportBiDiStreamToStream( From c3f2912628ec296446e8d3779f57c6bc4bad55c9 Mon Sep 17 00:00:00 2001 From: Suchitra Swain Date: Wed, 18 Jun 2025 10:43:23 +0200 Subject: [PATCH 15/15] reinstate --- .../src/private-to-private/signaling-stream-handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts b/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts index 93b3bb4dff..44dc02856e 100644 --- a/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts +++ b/packages/transport-webrtc/src/private-to-private/signaling-stream-handler.ts @@ -96,7 +96,7 @@ export async function handleIncomingStream ({ peerConnection, stream, signal, co peerConnection.close() throw err } else { - log.error('error while handling signaling stream from peer %a', connection.remoteAddr, err) + log('error while handling signaling stream from peer %a, ignoring as the RTCPeerConnection is already connected', connection.remoteAddr, err) } }