From 8689cff26bbe5e1569efcaac112d6c90abb02e1a Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Mon, 17 Sep 2018 10:42:22 +0200 Subject: [PATCH] feat(emit-async): handle async listeners (#3416) Extracted from xo-server. --- @xen-orchestra/emit-async/.babelrc.js | 3 + @xen-orchestra/emit-async/.npmignore | 24 ++++++++ @xen-orchestra/emit-async/README.md | 71 +++++++++++++++++++++++ @xen-orchestra/emit-async/package.json | 47 +++++++++++++++ @xen-orchestra/emit-async/src/index.js | 26 +++++++++ CHANGELOG.md | 1 + packages/xo-server/package.json | 1 + packages/xo-server/src/xo-mixins/hooks.js | 28 +-------- 8 files changed, 174 insertions(+), 27 deletions(-) create mode 100644 @xen-orchestra/emit-async/.babelrc.js create mode 100644 @xen-orchestra/emit-async/.npmignore create mode 100644 @xen-orchestra/emit-async/README.md create mode 100644 @xen-orchestra/emit-async/package.json create mode 100644 @xen-orchestra/emit-async/src/index.js diff --git a/@xen-orchestra/emit-async/.babelrc.js b/@xen-orchestra/emit-async/.babelrc.js new file mode 100644 index 000000000..4e27ec135 --- /dev/null +++ b/@xen-orchestra/emit-async/.babelrc.js @@ -0,0 +1,3 @@ +module.exports = require('../../@xen-orchestra/babel-config')( + require('./package.json') +) diff --git a/@xen-orchestra/emit-async/.npmignore b/@xen-orchestra/emit-async/.npmignore new file mode 100644 index 000000000..e058b6bc1 --- /dev/null +++ b/@xen-orchestra/emit-async/.npmignore @@ -0,0 +1,24 @@ +/benchmark/ +/benchmarks/ +*.bench.js +*.bench.js.map + +/examples/ +example.js +example.js.map +*.example.js +*.example.js.map + +/fixture/ +/fixtures/ +*.fixture.js +*.fixture.js.map +*.fixtures.js +*.fixtures.js.map + +/test/ +/tests/ +*.spec.js +*.spec.js.map + +__snapshots__/ diff --git a/@xen-orchestra/emit-async/README.md b/@xen-orchestra/emit-async/README.md new file mode 100644 index 000000000..dec68a637 --- /dev/null +++ b/@xen-orchestra/emit-async/README.md @@ -0,0 +1,71 @@ +# @xen-orchestra/emit-async [![Build Status](https://travis-ci.org/${pkg.shortGitHubPath}.png?branch=master)](https://travis-ci.org/${pkg.shortGitHubPath}) + +> ${pkg.description} + +## Install + +Installation of the [npm package](https://npmjs.org/package/@xen-orchestra/emit-async): + +``` +> npm install --save @xen-orchestra/emit-async +``` + +## Usage + +```js +import EE from 'events' +import emitAsync from '@xen-orchestra/emit-async' + +const ee = new EE() +ee.emitAsync = emitAsync + +ee.on('start', async function () { + // whatever +}) + +// similar to EventEmmiter#emit() but returns a promise which resolves when all +// listeners have resolved +await ee.emitAsync('start') + +// by default, it will rejects as soon as one listener reject, you can customise +// error handling though: +await ee.emitAsync({ + onError (error) { + console.warn(error) + } +}, 'start') +``` + +## Development + +``` +# Install dependencies +> yarn + +# Run the tests +> yarn test + +# Continuously compile +> yarn dev + +# Continuously run the tests +> yarn dev-test + +# Build for production (automatically called by npm install) +> yarn build +``` + +## Contributions + +Contributions are *very* welcomed, either on the documentation or on +the code. + +You may: + +- report any [issue](${pkg.bugs}) + you've encountered; +- fork and create a pull request. + +## License + +${pkg.license} © [${pkg.author.name}](${pkg.author.url}) diff --git a/@xen-orchestra/emit-async/package.json b/@xen-orchestra/emit-async/package.json new file mode 100644 index 000000000..62b343fe2 --- /dev/null +++ b/@xen-orchestra/emit-async/package.json @@ -0,0 +1,47 @@ +{ + "private": true, + "name": "@xen-orchestra/emit-async", + "version": "0.0.0", + "license": "ISC", + "description": "", + "keywords": [], + "homepage": "https://github.com/vatesfr/xen-orchestra/tree/master/@xen-orchestra/emit-async", + "bugs": "https://github.com/vatesfr/xen-orchestra/issues", + "repository": { + "type": "git", + "url": "https://github.com/vatesfr/xen-orchestra.git" + }, + "author": { + "name": "Julien Fontanet", + "email": "julien.fontanet@vates.fr" + }, + "preferGlobal": false, + "main": "dist/", + "bin": {}, + "files": [ + "dist/" + ], + "browserslist": [ + ">2%" + ], + "engines": { + "node": ">=6" + }, + "dependencies": {}, + "devDependencies": { + "@babel/cli": "7.0.0", + "@babel/core": "7.0.0", + "@babel/preset-env": "7.0.0", + "babel-plugin-lodash": "^3.3.2", + "cross-env": "^5.1.3", + "rimraf": "^2.6.2" + }, + "scripts": { + "build": "cross-env NODE_ENV=production babel --source-maps --out-dir=dist/ src/", + "clean": "rimraf dist/", + "dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/", + "prebuild": "yarn run clean", + "predev": "yarn run prebuild", + "prepublishOnly": "yarn run build" + } +} diff --git a/@xen-orchestra/emit-async/src/index.js b/@xen-orchestra/emit-async/src/index.js new file mode 100644 index 000000000..177dff6c9 --- /dev/null +++ b/@xen-orchestra/emit-async/src/index.js @@ -0,0 +1,26 @@ +export default function emitAsync (event) { + let opts + let i = 1 + + // an option object has been passed as first param + if (typeof event !== 'string') { + opts = event + event = arguments[i++] + } + + const n = arguments.length - i + const args = new Array(n) + for (let j = 0; j < n; ++j) { + args[j] = arguments[j + i] + } + + const onError = opts != null && opts.onError + + return Promise.all( + this.listeners(event).map(listener => + new Promise(resolve => { + resolve(listener.apply(this, args)) + }).catch(onError) + ) + ) +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 687a43dfd..55fcd0477 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ ### Released packages +- @xen-orchestra/emit-async v0.0.0 - xo-server v5.27.0 - xo-web v5.27.0 diff --git a/packages/xo-server/package.json b/packages/xo-server/package.json index 71fb2ceee..20b90e41a 100644 --- a/packages/xo-server/package.json +++ b/packages/xo-server/package.json @@ -33,6 +33,7 @@ "dependencies": { "@babel/polyfill": "7.0.0", "@xen-orchestra/cron": "^1.0.3", + "@xen-orchestra/emit-async": "^0.0.0", "@xen-orchestra/fs": "^0.3.0", "ajv": "^6.1.1", "app-conf": "^0.5.0", diff --git a/packages/xo-server/src/xo-mixins/hooks.js b/packages/xo-server/src/xo-mixins/hooks.js index ce6565b6b..940b407a5 100644 --- a/packages/xo-server/src/xo-mixins/hooks.js +++ b/packages/xo-server/src/xo-mixins/hooks.js @@ -1,34 +1,8 @@ import createLogger from 'debug' +import emitAsync from '@xen-orchestra/emit-async' const debug = createLogger('xo:hooks') -function emitAsync (event) { - let opts - let i = 1 - - // an option object has been passed as first param - if (typeof event !== 'string') { - opts = event - event = arguments[i++] - } - - const n = arguments.length - i - const args = new Array(n) - for (let j = 0; j < n; ++j) { - args[j] = arguments[j + i] - } - - const onError = opts != null && opts.onError - - return Promise.all( - this.listeners(event).map(listener => - new Promise(resolve => { - resolve(listener.apply(this, args)) - }).catch(onError) - ) - ) -} - const makeSingletonHook = (hook, postEvent) => { let promise return function () {