Skip to content
This repository has been archived by the owner on Aug 23, 2019. It is now read-only.

Commit

Permalink
feat: Circuit Relay (#224)
Browse files Browse the repository at this point in the history
  • Loading branch information
dryajov authored and daviddias committed Oct 23, 2017
1 parent 4208f24 commit 30fb36f
Show file tree
Hide file tree
Showing 22 changed files with 240 additions and 54 deletions.
18 changes: 12 additions & 6 deletions gulpfile.js → .aegir.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use strict'

const gulp = require('gulp')
const PeerInfo = require('peer-info')
const PeerId = require('peer-id')
const WebSockets = require('libp2p-websockets')
Expand All @@ -23,7 +22,7 @@ const options = {
host: '127.0.0.1'
}

gulp.task('test:browser:before', (done) => {
function before (done) {
function createListenerA (cb) {
PeerId.createFromJSON(
JSON.parse(
Expand Down Expand Up @@ -79,15 +78,22 @@ gulp.task('test:browser:before', (done) => {
function echo (protocol, conn) {
pull(conn, conn)
}
})
}

gulp.task('test:browser:after', (done) => {
function after (done) {
let count = 0
const ready = () => ++count === 3 ? done() : null

swarmA.transport.close('ws', ready)
swarmB.close(ready)
sigS.stop(ready)
})
}

require('aegir/gulp')(gulp)
module.exports = {
hooks: {
browser: {
pre: before,
post: after
}
}
}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

**/node_modules/
**/*.log
test/repo-tests*
Expand Down Expand Up @@ -38,5 +39,7 @@ test/test-data/go-ipfs-repo/LOCK
test/test-data/go-ipfs-repo/LOG
test/test-data/go-ipfs-repo/LOG.old

docs
# while testing npm5
package-lock.json
yarn.lock
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ addons:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.8
- g++-4.8
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,16 @@ const secio = require('libp2p-secio')
swarm.connection.crypto(secio.tag, secio.encrypt)
```

##### `swarm.connection.enableCircuitRelay(options)`

Enable circuit relaying.

- `options`
- enabled - activates relay dialing and listening functionality
- hop - an object with two properties
- enabled - enables circuit relaying
- active - is it an active or passive relay (default false)

### `swarm.dial(peer, protocol, callback)`

dial uses the best transport (whatever works first, in the future we can have some criteria), and jump starts the connection until the point where we have to negotiate the protocol. If a muxer is available, then drop the muxer onto that connection. Good to warm up connections or to check for connectivity. If we have already a muxer for that peerInfo, then do nothing.
Expand Down
6 changes: 5 additions & 1 deletion circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ dependencies:
pre:
- google-chrome --version
- curl -L -o google-chrome.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
- for v in $(curl http://archive.ubuntu.com/ubuntu/pool/main/n/nss/ | grep "href=" | grep "libnss3.*deb\"" -o | grep -o "libnss3.*deb" | grep "3.28" | grep "14.04"); do curl -L -o $v http://archive.ubuntu.com/ubuntu/pool/main/n/nss/$v; done && rm libnss3-tools*_i386.deb libnss3-dev*_i386.deb
- sudo dpkg -i google-chrome.deb || true
- sudo dpkg -i libnss3*.deb || true
- sudo apt-get update
- sudo apt-get install -f || true
- sudo dpkg -i libnss3*.deb
- sudo apt-get install -f
- sudo apt-get install --only-upgrade lsb-base
- sudo dpkg -i google-chrome.deb
- google-chrome --version
- google-chrome --version
42 changes: 22 additions & 20 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@
"description": "libp2p swarm implementation in JavaScript",
"main": "src/index.js",
"scripts": {
"lint": "gulp lint",
"build": "gulp build",
"test": "gulp test --dom",
"test:node": "gulp test:node",
"test:browser": "gulp test:browser --dom",
"release": "gulp release --dom",
"release-minor": "gulp release --type minor --dom",
"release-major": "gulp release --type major --dom",
"coverage": "gulp coverage",
"coverage-publish": "aegir-coverage publish"
"lint": "aegir lint",
"build": "aegir build",
"test": "aegir test --target node --target browser --no-parallel",
"test:node": "aegir test --target node --no-parallel",
"test:browser": "aegir test --target browser --no-parallel",
"release": "aegir test release --target node --target browser --no-parallel",
"release-minor": "aegir release --type minor --target node --target browser --no-parallel",
"release-major": "aegir release --type major --target node --target browser --no-parallel",
"coverage": "aegir coverage",
"coverage-publish": "aegir coverage --provider coveralls"
},
"browser": {
"zlib": "browserify-zlib-next"
"zlib": "browserify-zlib"
},
"repository": {
"type": "git",
Expand All @@ -40,35 +40,37 @@
"npm": ">=3.0.0"
},
"devDependencies": {
"aegir": "^11.0.2",
"aegir": "^12.1.0",
"buffer-loader": "0.0.1",
"chai": "^4.1.2",
"dirty-chai": "^2.0.1",
"gulp": "^3.9.1",
"libp2p-multiplex": "~0.5.0",
"libp2p-secio": "~0.8.1",
"libp2p-spdy": "~0.11.0",
"libp2p-tcp": "~0.11.0",
"libp2p-tcp": "~0.11.1",
"libp2p-webrtc-star": "~0.13.2",
"libp2p-websockets": "~0.10.1",
"libp2p-websockets": "~0.10.2",
"peer-book": "~0.5.1",
"pre-commit": "^1.2.2",
"pull-goodbye": "0.0.2",
"peer-book": "~0.5.1",
"sinon": "^4.0.1",
"webrtcsupport": "^2.2.0"
},
"dependencies": {
"async": "^2.5.0",
"browserify-zlib-next": "^1.0.1",
"debug": "^3.0.1",
"browserify-zlib": "^0.2.0",
"debug": "^3.1.0",
"interface-connection": "~0.3.2",
"ip-address": "^5.8.8",
"libp2p-circuit": "~0.1.0",
"libp2p-identify": "~0.6.1",
"lodash.includes": "^4.3.0",
"multiaddr": "^3.0.1",
"multistream-select": "~0.13.5",
"once": "^1.4.0",
"peer-id": "~0.10.1",
"peer-info": "~0.11.0",
"peer-id": "^0.10.2",
"peer-info": "^0.11.0",
"pull-stream": "^3.6.1"
},
"contributors": [
Expand All @@ -88,4 +90,4 @@
"greenkeeper[bot] <greenkeeper[bot]@users.noreply.github.com>",
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <[email protected]>"
]
}
}
15 changes: 15 additions & 0 deletions src/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ const debug = require('debug')
const log = debug('libp2p:swarm:connection')
const setImmediate = require('async/setImmediate')

const Circuit = require('libp2p-circuit')

const protocolMuxer = require('./protocol-muxer')
const plaintext = require('./plaintext')

Expand Down Expand Up @@ -92,6 +94,19 @@ module.exports = function connection (swarm) {
})
},

enableCircuitRelay (config) {
config = config || {}

if (config.enabled) {
if (!config.hop) {
Object.assign(config, { hop: { enabled: false, active: false } })
}

// TODO: should we enable circuit listener and dialer by default?
swarm.transport.add(Circuit.tag, new Circuit(swarm, config))
}
},

crypto (tag, encrypt) {
if (!tag && !encrypt) {
tag = plaintext.tag
Expand Down
33 changes: 26 additions & 7 deletions src/dial.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const multistream = require('multistream-select')
const Connection = require('interface-connection').Connection
const setImmediate = require('async/setImmediate')
const getPeerInfo = require('./get-peer-info')
const Circuit = require('libp2p-circuit')

const debug = require('debug')
const log = debug('libp2p:swarm:dial')

Expand Down Expand Up @@ -81,18 +83,22 @@ function dial (swarm) {
function attemptDial (pi, cb) {
const tKeys = swarm.availableTransports(pi)

if (tKeys.length === 0) {
return cb(new Error('No available transport to dial to'))
}

nextTransport(tKeys.shift())

function nextTransport (key) {
if (!key) {
return dialCircuit((err, circuit) => {
if (err) {
return cb(new Error('Could not dial in any of the transports or relays'))
}

cb(null, circuit)
})
}

log(`dialing transport ${key}`)
swarm.transport.dial(key, pi, (err, conn) => {
if (err) {
if (tKeys.length === 0) {
return cb(new Error('Could not dial in any of the transports'))
}
return nextTransport(tKeys.shift())
}

Expand Down Expand Up @@ -121,6 +127,19 @@ function dial (swarm) {
}
}

function dialCircuit (cb) {
log(`Falling back to dialing over circuit`)
pi.multiaddrs.add(`/p2p-circuit/ipfs/${pi.id.toB58String()}`)
swarm.transport.dial(Circuit.tag, pi, (err, conn) => {
if (err) {
log(err)
return cb(err)
}

cb(null, conn)
})
}

function attemptMuxerUpgrade (conn, cb) {
const muxers = Object.keys(swarm.muxers)
if (muxers.length === 0) {
Expand Down
4 changes: 4 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ function Swarm (peerInfo, peerBook) {

// Only listen on transports we actually have addresses for
return myTransports.filter((ts) => this.transports[ts].filter(myAddrs).length > 0)
// push Circuit to be the last proto to be dialed
.sort((a) => {
return a === 'Circuit' ? -1 : 0
})
}

// higher level (public) API
Expand Down
2 changes: 2 additions & 0 deletions src/limit-dialer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const map = require('async/map')
const debug = require('debug')
const once = require('once')

const log = debug('libp2p:swarm:dialer')

Expand Down Expand Up @@ -37,6 +38,7 @@ class LimitDialer {
log('dialMany:start')
// we use a token to track if we want to cancel following dials
const token = { cancel: false }
callback = once(callback) // only call callback once

map(addrs, (m, cb) => {
this.dialSingle(peer, transport, m, token, cb)
Expand Down
2 changes: 1 addition & 1 deletion src/transport.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ module.exports = function (swarm) {
if (!Array.isArray(multiaddrs)) {
multiaddrs = [multiaddrs]
}
log('dialing %s', key, multiaddrs.map((m) => m.toString()))
// filter the multiaddrs that are actually valid for this transport (use a func from the transport itself) (maybe even make the transport do that)
multiaddrs = dialables(t, multiaddrs)
log('dialing %s', key, multiaddrs.map((m) => m.toString()))

dialer.dialMany(pi.id, t, multiaddrs, (err, success) => {
if (err) {
Expand Down
4 changes: 2 additions & 2 deletions test/browser-swarm-with-muxing-plus-websockets.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const PeerBook = require('peer-book')

const Swarm = require('../src')

describe('high level API (swarm with spdy + websockets)', () => {
describe.skip('high level API (swarm with spdy + websockets)', () => {
let swarm
let peerDst

Expand Down Expand Up @@ -58,7 +58,7 @@ describe('high level API (swarm with spdy + websockets)', () => {
swarm.dial(peerDst, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist()
pull(
pull.values([Buffer('hello')]),
pull.values([Buffer.from('hello')]),
conn,
pull.onEnd(done)
)
Expand Down
2 changes: 1 addition & 1 deletion test/browser-transport-websockets.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ describe('transport - websockets', () => {
})

pull(
pull.values([Buffer('hey')]),
pull.values([Buffer.from('hey')]),
conn,
pull.collect((err, data) => {
expect(err).to.not.exist()
Expand Down
2 changes: 1 addition & 1 deletion test/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const Swarm = require('../src')

describe('basics', () => {
it('throws on missing peerInfo', (done) => {
expect(Swarm).to.throw(Error)
expect(Swarm).to.throw(/You must provide a `peerInfo`/)
done()
})
})
Expand Down
Loading

0 comments on commit 30fb36f

Please sign in to comment.