dotnode
Version:
.NET-like MVC framework for Node.js
260 lines (170 loc) • 6.99 kB
JavaScript
var fs = require('fs'),
path = require('path');
var dirName = path.dirname(fs.realpathSync(__filename)),
cwd = process.cwd();
var express = require('express'),
http = require('http'),
path = require('path'),
extend = require('xtend'),
connectDomain = require('connect-domain'),
RouteTable = require(dirName + '/routes/routeTable'),
Router = require(dirName + '/routes/router'),
BindingDictionary = require(dirName + '/ioc/bindingDictionary'),
ApplicationContext = require(dirName + '/models/applicationContext');
var routeConfig = null,
bindingConfig = null;
var MvcApp = function (configuration) {
configuration = configuration || {};
this._initConfiguration(configuration);
};
// #region express config
MvcApp.prototype._initConfiguration = function (configuration) {
this._initApplicationConfiguration(configuration);
this._initRoutesConfiguration(configuration);
this._initBindingsConfiguration(configuration);
};
MvcApp.prototype._initApplicationConfiguration = function (configuration) {
var appConfigPath = cwd + (configuration.configPath || '/config/appConfig');
this._appConfig = extend({}, configuration || {});
if (fs.existsSync(appConfigPath)) {
this._appConfig = extend(require(appConfigPath), this._appConfig);
}
};
MvcApp.prototype._initRoutesConfiguration = function (configuration) {
if (configuration.routeConfig) {
routeConfig = configuration.routeConfig;
} else {
if (fs.existsSync(cwd + '/app_start/routeConfig.js')) {
routeConfig = require(cwd + '/app_start/routeConfig');
} else {
routeConfig = function () {
throw new Error('You have no registered routes');
};
}
}
};
MvcApp.prototype._initBindingsConfiguration = function (configuration) {
if (fs.existsSync(cwd + '/app_start/bindingConfig.js')) {
bindingConfig = require(cwd + '/app_start/bindingConfig');
} else {
bindingConfig = function () { };
}
};
MvcApp.prototype._initExpress = function () {
var app = this.app;
app.configure(this._configureExpress.bind(this, this.app));
app.configure('development', this._configureExpressForDev.bind(this, this.app));
app.configure('release', this._configureExpressForRelease.bind(this, this.app));
this.app = app;
};
MvcApp.prototype._configureExpress = function (app) {
app.use(connectDomain());
app.use(express.logger('dev'));
this._configureStaticRoutes(app);
app.use(express.bodyParser());
app.use(app.router);
app.use(express.methodOverride());
app.use(express.favicon());
app.use(this._serverNotFoundHandler.bind(this));
};
MvcApp.prototype._configureExpressForDev = function (app) {
app.use(this._serverErrorHandler.bind(this));
app.set('port', 3000);
};
MvcApp.prototype._configureExpressForRelease = function (app) {
app.use(this._serverErrorHandler.bind(this));
app.set('port', 80);
};
MvcApp.prototype._configureStaticRoutes = function (app) {
this.publicDirectory = this.publicDirectory || 'public';
var appDirectory = path.dirname(require.main.filename);
app.use(express.static(path.join(appDirectory, this.publicDirectory)));
};
MvcApp.prototype._configureErrorPages = function (app) {
app.use(this._serverErrorHandler.bind(this));
};
MvcApp.prototype._serverErrorHandler = function (err, request, response, next) {
var env = process.env.NODE_ENV || 'development',
errorMessage = err.stack || err.toString();
if (err.status) {
response.statusCode = err.status
}
if (response.statusCode < 400) {
response.statusCode = 500;
}
if (env !== 'test') {
console.error(errorMessage);
}
if (response._header && request.socket && typeof request.socket == 'function') {
return request.socket.destroy();
}
if (this._appConfig.errors && this._appConfig.errors['' + response.statusCode]) {
var errorHandler = this._appConfig.errors['' + response.statusCode];
if (typeof errorHandler == 'function') {
errorHandler(err, request, response, next);
}
if (typeof errorHandler == 'string') {
response.writeHead(response.statusCode, { Location: errorHandler });
response.end();
}
} else {
response.writeHead(response.statusCode, { 'Content-Type': 'text/html' });
response.end('Server responded with status ' + response.statusCode + '. \n' + errorMessage);
}
};
MvcApp.prototype._serverNotFoundHandler = function (request, response, next) {
if (this._appConfig.errors && this._appConfig.errors['404']) {
var errorHandler = this._appConfig.errors['404'];
if (typeof errorHandler == 'function') {
errorHandler(request, response, next);
}
if (typeof errorHandler == 'string') {
response.writeHead(404, { Location: errorHandler });
response.end();
}
} else {
response.writeHead(response.statusCode, { 'Content-Type': 'text/html' });
response.end('Server responded with status 404. \n Page not found');
}
};
// #endregion
MvcApp.prototype._configureRoutes = function () {
var routeTable = new RouteTable();
routeConfig(routeTable);
var applicationContext = new ApplicationContext(routeTable.getRoutes());
applicationContext.bindings = this._getControllerBindings();
applicationContext.appConfig = extend({}, this._appConfig);
this.router = new Router(this.app, applicationContext);
this.router.registerRoutes(routeTable);
};
MvcApp.prototype._getControllerBindings = function () {
var bindingDictionary = new BindingDictionary();
bindingConfig(bindingDictionary);
return bindingDictionary;
};
// #region public methods
MvcApp.prototype.start = function () {
this.app = express();
this._initExpress();
this._configureRoutes();
var port = this.app.get('port');
this._server = http.createServer(this.app);
this._server.listen(port, function () {
console.log('listening on port ' + port);
});
};
MvcApp.prototype.setPublicDirectory = function (publicDirectory) {
this.publicDirectory = publicDirectory;
return this;
};
MvcApp.prototype.getApplicationContext = function () {
if (!this.appContext) {
var routes = this.router.getRoutes();
this.appContext = new ApplicationContext();
this.appContext.routes = routes;
this.appContext.publicDirectory = this.publicDirectory;
}
return this.appContext;
};
// #endregion
module.exports = MvcApp;