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..a8ade416 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", @@ -52,6 +46,9 @@ "dirty-chai": "^2.0.1", "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" @@ -61,21 +58,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 cb488242..aeebfefc 100644 --- a/src/index.js +++ b/src/index.js @@ -2,51 +2,37 @@ 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 -} +const {cleanMultiaddr} = require('./utils') 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) { @@ -55,12 +41,17 @@ class WebRTCStar { options = {} } + ma = cleanMultiaddr(String(ma)) + callback = callback ? once(callback) : noop - const intentId = (~~(Math.random() * 1e9)).toString(36) + Date.now() + let peerId = multiaddr(ma).getPeerId() + + log('dialing %s (id=%s)', ma, peerId) - const sioClient = this - .listenersRefs[Object.keys(this.listenersRefs)[0]].io + if (!peerId) { + return callback(new Error('Cannot dial peer: No Id provided!')) + } const spOptions = { initiator: true, trickle: false } @@ -73,43 +64,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(peerId), 'webrtc', Buffer.from(JSON.stringify({signal})), (err, result) => { + 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 @@ -127,53 +116,44 @@ class WebRTCStar { callback = callback ? once(callback) : noop if (!webrtcSupport.support && !this.wrtc) { - return setImmediate(() => callback(new Error('no WebRTC support'))) - } - - this.maSelf = ma - - const sioUrl = cleanUrlSIO(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) => { + const err = new Error('No WebRTC support') listener.emit('error', err) - listener.emit('close') - }) + return setImmediate(() => callback(err)) + } - listener.io.on('ws-handshake', incommingDial) - listener.io.on('ws-peer', this._peerDiscovered) + log('listening on %s', ma) - listener.io.on('connect', () => { - listener.io.emit('ss-join', ma.toString()) - }) + const ns = listener.ns = 'webrtc' // TODO: should this be ma.toString() ? + listener.ma = ma - listener.io.once('connect', () => { - listener.emit('listening') - callback() - }) + this.exchange.handle(ns, (from, request, cb) => { + let offer - 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 } // Use custom WebRTC implementation - if (self.wrtc) { spOptions.wrtc = self.wrtc } + if (this.wrtc) { spOptions.wrtc = this.wrtc } const channel = new SimplePeer(spOptions) const conn = new Connection(toPull.duplex(channel)) + const remoteMa = '/p2p-webrtc-star/ipfs/' + from.toB58String() + + log('incoming connection %s', remoteMa) + channel.once('connect', () => { + log('%s: connected', remoteMa) + conn.getObservedAddrs = (callback) => { - return callback(null, [offer.srcMultiaddr]) + return callback(null, [multiaddr(remoteMa)]) } listener.emit('connection', conn) @@ -181,31 +161,32 @@ class WebRTCStar { }) channel.once('signal', (signal) => { - offer.signal = signal - offer.answer = true - listener.io.emit('ss-handshake', offer) + log('%s: sending back signal', remoteMa) + cb(null, Buffer.from(JSON.stringify({signal}))) }) + // TODO: add error response? + channel.signal(offer.signal) - } + }) + + listener.emit('listening') + setImmediate(() => callback()) } listener.close = (callback) => { callback = callback ? once(callback) : noop - listener.io.emit('ss-leave') + this.exchange.unhandle(listener.ns) - setImmediate(() => { - listener.emit('close') - callback() - }) + listener.emit('close') + 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 +203,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 index 13b39d58..44533fe2 100644 --- a/src/utils.js +++ b/src/utils.js @@ -2,29 +2,6 @@ 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' @@ -44,6 +21,6 @@ function cleanMultiaddr (maStr) { return maStr } -exports = module.exports -exports.cleanUrlSIO = cleanUrlSIO -exports.cleanMultiaddr = cleanMultiaddr +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..e053bd7d 100644 --- a/test/transport/dial.js +++ b/test/transport/dial.js @@ -7,13 +7,16 @@ 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('dial', () => { let ws1 let ws2 + let m let ma1 let ma2 @@ -27,36 +30,35 @@ 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((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) { - this.timeout(20 * 1000) + it('dial, check callback', function (done) { + this.timeout(2 * 60 * 1000) ws1.dial(ma2, (err, conn) => { expect(err).to.not.exist() @@ -75,17 +77,22 @@ 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([ + 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/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..b6418cbf 100644 --- a/test/transport/listen.js +++ b/test/transport/listen.js @@ -12,10 +12,10 @@ 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(() => { - 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/transport/valid-connection.js b/test/transport/valid-connection.js index 38e4e053..8b9384cf 100644 --- a/test/transport/valid-connection.js +++ b/test/transport/valid-connection.js @@ -6,45 +6,43 @@ 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 ma2 = multiaddr(base('QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooo3B')) + const ma1 = multiaddr(base('Qmf2uGBMP8VcLYAbh7katNyXyhiptYoUf1kLzbFd1jpRbf')) + const ma2 = multiaddr(base('QmY6yfBGWghP7NcW3gFeJC9FgRQe2rbV8BkfyWAYfBAT3g')) let conn - before(function (done) { - this.timeout(40 * 1000) - - series([first, second], dial) + before(async function () { + this.timeout(2 * 60 * 1000) - function first (next) { - ws1 = create() + let listener - 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() + await promisify((cb) => Utils.Exchange.before(ws1.exchange, ws2.exchange, m.exchange, cb))() - const listener = ws2.createListener((conn) => pull(conn, conn)) - listener.listen(ma2, next) - } + listener = ws1.createListener((conn) => pull(conn, conn)) + await promisify(listener.listen)(ma1) + listener = ws2.createListener((conn) => pull(conn, conn)) + await promisify(listener.listen)(ma2) - function dial () { - conn = ws1.dial(ma2, done) - } + await promisify((cb) => (conn = ws1.dial(ma2, cb)))() }) it('get observed addrs', (done) => { @@ -70,5 +68,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.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..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,41 +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('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)