UNPKG

7.19 kBJavaScriptView Raw
1//
2// # Application
3//
4// Core application object. Manages application state and directs all the
5// different parts.
6//
7
8var util = require('util');
9var events = require('events');
10var async = require('async');
11var path = require('path');
12var http = require('http');
13var routes = require('routes');
14var dispatcher = require('./lib/dispatcher');
15var render = require('./lib/renderer');
16
17//
18// ## Application Constructor
19//
20// Create a new application object that inherits from *EventEmitter*.
21//
22// * **logger**, a custom instance of `Winston`. If not specified a default
23// logger will be created.
24//
25var Application = function (logger) {
26 events.EventEmitter.call(this);
27
28 this.controllers = {};
29 this.helpers = {};
30 this.paths = null;
31 this.config = null;
32 this.dispatcher = null;
33 this.renderer = null;
34 this.server = null;
35 this.logger = logger || new (require('winston').Logger)({
36 transports: [
37 new (require('winston').transports.Console)()
38 ]
39 });
40};
41
42// Extend event emitter.
43util.inherits(Application, events.EventEmitter);
44
45//
46// ## Shutdown
47//
48// Shutdown HTTP server and other connections.
49//
50Application.prototype.shutDown = function () {
51 this.server.close();
52};
53
54//
55// ## Bootstrap
56//
57// Bootstrap application by loading controllers, and helpers and everything.
58//
59// * **root**, root directory to bootstrap in.
60// * **callback**, called when boostrap is complete or if an error
61// is encountered.
62//
63Application.prototype.bootstrap = function (root, callback) {
64 var log = this.getLogger('info');
65 log('[Bootstrap] Bootstrap sequence initiated.');
66 this.root = root;
67 var self = this;
68 async.series(
69 [
70 // Setup paths
71 function loadPaths(fn) {
72 var paths = require('./lib/bootstrap/paths');
73 log('[Bootstrap] Initializing paths.');
74 self.paths = new paths(root, fn);
75 },
76 // Load configuration
77 function loadConf(fn) {
78 var config = require('./lib/bootstrap/conf');
79 var p = path.join(self.paths.get('config'), 'config.json');
80 self.config = config(p);
81 log('[Bootstrap] Config loaded.');
82 fn();
83 },
84 // Load controllers
85 function loadControllers(fn) {
86 var controllerLoader = require('./lib/bootstrap/controllerloader');
87 var p = self.paths.get('controllers');
88 log('[Bootstrap] Loading controllers:');
89 controllerLoader(p, function (n, c) {
90 log('\t Did load controller: %s', n);
91 self.setController(n, c);
92 }, fn);
93 },
94 // Load helpers
95 function loadHelpers(fn) {
96 var helperLoader = require('./lib/bootstrap/helperloader');
97 var p = self.paths.get('helpers');
98 log('[Bootstrap] Loading helpers:');
99 helperLoader(p, function (n, c) {
100 log('\t Did load helper: %s', n);
101 self.setHelper(n, c);
102 }, fn);
103 },
104 // Setup router and load routes
105 function setupRoutes(fn) {
106 var p = self.paths.get('config');
107 var routes = path.join(p, 'routes.json');
108 self.dispatcher = new dispatcher(self);
109 log('[Bootstrap] Loading routes.');
110 self.dispatcher.batchLoad(routes, fn);
111 },
112 // Initialize controllers, and helpers
113 function initializeControllers(fn) {
114 var initializers = [];
115 log('[Bootstrap] Initializing helpers and controllers:');
116
117 // Make sure the controllers maintain this-context in init.
118 function init(obj, app, name) {
119 return function (fn) {
120 log('\t Initializing %s', name);
121 if (obj.init.length === 2) {
122 obj.init(app, fn);
123 }
124 else {
125 obj.init(app);
126 fn();
127 }
128 };
129 }
130
131 // Get all controllers and helpers with init functions
132 for (var controller in self.controllers) {
133 if (typeof self.controllers[controller].init === 'function') {
134 initializers.push(init(self.controllers[controller], self, controller));
135 }
136 }
137 for (var helper in self.helpers) {
138 if (typeof self.helpers[helper].init === 'function') {
139 initializers.push(init(self.helpers[helper], self, helper));
140 }
141 }
142
143 // Execute initialize
144 async.parallel(initializers, fn);
145 },
146 // Preload views
147 function preloadViews(fn) {
148 var viewspath = self.paths.get('views');
149 self.renderer = new render(viewspath);
150 log('[Bootstrap] Views loaded.');
151 self.renderer.preload(fn);
152 },
153 // Setup server
154 function setupServer(fn) {
155 self.server = http.createServer(function (req, res) {
156 self.dispatcher.dispatch(req, res);
157 });
158
159 var port = self.config.get('http:port') || 3000;
160 self.server.listen(port, function () {
161 log('[Bootstrap] Server listning on port %d', port);
162 fn();
163 });
164 }
165 ],
166 function (err) {
167 callback(err);
168 });
169};
170
171//
172// ## Set Controller
173//
174// * **name**, the name of the controller.
175// * **controller**, the actual controller.
176//
177// **Returns** `false` if a controller by that name already exists.
178//
179Application.prototype.setController = function (name, controller) {
180 var ret = false;
181 if (!this.controllers[name]) {
182 this.controllers[name] = controller;
183 ret = true;
184 this.emit('controllerSet', [controller]);
185 }
186
187 return ret;
188};
189
190//
191// ## Get Controller
192//
193// * **name**, the name of the controller.
194//
195// **Returns** a controller or `false` if controller does not exist.
196//
197Application.prototype.getController = function (name) {
198 var ret = false;
199 if (this.controllers[name]) {
200 ret = this.controllers[name];
201 }
202
203 return ret;
204};
205
206//
207// ## Set Helper
208//
209// * **name**, name of the helper.
210// * **helper**, the helper.
211//
212// **Returns** `false` if a helper by that name already exists.
213//
214Application.prototype.setHelper = function (name, helper) {
215 var ret = false;
216 if (!this.helpers[name]) {
217 this.helpers[name] = helper;
218 ret = true;
219 this.emit('helperSet', [helper]);
220 }
221
222 return ret;
223};
224
225//
226// ## Get Helper
227//
228// * **name**, name of the helper.
229//
230// **Returns** a helper or `false` if a helper does not exist.
231//
232Application.prototype.getHelper = function (name) {
233 var ret = false;
234 if (this.helpers[name]) {
235 ret = this.helpers[name];
236 }
237
238 return ret;
239};
240
241//
242// ## Get logger
243//
244// Returns a function that can be used for convenience. It wraps the `logger`
245// in a closure so that you can do something like this in your code:
246//
247// var log = this.app.getLogger('info');
248// log('Foobar');
249//
250// All calls to `log` will behave like if you did:
251//
252// this.app.logger('info', 'Foobar');
253//
254// * **type**, the type of logger you want; `info`, `error` etc.
255//
256// **Returns** a function for logging.
257//
258Application.prototype.getLogger = function (type) {
259 var self = this;
260 return function () {
261 var args = Array.prototype.slice.call(arguments, 0);
262 args.unshift(type);
263 self.logger.log.apply(self.logger, args);
264 };
265};
266
267module.exports = Application;
268