Skip to content

Commit

Permalink
fix: start and stop error callback (#316)
Browse files Browse the repository at this point in the history
* fix: ensure start and stop callbacks are called
  • Loading branch information
jacobheun authored Feb 1, 2019
1 parent c4cab00 commit 8047fb7
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 6 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"libp2p-websockets": "~0.12.0",
"mafmt": "^6.0.2",
"multiaddr": "^6.0.2",
"once": "^1.4.0",
"peer-book": "~0.9.0",
"peer-id": "~0.12.0",
"peer-info": "~0.15.0"
Expand Down
10 changes: 6 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const Ping = require('libp2p-ping')
const WebSockets = require('libp2p-websockets')
const ConnectionManager = require('libp2p-connection-manager')

const { emitFirst } = require('./util')
const peerRouting = require('./peer-routing')
const contentRouting = require('./content-routing')
const dht = require('./dht')
Expand Down Expand Up @@ -194,7 +195,7 @@ class Node extends EventEmitter {
* @returns {void}
*/
start (callback = () => {}) {
this.once('start', callback)
emitFirst(this, ['error', 'start'], callback)
this.state('start')
}

Expand All @@ -205,7 +206,7 @@ class Node extends EventEmitter {
* @returns {void}
*/
stop (callback = () => {}) {
this.once('stop', callback)
emitFirst(this, ['error', 'stop'], callback)
this.state('stop')
}

Expand Down Expand Up @@ -473,8 +474,9 @@ class Node extends EventEmitter {
this._switch.stop(cb)
},
(cb) => {
// Ensures idempotent restarts
this._switch.transport.removeAll(cb)
// Ensures idempotent restarts, ignore any errors
// from removeAll, they're not useful at this point
this._switch.transport.removeAll(() => cb())
}
], (err) => {
if (err) {
Expand Down
33 changes: 33 additions & 0 deletions src/util/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
'use strict'
const once = require('once')

/**
* Registers `handler` to each event in `events`. The `handler`
* will only be called for the first event fired, at which point
* the `handler` will be removed as a listener.
*
* Ensures `handler` is only called once.
*
* @example
* // will call `callback` when `start` or `error` is emitted by `this`
* emitFirst(this, ['error', 'start'], callback)
*
* @private
* @param {EventEmitter} emitter The emitter to listen on
* @param {Array<string>} events The events to listen for
* @param {function(*)} handler The handler to call when an event is triggered
* @returns {void}
*/
function emitFirst (emitter, events, handler) {
handler = once(handler)
events.forEach((e) => {
emitter.once(e, (...args) => {
events.forEach((ev) => {
emitter.removeListener(ev, handler)
})
handler.apply(emitter, args)
})
})
}

module.exports.emitFirst = emitFirst
24 changes: 22 additions & 2 deletions test/fsm.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ describe('libp2p state machine (fsm)', () => {
})
afterEach(() => {
node.removeAllListeners()
sinon.restore()
})
after((done) => {
node.stop(done)
Expand Down Expand Up @@ -64,6 +65,23 @@ describe('libp2p state machine (fsm)', () => {
node.start()
})

it('should callback with an error when it occurs on stop', (done) => {
const error = new Error('some error starting')
node.once('start', () => {
node.once('error', (err) => {
expect(err).to.eql(error).mark()
})
node.stop((err) => {
expect(err).to.eql(error).mark()
})
})

expect(2).checks(done)

sinon.stub(node._switch, 'stop').callsArgWith(0, error)
node.start()
})

it('should noop when starting a started node', (done) => {
node.once('start', () => {
node.state.on('STARTING', () => {
Expand Down Expand Up @@ -116,9 +134,11 @@ describe('libp2p state machine (fsm)', () => {
throw new Error('should not start')
})

expect(2).checks(done)
expect(3).checks(done)

node.start()
node.start((err) => {
expect(err).to.eql(error).mark()
})
})

it('should not dial when the node is stopped', (done) => {
Expand Down

0 comments on commit 8047fb7

Please sign in to comment.