Skip to content

Commit 252166e

Browse files
committed
chore: use maConn
1 parent 4c88bcd commit 252166e

14 files changed

+370
-264
lines changed

README.md

+79
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,69 @@ js-libp2p-utp
2020

2121
[Vasco Santos](https://github.com/vasco-santos).
2222

23+
## Table of Contents
24+
25+
- [Install](#install)
26+
- [npm](#npm)
27+
- [Usage](#usage)
28+
- [API](#api)
29+
- [Contribute](#contribute)
30+
- [License](#license)
31+
- [Acknowledgements](#acknowledgements)
32+
33+
## Install
34+
35+
### npm
36+
37+
```sh
38+
> npm install libp2p-utp
39+
```
40+
41+
```js
42+
const UTP = require('libp2p-utp')
43+
const multiaddr = require('multiaddr')
44+
const pipe = require('it-pipe')
45+
const { collect } = require('streaming-iterables')
46+
47+
// A simple upgrader that just returns the MultiaddrConnection
48+
const upgrader = {
49+
upgradeInbound: maConn => maConn,
50+
upgradeOutbound: maConn => maConn
51+
}
52+
53+
const utp = new UTP({ upgrader })
54+
55+
const listener = utp.createListener((socket) => {
56+
console.log('new connection opened')
57+
pipe(
58+
['hello'],
59+
socket
60+
)
61+
})
62+
63+
const addr = multiaddr('/ip4/127.0.0.1/udp/6000/utp')
64+
await listener.listen(addr)
65+
console.log('listening')
66+
67+
const socket = await utp.dial(addr)
68+
const values = await pipe(
69+
socket,
70+
collect
71+
)
72+
console.log(`Value: ${values.toString()}`)
73+
74+
// Close connection after reading
75+
await listener.close()
76+
```
77+
78+
Outputs:
79+
80+
```sh
81+
listening
82+
new connection opened
83+
Value: hello
84+
```
85+
2386
## API
2487

2588
### Transport
@@ -30,6 +93,22 @@ js-libp2p-utp
3093

3194
[![](https://raw.githubusercontent.com/libp2p/interface-connection/master/img/badge.png)](https://github.com/libp2p/interface-connection)
3295

96+
## Contribute
97+
98+
Contributions are welcome! The libp2p implementation in JavaScript is a work in progress. As such, there's a few things you can do right now to help out:
99+
100+
- [Check out the existing issues](//github.com/libp2p/js-libp2p-utp/issues).
101+
- **Perform code reviews**.
102+
- **Add tests**. There can never be enough tests.
103+
104+
Please be aware that all interactions related to libp2p are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
105+
106+
Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
107+
33108
# Acknowledgements
34109

35110
`js-libp2p-utp` is a wrapper on top on [utp](https://github.com/mafintosh/utp) originally developed by [Mathias Buus](https://github.com/mafintosh)
111+
112+
## License
113+
114+
[MIT](LICENSE) © Protocol Labs Inc.

package.json

+14-10
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,17 @@
1414
"coverage": "aegir coverage",
1515
"coverage-publish": "aegir coverage publish --providers coveralls"
1616
},
17+
"pre-push": [
18+
"lint"
19+
],
1720
"repository": {
1821
"type": "git",
1922
"url": "https://github.com/libp2p/js-libp2p-utp.git"
2023
},
2124
"keywords": [
25+
"libp2p",
26+
"transport",
27+
"websocket",
2228
"IPFS"
2329
],
2430
"license": "MIT",
@@ -27,26 +33,24 @@
2733
},
2834
"homepage": "https://github.com/libp2p/js-libp2p-utp",
2935
"devDependencies": {
30-
"aegir": "^20.0.0",
36+
"aegir": "^20.3.1",
3137
"chai": "^4.2.0",
32-
"dirty-chai": "^2.0.1"
38+
"dirty-chai": "^2.0.1",
39+
"interface-transport": "^0.7.0",
40+
"sinon": "^7.5.0"
3341
},
3442
"dependencies": {
3543
"abortable-iterator": "^2.1.0",
3644
"class-is": "^1.1.0",
3745
"debug": "^4.1.1",
3846
"err-code": "^2.0.0",
39-
"interface-connection": "~0.3.3",
40-
"interface-transport": "^0.5.2",
4147
"ip-address": "^6.1.0",
4248
"it-pipe": "^1.0.1",
43-
"lodash.includes": "^4.3.0",
44-
"lodash.isfunction": "^3.0.9",
45-
"mafmt": "^6.0.8",
46-
"multiaddr": "^6.1.0",
49+
"libp2p-utils": "^0.1.0",
50+
"mafmt": "^7.0.0",
51+
"multiaddr": "^7.1.0",
4752
"once": "^1.4.0",
48-
"pull-stream": "^3.6.11",
49-
"stream-to-pull-stream": "^1.7.3",
53+
"stream-to-it": "^0.1.1",
5054
"streaming-iterables": "^4.1.0",
5155
"utp-native": "^2.1.4"
5256
},

src/adapter.js

-17
This file was deleted.

src/constants.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
'use strict'
22

3-
// IPFS multi-address code
4-
module.exports.IPFS_MA_CODE = 421
3+
// p2p multi-address code
4+
exports.CODE_P2P = 421
5+
exports.CODE_CIRCUIT = 290
56

6-
// Time to wait for a connection to close gracefully before destroying it
7-
// manually
8-
module.exports.CLOSE_TIMEOUT = 2000
7+
// Time to wait for a connection to close gracefully before destroying it manually
8+
exports.CLOSE_TIMEOUT = 2000

src/get-multiaddr.js

-33
This file was deleted.

src/index.js

+74-36
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,141 @@
11
'use strict'
22

3+
const assert = require('assert')
34
const debug = require('debug')
45
const log = debug('libp2p:utp')
56
const errcode = require('err-code')
67

78
const utp = require('utp-native')
89
const mafmt = require('mafmt')
910
const withIs = require('class-is')
10-
const includes = require('lodash.includes')
11-
const isFunction = require('lodash.isfunction')
12-
const { AbortError } = require('interface-transport')
13-
const Libp2pSocket = require('./socket')
14-
const createListener = require('./create-listener.js')
11+
const { AbortError } = require('abortable-iterator')
12+
13+
const { CODE_CIRCUIT, CODE_P2P, CLOSE_TIMEOUT } = require('./constants')
14+
const createListener = require('./listener.js')
15+
const toConnection = require('./socket-to-conn')
1516

1617
function noop () {}
1718

19+
/**
20+
* @class UTP
21+
*/
1822
class UTP {
23+
/**
24+
* @constructor
25+
* @param {object} options
26+
* @param {Upgrader} options.upgrader
27+
*/
28+
constructor ({ upgrader }) {
29+
assert(upgrader, 'An upgrader must be provided. See https://github.com/libp2p/interface-transport#upgrader.')
30+
this._upgrader = upgrader
31+
}
32+
33+
/**
34+
* @async
35+
* @param {Multiaddr} ma
36+
* @param {object} options
37+
* @param {AbortSignal} options.signal Used to abort dial requests
38+
* @returns {Connection} An upgraded Connection
39+
*/
1940
async dial (ma, options = {}) {
20-
const rawSocket = await this._connect(ma, options)
21-
return new Libp2pSocket(rawSocket, ma, options)
41+
const rawConn = await this._connect(ma, options)
42+
const maConn = toConnection(rawConn, { remoteAddr: ma, signal: options.signal })
43+
log('new outbound connection %s', maConn.remoteAddr)
44+
const conn = await this._upgrader.upgradeOutbound(maConn)
45+
log('outbound connection %s upgraded', maConn.remoteAddr)
46+
return conn
2247
}
2348

24-
_connect (ma, options) {
49+
/**
50+
* @private
51+
* @param {Multiaddr} ma
52+
* @param {object} options
53+
* @param {AbortSignal} options.signal Used to abort dial requests
54+
* @returns {Promise<UTP>} Resolves a UTP Socket
55+
*/
56+
_connect (ma, options = {}) {
57+
if (options.signal && options.signal.aborted) {
58+
throw new AbortError()
59+
}
60+
2561
const cOpts = ma.toOptions()
26-
log('Dialing %s:%s', cOpts.host, cOpts.port)
62+
log('dialing %s:%s', cOpts.host, cOpts.port)
2763

2864
return new Promise((resolve, reject) => {
29-
if ((options.signal || {}).aborted) {
30-
return reject(new AbortError())
31-
}
32-
3365
const start = Date.now()
34-
const rawSocket = utp.connect(cOpts)
66+
const rawSocket = utp.connect(Number(cOpts.port), cOpts.host)
3567

3668
const onError = (err) => {
37-
const msg = `Error dialing ${cOpts.host}:${cOpts.port}: ${err.message}`
38-
done(errcode(new Error(msg), err.code))
69+
err.message = `connection error ${cOpts.host}:${cOpts.port}: ${err.message}`
70+
done(err)
3971
}
4072

4173
const onTimeout = () => {
42-
log('Timeout dialing %s:%s', cOpts.host, cOpts.port)
43-
const err = errcode(new Error(`Timeout after ${Date.now() - start}ms`), 'ETIMEDOUT')
74+
log('connnection timeout %s:%s', cOpts.host, cOpts.port)
75+
const err = errcode(new Error(`connection timeout after ${Date.now() - start}ms`), 'ERR_CONNECT_TIMEOUT')
4476
// Note: this will result in onError() being called
4577
rawSocket.emit('error', err)
4678
}
4779

4880
const onConnect = () => {
49-
log('Connected to %s:%s', cOpts.host, cOpts.port)
50-
done(null, rawSocket)
81+
log('connection opened %s:%s', cOpts.host, cOpts.port)
82+
done(null)
5183
}
5284

5385
const onAbort = () => {
54-
log('Dial to %s:%s aborted', cOpts.host, cOpts.port)
86+
log('connection aborted %s:%s', cOpts.host, cOpts.port)
5587
done(new AbortError())
5688
}
5789

58-
const done = (err, res) => {
90+
const done = (err) => {
5991
rawSocket.removeListener('error', onError)
6092
rawSocket.removeListener('timeout', onTimeout)
6193
rawSocket.removeListener('connect', onConnect)
6294
options.signal && options.signal.removeEventListener('abort', onAbort)
6395

64-
err ? reject(err) : resolve(res)
96+
err ? reject(err) : resolve(rawSocket)
6597
}
6698

6799
rawSocket.once('error', onError)
68-
rawSocket.once('timeout', onTimeout)
69100
rawSocket.once('connect', onConnect)
70-
rawSocket.on('close', () => rawSocket.destroy())
101+
rawSocket.setTimeout(CLOSE_TIMEOUT, onTimeout)
71102
options.signal && options.signal.addEventListener('abort', onAbort)
72103
})
73104
}
74105

106+
/**
107+
* Creates a UTP listener. The provided `handler` function will be called
108+
* anytime a new incoming Connection has been successfully upgraded via
109+
* `upgrader.upgradeInbound`.
110+
* @param {object} [options]
111+
* @param {function (Connection)} handler
112+
* @returns {Listener} A UTP listener
113+
*/
75114
createListener (options, handler) {
76-
if (isFunction(options)) {
115+
if (typeof options === 'function') {
77116
handler = options
78117
options = {}
79118
}
80119

81120
handler = handler || noop
82121

83-
return createListener(handler)
122+
return createListener({ handler, upgrader: this._upgrader }, options)
84123
}
85124

125+
/**
126+
* Takes a list of `Multiaddr`s and returns only valid UTP addresses
127+
* @param {Multiaddr[]} multiaddrs
128+
* @returns {Multiaddr[]} Valid UTP multiaddrs
129+
*/
86130
filter (multiaddrs) {
87-
if (!Array.isArray(multiaddrs)) {
88-
multiaddrs = [multiaddrs]
89-
}
131+
multiaddrs = Array.isArray(multiaddrs) ? multiaddrs : [multiaddrs]
90132

91133
return multiaddrs.filter((ma) => {
92-
if (includes(ma.protoNames(), 'p2p-circuit')) {
134+
if (ma.protoCodes().includes(CODE_CIRCUIT)) {
93135
return false
94136
}
95137

96-
if (includes(ma.protoNames(), 'ipfs')) {
97-
ma = ma.decapsulate('ipfs')
98-
}
99-
100-
return mafmt.UTP.matches(ma)
138+
return mafmt.UTP.matches(ma.decapsulateCode(CODE_P2P))
101139
})
102140
}
103141
}

0 commit comments

Comments
 (0)