Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugin dependencies #1088

Merged
merged 4 commits into from
Oct 1, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 73 additions & 17 deletions docs/Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,10 @@
- [`plugin.hapi`](#pluginhapi)
- [`plugin.app`](#pluginapp)
- [`plugin.events`](#pluginevents)
- [`plugin.plugins`](#pluginplugins)
- [`plugin.log(tags, [data, [timestamp]])`](#pluginlogtags-data-timestamp)
- [`plugin.dependency(deps)`](#plugindependencydeps)
- [`plugin.dependency(deps, [after])`](#plugindependencydeps-after)
- [`plugin.after(method)`](#pluginaftermethod)
- [`plugin.views(options)`](#pluginviewsoptions)
- [`plugin.helper(name, method, [options])`](#pluginhelpername-method-options)
- [`plugin.helpers`](#pluginhelpers)
Expand All @@ -108,8 +110,8 @@
- [Selectable methods and properties](#selectable-methods-and-properties)
- [`plugin.select(labels)`](#pluginselectlabels)
- [`plugin.length`](#pluginlength)
- [`plugin.api(key, value)`](#pluginapikey-value)
- [`plugin.api(obj)`](#pluginapiobj)
- [`plugin.expose(key, value)`](#pluginexposekey-value)
- [`plugin.expose(obj)`](#pluginexposeobj)
- [`plugin.route(options)`](#pluginrouteoptions)
- [`plugin.route(routes)`](#pluginrouteroutes)
- [`plugin.state(name, [options])`](#pluginstatename-options)
Expand Down Expand Up @@ -281,7 +283,7 @@ Each instance of the `Server` object have the following properties:
- `uri` - a string with the following format: 'protocol://host:port' (e.g. 'http://example.com:8080').
- `listener` - the node HTTP server object.
- `pack` - the [`Pack`](#hapipack) object the server belongs to (automatically assigned when creating a server instance directly).
- `plugins` - an object where each key is a plugin name and the value is the API registered by that plugin using [`plugin.api()`](#pluginapikey-value).
- `plugins` - an object where each key is a plugin name and the value are the exposed properties by that plugin using [`plugin.expose()`](#pluginexposekey-value).
- `settings` - an object containing the [server options](#server-options) after applying the defaults.

### `Server` methods
Expand Down Expand Up @@ -2593,7 +2595,7 @@ Registers a list of plugins where:
- `err` - an error returned from `exports.register()`. Note that incorrect usage, bad configuration, missing permissions, or namespace conflicts
(e.g. among routes, helpers, state) will throw an error and will not return a callback.

Batch registration is required when plugins declare a [dependency](#plugindependencydeps), so that all the required dependencies are loaded in
Batch registration is required when plugins declare a [dependency](#plugindependencydeps-after), so that all the required dependencies are loaded in
a single transaction (internal order does not matter).

```javascript
Expand Down Expand Up @@ -2842,7 +2844,7 @@ exports.register = function (plugin, options, next) {
return plugins;
};

plugin.api('plugins', listPlugins);
plugin.expose('plugins', listPlugins);
next();
};
```
Expand Down Expand Up @@ -2948,6 +2950,19 @@ exports.register = function (plugin, options, next) {
};
```

#### `plugin.plugins`

An object where each key is a plugin name and the value are the exposed properties by that plugin using [`plugin.expose()`](#pluginexposekey-value)
when called at the plugin root level (without calling `plugin.select()`).

```javascript
exports.register = function (plugin, options, next) {

console.log(plugin.plugins.example.key);
next();
};
```

#### `plugin.log(tags, [data, [timestamp]])`

Emits a `'log'` event on the `pack.events` emitter using the same interface as [`server.log()`](#serverlogtags-data-timestamp).
Expand All @@ -2960,18 +2975,58 @@ exports.register = function (plugin, options, next) {
};
```

#### `plugin.dependency(deps)`
#### `plugin.dependency(deps, [after])`

Declares a required dependency upon other plugins where:

- `deps` - a single string or array of strings of plugin names which must be registered in order for this plugin to operate. Plugins listed
must be registered in the same pack transaction to allow validation of the dependency requirements. Does not provide version dependency which
should be implemented using [npm peer dependencies](http://blog.nodejs.org/2013/02/07/peer-dependencies/).
- `after` - an optional function called after all the specified dependencies have been registered and before the servers start. The function is only
called if the pack servers are started. If a circular dependency is created, the call will assert (e.g. two plugins each has an `after` function
to be called after the other). The function signature is `function(plugin, next)` where:
- `plugin` - the [plugin interface](#plugin-interface) object.
- `next` - the callback function the method must call to return control over to the application and complete the registration process. The function
signature is `function(err)` where:
- `err` - internal plugin error condition, which is returned back via the [`pack.start(callback)`](#packstartcallback) callback. A plugin
registration error is considered an unrecoverable event which should terminate the application.

```javascript
exports.register = function (plugin, options, next) {

plugin.dependency('yar');
plugin.dependency('yar', after);
next();
};

var after = function (plugin, next) {

// Additional plugin registration logic
next();
};
```

#### `plugin.after(method)`

Add a method to be called after all the required plugins have been registered and before the servers start. The function is only
called if the pack servers are started. Arguments:

- `after` - the method with signature `function(plugin, next)` where:
- `plugin` - the [plugin interface](#plugin-interface) object.
- `next` - the callback function the method must call to return control over to the application and complete the registration process. The function
signature is `function(err)` where:
- `err` - internal plugin error condition, which is returned back via the [`pack.start(callback)`](#packstartcallback) callback. A plugin
registration error is considered an unrecoverable event which should terminate the application.

```javascript
exports.register = function (plugin, options, next) {

plugin.after(after);
next();
};

var after = function (plugin, next) {

// Additional plugin registration logic
next();
};
```
Expand Down Expand Up @@ -3179,32 +3234,33 @@ exports.register = function (plugin, options, next) {
};
```

#### `plugin.api(key, value)`
#### `plugin.expose(key, value)`

Adds an plugin API to the `server.plugins[name]` ('name' of plugin) object of each selected pack server where:
Exposes a property via `plugin.plugins[name]` (if added to the plugin root without first calling `plugin.select()`) and `server.plugins[name]`
('name' of plugin) object of each selected pack server where:

- `key` - the key assigned (`server.plugins[name][key]`).
- `key` - the key assigned (`server.plugins[name][key]` or `plugin.plugins[name][key]`).
- `value` - the value assigned.

```javascript
exports.register = function (plugin, options, next) {

plugin.api('util', function () { console.log('something'); });
plugin.expose('util', function () { console.log('something'); });
next();
};
```

#### `plugin.api(obj)`
#### `plugin.expose(obj)`

Merges a deep copy of an object into to the existing content of the `server.plugins[name]` ('name' of plugin) object of each
selected pack server where:
Merges a deep copy of an object into to the existing content of `plugin.plugins[name]` (if added to the plugin root without first calling
`plugin.select()`) and `server.plugins[name]` ('name' of plugin) object of each selected pack server where:

- `obj` - the object merged into the API container.
- `obj` - the object merged into the exposed properties container.

```javascript
exports.register = function (plugin, options, next) {

plugin.api({ util: function () { console.log('something'); } });
plugin.expose({ util: function () { console.log('something'); } });
next();
};
```
Expand Down
39 changes: 20 additions & 19 deletions lib/ext.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,15 @@ var Utils = require('./utils');

var internals = {};

/*
Extension functions use the following signature: function (request, next) { next(); }
*/

module.exports = internals.Ext = function () {

this._events = {
onRequest: null, // New request, before handing over to the router (allows changes to the request method, url, etc.)
onPreAuth: null, // After cookie parse and before authentication (skipped if state error)
onPostAuth: null, // After authentication (and payload processing) and before validation (skipped if auth or payload error)
onPreHandler: null, // After validation and body parsing, before route handler (skipped if auth or validation error)
onPostHandler: null, // After route handler returns, before sending response (skipped if onPreHandler not called)
onPreResponse: null // Before response is sent (always called)
};

// Extension functions use the following signature: function (request, next) { next(); }

module.exports = internals.Ext = function (events) {

this._events = {};
for (var i = 0, il = events.length;i<il;++i) {
this._events[events[i]] = null;
}
};


Expand All @@ -39,7 +34,7 @@ internals.Ext.prototype._add = function (event, func, options, plugin) {

options = options || {};

Utils.assert(['onRequest', 'onPreAuth', 'onPostAuth', 'onPreHandler', 'onPostHandler', 'onPreResponse'].indexOf(event) !== -1, 'Unknown event type', event);
Utils.assert(this._events.hasOwnProperty(event), 'Unknown event type', event);

// Validate rules

Expand Down Expand Up @@ -85,23 +80,27 @@ internals.Ext.prototype.invoke = function (request, event, callback) {
return Utils.nextTick(callback)();
}

var log = request.log.bind(request);
var log = (request ? request.log.bind(request) : null);

Async.forEachSeries(handlers, function (ext, next) {

request.context = (ext.plugin ? ext.plugin.context : undefined);
if (request) {
request.context = (ext.plugin ? ext.plugin.context : undefined);
}

internals.Ext.runProtected(log, event, next, function (enter, exit) {

enter(function () {

ext.func(request, exit);
ext.func(request || ext.plugin.root, exit);
});
});
},
function (err) {

delete request.context;
if (request) {
delete request.context;
}

return callback(err);
});
Expand All @@ -110,6 +109,8 @@ internals.Ext.prototype.invoke = function (request, event, callback) {

internals.Ext.runProtected = function (log, tags, next, setup) { // setup: function (enter, exit)

log = log || Utils.ignore;

var domain = Domain.createDomain();

// Ensure only one next returned
Expand Down
Loading