Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Avatar for KuCalc : devops.
Download
50655 views
1
/*
2
* app.js: Core Application object for managing plugins and features in broadway
3
*
4
* (C) 2011, Nodejitsu Inc.
5
* MIT LICENSE
6
*
7
*/
8
9
var utile = require('utile'),
10
async = utile.async,
11
events = require('eventemitter2'),
12
bootstrapper = require('./bootstrapper'),
13
common = require('./common'),
14
features = require('./features');
15
16
var App = exports.App = function (options) {
17
//
18
// Setup options and `App` constants.
19
//
20
var self = this;
21
options = options || {};
22
this.root = options.root;
23
this.delimiter = options.delimiter || '::';
24
25
//
26
// Inherit from `EventEmitter2`
27
//
28
events.EventEmitter2.call(this, {
29
delimiter: this.delimiter,
30
wildcard: true
31
});
32
33
//
34
// Setup other relevant options such as the plugins
35
// for this instance.
36
//
37
this.options = options;
38
this.env = options.env || process.env['NODE_ENV'] || 'development'
39
this.plugins = options.plugins || {};
40
this.initialized = false;
41
this.bootstrapper = options.bootstrapper || bootstrapper;
42
this.initializers = {};
43
this.initlist = [];
44
45
//
46
// Bootstrap this instance
47
//
48
this.bootstrapper.bootstrap(this);
49
};
50
51
//
52
// Inherit from `EventEmitter2`.
53
//
54
utile.inherits(App, events.EventEmitter2);
55
56
//
57
// ### function init (options, callback)
58
// #### @options {Object} **Optional** Additional options to initialize with.
59
// #### @callback {function} Continuation to respond to when complete.
60
// Initializes this instance by the following procedure:
61
//
62
// 1. Initializes all plugins (starting with `core`).
63
// 2. Creates all directories in `this.config.directories` (if any).
64
// 3. Ensures the files in the core directory structure conform to the
65
// features required by this application.
66
//
67
App.prototype.init = function (options, callback) {
68
if (!callback && typeof options === 'function') {
69
callback = options;
70
options = {};
71
}
72
73
if (this.initialized) {
74
return callback();
75
}
76
77
var self = this;
78
options = options || {};
79
callback = callback || function () {};
80
this.env = options.env || this.env;
81
this.options = common.mixin({}, this.options, options);
82
83
function onComplete() {
84
self.initialized = true;
85
self.emit('init');
86
callback();
87
}
88
89
function ensureFeatures (err) {
90
return err
91
? onError(err)
92
: features.ensure(this, onComplete);
93
}
94
95
function initPlugin(plugin, next) {
96
if (typeof self.initializers[plugin] === 'function') {
97
return self.initializers[plugin].call(self, function (err) {
98
if (err) {
99
return next(err);
100
}
101
102
self.emit(['plugin', plugin, 'init']);
103
self.initializers[plugin] = true;
104
next();
105
});
106
}
107
108
next();
109
}
110
111
function initPlugins() {
112
async.forEach(self.initlist, initPlugin, ensureFeatures);
113
}
114
115
//
116
// Emit and respond with any errors that may short
117
// circuit the process.
118
//
119
function onError(err) {
120
self.emit(['error', 'init'], err);
121
callback(err);
122
}
123
124
//
125
// Run the bootstrapper, initialize plugins, and
126
// ensure features for this instance.
127
//
128
this.bootstrapper.init(this, initPlugins);
129
};
130
131
//
132
// ### function use(plugin, callback)
133
// Attachs the plugin with the specific name to this `App` instance.
134
//
135
App.prototype.use = function (plugin, options, callback) {
136
options = options || {};
137
138
if (typeof plugin === 'undefined') {
139
console.log('Cannot load invalid plugin!');
140
if (callback) {
141
callback(new Error('Invalid plugin'));
142
}
143
return;
144
}
145
146
var name = plugin.name,
147
self = this;
148
149
// If the plugin doesn't have a name, use itself as an identifier for the plugins hash.
150
if (!name) {
151
name = common.uuid();
152
}
153
154
if (this.plugins[name]) {
155
return callback && callback();
156
}
157
158
//
159
// Setup state on this instance for the specified plugin
160
//
161
this.plugins[name] = plugin;
162
this.options[name] = common.mixin({}, options, this.options[name] || {});
163
164
//
165
// Attach the specified plugin to this instance, extending
166
// the `App` with new functionality.
167
//
168
if (this.plugins[name].attach && options.attach !== false) {
169
this.plugins[name].attach.call(this, options);
170
}
171
172
//
173
// Setup the initializer only if `options.init` is
174
// not false. This allows for some plugins to be lazy-loaded
175
//
176
if (options.init === false) {
177
return;
178
}
179
180
if (!this.initialized) {
181
this.initializers[name] = plugin.init || true;
182
this.initlist.push(name);
183
}
184
else if (plugin.init) {
185
plugin.init.call(this, function (err) {
186
var args = err
187
? [['plugin', name, 'error'], err]
188
: [['plugin', name, 'init']];
189
190
self.emit.apply(self, args);
191
if (callback) {
192
return err ? callback(err) : callback();
193
}
194
});
195
}
196
};
197
198
//
199
// ### function remove(name)
200
// Detaches the plugin with the specific name from this `App` instance.
201
//
202
App.prototype.remove = function (name) {
203
// if this is a plugin object set the name to the plugins name
204
if (name.name) {
205
name = name.name;
206
}
207
208
if (this.plugins[name] && this.plugins[name].detach) {
209
this.plugins[name].detach.call(this);
210
}
211
212
delete this.plugins[name];
213
delete this.options[name];
214
delete this.initializers[name];
215
216
var init = this.initlist.indexOf(name);
217
218
if (init !== -1) {
219
this.initlist.splice(1, init);
220
}
221
}
222
223
//
224
// ### function inspect ()
225
// Inspects the modules and features used by the current
226
// application directory structure
227
//
228
App.prototype.inspect = function () {
229
230
};
231
232