UNPKG

dotnode

Version:

.NET-like MVC framework for Node.js

260 lines (170 loc) 6.99 kB
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;