feat(@embark/plugin): add priority to regsiterActionForEvents

This commit is contained in:
Jonathan Rainville 2019-11-06 14:45:05 -05:00
parent 6afe1ace08
commit 776db1b7f7
5 changed files with 126 additions and 6 deletions

View File

@ -5,6 +5,9 @@ const constants = require('embark-core/constants');
const fs = require('fs-extra');
const deepEqual = require('deep-equal');
// Default priority of actions with no specified priority. 1 => Highest
const DEFAULT_ACTION_PRIORITY = 50;
// TODO: pass other params like blockchainConfig, contract files, etc..
var Plugin = function(options) {
this.name = options.name;
@ -261,11 +264,15 @@ Plugin.prototype.registerImportFile = function(importName, importLocation) {
this.addPluginType('imports');
};
Plugin.prototype.registerActionForEvent = function(eventName, cb) {
Plugin.prototype.registerActionForEvent = function(eventName, options, cb) {
if (typeof options === 'function') {
cb = options;
options = {};
}
if (!this.eventActions[eventName]) {
this.eventActions[eventName] = [];
}
this.eventActions[eventName].push(cb);
this.eventActions[eventName].push({action: cb, options: Object.assign({priority: DEFAULT_ACTION_PRIORITY}, options)});
this.addPluginType('eventActions');
};

View File

@ -218,19 +218,31 @@ Plugins.prototype.runActionsForEvent = function(eventName, args, cb) {
return cb(null, args);
}
actionPlugins.sort((a, b) => {
const aPriority = a[0].options.priority;
const bPriority = b[0].options.priority;
if (aPriority < bPriority) {
return -1;
}
if (aPriority > bPriority) {
return 1;
}
return 0;
});
this.events.log("ACTION", eventName, "");
async.reduce(actionPlugins, args, function (current_args, pluginObj, nextEach) {
const [plugin, pluginName] = pluginObj;
self.events.log("== ACTION FOR " + eventName, plugin.name, pluginName);
self.events.log("== ACTION FOR " + eventName, plugin.action.name, pluginName);
if (typeof (args) === 'function') {
plugin.call(plugin, (...params) => {
plugin.action.call(plugin.action, (...params) => {
nextEach(...params || current_args);
});
} else {
plugin.call(plugin, args, (...params) => {
plugin.action.call(plugin.action, args, (...params) => {
nextEach(...params || current_args);
});
}

View File

@ -0,0 +1,60 @@
/*global __dirname, describe, it, beforeEach, afterEach, require*/
import * as i18n from 'embark-i18n';
const {fakeEmbark} = require('embark-testing');
const assert = require('assert');
const sinon = require('sinon');
const Plugins = require('../lib/core/plugins');
i18n.setOrDetectLocale('en');
describe('embark.plugins', function() {
this.timeout(0);
let plugins;
const {embark} = fakeEmbark();
embark.events.log = () => {};
beforeEach(() => {
plugins = new Plugins(embark);
});
afterEach(() => {
embark.teardown();
});
describe('runActionsForEvent', () => {
it('should run actions in order of priority', (done) => {
let lastFunctionSetsMeToTrue = false;
const getPluginsPropertyAndPluginNameStub = sinon.stub(plugins, 'getPluginsPropertyAndPluginName')
.returns([
[
{
action: (_params, cb) => {
// This function should be called second
lastFunctionSetsMeToTrue = true;
cb();
},
options: {priority: 50}
},
'Action 2'
],
[
{
action: (_params, cb) => {
// If this is called first, setting to false doesn't matter
lastFunctionSetsMeToTrue = false;
cb();
},
options: {priority: 30}
},
'Action 1'
]
]);
plugins.runActionsForEvent('bogusEvent', [], () => {
assert.strictEqual(lastFunctionSetsMeToTrue, true, 'Functions not called in order');
getPluginsPropertyAndPluginNameStub.restore();
done();
});
});
});
});

View File

@ -18,7 +18,7 @@ class EmbarkWeb3 {
this.setupEmbarkJS();
embark.registerActionForEvent("deployment:contract:deployed", this.registerInVm.bind(this));
embark.registerActionForEvent("deployment:contract:deployed", {priority: 40}, this.registerInVm.bind(this));
embark.registerActionForEvent("deployment:contract:undeployed", this.registerInVm.bind(this));
embark.registerActionForEvent("deployment:contract:deployed", this.registerArtifact.bind(this));
embark.registerActionForEvent("deployment:contract:undeployed", this.registerArtifact.bind(this));

View File

@ -438,3 +438,44 @@ module.exports = function(embark) {
embark.registerImportFile("my-lib", path.join(__dirname, "my-lib.js"));
}
```
## .registerActionForEvent(eventName, options, cb)
This lets you register an action for an event. An action, is like a regular command handler event, but enables multiple actions to be registered for the same event and let's you modify the params before sending them back to the next action or back to Embark.
Here is an example where, before deploying a contract, we check the length of the bytecode to see if it reaches the limit:
```
embark.registerActionForEvent("deployment:contract:beforeDeploy", async (params, cb) => {
cosnt contarct = params.contract;
if (!contract.code) {
return callback();
}
const code = (contract.code.indexOf('0x') === 0) ? contract.code.substr(2) : contract.code;
const contractCodeLength = Buffer.from(code, 'hex').toString().length;
if (contractCodeLength > MAX_CONTRACT_BYTECODE_LENGTH) {
return callback(new Error(`Bytecode for ${contract.className} contract is too large. Not deploying.`));
}
callback();
});
```
### Parameters
- `eventName`: String, Name fo the event you want an action to be registered to
- `options`: Object, optional, options for the action registration
- `priority`: Integer, priority for when the action should be called. Useful if you want to run before or after other actions. The default priority is 50 and the highest priority is 1 (so high priority runs first)
### Available events for actions
- `embark:engine:started`: Called when the engine just started. No params
- `blockchain:config:modify`: Let's you modify the blockchain configs before starting a blockchain node. Only param is the initial `blockchainConfig`
- `deployment:contract:beforeDeploy`: Called before a contract is deployed. Only param is the `contract`
- `deployment:contract:shouldDeploy`: Also called before a contract is deployed, but let's you determine if the contract should be deployed. Two params: `contract` and `shouldDeploy`, set `shouldDeploy` to `false` to disable its deployment
- `deployment:contract:undeployed`: Called after a contract is determined to not deploy. Only param is `contract`
- `deployment:contract:deployed`: Called after a contract deployed. Only param is `contract`
- `deployment:deployContracts:beforeAll`: Called before any contract is deployed. No params
- `deployment:deployContracts:afterAll`: Called after all contracts have deployed. No params
- `tests:contracts:compile:before`: Called before the contracts are compiled in the context of the test. Only param is `contractFiles`
- `tests:contracts:compile:after`: Called after the contracts are compiled in the context of the test. Only param is `compiledContracts`
- `blockchain:proxy:request`: Called before a request from Embark or the Dapp is sent to the blockchain node. You can modify or react to the payload of the request. Only param is `reqData`, an object containing the payload
- `blockchain:proxy:response`: Called before the node response is sent back to Embark or the Dapp. You can modify or react to the payload of the response. Two params, `reqData` and `respData`, objects containing the payloads