Skip to content
This repository was archived by the owner on Aug 29, 2023. It is now read-only.

Commit 3249e02

Browse files
authored
feat: add types (#145)
1 parent 4789cf1 commit 3249e02

File tree

9 files changed

+223
-90
lines changed

9 files changed

+223
-90
lines changed

.aegir.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module.exports = {
2+
build: {
3+
config: {
4+
platform: 'node'
5+
}
6+
}
7+
}

.github/workflows/main.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ jobs:
1313
steps:
1414
- uses: actions/checkout@v2
1515
- run: npm install
16-
- run: npx aegir lint
16+
- run: npm run lint
1717
- run: npx aegir dep-check -- -i wrtc -i electron-webrtc
18+
- run: npm run build
1819
test-node:
1920
needs: check
2021
runs-on: ${{ matrix.os }}

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ package-lock.json
33
coverage
44
.nyc_output
55
docs
6+
7+
dist

package.json

+8-5
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66
"main": "src/index.js",
77
"scripts": {
88
"lint": "aegir lint",
9+
"build": "aegir build",
910
"test": "aegir test -t node",
1011
"test:node": "aegir test -t node",
11-
"release": "aegir release -t node --no-build",
12-
"release-minor": "aegir release -t node --type minor --no-build",
13-
"release-major": "aegir-release -t node --type major --no-build",
12+
"release": "aegir release -t node",
13+
"release-minor": "aegir release -t node --type minor",
14+
"release-major": "aegir-release -t node --type major",
1415
"coverage": "nyc --reporter=text --reporter=lcov npm run test:node"
1516
},
1617
"pre-push": [
@@ -37,10 +38,12 @@
3738
"engines": {
3839
"node": ">=14.0.0"
3940
},
41+
"types": "dist/src/index.d.ts",
4042
"devDependencies": {
41-
"aegir": "^33.0.0",
43+
"@types/debug": "^4.1.5",
44+
"aegir": "^33.2.0",
4245
"it-pipe": "^1.1.0",
43-
"libp2p-interfaces": "^0.9.0",
46+
"libp2p-interfaces": "^0.11.0",
4447
"sinon": "^10.0.1",
4548
"streaming-iterables": "^5.0.2"
4649
},

src/index.js

+19-10
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
const net = require('net')
44
const mafmt = require('mafmt')
5+
// Missing Type
6+
// @ts-ignore
57
const withIs = require('class-is')
68
const errCode = require('err-code')
79
const log = require('debug')('libp2p:tcp')
@@ -14,6 +16,9 @@ const { CODE_CIRCUIT, CODE_P2P } = require('./constants')
1416
/**
1517
* @typedef {import('multiaddr').Multiaddr} Multiaddr
1618
* @typedef {import('libp2p-interfaces/src/connection').Connection} Connection
19+
* @typedef {import('libp2p-interfaces/src/transport/types').Upgrader} Upgrader
20+
* @typedef {import('libp2p-interfaces/src/transport/types').Listener} Listener
21+
* @typedef {import('net').Socket} Socket
1722
*/
1823

1924
class TCP {
@@ -33,8 +38,8 @@ class TCP {
3338
* @async
3439
* @param {Multiaddr} ma
3540
* @param {object} options
36-
* @param {AbortSignal} options.signal - Used to abort dial requests
37-
* @returns {Connection} An upgraded Connection
41+
* @param {AbortSignal} [options.signal] - Used to abort dial requests
42+
* @returns {Promise<Connection>} An upgraded Connection
3843
*/
3944
async dial (ma, options) {
4045
options = options || {}
@@ -50,7 +55,7 @@ class TCP {
5055
* @private
5156
* @param {Multiaddr} ma
5257
* @param {object} options
53-
* @param {AbortSignal} options.signal - Used to abort dial requests
58+
* @param {AbortSignal} [options.signal] - Used to abort dial requests
5459
* @returns {Promise<Socket>} Resolves a TCP Socket
5560
*/
5661
_connect (ma, options = {}) {
@@ -65,13 +70,13 @@ class TCP {
6570
log('dialing %j', cOpts)
6671
const rawSocket = net.connect(cOpts)
6772

68-
const onError = err => {
73+
const onError = /** @param {Error} err */ err => {
6974
err.message = `connection error ${cOpts.host}:${cOpts.port}: ${err.message}`
7075
done(err)
7176
}
7277

7378
const onTimeout = () => {
74-
log('connnection timeout %s:%s', cOpts.host, cOpts.port)
79+
log('connection timeout %s:%s', cOpts.host, cOpts.port)
7580
const err = errCode(new Error(`connection timeout after ${Date.now() - start}ms`), 'ERR_CONNECT_TIMEOUT')
7681
// Note: this will result in onError() being called
7782
rawSocket.emit('error', err)
@@ -88,7 +93,7 @@ class TCP {
8893
done(new AbortError())
8994
}
9095

91-
const done = err => {
96+
const done = /** @param {Error} [err] */ err => {
9297
rawSocket.removeListener('error', onError)
9398
rawSocket.removeListener('timeout', onTimeout)
9499
rawSocket.removeListener('connect', onConnect)
@@ -110,17 +115,21 @@ class TCP {
110115
* anytime a new incoming Connection has been successfully upgraded via
111116
* `upgrader.upgradeInbound`.
112117
*
113-
* @param {*} [options]
114-
* @param {function(Connection)} handler
118+
* @param {* | function(Connection):void} options
119+
* @param {function(Connection):void} [handler]
115120
* @returns {Listener} A TCP listener
116121
*/
117122
createListener (options, handler) {
123+
let listenerHandler
124+
118125
if (typeof options === 'function') {
119-
handler = options
126+
listenerHandler = options
120127
options = {}
128+
} else {
129+
listenerHandler = handler
121130
}
122131
options = options || {}
123-
return createListener({ handler, upgrader: this._upgrader }, options)
132+
return createListener({ handler: listenerHandler, upgrader: this._upgrader }, options)
124133
}
125134

126135
/**

src/listener.js

+91-58
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,30 @@
33
const net = require('net')
44
const EventEmitter = require('events')
55
const debug = require('debug')
6-
const log = debug('libp2p:tcp:listener')
7-
log.error = debug('libp2p:tcp:listener:error')
8-
6+
const log = Object.assign(
7+
debug('libp2p:tcp:listener'),
8+
{ error: debug('libp2p:tcp:listener:error') })
99
const toConnection = require('./socket-to-conn')
1010
const { CODE_P2P } = require('./constants')
1111
const {
1212
getMultiaddrs,
1313
multiaddrToNetConfig
1414
} = require('./utils')
1515

16+
/**
17+
* @typedef {import('multiaddr').Multiaddr} Multiaddr
18+
* @typedef {import('libp2p-interfaces/src/connection').Connection} Connection
19+
* @typedef {import('libp2p-interfaces/src/transport/types').Upgrader} Upgrader
20+
* @typedef {import('libp2p-interfaces/src/transport/types').MultiaddrConnection} MultiaddrConnection
21+
* @typedef {import('libp2p-interfaces/src/transport/types').Listener} Listener
22+
* @typedef {import('net').Server & {__connections: MultiaddrConnection[]}} Server
23+
*/
24+
1625
/**
1726
* Attempts to close the given maConn. If a failure occurs, it will be logged.
1827
*
1928
* @private
20-
* @param {import('libp2p-interfaces/src/transport/types').MultiaddrConnection} maConn
29+
* @param {MultiaddrConnection} maConn
2130
*/
2231
async function attemptClose (maConn) {
2332
try {
@@ -27,13 +36,80 @@ async function attemptClose (maConn) {
2736
}
2837
}
2938

39+
/**
40+
* Create listener
41+
*
42+
* @param {object} context
43+
* @param {function(Connection):void} context.handler
44+
* @param {Upgrader} context.upgrader
45+
* @param {*} options
46+
* @returns {Listener}
47+
*/
3048
module.exports = ({ handler, upgrader }, options) => {
31-
const listener = new EventEmitter()
49+
/** @type {Server} */
50+
// eslint-disable-next-line prefer-const
51+
let server
52+
53+
/** @type {string | null} */
54+
let peerId
55+
56+
/** @type {Multiaddr} */
57+
let listeningAddr
58+
59+
const listener = Object.assign(new EventEmitter(), {
60+
getAddrs: () => {
61+
/** @type {Multiaddr[]} */
62+
let addrs = []
63+
/** @type {import('net').AddressInfo} */
64+
// @ts-ignore
65+
const address = server.address()
66+
67+
if (!address) {
68+
throw new Error('Listener is not ready yet')
69+
}
70+
71+
// Because TCP will only return the IPv6 version
72+
// we need to capture from the passed multiaddr
73+
if (listeningAddr.toString().startsWith('/ip4')) {
74+
addrs = addrs.concat(getMultiaddrs('ip4', address.address, address.port))
75+
} else if (address.family === 'IPv6') {
76+
addrs = addrs.concat(getMultiaddrs('ip6', address.address, address.port))
77+
}
78+
79+
return addrs.map(ma => peerId ? ma.encapsulate(`/p2p/${peerId}`) : ma)
80+
},
81+
listen: async (/** @type {Multiaddr} */ ma) => {
82+
listeningAddr = ma
83+
peerId = ma.getPeerId()
84+
85+
if (peerId) {
86+
listeningAddr = ma.decapsulateCode(CODE_P2P)
87+
}
88+
89+
return new Promise((resolve, reject) => {
90+
const options = multiaddrToNetConfig(listeningAddr)
91+
server.listen(options, (/** @type {any} */ err) => {
92+
if (err) return reject(err)
93+
log('Listening on %s', server.address())
94+
resolve(undefined)
95+
})
96+
})
97+
},
98+
close: async () => {
99+
if (!server.listening) return
100+
101+
return new Promise((resolve, reject) => {
102+
server.__connections.forEach(maConn => attemptClose(maConn))
103+
server.close(err => err ? reject(err) : resolve(undefined))
104+
})
105+
}
106+
})
32107

33-
const server = net.createServer(async socket => {
108+
server = Object.assign(net.createServer(async socket => {
34109
// Avoid uncaught errors caused by unstable connections
35110
socket.on('error', err => log('socket error', err))
36111

112+
/** @type {MultiaddrConnection} */
37113
let maConn
38114
let conn
39115
try {
@@ -42,6 +118,7 @@ module.exports = ({ handler, upgrader }, options) => {
42118
conn = await upgrader.upgradeInbound(maConn)
43119
} catch (err) {
44120
log.error('inbound connection failed', err)
121+
// @ts-ignore
45122
return attemptClose(maConn)
46123
}
47124

@@ -51,73 +128,29 @@ module.exports = ({ handler, upgrader }, options) => {
51128

52129
if (handler) handler(conn)
53130
listener.emit('connection', conn)
54-
})
131+
}),
132+
// Keep track of open connections to destroy in case of timeout
133+
{ __connections: [] })
55134

56135
server
57136
.on('listening', () => listener.emit('listening'))
58137
.on('error', err => listener.emit('error', err))
59138
.on('close', () => listener.emit('close'))
60139

61-
// Keep track of open connections to destroy in case of timeout
62-
server.__connections = []
63-
64-
listener.close = () => {
65-
if (!server.listening) return
66-
67-
return new Promise((resolve, reject) => {
68-
server.__connections.forEach(maConn => attemptClose(maConn))
69-
server.close(err => err ? reject(err) : resolve())
70-
})
71-
}
72-
73-
let peerId, listeningAddr
74-
75-
listener.listen = ma => {
76-
listeningAddr = ma
77-
peerId = ma.getPeerId()
78-
79-
if (peerId) {
80-
listeningAddr = ma.decapsulateCode(CODE_P2P)
81-
}
82-
83-
return new Promise((resolve, reject) => {
84-
const options = multiaddrToNetConfig(listeningAddr)
85-
server.listen(options, err => {
86-
if (err) return reject(err)
87-
log('Listening on %s', server.address())
88-
resolve()
89-
})
90-
})
91-
}
92-
93-
listener.getAddrs = () => {
94-
let addrs = []
95-
const address = server.address()
96-
97-
if (!address) {
98-
throw new Error('Listener is not ready yet')
99-
}
100-
101-
// Because TCP will only return the IPv6 version
102-
// we need to capture from the passed multiaddr
103-
if (listeningAddr.toString().startsWith('/ip4')) {
104-
addrs = addrs.concat(getMultiaddrs('ip4', address.address, address.port))
105-
} else if (address.family === 'IPv6') {
106-
addrs = addrs.concat(getMultiaddrs('ip6', address.address, address.port))
107-
}
108-
109-
return addrs.map(ma => peerId ? ma.encapsulate(`/p2p/${peerId}`) : ma)
110-
}
111-
112140
return listener
113141
}
114142

143+
/**
144+
* @param {Server} server
145+
* @param {MultiaddrConnection} maConn
146+
*/
115147
function trackConn (server, maConn) {
116148
server.__connections.push(maConn)
117149

118150
const untrackConn = () => {
119151
server.__connections = server.__connections.filter(c => c !== maConn)
120152
}
121153

154+
// @ts-ignore
122155
maConn.conn.once('close', untrackConn)
123156
}

0 commit comments

Comments
 (0)