From e44dca3d7c427a9bb241fa2f44f9f09330402994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kr=C3=BCger?= Date: Fri, 15 Jun 2018 13:32:29 +0200 Subject: [PATCH 01/11] feat: Rewrite using exchange --- src/index.js | 169 +++++++++++------------------- src/sig-server/bin.js | 28 ----- src/sig-server/config.js | 21 ---- src/sig-server/index.html | 65 ------------ src/sig-server/index.js | 56 ---------- src/sig-server/routes-ws/index.js | 122 --------------------- src/utils.js | 49 --------- 7 files changed, 59 insertions(+), 451 deletions(-) delete mode 100755 src/sig-server/bin.js delete mode 100644 src/sig-server/config.js delete mode 100644 src/sig-server/index.html delete mode 100644 src/sig-server/index.js delete mode 100644 src/sig-server/routes-ws/index.js delete mode 100644 src/utils.js diff --git a/src/index.js b/src/index.js index cb488242..edb6aff8 100644 --- a/src/index.js +++ b/src/index.js @@ -2,51 +2,35 @@ const debug = require('debug') const log = debug('libp2p:webrtc-star') + const multiaddr = require('multiaddr') const mafmt = require('mafmt') +const Id = require('peer-id') + const withIs = require('class-is') -const io = require('socket.io-client') const EE = require('events').EventEmitter +const assert = require('assert') + const SimplePeer = require('simple-peer') -const PeerId = require('peer-id') -const PeerInfo = require('peer-info') +const webrtcSupport = require('webrtcsupport') + const Connection = require('interface-connection').Connection const toPull = require('stream-to-pull-stream') -const once = require('once') -const setImmediate = require('async/setImmediate') -const webrtcSupport = require('webrtcsupport') -const utils = require('./utils') -const cleanUrlSIO = utils.cleanUrlSIO -const cleanMultiaddr = utils.cleanMultiaddr +const setImmediate = require('async/setImmediate') +const once = require('once') const noop = once(() => {}) -const sioOptions = { - transports: ['websocket'], - 'force new connection': true -} - class WebRTCStar { constructor (options) { options = options || {} - this.maSelf = undefined - - this.sioOptions = { - transports: ['websocket'], - 'force new connection': true - } - if (options.wrtc) { this.wrtc = options.wrtc } - this.discovery = new EE() - this.discovery.start = (callback) => { setImmediate(callback) } - this.discovery.stop = (callback) => { setImmediate(callback) } - - this.listenersRefs = {} - this._peerDiscovered = this._peerDiscovered.bind(this) + assert(options.exchange, 'Exchange missing!') + this.exchange = options.exchange } dial (ma, options, callback) { @@ -57,10 +41,9 @@ class WebRTCStar { callback = callback ? once(callback) : noop - const intentId = (~~(Math.random() * 1e9)).toString(36) + Date.now() + let b58 = ma.toString().split('ipfs/').pop() - const sioClient = this - .listenersRefs[Object.keys(this.listenersRefs)[0]].io + log('dialing %s %s', ma, b58) const spOptions = { initiator: true, trickle: false } @@ -73,43 +56,41 @@ class WebRTCStar { let connected = false channel.on('signal', (signal) => { - sioClient.emit('ss-handshake', { - intentId: intentId, - srcMultiaddr: this.maSelf.toString(), - dstMultiaddr: ma.toString(), - signal: signal - }) - }) - - channel.once('timeout', () => callback(new Error('timeout'))) - - channel.once('error', (err) => { - if (!connected) { callback(err) } - }) + log('dial#%s got signal', ma) + this.exchange.request(Id.createFromB58String(b58), 'webrtc', Buffer.from(JSON.stringify({signal, ma: '/ip4/0.0.0.0/tcp/127.0.0.1'})), (err, result) => { // TODO: fix this + if (err) { + log('dial#%s exchange failed %s', ma, err) + return callback(err) + } - // NOTE: aegir segfaults if we do .once on the socket.io event emitter and we - // are clueless as to why. - sioClient.on('ws-handshake', (offer) => { - if (offer.intentId === intentId && offer.err) { - return callback(new Error(offer.err)) - } + let offer + try { + offer = JSON.parse(String(result)) + } catch (err) { + log('dial#%s malformed response %s', ma, err) + return callback(err) + } - if (offer.intentId !== intentId || !offer.answer) { - return - } + channel.once('connect', () => { + log('dial#%s connected', ma) + connected = true + conn.destroy = channel.destroy.bind(channel) - channel.once('connect', () => { - connected = true - conn.destroy = channel.destroy.bind(channel) + channel.once('close', () => conn.destroy()) - channel.once('close', () => conn.destroy()) + conn.getObservedAddrs = (callback) => callback(null, [ma]) - conn.getObservedAddrs = (callback) => callback(null, [ma]) + callback(null, conn) + }) - callback(null, conn) + channel.signal(offer.signal) }) + }) - channel.signal(offer.signal) + channel.once('timeout', () => callback(new Error('timeout'))) + + channel.once('error', (err) => { + if (!connected) { callback(err) } }) return conn @@ -130,36 +111,19 @@ class WebRTCStar { return setImmediate(() => callback(new Error('no WebRTC support'))) } - this.maSelf = ma + log('listening on %s', ma) - const sioUrl = cleanUrlSIO(ma) + let ns = listener.ns = 'webrtc' // TODO: should this be ma.toString() ? + listener.ma = ma - log('Dialing to Signalling Server on: ' + sioUrl) - - listener.io = io.connect(sioUrl, sioOptions) - - listener.io.once('connect_error', callback) - listener.io.once('error', (err) => { - listener.emit('error', err) - listener.emit('close') - }) + this.exchange.listen(ns, (request, cb) => { + let offer - 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') - callback() - }) - - const self = this - function incommingDial (offer) { - if (offer.answer || offer.err) { - return + try { + offer = JSON.parse(String(request)) + } catch (err) { + log('got malformed offer', err) + return cb(err) } const spOptions = { trickle: false } @@ -172,8 +136,10 @@ class WebRTCStar { const conn = new Connection(toPull.duplex(channel)) channel.once('connect', () => { + log('connected') + conn.getObservedAddrs = (callback) => { - return callback(null, [offer.srcMultiaddr]) + return callback(null, [multiaddr(offer.ma)]) // TODO: this isn't really safe AT ALL... } listener.emit('connection', conn) @@ -181,31 +147,26 @@ class WebRTCStar { }) channel.once('signal', (signal) => { - offer.signal = signal - offer.answer = true - listener.io.emit('ss-handshake', offer) + log('sending back signal') + cb(null, Buffer.from(JSON.stringify({signal, ma: listener.ma.toString()}))) }) channel.signal(offer.signal) - } + }) } listener.close = (callback) => { callback = callback ? once(callback) : noop - listener.io.emit('ss-leave') + this.exchange.unhandle(listener.ns) - setImmediate(() => { - listener.emit('close') - callback() - }) + setImmediate(callback) } listener.getAddrs = (callback) => { - setImmediate(() => callback(null, [this.maSelf])) + setImmediate(() => callback(null, listener.ma ? [listener.ma] : [])) } - this.listenersRefs[multiaddr.toString()] = listener return listener } @@ -222,18 +183,6 @@ class WebRTCStar { return mafmt.WebRTCStar.matches(ma) }) } - - _peerDiscovered (maStr) { - log('Peer Discovered:', maStr) - maStr = cleanMultiaddr(maStr) - - const split = maStr.split('/ipfs/') - const peerIdStr = split[split.length - 1] - const peerId = PeerId.createFromB58String(peerIdStr) - const peerInfo = new PeerInfo(peerId) - peerInfo.multiaddrs.add(multiaddr(maStr)) - this.discovery.emit('peer', peerInfo) - } } module.exports = withIs(WebRTCStar, { className: 'WebRTCStar', symbolName: '@libp2p/js-libp2p-webrtc-star/webrtcstar' }) diff --git a/src/sig-server/bin.js b/src/sig-server/bin.js deleted file mode 100755 index cdf29684..00000000 --- a/src/sig-server/bin.js +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env node - -'use strict' - -const signalling = require('./index') -const argv = require('minimist')(process.argv.slice(2)) - -let server - -signalling.start({ - port: argv.port || argv.p || process.env.PORT || 9090, - host: argv.host || argv.h || process.env.HOST || '0.0.0.0', - metrics: !(argv.disableMetrics || process.env.DISABLE_METRICS) -}, (err, _server) => { - if (err) { - throw err - } - server = _server - - console.log('Listening on:', server.info.uri) -}) - -process.on('SIGINT', () => { - server.stop(() => { - console.log('Signalling server stopped') - process.exit() - }) -}) diff --git a/src/sig-server/config.js b/src/sig-server/config.js deleted file mode 100644 index c8003d29..00000000 --- a/src/sig-server/config.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict' - -const debug = require('debug') -const log = debug('signalling-server') -log.error = debug('signalling-server:error') - -module.exports = { - log: log, - hapi: { - port: process.env.PORT || 13579, - host: '0.0.0.0', - options: { - connections: { - routes: { - cors: true - } - } - } - }, - refreshPeerListIntervalMS: 10000 -} diff --git a/src/sig-server/index.html b/src/sig-server/index.html deleted file mode 100644 index e927bddf..00000000 --- a/src/sig-server/index.html +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - Signalling Server - - - - - -
-
- Libp2p Logo -

This is a libp2p-webrtc-star signalling-server

-

Signaling Servers are used in libp2p to allow browsers and clients with restricted port-forwarding
to communicate with other peers in the libp2p network

-
- ยป Learn more -
- - - - - diff --git a/src/sig-server/index.js b/src/sig-server/index.js deleted file mode 100644 index baccf966..00000000 --- a/src/sig-server/index.js +++ /dev/null @@ -1,56 +0,0 @@ -'use strict' - -const Hapi = require('hapi') -const config = require('./config') -const log = config.log -const epimetheus = require('epimetheus') -const path = require('path') - -exports = module.exports - -exports.start = (options, callback) => { - if (typeof options === 'function') { - callback = options - options = {} - } - - const port = options.port || config.hapi.port - const host = options.host || config.hapi.host - - const http = new Hapi.Server(config.hapi.options) - - http.connection({ - port: port, - host: host - }) - - http.register({ register: require('inert') }, (err) => { - if (err) { - return callback(err) - } - - http.start((err) => { - if (err) { - return callback(err) - } - - log('signaling server has started on: ' + http.info.uri) - - http.peers = require('./routes-ws')(http, options.metrics).peers - - http.route({ - method: 'GET', - path: '/', - handler: (request, reply) => reply.file(path.join(__dirname, 'index.html'), { - confine: false - }) - }) - - callback(null, http) - }) - - if (options.metrics) { epimetheus.instrument(http) } - }) - - return http -} diff --git a/src/sig-server/routes-ws/index.js b/src/sig-server/routes-ws/index.js deleted file mode 100644 index a3ddadeb..00000000 --- a/src/sig-server/routes-ws/index.js +++ /dev/null @@ -1,122 +0,0 @@ -'use strict' - -const config = require('../config') -const log = config.log -const SocketIO = require('socket.io') -const client = require('prom-client') - -const fake = { - gauge: { - set: () => {} - }, - counter: { - inc: () => {} - } -} - -module.exports = (http, hasMetrics) => { - const io = new SocketIO(http.listener) - io.on('connection', handle) - - const peers = {} - - const peersMetric = hasMetrics ? new client.Gauge({ name: 'signalling_peers', help: 'peers online now' }) : fake.gauge - const dialsSuccessTotal = hasMetrics ? new client.Counter({ name: 'signalling_dials_total_success', help: 'sucessfully completed dials since server started' }) : fake.counter - const dialsFailureTotal = hasMetrics ? new client.Counter({ name: 'signalling_dials_total_failure', help: 'failed dials since server started' }) : fake.counter - const dialsTotal = hasMetrics ? new client.Counter({ name: 'signalling_dials_total', help: 'all dials since server started' }) : fake.counter - const joinsSuccessTotal = hasMetrics ? new client.Counter({ name: 'signalling_joins_total_success', help: 'sucessfully completed joins since server started' }) : fake.counter - const joinsFailureTotal = hasMetrics ? new client.Counter({ name: 'signalling_joins_total_failure', help: 'failed joins since server started' }) : fake.counter - const joinsTotal = hasMetrics ? new client.Counter({ name: 'signalling_joins_total', help: 'all joins since server started' }) : fake.counter - - const refreshMetrics = () => peersMetric.set(Object.keys(peers).length) - - this.peers = () => { - return peers - } - - function safeEmit (addr, event, arg) { - const peer = peers[addr] - if (!peer) { - log('trying to emit %s but peer is gone', event) - return - } - - peer.emit(event, arg) - } - - function handle (socket) { - socket.on('ss-join', join.bind(socket)) - socket.on('ss-leave', leave.bind(socket)) - socket.on('disconnect', disconnect.bind(socket)) // socket.io own event - socket.on('ss-handshake', forwardHandshake) - } - - // join this signaling server network - function join (multiaddr) { - joinsTotal.inc() - if (!multiaddr) { return joinsFailureTotal.inc() } - const socket = peers[multiaddr] = this // socket - let refreshInterval = setInterval(sendPeers, config.refreshPeerListIntervalMS) - - socket.once('ss-leave', stopSendingPeers) - socket.once('disconnect', stopSendingPeers) - - sendPeers() - - function sendPeers () { - Object.keys(peers).forEach((mh) => { - if (mh === multiaddr) { - return - } - safeEmit(mh, 'ws-peer', multiaddr) - }) - } - - function stopSendingPeers () { - if (refreshInterval) { - clearInterval(refreshInterval) - refreshInterval = null - } - } - - joinsSuccessTotal.inc() - refreshMetrics() - } - - function leave (multiaddr) { - if (!multiaddr) { return } - if (peers[multiaddr]) { - delete peers[multiaddr] - refreshMetrics() - } - } - - function disconnect () { - Object.keys(peers).forEach((mh) => { - if (peers[mh].id === this.id) { - delete peers[mh] - } - refreshMetrics() - }) - } - - // forward an WebRTC offer to another peer - function forwardHandshake (offer) { - dialsTotal.inc() - if (offer == null || typeof offer !== 'object' || !offer.srcMultiaddr || !offer.dstMultiaddr) { return dialsFailureTotal.inc() } - if (offer.answer) { - dialsSuccessTotal.inc() - safeEmit(offer.srcMultiaddr, 'ws-handshake', offer) - } else { - if (peers[offer.dstMultiaddr]) { - safeEmit(offer.dstMultiaddr, 'ws-handshake', offer) - } else { - dialsFailureTotal.inc() - offer.err = 'peer is not available' - safeEmit(offer.srcMultiaddr, 'ws-handshake', offer) - } - } - } - - return this -} diff --git a/src/utils.js b/src/utils.js deleted file mode 100644 index 13b39d58..00000000 --- a/src/utils.js +++ /dev/null @@ -1,49 +0,0 @@ -'use strict' - -const multiaddr = require('multiaddr') - -function cleanUrlSIO (ma) { - const maStrSplit = ma.toString().split('/') - const tcpProto = ma.protos()[1].name - const wsProto = ma.protos()[2].name - const tcpPort = ma.stringTuples()[1][1] - - if (tcpProto !== 'tcp' || (wsProto !== 'ws' && wsProto !== 'wss')) { - throw new Error('invalid multiaddr: ' + ma.toString()) - } - - if (!multiaddr.isName(ma)) { - return 'http://' + maStrSplit[2] + ':' + maStrSplit[4] - } - - if (wsProto === 'ws') { - return 'http://' + maStrSplit[2] + (tcpPort === 80 ? '' : ':' + tcpPort) - } - - if (wsProto === 'wss') { - return 'https://' + maStrSplit[2] + (tcpPort === 443 ? '' : ':' + tcpPort) - } -} - -function cleanMultiaddr (maStr) { - const legacy = '/libp2p-webrtc-star' - - if (maStr.indexOf(legacy) !== -1) { - maStr = maStr.substring(legacy.length, maStr.length) - let ma = multiaddr(maStr) - const tuppleIPFS = ma.stringTuples().filter((tupple) => { - return tupple[0] === 421 // ipfs code - })[0] - - ma = ma.decapsulate('ipfs') - ma = ma.encapsulate('/p2p-webrtc-star') - ma = ma.encapsulate(`/ipfs/${tuppleIPFS[1]}`) - maStr = ma.toString() - } - - return maStr -} - -exports = module.exports -exports.cleanUrlSIO = cleanUrlSIO -exports.cleanMultiaddr = cleanMultiaddr From ec5e614b044dc8e35efdc0ad4eb9294783f00de4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kr=C3=BCger?= Date: Fri, 15 Jun 2018 13:43:03 +0200 Subject: [PATCH 02/11] misc: Remove signal-server leftovers --- .aegir.js | 34 ---------------------------------- DEPLOYMENT.md | 11 ----------- Procfile | 1 - appveyor.yml | 29 ----------------------------- circle.yml | 15 --------------- package.json | 13 ------------- src/index.js | 23 ++++++++++++++++++++++- 7 files changed, 22 insertions(+), 104 deletions(-) delete mode 100644 .aegir.js delete mode 100644 DEPLOYMENT.md delete mode 100644 Procfile delete mode 100644 appveyor.yml delete mode 100644 circle.yml diff --git a/.aegir.js b/.aegir.js deleted file mode 100644 index 53573e0b..00000000 --- a/.aegir.js +++ /dev/null @@ -1,34 +0,0 @@ -'use strict' - -const sigServer = require('./src/sig-server') -let firstRun = true -let sigS - -function boot (done) { - const options = { - port: 15555, - host: '127.0.0.1', - metrics: firstRun - } - - if (firstRun) { firstRun = false } - - sigServer.start(options, (err, server) => { - if (err) { throw err } - - sigS = server - console.log('signalling on:', server.info.uri) - done() - }) -} - -function stop (done) { - sigS.stop(done) -} - -module.exports = { - hooks: { - pre: boot, - post: stop - } -} diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md deleted file mode 100644 index 86328b68..00000000 --- a/DEPLOYMENT.md +++ /dev/null @@ -1,11 +0,0 @@ -# Deployment - -We have a [dokku](https://github.com/ipfs/ops-requests/issues/31) setup ready for this to be deployed, to deploy simple do (you have to have permission first): - -```sh -# if you already have added the remote, you don't need to do it again -> git remote add dokku dokku@cloud.ipfs.team:star-signal -> git push dokku master -``` - -More info: https://github.com/libp2p/js-libp2p-webrtc-star/pull/48 diff --git a/Procfile b/Procfile deleted file mode 100644 index 26e9df8b..00000000 --- a/Procfile +++ /dev/null @@ -1 +0,0 @@ -web: npm run star-signal diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 046bf910..00000000 --- a/appveyor.yml +++ /dev/null @@ -1,29 +0,0 @@ -# Warning: This file is automatically synced from https://github.com/ipfs/ci-sync so if you want to change it, please change it there and ask someone to sync all repositories. -version: "{build}" - -environment: - matrix: - - nodejs_version: "6" - - nodejs_version: "8" - -matrix: - fast_finish: true - -install: - # Install Node.js - - ps: Install-Product node $env:nodejs_version - - # Upgrade npm - - npm install -g npm - - # Output our current versions for debugging - - node --version - - npm --version - - # Install our package dependencies - - npm install - -test_script: - - npm run test:node - -build: off diff --git a/circle.yml b/circle.yml deleted file mode 100644 index 00096937..00000000 --- a/circle.yml +++ /dev/null @@ -1,15 +0,0 @@ -# Warning: This file is automatically synced from https://github.com/ipfs/ci-sync so if you want to change it, please change it there and ask someone to sync all repositories. -machine: - node: - version: stable - -dependencies: - pre: - - google-chrome --version - - curl -L -o google-chrome.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb - - sudo dpkg -i google-chrome.deb || true - - sudo apt-get update - - sudo apt-get install -f - - sudo apt-get install --only-upgrade lsb-base - - sudo dpkg -i google-chrome.deb - - google-chrome --version diff --git a/package.json b/package.json index 9548be07..943dcf3b 100644 --- a/package.json +++ b/package.json @@ -3,13 +3,7 @@ "version": "0.15.1", "description": "libp2p WebRTC transport that includes a discovery mechanism provided by the signalling-star", "main": "src/index.js", - "bin": { - "webrtc-star": "src/sig-server/bin.js", - "star-sig": "src/sig-server/bin.js", - "star-signal": "src/sig-server/bin.js" - }, "scripts": { - "star-signal": "node src/sig-server/bin.js", "lint": "aegir lint", "build": "aegir build", "test": "aegir test -t node -t browser", @@ -61,21 +55,14 @@ "class-is": "^1.1.0", "debug": "^3.1.0", "detect-node": "^2.0.3", - "epimetheus": "^1.0.55", - "hapi": "^16.6.2", - "inert": "^4.2.1", "interface-connection": "~0.3.2", "mafmt": "^6.0.0", "minimist": "^1.2.0", "multiaddr": "^5.0.0", "once": "^1.4.0", "peer-id": "~0.10.7", - "peer-info": "~0.14.1", "pull-stream": "^3.6.8", "simple-peer": "^9.1.1", - "socket.io": "^2.1.0", - "socket.io-client": "^2.1.0", - "stream-to-pull-stream": "^1.7.2", "webrtcsupport": "github:ipfs/webrtcsupport" }, "contributors": [ diff --git a/src/index.js b/src/index.js index edb6aff8..025be3ce 100644 --- a/src/index.js +++ b/src/index.js @@ -21,6 +21,25 @@ const setImmediate = require('async/setImmediate') const once = require('once') const noop = once(() => {}) +function cleanMultiaddr (maStr) { + const legacy = '/libp2p-webrtc-star' + + if (maStr.indexOf(legacy) !== -1) { + maStr = maStr.substring(legacy.length, maStr.length) + let ma = multiaddr(maStr) + const tuppleIPFS = ma.stringTuples().filter((tupple) => { + return tupple[0] === 421 // ipfs code + })[0] + + ma = ma.decapsulate('ipfs') + ma = ma.encapsulate('/p2p-webrtc-star') + ma = ma.encapsulate(`/ipfs/${tuppleIPFS[1]}`) + maStr = ma.toString() + } + + return maStr +} + class WebRTCStar { constructor (options) { options = options || {} @@ -39,9 +58,11 @@ class WebRTCStar { options = {} } + ma = cleanMultiaddr(String(ma)) + callback = callback ? once(callback) : noop - let b58 = ma.toString().split('ipfs/').pop() + let b58 = ma.split('ipfs/').pop() log('dialing %s %s', ma, b58) From 7bd36263ad29f29f1627c11feab4fcf7f7a4dee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kr=C3=BCger?= Date: Sun, 17 Jun 2018 10:12:58 +0200 Subject: [PATCH 03/11] tests: rewrite tests (WIP) --- package.json | 2 + src/index.js | 23 +--- src/utils.js | 26 ++++ test/browser.js | 6 +- test/node.js | 16 +-- test/sig-server.js | 230 ------------------------------- test/transport/dial.js | 26 ++-- test/transport/discovery.js | 46 ------- test/transport/filter.js | 8 +- test/transport/instance.spec.js | 2 +- test/transport/listen.js | 4 +- test/transport/reconnect.node.js | 84 ----------- test/utils.js | 16 +++ test/utils.spec.js | 17 --- 14 files changed, 77 insertions(+), 429 deletions(-) create mode 100644 src/utils.js delete mode 100644 test/sig-server.js delete mode 100644 test/transport/discovery.js delete mode 100644 test/transport/reconnect.node.js create mode 100644 test/utils.js diff --git a/package.json b/package.json index 943dcf3b..eb1d708b 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "dirty-chai": "^2.0.1", "electron-webrtc": "~0.3.0", "gulp": "^3.9.1", + "interface-data-exchange-devdeps": "0.0.1", "lodash": "^4.17.10", "mafmt": "^6.0.0", "wrtc": "0.1.1" @@ -56,6 +57,7 @@ "debug": "^3.1.0", "detect-node": "^2.0.3", "interface-connection": "~0.3.2", + "libp2p-exchange-direct": "0.0.2", "mafmt": "^6.0.0", "minimist": "^1.2.0", "multiaddr": "^5.0.0", diff --git a/src/index.js b/src/index.js index 025be3ce..1a3a7832 100644 --- a/src/index.js +++ b/src/index.js @@ -21,24 +21,7 @@ const setImmediate = require('async/setImmediate') const once = require('once') const noop = once(() => {}) -function cleanMultiaddr (maStr) { - const legacy = '/libp2p-webrtc-star' - - if (maStr.indexOf(legacy) !== -1) { - maStr = maStr.substring(legacy.length, maStr.length) - let ma = multiaddr(maStr) - const tuppleIPFS = ma.stringTuples().filter((tupple) => { - return tupple[0] === 421 // ipfs code - })[0] - - ma = ma.decapsulate('ipfs') - ma = ma.encapsulate('/p2p-webrtc-star') - ma = ma.encapsulate(`/ipfs/${tuppleIPFS[1]}`) - maStr = ma.toString() - } - - return maStr -} +const {cleanMultiaddr} = require('./utils') class WebRTCStar { constructor (options) { @@ -137,7 +120,7 @@ class WebRTCStar { let ns = listener.ns = 'webrtc' // TODO: should this be ma.toString() ? listener.ma = ma - this.exchange.listen(ns, (request, cb) => { + this.exchange.handle(ns, (request, cb) => { let offer try { @@ -174,6 +157,8 @@ class WebRTCStar { channel.signal(offer.signal) }) + + setImmediate(() => callback()) } listener.close = (callback) => { diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 00000000..44533fe2 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,26 @@ +'use strict' + +const multiaddr = require('multiaddr') + +function cleanMultiaddr (maStr) { + const legacy = '/libp2p-webrtc-star' + + if (maStr.indexOf(legacy) !== -1) { + maStr = maStr.substring(legacy.length, maStr.length) + let ma = multiaddr(maStr) + const tuppleIPFS = ma.stringTuples().filter((tupple) => { + return tupple[0] === 421 // ipfs code + })[0] + + ma = ma.decapsulate('ipfs') + ma = ma.encapsulate('/p2p-webrtc-star') + ma = ma.encapsulate(`/ipfs/${tuppleIPFS[1]}`) + maStr = ma.toString() + } + + return maStr +} + +module.exports = { + cleanMultiaddr +} diff --git a/test/browser.js b/test/browser.js index 8620fa88..15297466 100644 --- a/test/browser.js +++ b/test/browser.js @@ -2,13 +2,13 @@ 'use strict' const WStar = require('..') +const Utils = require('./utils') -const create = () => { - return new WStar() +const create = async (id) => { + return new WStar({ exchange: await Utils(id) }) } 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/node.js b/test/node.js index cfd87f79..b46fb0f9 100644 --- a/test/node.js +++ b/test/node.js @@ -4,32 +4,26 @@ const wrtc = require('wrtc') const electronWebRTC = require('electron-webrtc') const WStar = require('..') - -require('./sig-server.js') +const Utils = require('./utils') describe('transport: with wrtc', () => { - const create = () => { - return new WStar({ wrtc: wrtc }) + const create = async (id) => { + return new WStar({ exchange: await Utils(id), 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) }) describe('transport: with electron-wrtc', () => { - const create = () => { - return new WStar({ wrtc: electronWebRTC() }) + const create = async (id) => { + return new WStar({ exchange: await Utils(id), 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/sig-server.js b/test/sig-server.js deleted file mode 100644 index 4ced2d68..00000000 --- a/test/sig-server.js +++ /dev/null @@ -1,230 +0,0 @@ -/* eslint-env mocha */ -'use strict' - -const chai = require('chai') -const dirtyChai = require('dirty-chai') -const expect = chai.expect -chai.use(dirtyChai) -const io = require('socket.io-client') -const parallel = require('async/parallel') -const multiaddr = require('multiaddr') - -const sigServer = require('../src/sig-server') - -describe('signalling', () => { - const sioOptions = { - transports: ['websocket'], - 'force new connection': true - } - - let sioUrl - let sigS - let c1 - let c2 - let c3 - let c4 - - const base = (id) => { - return `/ip4/127.0.0.1/tcp/9090/ws/p2p-webrtc-star/ipfs/${id}` - } - - let c1mh = multiaddr(base('QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo1')) - let c2mh = multiaddr(base('QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo2')) - let c3mh = multiaddr(base('QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo3')) - let c4mh = multiaddr(base('QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo4')) - - it('start and stop signalling server (default port)', (done) => { - sigServer.start((err, server) => { - expect(err).to.not.exist() - expect(server.info.port).to.equal(13579) - expect(server.info.protocol).to.equal('http') - expect(server.info.address).to.equal('0.0.0.0') - server.stop(done) - }) - }) - - it('start and stop signalling server (default port) and spam it with invalid requests', (done) => { - sigServer.start((err, server) => { - expect(err).to.not.exist() - expect(server.info.port).to.equal(13579) - expect(server.info.protocol).to.equal('http') - expect(server.info.address).to.equal('0.0.0.0') - const cl = io.connect(server.info.uri) - cl.on('connect', () => { - cl.emit('ss-handshake', null) - cl.emit('ss-handshake', 1) - cl.emit('ss-handshake', [1, 2, 3]) - cl.emit('ss-handshake', {}) - setTimeout(() => { - server.stop(done) - }, 1000) - }) - }) - }) - - it('start and stop signalling server (custom port)', (done) => { - const options = { - port: 12345 - } - sigServer.start(options, (err, server) => { - expect(err).to.not.exist() - expect(server.info.port).to.equal(12345) - expect(server.info.protocol).to.equal('http') - expect(server.info.address).to.equal('0.0.0.0') - server.stop(done) - }) - }) - - it('start signalling server for client tests', (done) => { - const options = { - port: 12345 - } - - sigServer.start(options, (err, server) => { - expect(err).to.not.exist() - expect(server.info.port).to.equal(12345) - expect(server.info.protocol).to.equal('http') - expect(server.info.address).to.equal('0.0.0.0') - sioUrl = server.info.uri - sigS = server - done() - }) - }) - - it('zero peers', () => { - expect(Object.keys(sigS.peers).length).to.equal(0) - }) - - it('connect one client', (done) => { - c1 = io.connect(sioUrl, sioOptions) - c1.on('connect', done) - }) - - it('connect three more clients', (done) => { - let count = 0 - - c2 = io.connect(sioUrl, sioOptions) - c3 = io.connect(sioUrl, sioOptions) - c4 = io.connect(sioUrl, sioOptions) - - c2.on('connect', connected) - c3.on('connect', connected) - c4.on('connect', connected) - - function connected () { - if (++count === 3) { done() } - } - }) - - it('ss-join first client', (done) => { - c1.emit('ss-join', c1mh.toString()) - setTimeout(() => { - expect(Object.keys(sigS.peers()).length).to.equal(1) - done() - }, 10) - }) - - it('ss-join and ss-leave second client', (done) => { - c2.emit('ss-join', c2mh.toString()) - setTimeout(() => { - expect(Object.keys(sigS.peers()).length).to.equal(2) - c2.emit('ss-leave', c2mh.toString()) - setTimeout(() => { - expect(Object.keys(sigS.peers()).length).to.equal(1) - done() - }, 10) - }, 10) - }) - - it('ss-join and disconnect third client', (done) => { - c3.emit('ss-join', c3mh.toString()) - setTimeout(() => { - expect(Object.keys(sigS.peers()).length).to.equal(2) - c3.disconnect() - setTimeout(() => { - expect(Object.keys(sigS.peers()).length).to.equal(1) - done() - }, 10) - }, 10) - }) - - it('ss-join the fourth', (done) => { - c1.once('ws-peer', (multiaddr) => { - expect(multiaddr).to.equal(c4mh.toString()) - expect(Object.keys(sigS.peers()).length).to.equal(2) - done() - }) - c4.emit('ss-join', c4mh.toString()) - }) - - it('c1 handshake c4', (done) => { - c4.once('ws-handshake', (offer) => { - offer.answer = true - c4.emit('ss-handshake', offer) - }) - - c1.once('ws-handshake', (offer) => { - expect(offer.err).to.not.exist() - expect(offer.answer).to.equal(true) - done() - }) - - c1.emit('ss-handshake', { - srcMultiaddr: c1mh.toString(), - dstMultiaddr: c4mh.toString() - }) - }) - - it('c1 handshake c2 fail (does not exist() anymore)', (done) => { - c1.once('ws-handshake', (offer) => { - expect(offer.err).to.exist() - done() - }) - - c1.emit('ss-handshake', { - srcMultiaddr: c1mh.toString(), - dstMultiaddr: c2mh.toString() - }) - }) - - it('disconnects every client', (done) => { - [c1, c2, c3, c4].forEach((c) => c.disconnect()) - done() - }) - - it('emits ws-peer every 10 seconds', function (done) { - this.timeout(50000) - let peersEmitted = 0 - - c1 = io.connect(sioUrl, sioOptions) - c2 = io.connect(sioUrl, sioOptions) - c1.emit('ss-join', 'c1') - c2.emit('ss-join', 'c2') - - c1.on('ws-peer', (p) => { - expect(p).to.be.equal('c2') - check() - }) - - function check () { - if (++peersEmitted === 2) { - done() - } - } - }) - - it('stop signalling server', (done) => { - parallel([ - (cb) => { - c1.disconnect() - cb() - }, - (cb) => { - c2.disconnect() - cb() - } - ], () => { - sigS.stop(done) - }) - }) -}) diff --git a/test/transport/dial.js b/test/transport/dial.js index 70449d41..e214bbeb 100644 --- a/test/transport/dial.js +++ b/test/transport/dial.js @@ -9,11 +9,14 @@ chai.use(dirtyChai) const multiaddr = require('multiaddr') const series = require('async/series') const pull = require('pull-stream') +const promisify = require('promisify-es6') +const Utils = require('../utils') module.exports = (create) => { describe('dial', () => { let ws1 let ws2 + let m let ma1 let ma2 @@ -39,20 +42,19 @@ module.exports = (create) => { ma2 = maGen(maLS, 'QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooo2b') } - before((done) => { - series([first, second], done) + before(async () => { + let listener - function first (next) { - ws1 = create() - const listener = ws1.createListener((conn) => pull(conn, conn)) - listener.listen(ma1, next) - } + m = await create('m') + ws1 = await create('a') + ws2 = await create('b') - function second (next) { - ws2 = create() - const listener = ws2.createListener((conn) => pull(conn, conn)) - listener.listen(ma2, next) - } + await promisify((cb) => Utils.Exchange.before(ws1.exchange, ws2.exchange, m.exchange, cb))() + + listener = ws1.createListener((conn) => pull(conn, conn)) + await promisify(listener.listen)(ma1) + listener = ws2.createListener((conn) => pull(conn, conn)) + await promisify(listener.listen)(ma2) }) it('dial on IPv4, check callback', function (done) { diff --git a/test/transport/discovery.js b/test/transport/discovery.js deleted file mode 100644 index 46868317..00000000 --- a/test/transport/discovery.js +++ /dev/null @@ -1,46 +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') - -module.exports = (create) => { - describe('peer discovery', () => { - 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')) - - it('listen on the first', (done) => { - ws1 = create() - - const listener = ws1.createListener((conn) => {}) - listener.listen(ma1, (err) => { - expect(err).to.not.exist() - done() - }) - }) - - it('listen on the second, discover the first', (done) => { - ws2 = create() - - ws1.discovery.once('peer', (peerInfo) => { - expect(peerInfo.multiaddrs.has(ma2)).to.equal(true) - done() - }) - - const listener = ws2.createListener((conn) => {}) - listener.listen(ma2, (err) => { - expect(err).to.not.exist() - }) - }) - }) -} diff --git a/test/transport/filter.js b/test/transport/filter.js index 5a1b6895..3ecb41a9 100644 --- a/test/transport/filter.js +++ b/test/transport/filter.js @@ -9,8 +9,8 @@ const multiaddr = require('multiaddr') module.exports = (create) => { describe('filter', () => { - it('filters non valid webrtc-star multiaddrs', () => { - const ws = create() + it('filters non valid webrtc-star multiaddrs', async () => { + const ws = await create('a') const maArr = [ multiaddr('/ip4/127.0.0.1/tcp/9090/ws/p2p-webrtc-star/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo1'), @@ -31,8 +31,8 @@ module.exports = (create) => { expect(filtered.length).to.equal(7) }) - it('filter a single addr for this transport', () => { - const ws = create() + it('filter a single addr for this transport', async () => { + const ws = await create('a') const ma = multiaddr('/ip4/127.0.0.1/tcp/9090/ws/p2p-webrtc-star/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSoooo1') const filtered = ws.filter(ma) diff --git a/test/transport/instance.spec.js b/test/transport/instance.spec.js index ecd8eb33..a155355a 100644 --- a/test/transport/instance.spec.js +++ b/test/transport/instance.spec.js @@ -10,7 +10,7 @@ const WebRTCStar = require('../../src') describe('instantiate the transport', () => { it('create', () => { - const wstar = new WebRTCStar() + const wstar = new WebRTCStar({ exchange: true }) expect(wstar).to.exist() }) diff --git a/test/transport/listen.js b/test/transport/listen.js index 2ca12377..f1139c22 100644 --- a/test/transport/listen.js +++ b/test/transport/listen.js @@ -14,8 +14,8 @@ module.exports = (create) => { const ma = multiaddr('/ip4/127.0.0.1/tcp/15555/ws/p2p-webrtc-star/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooooA') - before(() => { - ws = create() + before(async () => { + ws = await create('a') }) it('listen, check for callback', (done) => { diff --git a/test/transport/reconnect.node.js b/test/transport/reconnect.node.js deleted file mode 100644 index 48a35935..00000000 --- a/test/transport/reconnect.node.js +++ /dev/null @@ -1,84 +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 sigServer = require('../../src/sig-server') - -const SERVER_PORT = 13580 - -module.exports = (create) => { - describe('reconnect to signaling server', () => { - let sigS - - const base = (id) => { - return `/ip4/127.0.0.1/tcp/15555/ws/p2p-webrtc-star/ipfs/${id}` - } - - let ws1 - let ws2 - let ws3 - - const ma1 = multiaddr(base('QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooo3A')) - const ma2 = multiaddr(base('QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooo3B')) - const ma3 = multiaddr(base('QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooo3C')) - - before((done) => { - sigS = sigServer.start({ port: SERVER_PORT }, done) - }) - - after((done) => sigS.stop(done)) - - it('listen on the first', (done) => { - ws1 = create() - - const listener = ws1.createListener((conn) => {}) - listener.listen(ma1, (err) => { - expect(err).to.not.exist() - done() - }) - }) - - it('listen on the second, discover the first', (done) => { - ws2 = create() - - ws1.discovery.once('peer', (peerInfo) => { - expect(peerInfo.multiaddrs.has(ma2)).to.equal(true) - done() - }) - - const listener = ws2.createListener((conn) => {}) - listener.listen(ma2, (err) => { - expect(err).to.not.exist() - }) - }) - - it('stops the server', (done) => { - sigS.stop(done) - }) - - it('starts the server again', (done) => { - sigS = sigServer.start({ port: SERVER_PORT }, done) - }) - - it('wait a bit for clients to reconnect', (done) => { - setTimeout(done, 2000) - }) - - it('listen on the third, first discovers it', (done) => { - ws3 = create() - - const listener = ws3.createListener((conn) => {}) - listener.listen(ma3, (err) => expect(err).to.not.exist()) - - ws1.discovery.once('peer', (peerInfo) => { - expect(peerInfo.multiaddrs.has(ma3)).to.equal(true) - done() - }) - }) - }) -} diff --git a/test/utils.js b/test/utils.js new file mode 100644 index 00000000..972e4193 --- /dev/null +++ b/test/utils.js @@ -0,0 +1,16 @@ +'use strict' + +const Utils = require('interface-data-exchange/src/test/utils') +const Exchange = require('libp2p-exchange-direct/test/testconfig') +const promisify = require('promisify-es6') + +module.exports = async (id) => { + let peer = await Utils.createPeer(id, Exchange.opt['peer' + id.toUpperCase()]) + await promisify(peer.start.bind(peer))() + const exchange = new Exchange.Exchange(peer, Exchange.opt['exchange' + id.toUpperCase()]) + await promisify(exchange.start.bind(exchange))() + + return exchange +} + +module.exports.Exchange = Exchange diff --git a/test/utils.spec.js b/test/utils.spec.js index 480d9d95..3b9b1f1e 100644 --- a/test/utils.spec.js +++ b/test/utils.spec.js @@ -35,23 +35,6 @@ describe('utils', () => { const invalidMultiaddrDNS2 = multiaddr(invalidMultiaddrStringDNS2) const invalidMultiaddrDNS3 = multiaddr(invalidMultiaddrStringDNS3) - it('cleanUrlSIO webrtc-star modern', () => { - const newUrlSIOStringDNS = cleanUrlSIO(modernMultiaddrDNS) - const newUrlSIOStringDNS2 = cleanUrlSIO(modernMultiaddrDNS2) - const newUrlSIOStringDNS3 = cleanUrlSIO(modernMultiaddrDNS3) - const newUrlSIOStringDNS4 = cleanUrlSIO(modernMultiaddrDNS4) - - expect(() => cleanUrlSIO(modernMultiaddrDNS)).to.not.throw() - expect(() => cleanUrlSIO(invalidMultiaddrDNS)).to.throw(Error, 'invalid multiaddr') - expect(() => cleanUrlSIO(invalidMultiaddrDNS2)).to.throw(Error, 'invalid multiaddr') - expect(() => cleanUrlSIO(invalidMultiaddrDNS3)).to.throw(Error, 'invalid multiaddr') - - expect(newUrlSIOStringDNS).to.equal('https://star-signal.cloud.ipfs.team') - expect(newUrlSIOStringDNS2).to.equal('https://star-signal.cloud.ipfs.team:9999') - expect(newUrlSIOStringDNS3).to.equal('http://star-signal.cloud.ipfs.team') - expect(newUrlSIOStringDNS4).to.equal('http://star-signal.cloud.ipfs.team:8080') - }) - it('cleanMultiaddr webrtc-star legacy', () => { const newMultiaddrStringDNS = cleanMultiaddr(legacyMultiaddrStringDNS) const newMultiaddrStringIP = cleanMultiaddr(legacyMultiaddrStringIP) From b639e8700db623fb899d3275d70be041295f8e35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kr=C3=BCger?= Date: Sun, 17 Jun 2018 10:23:44 +0200 Subject: [PATCH 04/11] misc: lint --- test/transport/dial.js | 11 ++++++- test/transport/valid-connection.js | 47 +++++++++++++++++------------- test/utils.spec.js | 22 +------------- 3 files changed, 37 insertions(+), 43 deletions(-) diff --git a/test/transport/dial.js b/test/transport/dial.js index e214bbeb..69552f01 100644 --- a/test/transport/dial.js +++ b/test/transport/dial.js @@ -7,7 +7,7 @@ const dirtyChai = require('dirty-chai') const expect = chai.expect chai.use(dirtyChai) const multiaddr = require('multiaddr') -const series = require('async/series') +const {parallel, waterfall} = require('async') const pull = require('pull-stream') const promisify = require('promisify-es6') const Utils = require('../utils') @@ -89,5 +89,14 @@ module.exports = (create) => { it.skip('dial on IPv6', (done) => { // TODO IPv6 not supported yet }) + + after(async () => { + await new Promise((resolve, reject) => { + waterfall([ + cb => parallel([ws1.exchange, ws2.exchange, m.exchange].map(e => cb => e.stop(cb)), e => cb(e)), + cb => parallel([ws1.exchange.swarm, ws2.exchange.swarm, m.exchange.swarm].map(p => cb => p.stop(cb)), e => cb(e)) + ], e => e ? reject(e) : resolve()) + }) + }) }) } diff --git a/test/transport/valid-connection.js b/test/transport/valid-connection.js index 38e4e053..61e9102a 100644 --- a/test/transport/valid-connection.js +++ b/test/transport/valid-connection.js @@ -6,45 +6,41 @@ const dirtyChai = require('dirty-chai') const expect = chai.expect chai.use(dirtyChai) const multiaddr = require('multiaddr') -const series = require('async/series') +const {parallel, waterfall} = require('async') const pull = require('pull-stream') +const promisify = require('promisify-es6') +const Utils = require('../utils') module.exports = (create) => { describe('valid Connection', () => { + let m let ws1 + let ws2 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 ma1 = multiaddr(base('QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooo3A')) const ma2 = multiaddr(base('QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooo3B')) let conn - before(function (done) { - this.timeout(40 * 1000) - - series([first, second], dial) + before(async () => { + let listener - function first (next) { - ws1 = create() + m = await create('m') + ws1 = await create('a') + ws2 = await create('b') - const listener = ws1.createListener((conn) => pull(conn, conn)) - listener.listen(ma1, next) - } + await promisify((cb) => Utils.Exchange.before(ws1.exchange, ws2.exchange, m.exchange, cb))() - function second (next) { - ws2 = create() + listener = ws1.createListener((conn) => pull(conn, conn)) + await promisify(listener.listen)(ma1) + listener = ws2.createListener((conn) => pull(conn, conn)) + await promisify(listener.listen)(ma2) - const listener = ws2.createListener((conn) => pull(conn, conn)) - listener.listen(ma2, next) - } - - function dial () { - conn = ws1.dial(ma2, done) - } + await promisify((cb) => (conn = ws1.dial(ma2, cb)))() }) it('get observed addrs', (done) => { @@ -70,5 +66,14 @@ module.exports = (create) => { done() }) }) + + after(async () => { + await new Promise((resolve, reject) => { + waterfall([ + cb => parallel([ws1.exchange, ws2.exchange, m.exchange].map(e => cb => e.stop(cb)), e => cb(e)), + cb => parallel([ws1.exchange.swarm, ws2.exchange.swarm, m.exchange.swarm].map(p => cb => p.stop(cb)), e => cb(e)) + ], e => e ? reject(e) : resolve()) + }) + }) }) } diff --git a/test/utils.spec.js b/test/utils.spec.js index 3b9b1f1e..7b070a05 100644 --- a/test/utils.spec.js +++ b/test/utils.spec.js @@ -6,9 +6,7 @@ const chai = require('chai') 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') describe('utils', () => { const legacyMultiaddrStringDNS = '/libp2p-webrtc-star/dns4/star-signal.cloud.ipfs.team/tcp/443/wss/ipfs/QmWxLfixekyv6GAzvDEtXfXjj7gb1z3G8i5aQNHLhw1zA1' @@ -17,24 +15,6 @@ describe('utils', () => { 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 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 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' - - // Create actual multiaddrs - const modernMultiaddrDNS = multiaddr(modernMultiaddrStringDNS) - const modernMultiaddrDNS2 = multiaddr(modernMultiaddrStringDNS2) - const modernMultiaddrDNS3 = multiaddr(modernMultiaddrStringDNS3) - const modernMultiaddrDNS4 = multiaddr(modernMultiaddrStringDNS4) - - const invalidMultiaddrDNS = multiaddr(invalidMultiaddrStringDNS) - const invalidMultiaddrDNS2 = multiaddr(invalidMultiaddrStringDNS2) - const invalidMultiaddrDNS3 = multiaddr(invalidMultiaddrStringDNS3) - it('cleanMultiaddr webrtc-star legacy', () => { const newMultiaddrStringDNS = cleanMultiaddr(legacyMultiaddrStringDNS) const newMultiaddrStringIP = cleanMultiaddr(legacyMultiaddrStringIP) From 6f714c040247bb9c133c60a3c321fc8a6ade0ad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kr=C3=BCger?= Date: Sun, 17 Jun 2018 10:32:10 +0200 Subject: [PATCH 05/11] test: fix some more tests --- src/index.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index 1a3a7832..9844748e 100644 --- a/src/index.js +++ b/src/index.js @@ -112,12 +112,14 @@ class WebRTCStar { callback = callback ? once(callback) : noop if (!webrtcSupport.support && !this.wrtc) { - return setImmediate(() => callback(new Error('no WebRTC support'))) + const err = new Error('No WebRTC support') + listener.emit('error', err) + return setImmediate(() => callback(err)) } log('listening on %s', ma) - let ns = listener.ns = 'webrtc' // TODO: should this be ma.toString() ? + const ns = listener.ns = 'webrtc' // TODO: should this be ma.toString() ? listener.ma = ma this.exchange.handle(ns, (request, cb) => { @@ -133,7 +135,7 @@ class WebRTCStar { const spOptions = { trickle: false } // Use custom WebRTC implementation - if (self.wrtc) { spOptions.wrtc = self.wrtc } + if (this.wrtc) { spOptions.wrtc = self.wrtc } const channel = new SimplePeer(spOptions) @@ -158,6 +160,7 @@ class WebRTCStar { channel.signal(offer.signal) }) + listener.emit('listening') setImmediate(() => callback()) } @@ -166,6 +169,7 @@ class WebRTCStar { this.exchange.unhandle(listener.ns) + listener.emit('close') setImmediate(callback) } From a178d9ca130b1dcad20ce42f09673bcc1da72631 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kr=C3=BCger?= Date: Sun, 17 Jun 2018 11:01:54 +0200 Subject: [PATCH 06/11] chore: update exchange packages --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index eb1d708b..a8ade416 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,8 @@ "electron-webrtc": "~0.3.0", "gulp": "^3.9.1", "interface-data-exchange-devdeps": "0.0.1", + "libp2p-exchange-direct": "0.0.3", + "libp2p-exchange-rendezvous": "0.0.2", "lodash": "^4.17.10", "mafmt": "^6.0.0", "wrtc": "0.1.1" @@ -57,7 +59,6 @@ "debug": "^3.1.0", "detect-node": "^2.0.3", "interface-connection": "~0.3.2", - "libp2p-exchange-direct": "0.0.2", "mafmt": "^6.0.0", "minimist": "^1.2.0", "multiaddr": "^5.0.0", From 9498f7912432be807b4ca3eb2afb0f071c9ea0de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kr=C3=BCger?= Date: Sun, 17 Jun 2018 12:05:10 +0200 Subject: [PATCH 07/11] fix: more fixes --- src/index.js | 2 +- test/transport/dial.js | 14 +++++++------- test/transport/listen.js | 2 +- test/transport/valid-connection.js | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/index.js b/src/index.js index 9844748e..d924bc68 100644 --- a/src/index.js +++ b/src/index.js @@ -122,7 +122,7 @@ class WebRTCStar { const ns = listener.ns = 'webrtc' // TODO: should this be ma.toString() ? listener.ma = ma - this.exchange.handle(ns, (request, cb) => { + this.exchange.handle(ns, (from, request, cb) => { let offer try { diff --git a/test/transport/dial.js b/test/transport/dial.js index 69552f01..55f12c69 100644 --- a/test/transport/dial.js +++ b/test/transport/dial.js @@ -30,16 +30,16 @@ module.exports = (create) => { if (process.env.WEBRTC_STAR_REMOTE_SIGNAL_DNS) { // test with deployed signalling server using DNS console.log('Using DNS:', maHSDNS) - ma1 = maGen(maHSDNS, 'QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooo2a') - ma2 = maGen(maHSDNS, 'QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooo2b') + ma1 = maGen(maHSDNS, 'Qmf2uGBMP8VcLYAbh7katNyXyhiptYoUf1kLzbFd1jpRbf') + ma2 = maGen(maHSDNS, 'QmY6yfBGWghP7NcW3gFeJC9FgRQe2rbV8BkfyWAYfBAT3g') } else if (process.env.WEBRTC_STAR_REMOTE_SIGNAL_IP) { // test with deployed signalling server using IP console.log('Using IP:', maHSIP) - ma1 = maGen(maHSIP, 'QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooo2a') - ma2 = maGen(maHSIP, 'QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooo2b') + ma1 = maGen(maHSIP, 'Qmf2uGBMP8VcLYAbh7katNyXyhiptYoUf1kLzbFd1jpRbf') + ma2 = maGen(maHSIP, 'QmY6yfBGWghP7NcW3gFeJC9FgRQe2rbV8BkfyWAYfBAT3g') } else { - ma1 = maGen(maLS, 'QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooo2a') - ma2 = maGen(maLS, 'QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooo2b') + ma1 = maGen(maLS, 'Qmf2uGBMP8VcLYAbh7katNyXyhiptYoUf1kLzbFd1jpRbf') + ma2 = maGen(maLS, 'QmY6yfBGWghP7NcW3gFeJC9FgRQe2rbV8BkfyWAYfBAT3g') } before(async () => { @@ -58,7 +58,7 @@ module.exports = (create) => { }) it('dial on IPv4, check callback', function (done) { - this.timeout(20 * 1000) + this.timeout(60 * 1000) ws1.dial(ma2, (err, conn) => { expect(err).to.not.exist() diff --git a/test/transport/listen.js b/test/transport/listen.js index f1139c22..b6418cbf 100644 --- a/test/transport/listen.js +++ b/test/transport/listen.js @@ -12,7 +12,7 @@ module.exports = (create) => { describe('listen', () => { let ws - const ma = multiaddr('/ip4/127.0.0.1/tcp/15555/ws/p2p-webrtc-star/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooooA') + const ma = multiaddr('/ip4/127.0.0.1/tcp/15555/ws/p2p-webrtc-star/ipfs/Qmf2uGBMP8VcLYAbh7katNyXyhiptYoUf1kLzbFd1jpRbf') before(async () => { ws = await create('a') diff --git a/test/transport/valid-connection.js b/test/transport/valid-connection.js index 61e9102a..a778cf27 100644 --- a/test/transport/valid-connection.js +++ b/test/transport/valid-connection.js @@ -21,8 +21,8 @@ module.exports = (create) => { return `/ip4/127.0.0.1/tcp/15555/ws/p2p-webrtc-star/ipfs/${id}` } - const ma1 = multiaddr(base('QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooo3A')) - const ma2 = multiaddr(base('QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooo3B')) + const ma1 = multiaddr(base('Qmf2uGBMP8VcLYAbh7katNyXyhiptYoUf1kLzbFd1jpRbf')) + const ma2 = multiaddr(base('QmY6yfBGWghP7NcW3gFeJC9FgRQe2rbV8BkfyWAYfBAT3g')) let conn From 554e7edf6fbe82b485da567d782e677e75be62f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kr=C3=BCger?= Date: Sun, 17 Jun 2018 12:52:21 +0200 Subject: [PATCH 08/11] test: fix tests --- src/index.js | 2 +- test/transport/dial.js | 14 +++++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/index.js b/src/index.js index d924bc68..8c536412 100644 --- a/src/index.js +++ b/src/index.js @@ -135,7 +135,7 @@ class WebRTCStar { const spOptions = { trickle: false } // Use custom WebRTC implementation - if (this.wrtc) { spOptions.wrtc = self.wrtc } + if (this.wrtc) { spOptions.wrtc = this.wrtc } const channel = new SimplePeer(spOptions) diff --git a/test/transport/dial.js b/test/transport/dial.js index 55f12c69..e053bd7d 100644 --- a/test/transport/dial.js +++ b/test/transport/dial.js @@ -57,8 +57,8 @@ module.exports = (create) => { await promisify(listener.listen)(ma2) }) - it('dial on IPv4, check callback', function (done) { - this.timeout(60 * 1000) + it('dial, check callback', function (done) { + this.timeout(2 * 60 * 1000) ws1.dial(ma2, (err, conn) => { expect(err).to.not.exist() @@ -77,19 +77,15 @@ module.exports = (create) => { }) }) - it('dial offline / non-exist()ent node on IPv4, check callback', function (done) { - this.timeout(20 * 1000) - let maOffline = multiaddr('/ip4/127.0.0.1/tcp/15555/ws/p2p-webrtc-star/ipfs/ABCD') + it('dial offline / non-exist()ent node, check callback', function (done) { + this.timeout(60 * 1000) + let maOffline = multiaddr('/p2p-webrtc-star/ipfs/ABCD') ws1.dial(maOffline, (err, conn) => { expect(err).to.exist() done() }) }) - it.skip('dial on IPv6', (done) => { - // TODO IPv6 not supported yet - }) - after(async () => { await new Promise((resolve, reject) => { waterfall([ From d0808955a9ba457a3fdbb0d10111c835e37844f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kr=C3=BCger?= Date: Sun, 17 Jun 2018 12:53:35 +0200 Subject: [PATCH 09/11] misc: increase timeouts Some ISPs really _love_ WebRTC (Yes, it really does take 40s until 'signal' gets emitted - and 20s more just to get sure) --- test/transport/valid-connection.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/transport/valid-connection.js b/test/transport/valid-connection.js index a778cf27..8b9384cf 100644 --- a/test/transport/valid-connection.js +++ b/test/transport/valid-connection.js @@ -26,7 +26,9 @@ module.exports = (create) => { let conn - before(async () => { + before(async function () { + this.timeout(2 * 60 * 1000) + let listener m = await create('m') From 4238cb8ddc3f3a74c6e43c29eb3ed0f98b06bc02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kr=C3=BCger?= Date: Sun, 17 Jun 2018 13:07:45 +0200 Subject: [PATCH 10/11] fix: some multiaddr fixes and improvments --- src/index.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/index.js b/src/index.js index 8c536412..e611fad9 100644 --- a/src/index.js +++ b/src/index.js @@ -47,7 +47,7 @@ class WebRTCStar { let b58 = ma.split('ipfs/').pop() - log('dialing %s %s', ma, b58) + log('dialing %s (id=%s)', ma, b58) const spOptions = { initiator: true, trickle: false } @@ -61,7 +61,7 @@ class WebRTCStar { channel.on('signal', (signal) => { log('dial#%s got signal', ma) - this.exchange.request(Id.createFromB58String(b58), 'webrtc', Buffer.from(JSON.stringify({signal, ma: '/ip4/0.0.0.0/tcp/127.0.0.1'})), (err, result) => { // TODO: fix this + this.exchange.request(Id.createFromB58String(b58), 'webrtc', Buffer.from(JSON.stringify({signal})), (err, result) => { if (err) { log('dial#%s exchange failed %s', ma, err) return callback(err) @@ -141,11 +141,15 @@ class WebRTCStar { const conn = new Connection(toPull.duplex(channel)) + const remoteMa = '/p2p-webrtc-star/ipfs/' + from.toB58String() + + log('incoming connection %s', remoteMa) + channel.once('connect', () => { - log('connected') + log('%s: connected', remoteMa) conn.getObservedAddrs = (callback) => { - return callback(null, [multiaddr(offer.ma)]) // TODO: this isn't really safe AT ALL... + return callback(null, [multiaddr(remoteMa)]) } listener.emit('connection', conn) @@ -153,10 +157,12 @@ class WebRTCStar { }) channel.once('signal', (signal) => { - log('sending back signal') - cb(null, Buffer.from(JSON.stringify({signal, ma: listener.ma.toString()}))) + log('%s: sending back signal', remoteMa) + cb(null, Buffer.from(JSON.stringify({signal}))) }) + // TODO: add error response? + channel.signal(offer.signal) }) From 3cb9bb29dfabbd5f5ee5258674cd17ba421f07b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kr=C3=BCger?= Date: Fri, 22 Jun 2018 13:00:19 +0200 Subject: [PATCH 11/11] fix: return error if dialing ma without id --- src/index.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index e611fad9..aeebfefc 100644 --- a/src/index.js +++ b/src/index.js @@ -45,9 +45,13 @@ class WebRTCStar { callback = callback ? once(callback) : noop - let b58 = ma.split('ipfs/').pop() + let peerId = multiaddr(ma).getPeerId() - log('dialing %s (id=%s)', ma, b58) + log('dialing %s (id=%s)', ma, peerId) + + if (!peerId) { + return callback(new Error('Cannot dial peer: No Id provided!')) + } const spOptions = { initiator: true, trickle: false } @@ -61,7 +65,7 @@ class WebRTCStar { channel.on('signal', (signal) => { log('dial#%s got signal', ma) - this.exchange.request(Id.createFromB58String(b58), 'webrtc', Buffer.from(JSON.stringify({signal})), (err, result) => { + this.exchange.request(Id.createFromB58String(peerId), 'webrtc', Buffer.from(JSON.stringify({signal})), (err, result) => { if (err) { log('dial#%s exchange failed %s', ma, err) return callback(err)