thinknode
Version:
A fast, flexible and all-in-one web framework for node.js.
356 lines (309 loc) • 11 kB
JavaScript
;
exports.__esModule = true;
var _promise = require('babel-runtime/core-js/promise');
var _promise2 = _interopRequireDefault(_promise);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
var _cluster = require('cluster');
var _cluster2 = _interopRequireDefault(_cluster);
var _os = require('os');
var _os2 = _interopRequireDefault(_os);
var _http2 = require('http');
var _http3 = _interopRequireDefault(_http2);
var _Base = require('../Base');
var _Base2 = _interopRequireDefault(_Base);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* remove / start or end of pathname
* @return {} []
*/
/**
*
* @author richen
* @copyright Copyright (c) 2015 - <richenlin(at)gmail.com>
* @license MIT
* @version 15/11/26
*/
var cleanPathname = function cleanPathname(pathname) {
if (pathname === '/') {
return '';
}
if (pathname[0] === '/') {
pathname = pathname.slice(1);
}
if (pathname.slice(-1) === '/') {
pathname = pathname.slice(0, -1);
}
return pathname;
};
/**
* 小驼峰命名正则转换
* @type {RegExp}
*/
var sCamelReg = function sCamelReg(str) {
var re = /_(\w)/g;
return str.replace(re, function (all, letter) {
return letter.toUpperCase();
});
};
/**
* 大驼峰命名正则转换
* @type {RegExp}
*/
var bCamelReg = function bCamelReg(str) {
var re = /_(\w)/g;
var rstr = str.slice(1).replace(re, function (all, letter) {
return letter.toUpperCase();
});
return str[0].toUpperCase() + rstr;
};
/**
* 检测Group,Controller和Action是否合法
* @type {RegExp}
*/
var nameReg = function nameReg(str) {
if (/^[A-Za-z\_0-9]\w*$/.test(str)) {
return true;
}
return false;
};
/**
* 解析pathname获取group
* @param group
* @param defaultValue
* @returns {*}
*/
var parseGroup = function parseGroup(group) {
var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'Home';
if (!group) {
return defaultValue;
} else if (!nameReg(group)) {
return null;
}
return bCamelReg(group);
};
/**
* 解析pathname获取controller
* @param controller
* @param defaultValue
* @returns {*}
*/
var parseController = function parseController(controller) {
var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'Index';
if (!controller) {
return defaultValue;
} else if (!nameReg(controller)) {
return null;
}
return bCamelReg(controller);
};
/**
* 解析pathname获取action
* @param action
* @param defaultValue
* @returns {*}
*/
var parseAction = function parseAction(action) {
var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'Index';
if (!action) {
return defaultValue;
} else if (!nameReg(action)) {
return null;
}
return sCamelReg(action);
};
var _class = function (_base) {
(0, _inherits3.default)(_class, _base);
function _class() {
(0, _classCallCheck3.default)(this, _class);
return (0, _possibleConstructorReturn3.default)(this, _base.apply(this, arguments));
}
/* eslint-disable consistent-return */
_class.run = function run() {
var clusterNums = THINK.config('use_cluster');
//不使用cluster
if (!clusterNums) {
return this.createServer();
} else {
//使用cpu的个数
if (clusterNums === true) {
clusterNums = _os2.default.cpus().length;
}
if (_cluster2.default.isMaster) {
for (var i = 0; i < clusterNums; i++) {
_cluster2.default.fork();
}
_cluster2.default.on('exit', function (worker) {
THINK.log(new Error('worker ' + worker.process.pid + ' died'));
process.nextTick(function () {
return _cluster2.default.fork();
});
});
} else {
this.createServer();
}
}
};
/**
* 创建HTTP服务
*/
_class.createServer = function createServer() {
var server = _http3.default.createServer(function (req, res) {
var _http = void 0;
return THINK.Http.run(req, res).then(function (data) {
_http = data;
var app = new THINK.App();
return app.exec(_http);
}).then(function () {
return THINK.statusAction(_http, 200);
}).catch(function (err) {
return THINK.statusAction(_http, _http._status || 500, err);
});
});
//invoke bootstrap middleware
return THINK.run('bootstrap', { server: server, app: new this() }).then(function () {
//listening
var host = THINK.config('app_host');
var port = THINK.config('app_port');
if (host) {
server.listen(port, host);
} else {
server.listen(port);
}
THINK.log('====================================', 'THINK');
THINK.log('Server running at http://' + (host || '127.0.0.1') + ':' + port + '/', 'THINK');
THINK.log('Node.js Version: ' + process.version, 'THINK');
THINK.log('ThinkNode Version: ' + THINK.THINK_VERSION, 'THINK');
THINK.log('App Cluster Status: ' + (THINK.config('use_cluster') ? 'open' : 'closed'), 'THINK');
THINK.log('App File Auto Reload: ' + (THINK.APP_DEBUG ? 'open' : 'closed'), 'THINK');
THINK.log('App Enviroment: ' + (THINK.APP_DEBUG ? 'debug mode' : 'stand mode'), 'THINK');
THINK.log('====================================', 'THINK');
THINK.APP_DEBUG && THINK.log('Debugging mode is running, if the production environment, please modify the APP_DEBUG value to false', 'WARNING');
});
};
/**
*
* @param _http
* @return {*}
*/
_class.prototype.exec = function exec(_http) {
var _this2 = this;
//禁止远程直接用带端口的访问,websocket下允许
if (THINK.config('use_proxy')) {
if (_http.host !== _http.hostname && !_http.isWebSocket) {
return THINK.statusAction(_http, 403);
}
}
_http = this.getController(_http);
//app begin
return THINK.run('app_begin', _http).then(function () {
process.nextTick(function () {
//app end
THINK.run('app_end', _http);
});
return _this2.execController(_http);
});
};
/**
* 根据pathname解析定位分组/控制器/方法,及其他/格式参数
* @param _http
* @param pathname
* @return {*}
*/
_class.prototype.getController = function getController(_http, pathname) {
if (pathname || !_http.group) {
pathname = cleanPathname(pathname || _http.pathname);
//去除pathname后缀
var suffix = THINK.config('url_pathname_suffix');
if (suffix && pathname.slice(0 - suffix.length) === suffix) {
pathname = pathname.slice(0, pathname.length - suffix.length);
}
var paths = _http.splitPathName(pathname);
var group = void 0,
groupList = THINK.config('app_group_list');
if (groupList.length && paths[0] && groupList.indexOf(paths[0].toLowerCase()) > -1) {
group = paths.shift();
}
var controller = paths.shift();
var action = paths.shift();
//解析剩余path的参数
if (paths.length) {
for (var i = 0, length = Math.ceil(paths.length) / 2; i < length; i++) {
_http._get[paths[i * 2]] = paths[i * 2 + 1] || '';
}
}
_http.group = parseGroup(group, THINK.config('default_group'));
_http.controller = parseController(controller, THINK.config('default_controller'));
_http.action = parseAction(action, THINK.config('default_action'));
}
return _http;
};
/**
* 执行controller
* @param _http
* @return {Promise.<*>}
*/
_class.prototype.execController = function execController(_http) {
//_http对象的group或controller不存在直接返回
if (!_http.group || !_http.controller) {
return THINK.statusAction(_http, 404, 'Controller not found.');
}
//controller instance
var controller = void 0;
try {
var instance = THINK.controller(_http.group + '/' + _http.controller);
controller = new instance(_http);
} catch (e) {
return THINK.statusAction(_http, 404, 'Controller ' + _http.group + '/' + _http.controller + ' not found.');
}
return this.execAction(_http, controller);
};
/**
* 执行action
* @param _http
* @param controller
* @return {Promise.<*>}
*/
_class.prototype.execAction = function execAction(_http, controller) {
var suffix = _http.actionSuffix === '' ? '' : 'Action';
var act = '' + _http.action + suffix;
var call = '__empty';
var flag = false;
//action不存在时执行空方法
if (!controller[act]) {
if (call && controller[call]) {
flag = true;
act = call;
}
}
//action不存在
if (!controller[act] && !flag) {
return THINK.statusAction(_http, 404, 'action ' + (_http.action || '') + ' not found.');
}
//action前置操作
var commonBefore = '__before';
var before = '_before_';
var promises = _promise2.default.resolve();
//公共action前置操作
if (commonBefore && controller[commonBefore]) {
promises = promises.then(function () {
return controller[commonBefore]();
});
}
//当前action前置操作
if (before && controller['' + before + _http.action]) {
promises = promises.then(function () {
return controller['' + before + _http.action]();
});
}
return promises.then(function () {
return controller[act]();
});
};
return _class;
}(_Base2.default);
exports.default = _class;