@libp2p/tcp 1.0.0 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,86 +1,155 @@
1
1
  {
2
2
  "name": "@libp2p/tcp",
3
- "version": "1.0.0",
3
+ "version": "1.0.4",
4
4
  "description": "Node.js implementation of the TCP module that libp2p uses, which implements the interface-connection and interface-transport interfaces",
5
- "main": "./dist/src/index.js",
5
+ "license": "Apache-2.0 OR MIT",
6
+ "homepage": "https://github.com/libp2p/js-libp2p-tcp#readme",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/libp2p/js-libp2p-tcp.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/libp2p/js-libp2p-tcp/issues"
13
+ },
14
+ "keywords": [
15
+ "IPFS",
16
+ "TCP",
17
+ "libp2p",
18
+ "network",
19
+ "p2p",
20
+ "peer",
21
+ "peer-to-peer"
22
+ ],
23
+ "engines": {
24
+ "node": ">=16.0.0",
25
+ "npm": ">=7.0.0"
26
+ },
6
27
  "type": "module",
28
+ "types": "./dist/src/index.d.ts",
29
+ "files": [
30
+ "src",
31
+ "dist/src",
32
+ "!dist/test",
33
+ "!**/*.tsbuildinfo"
34
+ ],
7
35
  "exports": {
8
36
  ".": {
9
37
  "import": "./dist/src/index.js"
10
38
  }
11
39
  },
40
+ "eslintConfig": {
41
+ "extends": "ipfs",
42
+ "parserOptions": {
43
+ "sourceType": "module"
44
+ }
45
+ },
46
+ "release": {
47
+ "branches": [
48
+ "master"
49
+ ],
50
+ "plugins": [
51
+ [
52
+ "@semantic-release/commit-analyzer",
53
+ {
54
+ "preset": "conventionalcommits",
55
+ "releaseRules": [
56
+ {
57
+ "breaking": true,
58
+ "release": "major"
59
+ },
60
+ {
61
+ "revert": true,
62
+ "release": "patch"
63
+ },
64
+ {
65
+ "type": "feat",
66
+ "release": "minor"
67
+ },
68
+ {
69
+ "type": "fix",
70
+ "release": "patch"
71
+ },
72
+ {
73
+ "type": "chore",
74
+ "release": "patch"
75
+ },
76
+ {
77
+ "type": "docs",
78
+ "release": "patch"
79
+ },
80
+ {
81
+ "type": "test",
82
+ "release": "patch"
83
+ },
84
+ {
85
+ "scope": "no-release",
86
+ "release": false
87
+ }
88
+ ]
89
+ }
90
+ ],
91
+ [
92
+ "@semantic-release/release-notes-generator",
93
+ {
94
+ "preset": "conventionalcommits",
95
+ "presetConfig": {
96
+ "types": [
97
+ {
98
+ "type": "feat",
99
+ "section": "Features"
100
+ },
101
+ {
102
+ "type": "fix",
103
+ "section": "Bug Fixes"
104
+ },
105
+ {
106
+ "type": "chore",
107
+ "section": "Trivial Changes"
108
+ },
109
+ {
110
+ "type": "docs",
111
+ "section": "Trivial Changes"
112
+ },
113
+ {
114
+ "type": "test",
115
+ "section": "Tests"
116
+ }
117
+ ]
118
+ }
119
+ }
120
+ ],
121
+ "@semantic-release/changelog",
122
+ "@semantic-release/npm",
123
+ "@semantic-release/github",
124
+ "@semantic-release/git"
125
+ ]
126
+ },
12
127
  "scripts": {
13
128
  "lint": "aegir lint",
14
129
  "dep-check": "aegir dep-check dist/src/**/*.js dist/test/**/*.js",
15
130
  "build": "tsc",
16
131
  "pretest": "npm run build",
17
- "test": "aegir test -f ./dist/test/**/*.js",
132
+ "test": "aegir test -f ./dist/test/*.js -f ./dist/test/**/*.js",
18
133
  "test:node": "npm run test -- -t node --cov",
19
134
  "test:electron-main": "npm run test -- -t electron-main",
20
135
  "release": "semantic-release"
21
136
  },
22
- "repository": {
23
- "type": "git",
24
- "url": "https://github.com/libp2p/js-libp2p-tcp.git"
25
- },
26
- "keywords": [
27
- "libp2p",
28
- "network",
29
- "p2p",
30
- "peer",
31
- "peer-to-peer",
32
- "IPFS",
33
- "TCP"
34
- ],
35
- "license": "(Apache-2.0 OR MIT)",
36
- "bugs": {
37
- "url": "https://github.com/libp2p/js-libp2p-tcp/issues"
38
- },
39
- "homepage": "https://github.com/libp2p/js-libp2p-tcp",
40
- "engines": {
41
- "node": ">=14.0.0"
42
- },
43
- "types": "dist/src/index.d.ts",
44
- "devDependencies": {
45
- "@libp2p/interface-compliance-tests": "^1.0.1",
46
- "@libp2p/interfaces": "^1.0.0",
47
- "@types/debug": "^4.1.5",
48
- "@types/mocha": "^9.0.0",
49
- "aegir": "^36.1.3",
50
- "it-pipe": "^1.1.0",
51
- "sinon": "^12.0.0",
52
- "streaming-iterables": "^6.0.0"
53
- },
54
137
  "dependencies": {
55
- "@libp2p/utils": "^1.0.1",
138
+ "@libp2p/logger": "^1.0.2",
139
+ "@libp2p/utils": "^1.0.6",
56
140
  "@multiformats/mafmt": "^11.0.0",
57
141
  "@multiformats/multiaddr": "^10.1.1",
58
- "abortable-iterator": "^3.0.1",
59
- "debug": "^4.3.1",
142
+ "abortable-iterator": "^4.0.2",
60
143
  "err-code": "^3.0.1",
61
144
  "stream-to-it": "^0.2.2"
62
145
  },
63
- "contributors": [
64
- "David Dias <daviddias.p@gmail.com>",
65
- "Jacob Heun <jacobheun@gmail.com>",
66
- "Vasco Santos <vasco.santos@moxy.studio>",
67
- "Stephen Whitmore <stephen.whitmore@gmail.com>",
68
- "Friedel Ziegelmayer <dignifiedquire@gmail.com>",
69
- "Alex Potsides <alex@achingbrain.net>",
70
- "Richard Littauer <richard.littauer@gmail.com>",
71
- "Tom White <tomtinkerer@gmail.com>",
72
- "Alan Shaw <alan@tableflip.io>",
73
- "Nazar Hussain <nazarhussain@gmail.com>",
74
- "Pedro Teixeira <i@pgte.me>",
75
- "Prashanth Chandra <coolshanth94@gmail.com>",
76
- "Ryan Mehta <ryan.mehta@gmail.com>",
77
- "Linus Unnebäck <linus@folkdatorn.se>",
78
- "Cayman <caymannava@gmail.com>",
79
- "Diogo Silva <fsdiogo@gmail.com>",
80
- "Dmitriy Ryajov <dryajov@gmail.com>",
81
- "Drew Stone <drewstone329@gmail.com>",
82
- "Evan Schwartz <evan.mark.schwartz@gmail.com>",
83
- "João Antunes <j.goncalo.antunes@gmail.com>",
84
- "Mikeal Rogers <mikeal.rogers@gmail.com>"
85
- ]
146
+ "devDependencies": {
147
+ "@libp2p/interface-compliance-tests": "^1.1.2",
148
+ "@libp2p/interfaces": "^1.3.2",
149
+ "aegir": "^36.1.3",
150
+ "it-pipe": "^2.0.3",
151
+ "sinon": "^13.0.0",
152
+ "streaming-iterables": "^6.0.0",
153
+ "uint8arrays": "^3.0.0"
154
+ }
86
155
  }
package/src/index.ts CHANGED
@@ -1,18 +1,17 @@
1
1
  import net from 'net'
2
2
  import * as mafmt from '@multiformats/mafmt'
3
3
  import errCode from 'err-code'
4
- import debug from 'debug'
5
- import { toConnection } from './socket-to-conn.js'
4
+ import { logger } from '@libp2p/logger'
5
+ import { toMultiaddrConnection } from './socket-to-conn.js'
6
6
  import { createListener } from './listener.js'
7
7
  import { multiaddrToNetConfig } from './utils.js'
8
8
  import { AbortError } from 'abortable-iterator'
9
9
  import { CODE_CIRCUIT, CODE_P2P } from './constants.js'
10
- import type { Transport, Upgrader } from '@libp2p/interfaces/transport'
11
- import type { Connection } from '@libp2p/interfaces/connection'
10
+ import type { Transport, Upgrader, ListenerOptions, Listener } from '@libp2p/interfaces/transport'
12
11
  import type { Multiaddr } from '@multiformats/multiaddr'
13
12
  import type { Socket } from 'net'
14
13
 
15
- const log = debug('libp2p:tcp')
14
+ const log = logger('libp2p:tcp')
16
15
 
17
16
  /**
18
17
  * @typedef {import('multiaddr').Multiaddr} Multiaddr
@@ -30,7 +29,7 @@ interface DialOptions {
30
29
  signal?: AbortSignal
31
30
  }
32
31
 
33
- export class TCP implements Transport<DialOptions, {}> {
32
+ export class TCP implements Transport<DialOptions, ListenerOptions> {
34
33
  private readonly _upgrader: Upgrader
35
34
 
36
35
  constructor (options: TCPOptions) {
@@ -51,7 +50,7 @@ export class TCP implements Transport<DialOptions, {}> {
51
50
  log('socket error', err)
52
51
  })
53
52
 
54
- const maConn = toConnection(socket, { remoteAddr: ma, signal: options.signal })
53
+ const maConn = toMultiaddrConnection(socket, { remoteAddr: ma, signal: options.signal })
55
54
  log('new outbound connection %s', maConn.remoteAddr)
56
55
  const conn = await this._upgrader.upgradeOutbound(maConn)
57
56
  log('outbound connection %s upgraded', maConn.remoteAddr)
@@ -126,8 +125,8 @@ export class TCP implements Transport<DialOptions, {}> {
126
125
  * anytime a new incoming Connection has been successfully upgraded via
127
126
  * `upgrader.upgradeInbound`.
128
127
  */
129
- createListener (options: {}, handler?: (connection: Connection) => void) {
130
- return createListener({ handler: handler, upgrader: this._upgrader })
128
+ createListener (options: ListenerOptions = {}): Listener {
129
+ return createListener({ upgrader: this._upgrader, ...options })
131
130
  }
132
131
 
133
132
  /**
package/src/listener.ts CHANGED
@@ -1,24 +1,18 @@
1
1
  import net from 'net'
2
- import { EventEmitter } from 'events'
3
- import debug from 'debug'
4
- import { toConnection } from './socket-to-conn.js'
2
+ import { logger } from '@libp2p/logger'
3
+ import { toMultiaddrConnection } from './socket-to-conn.js'
5
4
  import { CODE_P2P } from './constants.js'
6
5
  import {
7
6
  getMultiaddrs,
8
7
  multiaddrToNetConfig
9
8
  } from './utils.js'
9
+ import { EventEmitter, CustomEvent } from '@libp2p/interfaces'
10
10
  import type { Connection } from '@libp2p/interfaces/connection'
11
- import type { MultiaddrConnection, Upgrader, Listener } from '@libp2p/interfaces/transport'
11
+ import type { MultiaddrConnection, Upgrader, Listener, ListenerEvents, ConnectionHandler } from '@libp2p/interfaces/transport'
12
12
  import type { Server } from 'net'
13
13
  import type { Multiaddr } from '@multiformats/multiaddr'
14
14
 
15
- const log = Object.assign(
16
- debug('libp2p:tcp:listener'),
17
- { error: debug('libp2p:tcp:listener:error') })
18
-
19
- interface ServerWithMultiaddrConnections extends Server {
20
- __connections: MultiaddrConnection[]
21
- }
15
+ const log = logger('libp2p:tcp:listener')
22
16
 
23
17
  /**
24
18
  * Attempts to close the given maConn. If a failure occurs, it will be logged
@@ -36,137 +30,159 @@ interface Context {
36
30
  upgrader: Upgrader
37
31
  }
38
32
 
39
- /**
40
- * Create listener
41
- */
42
- export function createListener (context: Context) {
43
- const {
44
- handler, upgrader
45
- } = context
33
+ class TCPListener extends EventEmitter<ListenerEvents> implements Listener {
34
+ private peerId?: string
35
+ private listeningAddr?: Multiaddr
36
+ private readonly server: Server
37
+ private connections: MultiaddrConnection[]
38
+
39
+ constructor (upgrader: Upgrader, handler?: ConnectionHandler) {
40
+ super()
41
+
42
+ this.connections = []
43
+
44
+ this.server = net.createServer(socket => {
45
+ // Avoid uncaught errors caused by unstable connections
46
+ socket.on('error', err => {
47
+ log('socket error', err)
48
+ })
46
49
 
47
- let peerId: string | null
48
- let listeningAddr: Multiaddr
50
+ let maConn: MultiaddrConnection
51
+ try {
52
+ maConn = toMultiaddrConnection(socket, { listeningAddr: this.listeningAddr })
53
+ } catch (err) {
54
+ log.error('inbound connection failed', err)
55
+ return
56
+ }
49
57
 
50
- const server: ServerWithMultiaddrConnections = Object.assign(net.createServer(socket => {
51
- // Avoid uncaught errors caused by unstable connections
52
- socket.on('error', err => {
53
- log('socket error', err)
58
+ log('new inbound connection %s', maConn.remoteAddr)
59
+ try {
60
+ upgrader.upgradeInbound(maConn)
61
+ .then((conn) => {
62
+ log('inbound connection %s upgraded', maConn.remoteAddr)
63
+
64
+ this.trackConn(maConn, socket)
65
+
66
+ if (handler != null) {
67
+ handler(conn)
68
+ }
69
+
70
+ this.dispatchEvent(new CustomEvent('connection', {
71
+ detail: conn
72
+ }))
73
+ })
74
+ .catch(async err => {
75
+ log.error('inbound connection failed', err)
76
+
77
+ await attemptClose(maConn)
78
+ })
79
+ .catch(err => {
80
+ log.error('closing inbound connection failed', err)
81
+ })
82
+ } catch (err) {
83
+ log.error('inbound connection failed', err)
84
+
85
+ attemptClose(maConn)
86
+ .catch(err => {
87
+ log.error('closing inbound connection failed', err)
88
+ })
89
+ }
90
+ })
91
+ this.server.on('error', err => {
92
+ this.dispatchEvent(new CustomEvent('error', {
93
+ detail: err
94
+ }))
54
95
  })
96
+ this.server.on('close', () => {
97
+ this.dispatchEvent(new CustomEvent('close'))
98
+ })
99
+ this.server.on('listening', () => {
100
+ this.dispatchEvent(new CustomEvent('listening'))
101
+ })
102
+ }
55
103
 
56
- let maConn: MultiaddrConnection
57
- try {
58
- maConn = toConnection(socket, { listeningAddr })
59
- } catch (err) {
60
- log.error('inbound connection failed', err)
61
- return
104
+ getAddrs () {
105
+ let addrs: Multiaddr[] = []
106
+ const address = this.server.address()
107
+
108
+ if (address == null) {
109
+ throw new Error('Listener is not ready yet')
62
110
  }
63
111
 
64
- log('new inbound connection %s', maConn.remoteAddr)
65
- try {
66
- upgrader.upgradeInbound(maConn)
67
- .then((conn) => {
68
- log('inbound connection %s upgraded', maConn.remoteAddr)
69
-
70
- trackConn(server, maConn)
71
-
72
- if (handler != null) {
73
- handler(conn)
74
- }
75
-
76
- listener.emit('connection', conn)
77
- })
78
- .catch(async err => {
79
- log.error('inbound connection failed', err)
80
-
81
- await attemptClose(maConn)
82
- })
83
- .catch(err => {
84
- log.error('closing inbound connection failed', err)
85
- })
86
- } catch (err) {
87
- log.error('inbound connection failed', err)
88
-
89
- attemptClose(maConn)
90
- .catch(err => {
91
- log.error('closing inbound connection failed', err)
92
- })
112
+ if (typeof address === 'string') {
113
+ throw new Error('Incorrect server address type')
93
114
  }
94
- }),
95
- // Keep track of open connections to destroy in case of timeout
96
- { __connections: [] })
97
115
 
98
- const listener: Listener = Object.assign(new EventEmitter(), {
99
- getAddrs: () => {
100
- let addrs: Multiaddr[] = []
101
- const address = server.address()
116
+ if (this.listeningAddr == null) {
117
+ throw new Error('Listener is not ready yet')
118
+ }
102
119
 
103
- if (address == null) {
104
- throw new Error('Listener is not ready yet')
105
- }
120
+ // Because TCP will only return the IPv6 version
121
+ // we need to capture from the passed multiaddr
122
+ if (this.listeningAddr.toString().startsWith('/ip4')) {
123
+ addrs = addrs.concat(getMultiaddrs('ip4', address.address, address.port))
124
+ } else if (address.family === 'IPv6') {
125
+ addrs = addrs.concat(getMultiaddrs('ip6', address.address, address.port))
126
+ }
106
127
 
107
- if (typeof address === 'string') {
108
- throw new Error('Incorrect server address type')
109
- }
128
+ return addrs.map(ma => this.peerId != null ? ma.encapsulate(`/p2p/${this.peerId}`) : ma)
129
+ }
110
130
 
111
- // Because TCP will only return the IPv6 version
112
- // we need to capture from the passed multiaddr
113
- if (listeningAddr.toString().startsWith('/ip4')) {
114
- addrs = addrs.concat(getMultiaddrs('ip4', address.address, address.port))
115
- } else if (address.family === 'IPv6') {
116
- addrs = addrs.concat(getMultiaddrs('ip6', address.address, address.port))
117
- }
131
+ async listen (ma: Multiaddr) {
132
+ const peerId = ma.getPeerId()
118
133
 
119
- return addrs.map(ma => peerId != null ? ma.encapsulate(`/p2p/${peerId}`) : ma)
120
- },
121
- listen: async (ma: Multiaddr) => {
122
- listeningAddr = ma
123
- peerId = ma.getPeerId()
134
+ if (peerId == null) {
135
+ ma = ma.decapsulateCode(CODE_P2P)
136
+ } else {
137
+ this.peerId = peerId
138
+ }
124
139
 
125
- if (peerId == null) {
126
- listeningAddr = ma.decapsulateCode(CODE_P2P)
127
- }
140
+ this.listeningAddr = ma
128
141
 
129
- return await new Promise<void>((resolve, reject) => {
130
- const options = multiaddrToNetConfig(listeningAddr)
131
- server.listen(options, (err?: any) => {
132
- if (err != null) {
133
- return reject(err)
134
- }
135
- log('Listening on %s', server.address())
136
- resolve()
137
- })
142
+ return await new Promise<void>((resolve, reject) => {
143
+ const options = multiaddrToNetConfig(ma)
144
+ this.server.listen(options, (err?: any) => {
145
+ if (err != null) {
146
+ return reject(err)
147
+ }
148
+ log('Listening on %s', this.server.address())
149
+ resolve()
138
150
  })
139
- },
140
- close: async () => {
141
- if (!server.listening) {
142
- return
143
- }
144
-
145
- await Promise.all([
146
- server.__connections.map(async maConn => await attemptClose(maConn))
147
- ])
151
+ })
152
+ }
148
153
 
149
- await new Promise<void>((resolve, reject) => {
150
- server.close(err => (err != null) ? reject(err) : resolve())
151
- })
154
+ async close () {
155
+ if (!this.server.listening) {
156
+ return
152
157
  }
153
- })
154
158
 
155
- server
156
- .on('listening', () => listener.emit('listening'))
157
- .on('error', err => listener.emit('error', err))
158
- .on('close', () => listener.emit('close'))
159
+ await Promise.all([
160
+ this.connections.map(async maConn => await attemptClose(maConn))
161
+ ])
159
162
 
160
- return listener
161
- }
163
+ await new Promise<void>((resolve, reject) => {
164
+ this.server.close(err => (err != null) ? reject(err) : resolve())
165
+ })
166
+ }
167
+
168
+ trackConn (maConn: MultiaddrConnection, socket: net.Socket) {
169
+ this.connections.push(maConn)
162
170
 
163
- function trackConn (server: ServerWithMultiaddrConnections, maConn: MultiaddrConnection) {
164
- server.__connections.push(maConn)
171
+ const untrackConn = () => {
172
+ this.connections = this.connections.filter(c => c !== maConn)
173
+ }
165
174
 
166
- const untrackConn = () => {
167
- server.__connections = server.__connections.filter(c => c !== maConn)
175
+ socket.once('close', untrackConn)
168
176
  }
177
+ }
178
+
179
+ /**
180
+ * Create listener
181
+ */
182
+ export function createListener (context: Context) {
183
+ const {
184
+ handler, upgrader
185
+ } = context
169
186
 
170
- // @ts-expect-error
171
- maConn.conn.once('close', untrackConn)
187
+ return new TCPListener(upgrader, handler)
172
188
  }
@@ -1,5 +1,5 @@
1
- import abortable from 'abortable-iterator'
2
- import debug from 'debug'
1
+ import { abortableSource } from 'abortable-iterator'
2
+ import { logger } from '@libp2p/logger'
3
3
  // @ts-expect-error no types
4
4
  import toIterable from 'stream-to-it'
5
5
  import { ipPortToMultiaddr as toMultiaddr } from '@libp2p/utils/ip-port-to-multiaddr'
@@ -8,7 +8,7 @@ import type { Socket } from 'net'
8
8
  import type { Multiaddr } from '@multiformats/multiaddr'
9
9
  import type { MultiaddrConnection } from '@libp2p/interfaces/transport'
10
10
 
11
- const log = debug('libp2p:tcp:socket')
11
+ const log = logger('libp2p:tcp:socket')
12
12
 
13
13
  interface ToConnectionOptions {
14
14
  listeningAddr?: Multiaddr
@@ -21,7 +21,7 @@ interface ToConnectionOptions {
21
21
  * Convert a socket into a MultiaddrConnection
22
22
  * https://github.com/libp2p/interface-transport#multiaddrconnection
23
23
  */
24
- export const toConnection = (socket: Socket, options?: ToConnectionOptions) => {
24
+ export const toMultiaddrConnection = (socket: Socket, options?: ToConnectionOptions) => {
25
25
  options = options ?? {}
26
26
 
27
27
  // Check if we are connected on a unix path
@@ -38,7 +38,7 @@ export const toConnection = (socket: Socket, options?: ToConnectionOptions) => {
38
38
  const maConn: MultiaddrConnection = {
39
39
  async sink (source) {
40
40
  if ((options?.signal) != null) {
41
- source = abortable(source, options.signal)
41
+ source = abortableSource(source, options.signal)
42
42
  }
43
43
 
44
44
  try {
@@ -61,11 +61,7 @@ export const toConnection = (socket: Socket, options?: ToConnectionOptions) => {
61
61
  },
62
62
 
63
63
  // Missing Type for "abortable"
64
- source: (options.signal != null) ? abortable(source, options.signal) : source,
65
-
66
- conn: socket,
67
-
68
- localAddr: options.localAddr ?? toMultiaddr(socket.localAddress ?? '', socket.localPort ?? ''),
64
+ source: (options.signal != null) ? abortableSource(source, options.signal) : source,
69
65
 
70
66
  // If the remote address was passed, use it - it may have the peer ID encapsulated
71
67
  remoteAddr: options.remoteAddr ?? toMultiaddr(socket.remoteAddress ?? '', socket.remotePort ?? ''),
package/.aegir.cjs DELETED
@@ -1,8 +0,0 @@
1
- module.exports = {
2
- build: {
3
- config: {
4
- platform: 'node'
5
- },
6
- bundlesizeMax: '44KB'
7
- }
8
- }