From 2397cf5851f97996517be3c1f7da09d4a45b90f1 Mon Sep 17 00:00:00 2001 From: Vasco Santos Date: Tue, 24 Sep 2019 18:30:38 +0200 Subject: [PATCH] chore: use multiaddr-conn --- README.md | 29 +++- package.json | 28 ++-- src/adapter.js | 17 --- src/constants.js | 9 +- src/index.js | 206 +++++++++++++---------------- src/listener.js | 101 ++++++++++++++ src/socket-to-conn.js | 100 ++++++++++++++ src/socket.js | 88 ------------ src/utils.js | 4 +- test/browser.js | 8 +- test/compliance.spec.js | 53 ++++++++ test/node.js | 11 +- test/transport/dial.js | 5 +- test/transport/discovery.js | 2 +- test/transport/filter.js | 25 ++-- test/transport/instance.spec.js | 7 +- test/transport/listen.js | 4 - test/transport/valid-connection.js | 44 ------ test/utils.spec.js | 24 ++-- 19 files changed, 442 insertions(+), 323 deletions(-) delete mode 100644 src/adapter.js create mode 100644 src/listener.js create mode 100644 src/socket-to-conn.js delete mode 100644 src/socket.js create mode 100644 test/compliance.spec.js delete mode 100644 test/transport/valid-connection.js diff --git a/README.md b/README.md index d4c0ec91..88faae22 100644 --- a/README.md +++ b/README.md @@ -54,8 +54,35 @@ const ws2 = new WStar({ wrtc: electronWebRTC() }) ```JavaScript const WStar = require('libp2p-webrtc-star') +const multiaddr = require('multiaddr') +const pipe = require('it-pipe') +const { collect } = require('streaming-iterables') -const ws = new WStar() +const addr = multiaddr('/ip4/188.166.203.82/tcp/20000/wss/p2p-webrtc-star/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooo2a') + +const ws = new WStar({ upgrader }) + +const listener = ws.createListener((socket) => { + console.log('new connection opened') + pipe( + ['hello'], + socket + ) +}) + +await listener.listen(addr) +console.log('listening') + +const socket = await ws.dial(addr) +const values = await pipe( + socket, + collect +) + +console.log(`Value: ${values.toString()}`) + +// Close connection after reading +await listener.close() ``` ## API diff --git a/package.json b/package.json index 58fa5606..a93ec733 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "coverage-publish": "aegir coverage --provider coveralls" }, "pre-push": [ - "test" + "lint" ], "engines": { "node": ">=10.0.0", @@ -45,32 +45,34 @@ }, "homepage": "https://github.com/libp2p/js-libp2p-webrtc-star#readme", "devDependencies": { - "aegir": "^20.0.0", + "aegir": "^20.3.1", "chai": "^4.2.0", "dirty-chai": "^2.0.1", "electron-webrtc": "~0.3.0", + "interface-discovery": "~0.1.1", + "interface-transport": "libp2p/interface-transport#chore/skip-abort-while-reading-for-webrtc", "prom-client": "^11.5.3", - "wrtc": "~0.4.1" + "wrtc": "~0.4.2" }, "dependencies": { - "@hapi/hapi": "^18.3.2", - "@hapi/inert": "^5.2.1", + "@hapi/hapi": "^18.4.0", + "@hapi/inert": "^5.2.2", "abortable-iterator": "^2.1.0", "class-is": "^1.1.0", "debug": "^4.1.1", "epimetheus": "^1.0.92", "err-code": "^2.0.0", - "interface-connection": "~0.3.3", - "interface-transport": "^0.5.2", "it-pipe": "^1.0.1", - "mafmt": "^6.0.8", + "libp2p-utils": "^0.1.0", + "mafmt": "^7.0.0", "minimist": "^1.2.0", - "multiaddr": "^6.1.0", + "multiaddr": "^7.1.0", "peer-id": "~0.13.2", - "peer-info": "~0.16.0", - "simple-peer": "^9.5.0", - "socket.io": "^2.2.0", - "socket.io-client": "^2.2.0", + "peer-info": "~0.17.0", + "simple-peer": "^9.6.0", + "socket.io": "^2.3.0", + "socket.io-client": "^2.3.0", + "stream-to-it": "^0.1.1", "streaming-iterables": "^4.1.0", "webrtcsupport": "github:ipfs/webrtcsupport" }, diff --git a/src/adapter.js b/src/adapter.js deleted file mode 100644 index df071aef..00000000 --- a/src/adapter.js +++ /dev/null @@ -1,17 +0,0 @@ -'use strict' - -const { Adapter } = require('interface-transport') -const withIs = require('class-is') -const WebRTCStar = require('.') - -// Legacy adapter to old transport & connection interface -class WebRTCStarAdapter extends Adapter { - constructor () { - super(new WebRTCStar()) - } -} - -module.exports = withIs(WebRTCStarAdapter, { - className: 'WebRTCStar', - symbolName: '@libp2p/js-libp2p-webrtc-star/webrtcstar' -}) diff --git a/src/constants.js b/src/constants.js index 7c9048c8..b7ab8fe2 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1,5 +1,8 @@ 'use strict' -// Time to wait for a connection to close gracefully before destroying it -// manually -module.exports.CLOSE_TIMEOUT = 2000 +// p2p multi-address code +exports.CODE_P2P = 421 +exports.CODE_CIRCUIT = 290 + +// Time to wait for a connection to close gracefully before destroying it manually +exports.CLOSE_TIMEOUT = 2000 diff --git a/src/index.js b/src/index.js index a642efee..7d9fffdc 100644 --- a/src/index.js +++ b/src/index.js @@ -2,31 +2,40 @@ const debug = require('debug') const log = debug('libp2p:webrtc-star') +const assert = require('assert') +const { EventEmitter } = require('events') const errcode = require('err-code') -const { AbortError } = require('interface-transport') +const withIs = require('class-is') + +const { AbortError } = require('abortable-iterator') +const SimplePeer = require('simple-peer') +const webrtcSupport = require('webrtcsupport') const multiaddr = require('multiaddr') const mafmt = require('mafmt') -const withIs = require('class-is') -const io = require('socket.io-client') -const { EventEmitter } = require('events') -const SimplePeer = require('simple-peer') const PeerId = require('peer-id') const PeerInfo = require('peer-info') -const webrtcSupport = require('webrtcsupport') -const { cleanUrlSIO, cleanMultiaddr } = require('./utils') -const Libp2pSocket = require('./socket') +const { CODE_CIRCUIT } = require('./constants') +const createListener = require('./listener') +const toConnection = require('./socket-to-conn') +const { cleanMultiaddr } = require('./utils') function noop () { } -const sioOptions = { - transports: ['websocket'], - 'force new connection': true -} - +/** + * @class WebRTCStar + */ class WebRTCStar { + /** + * @constructor + * @param {object} options + * @param {Upgrader} options.upgrader + */ constructor (options = {}) { + assert(options.upgrader, 'An upgrader must be provided. See https://github.com/libp2p/interface-transport#upgrader.') + this._upgrader = options.upgrader + this.maSelf = undefined this.sioOptions = { @@ -38,6 +47,9 @@ class WebRTCStar { this.wrtc = options.wrtc } + this.listenersRefs = {} + + // Discovery this.discovery = new EventEmitter() this.discovery.tag = 'webRTCStar' this.discovery._isStarted = false @@ -47,74 +59,92 @@ class WebRTCStar { this.discovery.stop = () => { this.discovery._isStarted = false } - - this.listenersRefs = {} this._peerDiscovered = this._peerDiscovered.bind(this) } + /** + * @async + * @param {Multiaddr} ma + * @param {object} options + * @param {AbortSignal} options.signal Used to abort dial requests + * @returns {Connection} An upgraded Connection + */ async dial (ma, options = {}) { - options = { - ...options, + const rawConn = await this._connect(ma, options) + const maConn = toConnection(rawConn, { remoteAddr: ma, signal: options.signal }) + log('new outbound connection %s', maConn.remoteAddr) + const conn = await this._upgrader.upgradeOutbound(maConn) + log('outbound connection %s upgraded', maConn.remoteAddr) + return conn + } + + /** + * @private + * @param {Multiaddr} ma + * @param {object} options + * @param {AbortSignal} options.signal Used to abort dial requests + * @returns {Promise} Resolves a SimplePeer Webrtc channel + */ + _connect (ma, options = {}) { + if (options.signal && options.signal.aborted) { + throw new AbortError() + } + + const spOptions = { initiator: true, trickle: false } // Use custom WebRTC implementation - if (this.wrtc) { options.wrtc = this.wrtc } + if (this.wrtc) { spOptions.wrtc = this.wrtc } - const rawConn = await this._connect(ma, options) - - return new Libp2pSocket(rawConn, ma, options) - } - - _connect (ma, options) { - const cma = ma.decapsulate('/p2p-webrtc-star') - const cOpts = cma.toOptions() - log('Dialing %s:%s', cOpts.host, cOpts.port) + const cOpts = ma.toOptions() const intentId = (~~(Math.random() * 1e9)).toString(36) + Date.now() - const sioClient = this .listenersRefs[Object.keys(this.listenersRefs)[0]].io return new Promise((resolve, reject) => { - if ((options.signal || {}).aborted) { - return reject(new AbortError()) - } - const start = Date.now() - const channel = new SimplePeer(options) + let connected + + log('dialing %s:%s', cOpts.host, cOpts.port) + const channel = new SimplePeer(spOptions) const onError = (err) => { - const msg = `Error dialing ${cOpts.host}:${cOpts.port}: ${err.message}` - done(errcode(new Error(msg), err.code)) + if (!connected) { + err.message = `connection error ${cOpts.host}:${cOpts.port}: ${err.message}` + done(err) + } } const onTimeout = () => { - log('Timeout dialing %s:%s', cOpts.host, cOpts.port) - const err = errcode(new Error(`Timeout after ${Date.now() - start}ms`), 'ETIMEDOUT') + log('connnection timeout %s:%s', cOpts.host, cOpts.port) + const err = errcode(new Error(`connection timeout after ${Date.now() - start}ms`), 'ERR_CONNECT_TIMEOUT') // Note: this will result in onError() being called channel.emit('error', err) } const onConnect = () => { - log('Connected to %s:%s', cOpts.host, cOpts.port) - done(null, channel) + connected = true + + log('connection opened %s:%s', cOpts.host, cOpts.port) + done(null) } const onAbort = () => { - log('Dial to %s:%s aborted', cOpts.host, cOpts.port) + log('connection aborted %s:%s', cOpts.host, cOpts.port) channel.destroy() done(new AbortError()) } - const done = (err, res) => { + const done = (err) => { channel.removeListener('error', onError) channel.removeListener('timeout', onTimeout) channel.removeListener('connect', onConnect) options.signal && options.signal.removeEventListener('abort', onAbort) - err ? reject(err) : resolve(res) + err ? reject(err) : resolve(channel) } channel.once('error', onError) @@ -140,7 +170,7 @@ class WebRTCStar { } if (offer.intentId !== intentId || !offer.answer) { - reject(errcode(new Error('invalid offer received'), 'ERR_INVALID_OFFER')) + return } channel.signal(offer.signal) @@ -148,6 +178,14 @@ class WebRTCStar { }) } + /** + * Creates a WebrtcStar listener. The provided `handler` function will be called + * anytime a new incoming Connection has been successfully upgraded via + * `upgrader.upgradeInbound`. + * @param {object} [options] + * @param {function (Connection)} handler + * @returns {Listener} A WebrtcStar listener + */ createListener (options, handler) { if (!webrtcSupport.support && !this.wrtc) { throw errcode(new Error('no WebRTC support'), 'ERR_NO_WEBRTC_SUPPORT') @@ -160,83 +198,19 @@ class WebRTCStar { handler = handler || noop - const listener = new EventEmitter() - - listener.listen = (ma) => { - this.maSelf = ma - const sioUrl = cleanUrlSIO(ma) - - return new Promise((resolve, reject) => { - log('Dialing to Signalling Server on: ' + sioUrl) - listener.io = io.connect(sioUrl, sioOptions) - - const incommingDial = (offer) => { - if (offer.answer || offer.err) { - return - } - - const spOptions = { trickle: false } - - // Use custom WebRTC implementation - if (this.wrtc) { spOptions.wrtc = this.wrtc } - - const channel = new SimplePeer(spOptions) - const conn = new Libp2pSocket(channel) - - channel.once('connect', () => { - listener.emit('connection', conn) - handler(conn) - }) - - channel.once('signal', (signal) => { - offer.signal = signal - offer.answer = true - listener.io.emit('ss-handshake', offer) - }) - - channel.signal(offer.signal) - } - - listener.io.once('connect_error', (err) => reject(err)) - listener.io.once('error', (err) => { - listener.emit('error', err) - listener.emit('close') - }) - - listener.io.on('ws-handshake', incommingDial) - listener.io.on('ws-peer', this._peerDiscovered) - - listener.io.on('connect', () => { - listener.io.emit('ss-join', ma.toString()) - }) - - listener.io.once('connect', () => { - listener.emit('listening') - resolve() - }) - }) - } - - listener.close = () => { - listener.io.emit('ss-leave') - listener.emit('close') - } - - listener.getAddrs = () => { - return [this.maSelf] - } - - this.listenersRefs[multiaddr.toString()] = listener - return listener + return createListener({ handler, upgrader: this._upgrader }, this, options) } + /** + * Takes a list of `Multiaddr`s and returns only valid TCP addresses + * @param {Multiaddr[]} multiaddrs + * @returns {Multiaddr[]} Valid TCP multiaddrs + */ filter (multiaddrs) { - if (!Array.isArray(multiaddrs)) { - multiaddrs = [multiaddrs] - } + multiaddrs = Array.isArray(multiaddrs) ? multiaddrs : [multiaddrs] return multiaddrs.filter((ma) => { - if (ma.protoNames().indexOf('p2p-circuit') > -1) { + if (ma.protoCodes().includes(CODE_CIRCUIT)) { return false } @@ -250,7 +224,7 @@ class WebRTCStar { log('Peer Discovered:', maStr) maStr = cleanMultiaddr(maStr) - const split = maStr.split('/ipfs/') + const split = maStr.split('/p2p/') const peerIdStr = split[split.length - 1] const peerId = PeerId.createFromB58String(peerIdStr) const peerInfo = new PeerInfo(peerId) diff --git a/src/listener.js b/src/listener.js new file mode 100644 index 00000000..a99e82f0 --- /dev/null +++ b/src/listener.js @@ -0,0 +1,101 @@ +'use strict' + +const EventEmitter = require('events') +const log = require('debug')('libp2p:libp2p:webrtc-star:listener') + +const multiaddr = require('multiaddr') + +const io = require('socket.io-client') +const SimplePeer = require('simple-peer') + +const toConnection = require('./socket-to-conn') +const { cleanUrlSIO } = require('./utils') + +const sioOptions = { + transports: ['websocket'], + 'force new connection': true +} + +module.exports = ({ handler, upgrader }, WebRTCStar, options = {}) => { + const listener = new EventEmitter() + + listener.__connections = [] + listener.listen = (ma) => { + WebRTCStar.maSelf = ma + const sioUrl = cleanUrlSIO(ma) + + log('Dialing to Signalling Server on: ' + sioUrl) + listener.io = io.connect(sioUrl, sioOptions) + + return new Promise((resolve, reject) => { + const incommingDial = async (offer) => { + if (offer.answer || offer.err) { + return + } + + const spOptions = { trickle: false } + + // Use custom WebRTC implementation + if (WebRTCStar.wrtc) { spOptions.wrtc = WebRTCStar.wrtc } + + const channel = new SimplePeer(spOptions) + + const maConn = toConnection(channel) + log('new inbound connection %s', maConn.remoteAddr) + + const conn = await upgrader.upgradeInbound(maConn) + log('inbound connection %s upgraded', maConn.remoteAddr) + + trackConn(listener, maConn) + + channel.once('connect', () => { + listener.emit('connection', conn) + handler(conn) + }) + + channel.once('signal', (signal) => { + offer.signal = signal + offer.answer = true + listener.io.emit('ss-handshake', offer) + }) + + channel.signal(offer.signal) + } + + listener.io.once('connect_error', (err) => reject(err)) + listener.io.once('error', (err) => { + listener.emit('error', err) + listener.emit('close') + }) + + listener.io.on('ws-handshake', incommingDial) + listener.io.on('ws-peer', WebRTCStar._peerDiscovered) + + listener.io.on('connect', () => { + listener.io.emit('ss-join', ma.toString()) + }) + + listener.io.once('connect', () => { + listener.emit('listening') + resolve() + }) + }) + } + + listener.close = () => { + listener.__connections.forEach(maConn => maConn.close()) + listener.io && listener.io.emit('ss-leave') + listener.emit('close') + } + + listener.getAddrs = () => { + return [WebRTCStar.maSelf] + } + + WebRTCStar.listenersRefs[multiaddr.toString()] = listener + return listener +} + +function trackConn (listener, maConn) { + listener.__connections.push(maConn) +} diff --git a/src/socket-to-conn.js b/src/socket-to-conn.js new file mode 100644 index 00000000..81ce4363 --- /dev/null +++ b/src/socket-to-conn.js @@ -0,0 +1,100 @@ +'use strict' + +const abortable = require('abortable-iterator') +const toIterable = require('stream-to-it') + +const { CLOSE_TIMEOUT } = require('./constants') +const toMultiaddr = require('libp2p-utils/src/ip-port-to-multiaddr') + +const debug = require('debug') +const log = debug('libp2p:libp2p:webrtc-star:socket') +log.error = debug('libp2p:libp2p:webrtc-star:socket:error') + +// Convert a socket into a MultiaddrConnection +// https://github.com/libp2p/interface-transport#multiaddrconnection +module.exports = (socket, options = {}) => { + const { sink, source } = toIterable.duplex(socket) + + const maConn = { + async sink (source) { + if (options.signal) { + source = abortable(source, options.signal) + } + + try { + await sink((async function * () { + for await (const chunk of source) { + // Convert BufferList to Buffer + yield Buffer.isBuffer(chunk) ? chunk : chunk.slice() + } + })()) + } catch (err) { + // If aborted we can safely ignore + if (err.type !== 'aborted') { + // If the source errored the socket will already have been destroyed by + // toIterable.duplex(). If the socket errored it will already be + // destroyed. There's nothing to do here except log the error & return. + log.error(err) + } + } + }, + + source: options.signal ? abortable(source, options.signal) : source, + + conn: socket, + + localAddr: socket.localAddress && socket.localPort + ? toMultiaddr(socket.localAddress, socket.localPort) : undefined, + + // If the remote address was passed, use it - it may have the peer ID encapsulated + remoteAddr: options.remoteAddr || (socket.remoteAddress && socket.remotePort + ? toMultiaddr(socket.remoteAddress, socket.remotePort) : undefined), + + timeline: { open: Date.now() }, + + close () { + if (socket.destroyed) return + + return new Promise((resolve, reject) => { + const start = Date.now() + + // Attempt to end the socket. If it takes longer to close than the + // timeout, destroy it manually. + const timeout = setTimeout(() => { + if (maConn.remoteAddr) { + const { host, port } = maConn.remoteAddr.toOptions() + log('timeout closing socket to %s:%s after %dms, destroying it manually', + host, port, Date.now() - start) + } + + if (!socket.destroyed) { + socket.destroy() + } + }, CLOSE_TIMEOUT) + + socket.once('close', () => { + clearTimeout(timeout) + maConn.timeline.close = Date.now() + resolve() + }) + + socket.end(err => { + if (err) return reject(err) + maConn.timeline.close = Date.now() + resolve() + }) + }) + } + } + + socket.once('close', () => { + // In instances where `close` was not explicitly called, + // such as an iterable stream ending, ensure we have set the close + // timeline + if (!maConn.timeline.close) { + maConn.timeline.close = Date.now() + } + }) + + return maConn +} diff --git a/src/socket.js b/src/socket.js deleted file mode 100644 index 9e41a693..00000000 --- a/src/socket.js +++ /dev/null @@ -1,88 +0,0 @@ -'use strict' - -const abortable = require('abortable-iterator') -// const toIterable = require('stream-to-it') - -const debug = require('debug') -const log = debug('libp2p:tcp:socket') - -const c = require('./constants') - -class Libp2pSocket { - constructor (rawSocket, ma, opts = {}) { - this._rawSocket = rawSocket - this._ma = ma - - this.sink = this._sink(opts) - this.source = opts.signal - ? abortable(this._rawSocket, opts.signal) : this._rawSocket - } - - _sink (opts) { - // By default, close when the source is exhausted - const closeOnEnd = opts.closeOnEnd !== false - - return async (source) => { - try { - const src = opts.signal ? abortable(source, opts.signal) : source - await this._write(src, closeOnEnd) - } catch (err) { - // If the connection is aborted just close the socket - if (err.type === 'aborted') { - return this.close() - } - - throw err - } - } - } - - async _write (source, closeOnEnd) { - for await (const data of source) { - if (this._rawSocket.destroyed) { - const cOpts = this._ma.toOptions() - throw new Error('Cannot write %d bytes to destroyed socket %s:%s', - data.length, cOpts.host, cOpts.port) - } - - const flushed = this._rawSocket.write(data) - if (!flushed) { - await new Promise((resolve) => this._rawSocket.once('drain', resolve)) - } - } - - if (closeOnEnd) { - await this.close() - } - } - - close (opts = {}) { - if (this._rawSocket.pending || this._rawSocket.destroyed) { - return - } - - return new Promise((resolve, reject) => { - const start = Date.now() - - // Attempt to end the socket. If it takes longer to close than the - // timeout, destroy it manually. - const timeout = setTimeout(() => { - const cOpts = this._ma.toOptions() - log('Timeout closing socket to %s:%s after %dms, destroying it manually', - cOpts.host, cOpts.port, Date.now() - start) - this._rawSocket.destroy() - resolve() - }, opts.timeout || c.CLOSE_TIMEOUT) - - this._rawSocket.once('close', () => clearTimeout(timeout)) - - this._rawSocket.end((err) => err ? reject(err) : resolve()) - }) - } - - getObservedAddrs () { - return [this._ma] - } -} - -module.exports = Libp2pSocket diff --git a/src/utils.js b/src/utils.js index 13b39d58..5fc9e257 100644 --- a/src/utils.js +++ b/src/utils.js @@ -35,9 +35,9 @@ function cleanMultiaddr (maStr) { return tupple[0] === 421 // ipfs code })[0] - ma = ma.decapsulate('ipfs') + ma = ma.decapsulate('p2p') ma = ma.encapsulate('/p2p-webrtc-star') - ma = ma.encapsulate(`/ipfs/${tuppleIPFS[1]}`) + ma = ma.encapsulate(`/p2p/${tuppleIPFS[1]}`) maStr = ma.toString() } diff --git a/test/browser.js b/test/browser.js index 8620fa88..a04133c2 100644 --- a/test/browser.js +++ b/test/browser.js @@ -3,12 +3,16 @@ const WStar = require('..') +const mockUpgrader = { + upgradeInbound: maConn => maConn, + upgradeOutbound: maConn => maConn +} + const create = () => { - return new WStar() + return new WStar({ upgrader: mockUpgrader }) } require('./transport/dial.js')(create) require('./transport/listen.js')(create) require('./transport/discovery.js')(create) require('./transport/filter.js')(create) -require('./transport/valid-connection.js')(create) diff --git a/test/compliance.spec.js b/test/compliance.spec.js new file mode 100644 index 00000000..c473b3e2 --- /dev/null +++ b/test/compliance.spec.js @@ -0,0 +1,53 @@ +/* eslint-env mocha */ +'use strict' + +const wrtc = require('wrtc') + +const sinon = require('sinon') +const testsTransport = require('interface-transport') +const testsDiscovery = require('interface-discovery') +const multiaddr = require('multiaddr') + +const WStar = require('../src') + +describe('interface-transport compliance', () => { + testsTransport({ + setup ({ upgrader }) { + const ws = new WStar({ upgrader, wrtc: wrtc }) + + const base = (id) => { + return `/ip4/127.0.0.1/tcp/15555/ws/p2p-webrtc-star/p2p/${id}` + } + + const addrs = [ + multiaddr(base('QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooo2a')), + multiaddr(base('QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooo2b')), + multiaddr(base('QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooo2c')) + ] + + // Used by the dial tests to simulate a delayed connect + const connector = { + delay () {}, + restore () { + sinon.restore() + } + } + + return { transport: ws, addrs, connector } + } + }) +}) + +describe('interface-discovery compliance', () => { + testsDiscovery({ + setup () { + const mockUpgrader = { + upgradeInbound: maConn => maConn, + upgradeOutbound: maConn => maConn + } + const ws = new WStar({ upgrader: mockUpgrader, wrtc: wrtc }) + + return ws.discovery + } + }) +}) diff --git a/test/node.js b/test/node.js index 228f8064..a45bb880 100644 --- a/test/node.js +++ b/test/node.js @@ -7,30 +7,33 @@ const WStar = require('..') require('./sig-server.js') +const mockUpgrader = { + upgradeInbound: maConn => maConn, + upgradeOutbound: maConn => maConn +} + describe('transport: with wrtc', () => { const create = () => { - return new WStar({ wrtc: wrtc }) + return new WStar({ upgrader: mockUpgrader, wrtc: wrtc }) } require('./transport/dial.js')(create) require('./transport/listen.js')(create) require('./transport/discovery.js')(create) require('./transport/filter.js')(create) - require('./transport/valid-connection.js')(create) require('./transport/reconnect.node.js')(create) }) // TODO: Electron-webrtc is currently unreliable on linux describe.skip('transport: with electron-webrtc', () => { const create = () => { - return new WStar({ wrtc: electronWebRTC() }) + return new WStar({ upgrader: mockUpgrader, wrtc: electronWebRTC() }) } require('./transport/dial.js')(create) require('./transport/listen.js')(create) require('./transport/discovery.js')(create) require('./transport/filter.js')(create) - require('./transport/valid-connection.js')(create) // TODO ensure that nodes from wrtc close properly (race issue in travis) // require('./transport/reconnect.node.js')(create) }) diff --git a/test/transport/dial.js b/test/transport/dial.js index ad72cdd9..9e673638 100644 --- a/test/transport/dial.js +++ b/test/transport/dial.js @@ -22,7 +22,7 @@ module.exports = (create) => { const maHSIP = '/ip4/188.166.203.82/tcp/20000' const maLS = '/ip4/127.0.0.1/tcp/15555' - const maGen = (base, id) => multiaddr(`${base}/wss/p2p-webrtc-star/ipfs/${id}`) // https + const maGen = (base, id) => multiaddr(`${base}/wss/p2p-webrtc-star/p2p/${id}`) // https // const maGen = (base, id) => multiaddr(`${base}/ws/p2p-webrtc-star/ipfs/${id}`) if (process.env.WEBRTC_STAR_REMOTE_SIGNAL_DNS) { @@ -66,8 +66,7 @@ module.exports = (create) => { expect(values).to.eql([data]) }) - // TODO: RE-ENABLE - it.skip('dial offline / non-exist()ent node on IPv4, check promise rejected', async function (done) { + it('dial offline / non-exist()ent node on IPv4, check promise rejected', async function () { this.timeout(20 * 1000) const maOffline = multiaddr('/ip4/127.0.0.1/tcp/15555/ws/p2p-webrtc-star/ipfs/ABCD') diff --git a/test/transport/discovery.js b/test/transport/discovery.js index a884b80b..18ca486a 100644 --- a/test/transport/discovery.js +++ b/test/transport/discovery.js @@ -13,7 +13,7 @@ module.exports = (create) => { let ws1 let ws1Listener const base = (id) => { - return `/ip4/127.0.0.1/tcp/15555/ws/p2p-webrtc-star/ipfs/${id}` + return `/ip4/127.0.0.1/tcp/15555/ws/p2p-webrtc-star/p2p/${id}` } const ma1 = multiaddr(base('QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooo3A')) diff --git a/test/transport/filter.js b/test/transport/filter.js index 5a1b6895..9345ab4f 100644 --- a/test/transport/filter.js +++ b/test/transport/filter.js @@ -5,6 +5,7 @@ const chai = require('chai') const dirtyChai = require('dirty-chai') const expect = chai.expect chai.use(dirtyChai) + const multiaddr = require('multiaddr') module.exports = (create) => { @@ -13,18 +14,18 @@ module.exports = (create) => { const ws = create() const maArr = [ - multiaddr('/ip4/127.0.0.1/tcp/9090/ws/p2p-webrtc-star/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo1'), + multiaddr('/ip4/127.0.0.1/tcp/9090/ws/p2p-webrtc-star/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo1'), multiaddr('/ip4/127.0.0.1/tcp/9090/ws/p2p-webrtc-star'), - multiaddr('/dnsaddr/libp2p.io/ws/p2p-webrtc-star/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo1'), - multiaddr('/dnsaddr/signal.libp2p.io/ws/p2p-webrtc-star/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo1'), - multiaddr('/dnsaddr/signal.libp2p.io/wss/p2p-webrtc-star/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo1'), - multiaddr('/ip4/127.0.0.1/tcp/9090/ws/p2p-webrtc-star/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo2'), - multiaddr('/ip4/127.0.0.1/tcp/9090/ws/p2p-webrtc-star/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo3'), - multiaddr('/ip4/127.0.0.1/tcp/9090/ws/p2p-webrtc-star/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo4'), - multiaddr('/ip4/127.0.0.1/tcp/9090/ws/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo4'), - multiaddr('/ip4/127.0.0.1/tcp/9090/p2p-webrtc-star/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo4'), - multiaddr('/ip4/127.0.0.1/tcp/9090/p2p-webrtc-star/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo4' + - '/p2p-circuit/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo1') + multiaddr('/dnsaddr/libp2p.io/ws/p2p-webrtc-star/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo1'), + multiaddr('/dnsaddr/signal.libp2p.io/ws/p2p-webrtc-star/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo1'), + multiaddr('/dnsaddr/signal.libp2p.io/wss/p2p-webrtc-star/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo1'), + multiaddr('/ip4/127.0.0.1/tcp/9090/ws/p2p-webrtc-star/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo2'), + multiaddr('/ip4/127.0.0.1/tcp/9090/ws/p2p-webrtc-star/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo3'), + multiaddr('/ip4/127.0.0.1/tcp/9090/ws/p2p-webrtc-star/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo4'), + multiaddr('/ip4/127.0.0.1/tcp/9090/ws/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo4'), + multiaddr('/ip4/127.0.0.1/tcp/9090/p2p-webrtc-star/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo4'), + multiaddr('/ip4/127.0.0.1/tcp/9090/p2p-webrtc-star/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo4' + + '/p2p-circuit/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo1') ] const filtered = ws.filter(maArr) @@ -33,7 +34,7 @@ module.exports = (create) => { it('filter a single addr for this transport', () => { const ws = create() - const ma = multiaddr('/ip4/127.0.0.1/tcp/9090/ws/p2p-webrtc-star/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo1') + const ma = multiaddr('/ip4/127.0.0.1/tcp/9090/ws/p2p-webrtc-star/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo1') const filtered = ws.filter(ma) expect(filtered.length).to.equal(1) diff --git a/test/transport/instance.spec.js b/test/transport/instance.spec.js index ecd8eb33..8e83391a 100644 --- a/test/transport/instance.spec.js +++ b/test/transport/instance.spec.js @@ -8,9 +8,14 @@ chai.use(dirtyChai) const WebRTCStar = require('../../src') +const mockUpgrader = { + upgradeInbound: maConn => maConn, + upgradeOutbound: maConn => maConn +} + describe('instantiate the transport', () => { it('create', () => { - const wstar = new WebRTCStar() + const wstar = new WebRTCStar({ upgrader: mockUpgrader }) expect(wstar).to.exist() }) diff --git a/test/transport/listen.js b/test/transport/listen.js index ea143f18..3d3d85a0 100644 --- a/test/transport/listen.js +++ b/test/transport/listen.js @@ -51,10 +51,6 @@ module.exports = (create) => { await p }) - it.skip('close listener with connections, through timeout', () => { - // TODO ? Should this apply ? - }) - it.skip('listen on IPv6 addr', () => { // TODO IPv6 not supported yet }) diff --git a/test/transport/valid-connection.js b/test/transport/valid-connection.js deleted file mode 100644 index 907bac17..00000000 --- a/test/transport/valid-connection.js +++ /dev/null @@ -1,44 +0,0 @@ -/* eslint-env mocha */ -'use strict' - -const chai = require('chai') -const dirtyChai = require('dirty-chai') -const expect = chai.expect -chai.use(dirtyChai) -const multiaddr = require('multiaddr') -const pipe = require('it-pipe') - -module.exports = (create) => { - describe('valid Connection', () => { - let ws1 - - const base = (id) => { - return `/ip4/127.0.0.1/tcp/15555/ws/p2p-webrtc-star/ipfs/${id}` - } - const ma1 = multiaddr(base('QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooo3A')) - - let ws2 - const ma2 = multiaddr(base('QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooo3B')) - - let conn - - before(async () => { - // first - ws1 = create() - const listener1 = ws1.createListener((conn) => pipe(conn, conn)) - - // second - ws2 = create() - const listener2 = ws2.createListener((conn) => pipe(conn, conn)) - - await Promise.all([listener1.listen(ma1), listener2.listen(ma2)]) - - conn = await ws1.dial(ma2) - }) - - it('get observed addrs', () => { - const addrs = conn.getObservedAddrs() - expect(addrs[0].toString()).to.equal(ma2.toString()) - }) - }) -} diff --git a/test/utils.spec.js b/test/utils.spec.js index 480d9d95..a08fa89d 100644 --- a/test/utils.spec.js +++ b/test/utils.spec.js @@ -7,23 +7,23 @@ const dirtyChai = require('dirty-chai') const expect = chai.expect chai.use(dirtyChai) const multiaddr = require('multiaddr') -const cleanMultiaddr = require('../src/utils').cleanMultiaddr -const cleanUrlSIO = require('../src/utils').cleanUrlSIO +const { cleanMultiaddr } = require('../src/utils') +const { cleanUrlSIO } = require('../src/utils') describe('utils', () => { - const legacyMultiaddrStringDNS = '/libp2p-webrtc-star/dns4/star-signal.cloud.ipfs.team/tcp/443/wss/ipfs/QmWxLfixekyv6GAzvDEtXfXjj7gb1z3G8i5aQNHLhw1zA1' - const legacyMultiaddrStringIP = '/libp2p-webrtc-star/ip4/127.0.0.1/tcp/1212/wss/ipfs/QmWxLfixekyv6GAzvDEtXfXjj7gb1z3G8i5aQNHLhw1zA1' + const legacyMultiaddrStringDNS = '/libp2p-webrtc-star/dns4/star-signal.cloud.ipfs.team/tcp/443/wss/p2p/QmWxLfixekyv6GAzvDEtXfXjj7gb1z3G8i5aQNHLhw1zA1' + const legacyMultiaddrStringIP = '/libp2p-webrtc-star/ip4/127.0.0.1/tcp/1212/wss/p2p/QmWxLfixekyv6GAzvDEtXfXjj7gb1z3G8i5aQNHLhw1zA1' - const modernMultiaddrStringDNS = '/dns4/star-signal.cloud.ipfs.team/tcp/443/wss/p2p-webrtc-star/ipfs/QmWxLfixekyv6GAzvDEtXfXjj7gb1z3G8i5aQNHLhw1zA1' - const modernMultiaddrStringIP = '/ip4/127.0.0.1/tcp/1212/wss/p2p-webrtc-star/ipfs/QmWxLfixekyv6GAzvDEtXfXjj7gb1z3G8i5aQNHLhw1zA1' + const modernMultiaddrStringDNS = '/dns4/star-signal.cloud.ipfs.team/tcp/443/wss/p2p-webrtc-star/p2p/QmWxLfixekyv6GAzvDEtXfXjj7gb1z3G8i5aQNHLhw1zA1' + const modernMultiaddrStringIP = '/ip4/127.0.0.1/tcp/1212/wss/p2p-webrtc-star/p2p/QmWxLfixekyv6GAzvDEtXfXjj7gb1z3G8i5aQNHLhw1zA1' - const modernMultiaddrStringDNS2 = '/dns4/star-signal.cloud.ipfs.team/tcp/9999/wss/p2p-webrtc-star/ipfs/QmWxLfixekyv6GAzvDEtXfXjj7gb1z3G8i5aQNHLhw1zA1' - const modernMultiaddrStringDNS3 = '/dns4/star-signal.cloud.ipfs.team/tcp/80/ws/p2p-webrtc-star/ipfs/QmWxLfixekyv6GAzvDEtXfXjj7gb1z3G8i5aQNHLhw1zA1' - const modernMultiaddrStringDNS4 = '/dns4/star-signal.cloud.ipfs.team/tcp/8080/ws/p2p-webrtc-star/ipfs/QmWxLfixekyv6GAzvDEtXfXjj7gb1z3G8i5aQNHLhw1zA1' + const modernMultiaddrStringDNS2 = '/dns4/star-signal.cloud.ipfs.team/tcp/9999/wss/p2p-webrtc-star/p2p/QmWxLfixekyv6GAzvDEtXfXjj7gb1z3G8i5aQNHLhw1zA1' + const modernMultiaddrStringDNS3 = '/dns4/star-signal.cloud.ipfs.team/tcp/80/ws/p2p-webrtc-star/p2p/QmWxLfixekyv6GAzvDEtXfXjj7gb1z3G8i5aQNHLhw1zA1' + const modernMultiaddrStringDNS4 = '/dns4/star-signal.cloud.ipfs.team/tcp/8080/ws/p2p-webrtc-star/p2p/QmWxLfixekyv6GAzvDEtXfXjj7gb1z3G8i5aQNHLhw1zA1' - const invalidMultiaddrStringDNS = '/dns4/star-signal.cloud.ipfs.team/udp/8080/wss/p2p-webrtc-star/ipfs/QmWxLfixekyv6GAzvDEtXfXjj7gb1z3G8i5aQNHLhw1zA1' - const invalidMultiaddrStringDNS2 = '/dns4/star-signal.cloud.ipfs.team/tcp/8080/p2p-webrtc-star/ipfs/QmWxLfixekyv6GAzvDEtXfXjj7gb1z3G8i5aQNHLhw1zA1' - const invalidMultiaddrStringDNS3 = '/dns4/star-signal.cloud.ipfs.team/ws/p2p-webrtc-star/ipfs/QmWxLfixekyv6GAzvDEtXfXjj7gb1z3G8i5aQNHLhw1zA1' + const invalidMultiaddrStringDNS = '/dns4/star-signal.cloud.ipfs.team/udp/8080/wss/p2p-webrtc-star/p2p/QmWxLfixekyv6GAzvDEtXfXjj7gb1z3G8i5aQNHLhw1zA1' + const invalidMultiaddrStringDNS2 = '/dns4/star-signal.cloud.ipfs.team/tcp/8080/p2p-webrtc-star/p2p/QmWxLfixekyv6GAzvDEtXfXjj7gb1z3G8i5aQNHLhw1zA1' + const invalidMultiaddrStringDNS3 = '/dns4/star-signal.cloud.ipfs.team/ws/p2p-webrtc-star/p2p/QmWxLfixekyv6GAzvDEtXfXjj7gb1z3G8i5aQNHLhw1zA1' // Create actual multiaddrs const modernMultiaddrDNS = multiaddr(modernMultiaddrStringDNS)