UNPKG

5.7 kBJavaScriptView Raw
1var fileExists = require('fs').existsSync,
2 path = require('path'),
3 fs = require('fs');
4
5var log = require('xqnode-logger'),
6 express = require('express'),
7 glob = require('glob'),
8 async = require('async');
9
10module.exports = function() {
11 "use strict";
12
13 var app, cbDone;
14
15 var ExpressServer = function(conf) {
16 conf = conf || {};
17
18
19 if (conf.logLevel) {
20 log.setLevel(conf.logLevel);
21 }
22 else {
23 log.setLevel('sys');
24 }
25
26 //Default port
27 this.port = conf.port || 3000;
28
29 //Default name
30 this.name = conf.name || 'Express server';
31
32 //Base dir
33 this.baseDir = conf.baseDir || process.cwd();
34
35 //API route (Default is disabled)
36 this.apiRoute = conf.apiRoute || null;
37
38 //Request logging config
39 if (conf.requestLog) {
40 this.requestLogFile = conf.requestLogFile || path.join(this.baseDir, 'log', 'request.log');
41 }
42
43 this.allRoutes = [];
44
45 app = express();
46 app.express = express;
47 app.logger = log;
48 this.app = app;
49 };
50
51 /**
52 * Starts an express server
53 *
54 * @method start
55 */
56 ExpressServer.prototype.start = function(opts, callback) {
57 if (typeof opts === 'function') {
58 callback = opts;
59 opts = null;
60 }
61
62 opts = opts || {
63 disableServer: false
64 };
65
66 cbDone = false;
67 if (!callback) {
68 callback = function() {};
69 }
70
71 app.addRoute = function(method, path, info, options, callback) {
72 if (typeof options === 'function') {
73 callback = options;
74 options = null;
75 }
76
77 var fn = Array.prototype.slice.call(arguments);
78 while(fn.length > 0 && typeof fn[0] !== 'function') {
79 fn.shift();
80 }
81
82 fn.unshift(path);
83 app[method].apply(app, fn);
84 this.allRoutes.push({
85 method: method,
86 path: path,
87 info: info,
88 options: options,
89 callback: callback
90 });
91 }.bind(this);
92
93 log.sys('Starting ' + this.name);
94 log.sys(' ... environment:', app.get('env'));
95 log.sys(' ... set base dir to:', this.baseDir);
96
97 // app.use(express.logger('dev'));
98 // app.engine('.hbs', require('hbs').__express);
99 // app.set('view engine', 'hbs');
100 // app.set('views', path.join(this.baseDir, 'views'));
101 app.baseDir = this.baseDir;
102
103 //Enable request logging
104 if (this.requestLogFile) {
105 app.use(this.requestLogger.bind(this));
106 }
107
108 var jobs = [];
109
110 //Load Environment configuration
111 var envConf = path.join(this.baseDir, 'server/env', app.get('env') + '.js');
112 if (fileExists(envConf)) {
113 jobs.push(function(callback) {
114 log.sys(' ... load environment config');
115 require(envConf).call(this, app, callback);
116 }.bind(this));
117 }
118 else {
119 log.sys(' ... no environment config found!');
120 }
121
122 //Load express.js
123 var expressFile = path.join(app.baseDir, 'server/express.js');
124 if (fileExists(expressFile)) {
125 jobs.push(function(callback) {
126 log.sys(' ... Load express.js');
127 require(expressFile)(app, callback);
128 }.bind(this));
129 }
130
131 //Load database.js
132 var databaseFile = path.join(app.baseDir, 'server/database.js');
133 if (fileExists(databaseFile)) {
134 jobs.push(function(callback) {
135 log.sys(' ... Load database.js');
136 require(databaseFile)(app, callback);
137 }.bind(this));
138 }
139
140 //Load routes
141 if (opts.disableRoutes !== true) {
142 jobs.push(function(callback) {
143 var routesDir = path.join(this.baseDir, 'routes/**/*.js');
144 var files = glob.sync(routesDir);
145 if (files.length !== 0) {
146 files.forEach(function(file) {
147 log.sys(' ... load route', file);
148 require(file).call(this, app, callback);
149 }.bind(this));
150 }
151 else {
152 callback();
153 }
154 }.bind(this));
155 }
156
157 //Load API view
158 if (this.apiRoute) {
159 jobs.push(function(callback) {
160 log.sys(' ... register api route', this.apiRoute);
161 require(path.join(__dirname, 'routes/api')).call(this, app);
162 callback();
163 }.bind(this));
164 }
165
166 async.series(jobs, function(err, result) {
167 if (cbDone) {
168 return;
169 }
170
171 cbDone = true;
172
173 if (err) {
174 log.err('Can\'t boot the server.');
175 log.err((err.message || err));
176 process.exit(1);
177 return;
178 }
179
180 app.use(function(err, req, res, next) {
181 console.error(err.stack);
182 res.send(500, 'Something broke!\n');
183 });
184
185 if (opts.disableServer !== true) {
186 log.sys(' ... listening on port ', this.port);
187 log.sys('Server started successfull!');
188 app.listen(this.port);
189 }
190
191 //Load init script
192 var initFile = path.join(app.baseDir, 'server/init.js');
193 if (fileExists(initFile)) {
194 require(initFile)(app, callback.bind(this, app));
195 }
196 else {
197
198 callback.call(this, app);
199 }
200
201 }.bind(this));
202
203 return app;
204 };
205
206 /**
207 * Stopping express server
208 */
209 ExpressServer.prototype.stop = function() {
210 log.sys('Stoping ' + this.name);
211 };
212
213 /**
214 * Handle JSON result
215 */
216 ExpressServer.prototype.handleJSONResult = function(err, data) {
217 if (err) {
218 log.err(err);
219 this.send(500, 'Something went wrong!');
220 return;
221 }
222
223 this.json(data);
224 };
225
226 ExpressServer.prototype.requestLogger = function(req, res, next) {
227 var startTime = Date.now(),
228 logFile = this.requestLogFile;
229
230 var LogIt = function() {
231 console.log('REQ:', req);
232 var parseTime = Date.now() - startTime;
233 res.removeListener('finish', LogIt);
234
235 var data = '[' + (new Date()).toString() + ']';
236 data += ' ' + res.statusCode;
237 data += ' ' + parseTime + 'ms';
238 data += ' ' + req.method;
239 data += ' "' + req.protocol;
240 data += '://' + req.get('host');
241 data += req.originalUrl + '"';
242 data += ' "' + res.get('content-type') + '"';
243 data += ' "' + req.get('user-agent') + '"';
244 if (req.sessionID) {
245 data += ' (' + req.sessionID + ')';
246 }
247 data += '\n';
248
249 fs.appendFile(logFile, data, function() {});
250 };
251
252 res.on('finish', LogIt);
253
254 next();
255 };
256
257 return ExpressServer;
258
259}();
\No newline at end of file