1 | var fileExists = require('fs').existsSync,
|
2 | path = require('path'),
|
3 | fs = require('fs');
|
4 |
|
5 | var log = require('xqnode-logger'),
|
6 | express = require('express'),
|
7 | glob = require('glob'),
|
8 | async = require('async');
|
9 |
|
10 | module.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 |
|
27 | this.port = conf.port || 3000;
|
28 |
|
29 |
|
30 | this.name = conf.name || 'Express server';
|
31 |
|
32 |
|
33 | this.baseDir = conf.baseDir || process.cwd();
|
34 |
|
35 |
|
36 | this.apiRoute = conf.apiRoute || null;
|
37 |
|
38 |
|
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 |
|
53 |
|
54 |
|
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 |
|
98 |
|
99 |
|
100 |
|
101 | app.baseDir = this.baseDir;
|
102 |
|
103 |
|
104 | if (this.requestLogFile) {
|
105 | app.use(this.requestLogger.bind(this));
|
106 | }
|
107 |
|
108 | var jobs = [];
|
109 |
|
110 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
208 |
|
209 | ExpressServer.prototype.stop = function() {
|
210 | log.sys('Stoping ' + this.name);
|
211 | };
|
212 |
|
213 | |
214 |
|
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 |