mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-04-25 10:32:14 +00:00
parent
686379efb0
commit
0b75f99d75
49
README.md
49
README.md
@ -49,6 +49,7 @@ We've come a long way, but this project is still in Alpha, lots of development i
|
||||
- [Install](#install)
|
||||
- [Usage](#usage)
|
||||
- [API](#api)
|
||||
- [Events](#events)
|
||||
- [Development](#development)
|
||||
- [Tests](#tests)
|
||||
- [Packages](#packages)
|
||||
@ -206,22 +207,20 @@ Required keys in the `options` object:
|
||||
|
||||
> Start the libp2p Node.
|
||||
|
||||
`callback` is a function with the following `function (err) {}` signature, where `err` is an Error in case starting the node fails.
|
||||
`callback` following signature `function (err) {}`, where `err` is an Error in case starting the node fails.
|
||||
|
||||
#### `libp2p.stop(callback)`
|
||||
|
||||
> Stop the libp2p Node.
|
||||
|
||||
`callback` is a function with the following `function (err) {}` signature, where `err` is an Error in case stopping the node fails.
|
||||
`callback` following signature `function (err) {}`, where `err` is an Error in case stopping the node fails.
|
||||
|
||||
#### `libp2p.dial(peer, callback)`
|
||||
|
||||
> Dials to another peer in the network, establishes the connection.
|
||||
|
||||
- `peer`: can be an instance of [PeerInfo][], [PeerId][], [multiaddr][], or a multiaddr string
|
||||
- `callback`: Function with signature `function (err, conn) {}` where `conn` is a [Connection](https://github.com/libp2p/interface-connection) object
|
||||
|
||||
`callback` is a function with the following `function (err, conn) {}` signature, where `err` is an Error in of failure to dial the connection and `conn` is a [Connection][] instance in case of a protocol selected, if not it is undefined.
|
||||
- `callback` following signature `function (err, conn) {}`, where `err` is an Error in of failure to dial the connection and `conn` is a [Connection][] instance in case of a protocol selected, if not it is undefined.
|
||||
|
||||
#### `libp2p.dialProtocol(peer, protocol, callback)`
|
||||
|
||||
@ -229,9 +228,17 @@ Required keys in the `options` object:
|
||||
|
||||
- `peer`: can be an instance of [PeerInfo][], [PeerId][], [multiaddr][], or a multiaddr string
|
||||
- `protocol`: String that defines the protocol (e.g '/ipfs/bitswap/1.1.0')
|
||||
- `callback`: Function with signature `function (err, conn) {}` where `conn` is a [Connection](https://github.com/libp2p/interface-connection) object
|
||||
- `callback`: Function with signature `function (err, conn) {}`, where `conn` is a [Connection](https://github.com/libp2p/interface-connection) object
|
||||
|
||||
`callback` is a function with the following `function (err, conn) {}` signature, where `err` is an Error in of failure to dial the connection and `conn` is a [Connection][] instance in case of a protocol selected, if not it is undefined.
|
||||
`callback` following signature `function (err, conn) {}`, where `err` is an Error in of failure to dial the connection and `conn` is a [Connection][] instance in case of a protocol selected, if not it is undefined.
|
||||
|
||||
#### `libp2p.dialFSM(peer, protocol, callback)`
|
||||
|
||||
> Behaves like `.dial` and `.dialProtocol` but calls back with a Connection State Machine
|
||||
|
||||
- `peer`: can be an instance of [PeerInfo][], [PeerId][], [multiaddr][], or a multiaddr string
|
||||
- `protocol`: an optional String that defines the protocol (e.g '/ipfs/bitswap/1.1.0')
|
||||
- `callback`: following signature `function (err, connFSM) {}`, where `connFSM` is a [Connection State Machine](https://github.com/libp2p/js-libp2p-switch#connection-state-machine)
|
||||
|
||||
#### `libp2p.hangUp(peer, callback)`
|
||||
|
||||
@ -239,7 +246,7 @@ Required keys in the `options` object:
|
||||
|
||||
- `peer`: can be an instance of [PeerInfo][], [PeerId][] or [multiaddr][]
|
||||
|
||||
`callback` is a function with the following `function (err) {}` signature, where `err` is an Error in case stopping the node fails.
|
||||
`callback` following signature `function (err) {}`, where `err` is an Error in case stopping the node fails.
|
||||
|
||||
#### `libp2p.peerRouting.findPeer(id, options, callback)`
|
||||
|
||||
@ -265,7 +272,7 @@ Required keys in the `options` object:
|
||||
> Handle new protocol
|
||||
|
||||
- `protocol`: String that defines the protocol (e.g '/ipfs/bitswap/1.1.0')
|
||||
- `handlerFunc`: Function with signature `function (protocol, conn) {}` where `conn` is a [Connection](https://github.com/libp2p/interface-connection) object
|
||||
- `handlerFunc`: following signature `function (protocol, conn) {}`, where `conn` is a [Connection](https://github.com/libp2p/interface-connection) object
|
||||
- `matchFunc`: Function for matching on protocol (exact matching, semver, etc). Default to exact match.
|
||||
|
||||
#### `libp2p.unhandle(protocol)`
|
||||
@ -274,19 +281,35 @@ Required keys in the `options` object:
|
||||
|
||||
- `protocol`: String that defines the protocol (e.g '/ipfs/bitswap/1.1.0')
|
||||
|
||||
#### `libp2p.on('peer:discovery', (peer) => {})`
|
||||
#### Events
|
||||
|
||||
##### `libp2p.on('start', () => {})`
|
||||
|
||||
> Libp2p has started, along with all its services.
|
||||
|
||||
##### `libp2p.on('stop', () => {})`
|
||||
|
||||
> Libp2p has stopped, along with all its services.
|
||||
|
||||
##### `libp2p.on('error', (err) => {})`
|
||||
|
||||
> An error has occurred
|
||||
|
||||
- `err`: instance of `Error`
|
||||
|
||||
##### `libp2p.on('peer:discovery', (peer) => {})`
|
||||
|
||||
> Peer has been discovered.
|
||||
|
||||
- `peer`: instance of [PeerInfo][]
|
||||
|
||||
#### `libp2p.on('peer:connect', (peer) => {})`
|
||||
##### `libp2p.on('peer:connect', (peer) => {})`
|
||||
|
||||
> We connected to a new peer
|
||||
|
||||
- `peer`: instance of [PeerInfo][]
|
||||
|
||||
#### `libp2p.on('peer:disconnect', (peer) => {})`
|
||||
##### `libp2p.on('peer:disconnect', (peer) => {})`
|
||||
|
||||
> We disconnected from Peer
|
||||
|
||||
@ -574,4 +597,4 @@ The libp2p implementation in JavaScript is a work in progress. As such, there ar
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE) © David Dias
|
||||
[MIT](LICENSE) © Protocol Labs
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
'use strict'
|
||||
|
||||
const libp2p = require('../../')
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
'use strict'
|
||||
|
||||
const libp2p = require('../../')
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
'use strict'
|
||||
|
||||
const domReady = require('detect-dom-ready')
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
'use strict'
|
||||
|
||||
const libp2p = require('../../')
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
'use strict'
|
||||
|
||||
const libp2p = require('../../')
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
'use strict'
|
||||
|
||||
const libp2p = require('../../')
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
'use strict'
|
||||
|
||||
const libp2p = require('../../')
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
'use strict'
|
||||
|
||||
const libp2p = require('../../')
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
'use strict'
|
||||
|
||||
const libp2p = require('../../')
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
'use strict'
|
||||
|
||||
const libp2p = require('../../')
|
||||
|
@ -38,13 +38,15 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"async": "^2.6.1",
|
||||
"debug": "^4.0.1",
|
||||
"err-code": "^1.1.2",
|
||||
"fsm-event": "^2.1.0",
|
||||
"joi": "^13.6.0",
|
||||
"joi-browser": "^13.4.0",
|
||||
"libp2p-connection-manager": "~0.0.2",
|
||||
"libp2p-floodsub": "~0.15.0",
|
||||
"libp2p-ping": "~0.8.0",
|
||||
"libp2p-switch": "~0.40.8",
|
||||
"libp2p-switch": "~0.41.0",
|
||||
"libp2p-websockets": "~0.12.0",
|
||||
"mafmt": "^6.0.2",
|
||||
"multiaddr": "^5.0.0",
|
||||
@ -57,16 +59,17 @@
|
||||
"@nodeutils/defaults-deep": "^1.1.0",
|
||||
"aegir": "^15.2.0",
|
||||
"chai": "^4.1.2",
|
||||
"chai-checkmark": "^1.0.1",
|
||||
"cids": "~0.5.3",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"electron-webrtc": "~0.3.0",
|
||||
"libp2p-bootstrap": "~0.9.3",
|
||||
"libp2p-circuit": "~0.2.1",
|
||||
"libp2p-delegated-content-routing": "~0.2.2",
|
||||
"libp2p-delegated-peer-routing": "~0.2.2",
|
||||
"libp2p-kad-dht": "~0.10.5",
|
||||
"libp2p-mdns": "~0.12.0",
|
||||
"libp2p-mplex": "~0.8.2",
|
||||
"libp2p-bootstrap": "~0.9.3",
|
||||
"libp2p-secio": "~0.10.0",
|
||||
"libp2p-spdy": "~0.12.1",
|
||||
"libp2p-tcp": "~0.13.0",
|
||||
|
295
src/index.js
295
src/index.js
@ -1,7 +1,11 @@
|
||||
'use strict'
|
||||
|
||||
const FSM = require('fsm-event')
|
||||
const EventEmitter = require('events').EventEmitter
|
||||
const assert = require('assert')
|
||||
const debug = require('debug')
|
||||
const log = debug('libp2p')
|
||||
log.error = debug('libp2p:error')
|
||||
|
||||
const each = require('async/each')
|
||||
const series = require('async/series')
|
||||
@ -22,6 +26,14 @@ const validateConfig = require('./config').validate
|
||||
|
||||
const NOT_STARTED_ERROR_MESSAGE = 'The libp2p node is not started yet'
|
||||
|
||||
/**
|
||||
* @fires Node#error Emitted when an error occurs
|
||||
* @fires Node#peer:connect Emitted when a peer is connected to this node
|
||||
* @fires Node#peer:disconnect Emitted when a peer disconnects from this node
|
||||
* @fires Node#peer:discovery Emitted when a peer is discovered
|
||||
* @fires Node#start Emitted when the node and its services has started
|
||||
* @fires Node#stop Emitted when the node and its services has stopped
|
||||
*/
|
||||
class Node extends EventEmitter {
|
||||
constructor (_options) {
|
||||
super()
|
||||
@ -109,15 +121,181 @@ class Node extends EventEmitter {
|
||||
|
||||
// Mount default protocols
|
||||
Ping.mount(this._switch)
|
||||
|
||||
this.state = new FSM('STOPPED', {
|
||||
STOPPED: {
|
||||
start: 'STARTING',
|
||||
stop: 'STOPPED'
|
||||
},
|
||||
STARTING: {
|
||||
done: 'STARTED',
|
||||
abort: 'STOPPED',
|
||||
stop: 'STOPPING'
|
||||
},
|
||||
STARTED: {
|
||||
stop: 'STOPPING',
|
||||
start: 'STARTED'
|
||||
},
|
||||
STOPPING: {
|
||||
stop: 'STOPPING',
|
||||
done: 'STOPPED'
|
||||
}
|
||||
})
|
||||
this.state.on('STARTING', () => {
|
||||
log('libp2p is starting')
|
||||
this._onStarting()
|
||||
})
|
||||
this.state.on('STOPPING', () => {
|
||||
log('libp2p is stopping')
|
||||
this._onStopping()
|
||||
})
|
||||
this.state.on('STARTED', () => {
|
||||
log('libp2p has started')
|
||||
this.emit('start')
|
||||
})
|
||||
this.state.on('STOPPED', () => {
|
||||
log('libp2p has stopped')
|
||||
this.emit('stop')
|
||||
})
|
||||
this.state.on('error', (err) => {
|
||||
log.error(err)
|
||||
this.emit('error', err)
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
* Start the libp2p node
|
||||
* - create listeners on the multiaddrs the Peer wants to listen
|
||||
/**
|
||||
* Starts the libp2p node and all sub services
|
||||
*
|
||||
* @param {function(Error)} callback
|
||||
* @returns {void}
|
||||
*/
|
||||
start (callback) {
|
||||
start (callback = () => {}) {
|
||||
this.once('start', callback)
|
||||
this.state('start')
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the libp2p node by closing its listeners and open connections
|
||||
*
|
||||
* @param {function(Error)} callback
|
||||
* @returns {void}
|
||||
*/
|
||||
stop (callback = () => {}) {
|
||||
this.once('stop', callback)
|
||||
this.state('stop')
|
||||
}
|
||||
|
||||
isStarted () {
|
||||
return this.state ? this.state._state === 'STARTED' : false
|
||||
}
|
||||
|
||||
/**
|
||||
* Dials to the provided peer. If successful, the `PeerInfo` of the
|
||||
* peer will be added to the nodes `PeerBook`
|
||||
*
|
||||
* @param {PeerInfo|PeerId|Multiaddr|string} peer The peer to dial
|
||||
* @param {function(Error)} callback
|
||||
* @returns {void}
|
||||
*/
|
||||
dial (peer, callback) {
|
||||
assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE)
|
||||
|
||||
this.dialProtocol(peer, null, callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Dials to the provided peer and handshakes with the given protocol.
|
||||
* If successful, the `PeerInfo` of the peer will be added to the nodes `PeerBook`,
|
||||
* and the `Connection` will be sent in the callback
|
||||
*
|
||||
* @param {PeerInfo|PeerId|Multiaddr|string} peer The peer to dial
|
||||
* @param {string} protocol
|
||||
* @param {function(Error, Connection)} callback
|
||||
* @returns {void}
|
||||
*/
|
||||
dialProtocol (peer, protocol, callback) {
|
||||
assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE)
|
||||
|
||||
if (typeof protocol === 'function') {
|
||||
callback = protocol
|
||||
protocol = undefined
|
||||
}
|
||||
|
||||
this._getPeerInfo(peer, (err, peerInfo) => {
|
||||
if (err) { return callback(err) }
|
||||
|
||||
this._switch.dial(peerInfo, protocol, (err, conn) => {
|
||||
if (err) { return callback(err) }
|
||||
this.peerBook.put(peerInfo)
|
||||
callback(null, conn)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to `dial` and `dialProtocol`, but the callback will contain a
|
||||
* Connection State Machine.
|
||||
*
|
||||
* @param {PeerInfo|PeerId|Multiaddr|string} peer The peer to dial
|
||||
* @param {string} protocol
|
||||
* @param {function(Error, ConnectionFSM)} callback
|
||||
* @returns {void}
|
||||
*/
|
||||
dialFSM (peer, protocol, callback) {
|
||||
assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE)
|
||||
|
||||
if (typeof protocol === 'function') {
|
||||
callback = protocol
|
||||
protocol = undefined
|
||||
}
|
||||
|
||||
this._getPeerInfo(peer, (err, peerInfo) => {
|
||||
if (err) { return callback(err) }
|
||||
|
||||
const connFSM = this._switch.dialFSM(peerInfo, protocol, (err) => {
|
||||
if (!err) {
|
||||
this.peerBook.put(peerInfo)
|
||||
}
|
||||
})
|
||||
|
||||
callback(null, connFSM)
|
||||
})
|
||||
}
|
||||
|
||||
hangUp (peer, callback) {
|
||||
assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE)
|
||||
|
||||
this._getPeerInfo(peer, (err, peerInfo) => {
|
||||
if (err) { return callback(err) }
|
||||
|
||||
this._switch.hangUp(peerInfo, callback)
|
||||
})
|
||||
}
|
||||
|
||||
ping (peer, callback) {
|
||||
if (!this.isStarted()) {
|
||||
return callback(new Error(NOT_STARTED_ERROR_MESSAGE))
|
||||
}
|
||||
|
||||
this._getPeerInfo(peer, (err, peerInfo) => {
|
||||
if (err) { return callback(err) }
|
||||
|
||||
callback(null, new Ping(this._switch, peerInfo))
|
||||
})
|
||||
}
|
||||
|
||||
handle (protocol, handlerFunc, matchFunc) {
|
||||
this._switch.handle(protocol, handlerFunc, matchFunc)
|
||||
}
|
||||
|
||||
unhandle (protocol) {
|
||||
this._switch.unhandle(protocol)
|
||||
}
|
||||
|
||||
_onStarting () {
|
||||
if (!this._modules.transport) {
|
||||
return callback(new Error('no transports were present'))
|
||||
this.emit('error', new Error('no transports were present'))
|
||||
return this.state('abort')
|
||||
}
|
||||
|
||||
let ws
|
||||
@ -214,12 +392,10 @@ class Node extends EventEmitter {
|
||||
// TODO: chicken-and-egg problem #2:
|
||||
// have to set started here because FloodSub requires libp2p is already started
|
||||
if (this._floodSub) {
|
||||
this._floodSub.start(cb)
|
||||
} else {
|
||||
cb()
|
||||
return this._floodSub.start(cb)
|
||||
}
|
||||
cb()
|
||||
},
|
||||
|
||||
(cb) => {
|
||||
// detect which multiaddrs we don't have a transport for and remove them
|
||||
const multiaddrs = this.peerInfo.multiaddrs.toArray()
|
||||
@ -231,18 +407,18 @@ class Node extends EventEmitter {
|
||||
}
|
||||
})
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
this.emit('start')
|
||||
cb()
|
||||
}
|
||||
], callback)
|
||||
], (err) => {
|
||||
if (err) {
|
||||
log.error(err)
|
||||
this.emit('error', err)
|
||||
return this.state('stop')
|
||||
}
|
||||
this.state('done')
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop the libp2p node by closing its listeners and open connections
|
||||
*/
|
||||
stop (callback) {
|
||||
_onStopping () {
|
||||
series([
|
||||
(cb) => {
|
||||
if (this._modules.peerDiscovery) {
|
||||
@ -269,86 +445,21 @@ class Node extends EventEmitter {
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
this.connectionManager.stop()
|
||||
this._switch.stop(cb)
|
||||
// Ensures idempotency for restarts
|
||||
this._switch.transport.removeAll(cb)
|
||||
},
|
||||
(cb) => {
|
||||
this.emit('stop')
|
||||
cb()
|
||||
this.connectionManager.stop()
|
||||
this._switch.stop(cb)
|
||||
}
|
||||
], (err) => {
|
||||
this._isStarted = false
|
||||
callback(err)
|
||||
if (err) {
|
||||
log.error(err)
|
||||
this.emit('error', err)
|
||||
}
|
||||
this.state('done')
|
||||
})
|
||||
}
|
||||
|
||||
isStarted () {
|
||||
return this._isStarted
|
||||
}
|
||||
|
||||
dial (peer, callback) {
|
||||
assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE)
|
||||
|
||||
this._getPeerInfo(peer, (err, peerInfo) => {
|
||||
if (err) { return callback(err) }
|
||||
|
||||
this._switch.dial(peerInfo, (err) => {
|
||||
if (err) { return callback(err) }
|
||||
|
||||
this.peerBook.put(peerInfo)
|
||||
callback()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
dialProtocol (peer, protocol, callback) {
|
||||
assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE)
|
||||
|
||||
if (typeof protocol === 'function') {
|
||||
callback = protocol
|
||||
protocol = undefined
|
||||
}
|
||||
|
||||
this._getPeerInfo(peer, (err, peerInfo) => {
|
||||
if (err) { return callback(err) }
|
||||
|
||||
this._switch.dial(peerInfo, protocol, (err, conn) => {
|
||||
if (err) { return callback(err) }
|
||||
this.peerBook.put(peerInfo)
|
||||
callback(null, conn)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
hangUp (peer, callback) {
|
||||
assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE)
|
||||
|
||||
this._getPeerInfo(peer, (err, peerInfo) => {
|
||||
if (err) { return callback(err) }
|
||||
|
||||
this._switch.hangUp(peerInfo, callback)
|
||||
})
|
||||
}
|
||||
|
||||
ping (peer, callback) {
|
||||
if (!this.isStarted()) {
|
||||
return callback(new Error(NOT_STARTED_ERROR_MESSAGE))
|
||||
}
|
||||
|
||||
this._getPeerInfo(peer, (err, peerInfo) => {
|
||||
if (err) { return callback(err) }
|
||||
|
||||
callback(null, new Ping(this._switch, peerInfo))
|
||||
})
|
||||
}
|
||||
|
||||
handle (protocol, handlerFunc, matchFunc) {
|
||||
this._switch.handle(protocol, handlerFunc, matchFunc)
|
||||
}
|
||||
|
||||
unhandle (protocol) {
|
||||
this._switch.unhandle(protocol)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Node
|
||||
|
118
test/fsm.spec.js
Normal file
118
test/fsm.spec.js
Normal file
@ -0,0 +1,118 @@
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
const chai = require('chai')
|
||||
chai.use(require('dirty-chai'))
|
||||
chai.use(require('chai-checkmark'))
|
||||
const expect = chai.expect
|
||||
const sinon = require('sinon')
|
||||
const series = require('async/series')
|
||||
const createNode = require('./utils/create-node')
|
||||
|
||||
describe('libp2p state machine (fsm)', () => {
|
||||
describe('starting and stopping', () => {
|
||||
let node
|
||||
beforeEach((done) => {
|
||||
createNode([], (err, _node) => {
|
||||
node = _node
|
||||
done(err)
|
||||
})
|
||||
})
|
||||
afterEach(() => {
|
||||
node.removeAllListeners()
|
||||
})
|
||||
after((done) => {
|
||||
node.stop(done)
|
||||
node = null
|
||||
})
|
||||
|
||||
it('should be able to start and stop several times', (done) => {
|
||||
node.on('start', (err) => {
|
||||
expect(err).to.not.exist().mark()
|
||||
})
|
||||
node.on('stop', (err) => {
|
||||
expect(err).to.not.exist().mark()
|
||||
})
|
||||
|
||||
expect(4).checks(done)
|
||||
|
||||
series([
|
||||
(cb) => node.start(cb),
|
||||
(cb) => node.stop(cb),
|
||||
(cb) => node.start(cb),
|
||||
(cb) => node.stop(cb)
|
||||
], () => {})
|
||||
})
|
||||
|
||||
it('should noop when stopping a stopped node', (done) => {
|
||||
node.once('start', node.stop)
|
||||
node.once('stop', () => {
|
||||
node.state.on('STOPPING', () => {
|
||||
throw new Error('should not stop a stopped node')
|
||||
})
|
||||
node.once('stop', done)
|
||||
|
||||
// stop the stopped node
|
||||
node.stop()
|
||||
})
|
||||
node.start()
|
||||
})
|
||||
|
||||
it('should noop when starting a started node', (done) => {
|
||||
node.once('start', () => {
|
||||
node.state.on('STARTING', () => {
|
||||
throw new Error('should not start a started node')
|
||||
})
|
||||
node.once('start', () => {
|
||||
node.once('stop', done)
|
||||
node.stop()
|
||||
})
|
||||
|
||||
// start the started node
|
||||
node.start()
|
||||
})
|
||||
node.start()
|
||||
})
|
||||
|
||||
it('should error on start with no transports', (done) => {
|
||||
let transports = node._modules.transport
|
||||
node._modules.transport = null
|
||||
|
||||
node.on('stop', () => {
|
||||
node._modules.transport = transports
|
||||
expect(node._modules.transport).to.exist().mark()
|
||||
})
|
||||
node.on('error', (err) => {
|
||||
expect(err).to.exist().mark()
|
||||
})
|
||||
node.on('start', () => {
|
||||
throw new Error('should not start')
|
||||
})
|
||||
|
||||
expect(2).checks(done)
|
||||
|
||||
node.start()
|
||||
})
|
||||
|
||||
it('should not start if the switch fails to start', (done) => {
|
||||
const error = new Error('switch didnt start')
|
||||
const stub = sinon.stub(node._switch, 'start')
|
||||
.callsArgWith(0, error)
|
||||
|
||||
node.on('stop', () => {
|
||||
expect(stub.calledOnce).to.eql(true).mark()
|
||||
stub.restore()
|
||||
})
|
||||
node.on('error', (err) => {
|
||||
expect(err).to.eql(error).mark()
|
||||
})
|
||||
node.on('start', () => {
|
||||
throw new Error('should not start')
|
||||
})
|
||||
|
||||
expect(2).checks(done)
|
||||
|
||||
node.start()
|
||||
})
|
||||
})
|
||||
})
|
@ -4,8 +4,9 @@ require('./pnet.node')
|
||||
require('./transports.node')
|
||||
require('./stream-muxing.node')
|
||||
require('./peer-discovery.node')
|
||||
require('./pubsub.node')
|
||||
require('./peer-routing.node')
|
||||
require('./ping.node')
|
||||
require('./pubsub.node')
|
||||
require('./content-routing.node')
|
||||
require('./circuit-relay.node')
|
||||
require('./multiaddr-trim.node')
|
||||
|
61
test/ping.node.js
Normal file
61
test/ping.node.js
Normal file
@ -0,0 +1,61 @@
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
const chai = require('chai')
|
||||
chai.use(require('dirty-chai'))
|
||||
const expect = chai.expect
|
||||
const parallel = require('async/parallel')
|
||||
|
||||
const createNode = require('./utils/create-node.js')
|
||||
const echo = require('./utils/echo')
|
||||
|
||||
describe('ping', () => {
|
||||
let nodeA
|
||||
let nodeB
|
||||
|
||||
before((done) => {
|
||||
parallel([
|
||||
(cb) => createNode('/ip4/0.0.0.0/tcp/0', (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeA = node
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
}),
|
||||
(cb) => createNode('/ip4/0.0.0.0/tcp/0', (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeB = node
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
})
|
||||
], done)
|
||||
})
|
||||
|
||||
after((done) => {
|
||||
parallel([
|
||||
(cb) => nodeA.stop(cb),
|
||||
(cb) => nodeB.stop(cb)
|
||||
], done)
|
||||
})
|
||||
|
||||
it('should be able to ping another node', (done) => {
|
||||
nodeA.ping(nodeB.peerInfo, (err, ping) => {
|
||||
expect(err).to.not.exist()
|
||||
ping.once('ping', (time) => {
|
||||
expect(time).to.exist()
|
||||
ping.stop()
|
||||
done()
|
||||
})
|
||||
|
||||
ping.start()
|
||||
})
|
||||
})
|
||||
|
||||
it('should be not be able to ping when stopped', (done) => {
|
||||
nodeA.stop(() => {
|
||||
nodeA.ping(nodeB.peerInfo, (err) => {
|
||||
expect(err).to.exist()
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
@ -148,6 +148,42 @@ describe('transports', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('.dialFSM check conn and close', (done) => {
|
||||
nodeA.dialFSM(peerB, (err, connFSM) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
connFSM.once('muxed', () => {
|
||||
expect(nodeA._switch.muxedConns).to.have.any.keys(
|
||||
peerB.id.toB58String()
|
||||
)
|
||||
|
||||
connFSM.once('error', done)
|
||||
connFSM.once('close', () => {
|
||||
// ensure the connection is closed
|
||||
expect(nodeA._switch.muxedConns).to.not.have.any.keys([
|
||||
peerB.id.toB58String()
|
||||
])
|
||||
done()
|
||||
})
|
||||
|
||||
connFSM.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('.dialFSM with a protocol, do an echo and close', (done) => {
|
||||
nodeA.dialFSM(peerB, '/echo/1.0.0', (err, connFSM) => {
|
||||
expect(err).to.not.exist()
|
||||
connFSM.once('connection', (conn) => {
|
||||
tryEcho(conn, () => {
|
||||
connFSM.close()
|
||||
})
|
||||
})
|
||||
connFSM.once('error', done)
|
||||
connFSM.once('close', done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('stress', () => {
|
||||
it('one big write', (done) => {
|
||||
nodeA.dialProtocol(peerB, '/echo/1.0.0', (err, conn) => {
|
||||
@ -194,6 +230,7 @@ describe('transports', () => {
|
||||
})
|
||||
|
||||
describe('webrtc-star', () => {
|
||||
/* eslint-disable-next-line no-console */
|
||||
if (!w.support) { return console.log('NO WEBRTC SUPPORT') }
|
||||
|
||||
let peer1
|
||||
|
@ -185,7 +185,7 @@ describe('transports', () => {
|
||||
})
|
||||
|
||||
it('nodeA.hangUp nodeB using PeerId (third)', (done) => {
|
||||
nodeA.hangUp(nodeB.peerInfo.multiaddrs.toArray()[0], (err) => {
|
||||
nodeA.hangUp(nodeB.peerInfo.id, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
setTimeout(check, 500)
|
||||
|
||||
@ -207,6 +207,51 @@ describe('transports', () => {
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('.dialFSM check conn and close', (done) => {
|
||||
nodeA.dialFSM(nodeB.peerInfo, (err, connFSM) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
connFSM.once('muxed', () => {
|
||||
expect(nodeA._switch.muxedConns).to.have.any.keys(
|
||||
nodeB.peerInfo.id.toB58String()
|
||||
)
|
||||
|
||||
connFSM.once('error', done)
|
||||
connFSM.once('close', () => {
|
||||
// ensure the connection is closed
|
||||
expect(nodeA._switch.muxedConns).to.not.have.any.keys([
|
||||
nodeB.peerInfo.id.toB58String()
|
||||
])
|
||||
done()
|
||||
})
|
||||
|
||||
connFSM.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('.dialFSM with a protocol, do an echo and close', (done) => {
|
||||
nodeA.dialFSM(nodeB.peerInfo, '/echo/1.0.0', (err, connFSM) => {
|
||||
expect(err).to.not.exist()
|
||||
connFSM.once('connection', (conn) => {
|
||||
expect(nodeA._switch.muxedConns).to.have.all.keys([
|
||||
nodeB.peerInfo.id.toB58String()
|
||||
])
|
||||
tryEcho(conn, () => {
|
||||
connFSM.close()
|
||||
})
|
||||
})
|
||||
connFSM.once('error', done)
|
||||
connFSM.once('close', () => {
|
||||
// ensure the connection is closed
|
||||
expect(nodeA._switch.muxedConns).to.not.have.any.keys([
|
||||
nodeB.peerInfo.id.toB58String()
|
||||
])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('TCP + WebSockets', () => {
|
||||
|
@ -42,6 +42,7 @@ describe('Turbolence tests', () => {
|
||||
}
|
||||
})
|
||||
|
||||
/* eslint-disable-next-line no-console */
|
||||
nodeSpawn.stderr.on('data', (data) => console.log(data.toString()))
|
||||
})
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user