diff --git a/package.json b/package.json index 6a963181..9422a497 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,7 @@ "p-fifo": "^1.0.0", "p-settle": "^4.0.1", "peer-id": "^0.14.2", + "proper-event-emitter": "^1.0.0", "protons": "^2.0.0", "retimer": "^2.0.0", "sanitize-filename": "^1.6.3", diff --git a/src/circuit/listener.js b/src/circuit/listener.js index 76870501..eeca99c4 100644 --- a/src/circuit/listener.js +++ b/src/circuit/listener.js @@ -1,6 +1,6 @@ 'use strict' -const EventEmitter = require('events') +const EventEmitter = require('proper-event-emitter') const multiaddr = require('multiaddr') const debug = require('debug') diff --git a/src/connection-manager/index.js b/src/connection-manager/index.js index 1b1d807c..d7c4a00f 100644 --- a/src/connection-manager/index.js +++ b/src/connection-manager/index.js @@ -9,7 +9,7 @@ const mergeOptions = require('merge-options') const LatencyMonitor = require('./latency-monitor') const retimer = require('retimer') -const { EventEmitter } = require('events') +const EventEmitter = require('proper-event-emitter') const PeerId = require('peer-id') @@ -199,6 +199,7 @@ class ConnectionManager extends EventEmitter { const storedConn = this.connections.get(peerIdStr) this.emit('peer:connect', connection) + if (storedConn) { storedConn.push(connection) } else { diff --git a/src/index.js b/src/index.js index cd900457..b64a1086 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,6 @@ 'use strict' -const { EventEmitter } = require('events') +const EventEmitter = require('proper-event-emitter') const debug = require('debug') const globalThis = require('ipfs-utils/src/globalthis') const log = debug('libp2p') diff --git a/src/peer-store/index.js b/src/peer-store/index.js index 69a1f15a..0c2e7fb5 100644 --- a/src/peer-store/index.js +++ b/src/peer-store/index.js @@ -5,7 +5,7 @@ const debug = require('debug') const log = debug('libp2p:peer-store') log.error = debug('libp2p:peer-store:error') -const { EventEmitter } = require('events') +const EventEmitter = require('proper-event-emitter') const PeerId = require('peer-id') const AddressBook = require('./address-book') diff --git a/test/core/event-handling-error.spec.js b/test/core/event-handling-error.spec.js new file mode 100644 index 00000000..7a30c70a --- /dev/null +++ b/test/core/event-handling-error.spec.js @@ -0,0 +1,98 @@ +'use strict' +/* eslint-env mocha */ + +const chai = require('chai') +chai.use(require('dirty-chai')) +const { expect } = chai + +const errCode = require('err-code') +const { isNode, isWebWorker } = require('ipfs-utils/src/env') + +const multiaddr = require('multiaddr') +const PeerId = require('peer-id') + +const peerUtils = require('../utils/creators/peer') +const mockConnection = require('../utils/mockConnection') +const baseOptions = require('../utils/base-options.browser') +const { MULTIADDRS_WEBSOCKETS } = require('../fixtures/browser') + +const relayAddr = MULTIADDRS_WEBSOCKETS[0] +const code = 'HANDLER_ERROR' +const errorMsg = 'handle error' + +describe('event handlers error', () => { + // TODO: Need a way of catching the error in the process and absorb it + if (isWebWorker) { + return + } + + let libp2p + let peerId + + before(async () => { + peerId = await PeerId.create() + }) + + beforeEach(async () => { + [libp2p] = await peerUtils.createPeer({ + config: { + modules: baseOptions.modules, + addresses: { + listen: [multiaddr(`${relayAddr}/p2p-circuit`)] + } + }, + started: true + }) + }) + + afterEach(async () => { + libp2p && await libp2p.stop() + }) + + it('should throw on "peer:connect" event handler error', async () => { + const p = catchGlobalError() + + libp2p.connectionManager.on('peer:connect', () => { + throw errCode(new Error(errorMsg), code) + }) + + const connection = await mockConnection() + libp2p.connectionManager.onConnect(connection) + + await p + }) + + it('should throw on "peer:discovery" event handler error', async () => { + const p = catchGlobalError() + + libp2p.on('peer:discovery', () => { + throw errCode(new Error(errorMsg), code) + }) + + const ma = multiaddr('/ip4/127.0.0.1/tcp/0') + libp2p.peerStore.addressBook.add(peerId, [ma]) + + await p + }) +}) + +const catchGlobalError = () => { + return new Promise((resolve) => { + if (isNode) { + const originalException = process.listeners('uncaughtException').pop() + + originalException && process.removeListener('uncaughtException', originalException) + process.once('uncaughtException', (err) => { + expect(err).to.exist() + expect(err.code).to.eql(code) + + originalException && process.listeners('uncaughtException').push(originalException) + resolve() + }) + } else { + window.onerror = () => { + resolve() + } + } + }) +}