重构App.js

This commit is contained in:
welefen 2014-07-01 13:31:37 +08:00
parent e62cbbee16
commit f70a01a924
7 changed files with 189 additions and 186 deletions

View File

@ -155,6 +155,7 @@
"BELONGS_TO": true,
"HAS_MANY": true,
"MANY_TO_MANY": true,
"isDate": true
"isDate": true,
"getThinkRequirePath": true
}
}

File diff suppressed because one or more lines are too long

View File

@ -9,7 +9,7 @@ var _autoload_callbacks = [];
* @param {[type]} name [description]
* @return {[type]} [description]
*/
function getThinkRequirePath(name){
global.getThinkRequirePath = function(name){
'use strict';
if (_alias[name]) {
return _alias[name];
@ -113,6 +113,7 @@ global.tag = function(name, http, data){
}
var result = B(behavior, http, http.tag_data);
return getPromise(result).then(function(data){
//如果返回值不是undefined那么认为有返回值
if (data !== undefined) {
http.tag_data = data;
}
@ -134,6 +135,7 @@ global.C = function(name, value){
//清除所有的配置
if (name === null) {
_config = {};
return;
}
if (isString(name)) {
name = name.toLowerCase();
@ -164,13 +166,8 @@ global.C = function(name, value){
*/
global.A = function(name, http, data){
'use strict';
if (name.indexOf('/') > -1) {
name = name.split('/');
}else if (name.indexOf(':') > -1) {
name = name.split(':');
}else{
name = [name];
}
//将/转为:,兼容之前的方式
name = name.replace(/\//g, ':').split(':');
var action;
if (name.length === 3) {
action = name.pop();

View File

@ -12,7 +12,7 @@ module.exports = {
Dispatcher: THINK_LIB_PATH + '/Core/Dispatcher.js',
Filter: THINK_LIB_PATH + '/Util/Filter.js',
Http: THINK_LIB_PATH + '/Core/Http.js',
Log: THINK_LIB_PATH + '/Util/Log.js',
//Log: THINK_LIB_PATH + '/Util/Log.js',
Model: THINK_LIB_PATH + '/Core/Model.js',
Session: THINK_LIB_PATH + '/Util/Session.js',
Think: THINK_LIB_PATH + '/Core/Think.js',

View File

@ -26,8 +26,8 @@ module.exports = {
default_action: 'index', //默认Action
call_controller: 'Home:Index:_404', //controller不存在时执行方法此配置表示调用Home分组下IndexController的_404Action方法
call_method: '__call', //当找不到方法时调用什么方法,这个方法存在时才有效
before_action_name: '__before', //调用一个action前调用的方法会将action名传递进去
after_action_name: '__after', //调用一个action之后调用的方法会将action名传递进去
before_action: '__before', //调用一个action前调用的方法会将action名传递进去
after_action: '__after', //调用一个action之后调用的方法会将action名传递进去
url_params_bind: true, //方法参数绑定,将URL参数值绑定到action的参数上
action_suffix: 'Action', //action后缀
url_callback_name: 'callback', //jsonp格式的callback名字

View File

@ -1,176 +1,173 @@
var cluster = require('cluster');
var fs = require('fs');
var domain = require('domain');
var thinkHttp = thinkRequire('Http');
var Dispatcher = thinkRequire('Dispatcher');
/**
* 应用程序
* @type {Object}
*/
var App = module.exports = Class(function(){
'use strict';
//controller和action的校验正则
var nameReg = /^[A-Za-z\_](\w)*$/;
//注释的正则
var commentReg = /((\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s))/mg;
//获取形参的正则
var parsReg = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
//注释的正则
var commentReg = /((\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s))/mg;
//获取形参的正则
var parsReg = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
return {
init: function(http){
this.http = http;
},
/**
* 解析路由
* @return {[type]} [description]
*/
dispatch: function(){
return Dispatcher(this.http).run();
},
/**
* 获取controller
* @return {[type]} [description]
*/
getController: function(){
var group = this.http.group;
var controller = '';
//检测controller名
if (nameReg.test(this.http.controller)) {
controller = A(group + '/' + this.http.controller, this.http);
if (controller) {
return controller;
}
}
//controller不存在时调用的魔术方法
var controllerConf = C('call_controller');
if (controllerConf) {
if (isString(controllerConf)) {
controllerConf = controllerConf.split(':');
}
var action = Dispatcher.getAction(controllerConf.pop());
controller = Dispatcher.getController(controllerConf.pop());
group = Dispatcher.getGroup(controllerConf.pop());
controller = A(group + '/' + controller, this.http);
if (controller && isFunction(controller[action + C('action_suffix')])) {
this.http.group = group;
this.http.controller = controller;
this.http.action = action;
return controller;
}
}
},
/**
* 执行
* @return {[type]} [description]
*/
exec: function(){
var controller = this.getController();
if (!controller) {
var err = new Error('Controller `' + this.http.controller + '` not found. ' + this.http.pathname);
return getPromise(err, true);
}
var self = this;
var action = this.http.action;
var act = action;
//添加action后缀
action += C('action_suffix') || '';
//检测action名
if (!nameReg.test(action)) {
return getPromise(new Error('action `' + act + '` is not valid. ' + this.http.pathname), true);
}
var initReturnPromise = getPromise(controller.__initReturn);
//对应的action方法存在
if (isFunction(controller[action])) {
//方法参数自动绑定,直接从形参里拿到对应的值
if (C('url_params_bind')) {
var toString = controller[action].toString().replace(commentReg, '');
var match = toString.match(parsReg)[1].split(/,/).filter(function(item){
return item;
});
//匹配到形参
if (match && match.length) {
return initReturnPromise.then(function(){
var data = match.map(function(item){
return self.http.post[item] || self.http.get[item] || '';
});
return self.execAction(controller, action, act, data);
});
}
}
return initReturnPromise.then(function(){
return self.execAction(controller, action, act);
});
}else{
//当指定的方法不存在时,调用魔术方法
//默认为__call方法
var callMethod = C('call_method');
if (callMethod && isFunction(controller[callMethod])) {
return initReturnPromise.then(function(){
return controller[callMethod](act, action);
});
}
}
return getPromise(new Error('action `' + action + '` not found. ' + self.http.pathname), true);
},
/**
* 执行一个action, 支持before和after的统一操作
* 不对每个action都增加一个before和after而是使用统一的策略
* 默认before和after调用名__before和__after
* @param {[type]} controller [description]
* @param {[type]} action [description]
* @param {[type]} act [description]
* @param {[type]} data [description]
* @return {[type]} [description]
*/
execAction: function(controller, action, act, data){
var promise = getPromise();
//before action
var before = C('before_action_name');
if (before && isFunction(controller[before])) {
promise = getPromise(controller[before](act, action));
}
return promise.then(function(){
if (data) {
return controller[action].apply(controller, data)
}else{
return controller[action]()
}
}).then(function(){
//after action
var after = C('after_action_name');
if (after && isFunction(controller[after])) {
return controller[after](act, action);
}
});
},
/**
* 发送错误信息
* @param {[type]} error [description]
* @return {[type]} [description]
*/
sendError: function(error){
var message = isError(error) ? error.stack : error;
var http = this.http;
console.log(message);
if (!http.res) {
return;
}
if (APP_DEBUG) {
http.res.statusCode = 500;
http.res.end(message);
}else{
http.res.statusCode = 500;
http.setHeader('Content-Type', 'text/html; charset=' + C('encoding'));
var readStream = fs.createReadStream(C('error_tpl_path'));
readStream.pipe(http.res);
readStream.on('end', function(){
http.res.end();
});
}
var App = module.exports = {};
/**
* 根据http里的group和controller获取对应的controller实例
* @param {[type]} http [description]
* @return {[type]} [description]
*/
App.getBaseController = function(http){
'use strict';
var gc = ucfirst(http.group) + '/' + ucfirst(http.controller) + 'Controller';
var path = getThinkRequirePath(gc);
if (path) {
return require(path)(http);
}
}
/**
* controller不存在时调用的默认controller
* @return {[type]} [description]
*/
App.getCallController = function(http){
'use strict';
var config = C('call_controller');
if (!config) {
return;
}
if (isString(config)) {
config = config.split(':');
}
var action = Dispatcher.getAction(config.pop());
var controller = Dispatcher.getController(config.pop());
var group = Dispatcher.getGroup(config.pop());
var instance = this.getBaseController({
group: group,
controller: controller
})
if (instance && isFunction(instance[action + C('action_suffix')])) {
http.group = group;
http.controller = controller;
http.action = action;
}
return instance;
}
/**
* 执行具体的action调用前置和后置操作
* @return {[type]} [description]
*/
App.execAction = function(controller, action, data, callMethod){
'use strict';
//action操作
var act = action + C('action_suffix');
var flag = false;
//action不存在时执行魔术方法
if (callMethod && !isFunction(controller[act])) {
var call = C('call_method');
if (call && isFunction(controller[call])) {
flag = true;
act = call;
}
};
});
}
//action不存在
if (!isFunction(controller[act])) {
return getPromise('action `' + action + '` not found. ', true);
}
var promise = getPromise();
//action前置操作
var before = C('before_action');
if (before && isFunction(controller[before])) {
promise = controller[before](action);
}
promise = promise.then(function(){
//action魔术方法只传递action参数
if (flag) {
return controller[act](action);
}
if (data) {
return controller[act].apply(controller, data);
}else{
return controller[act]();
}
});
//action后置操作
var after = C('after_action');
if (after && isFunction(controller[after])) {
promise = promise.then(function(){
return controller[after](action);
})
}
return promise;
}
/**
* 获取action的形参
* @return {[type]} [description]
*/
App.getActionParams = function(fn, http){
'use strict';
var toString = fn.toString().replace(commentReg, '');
var match = toString.match(parsReg)[1].split(/\s*,\s*/);
//匹配到形参
var params;
if (match && match.length) {
params = match.map(function(item){
return http.post[item] || http.get[item] || '';
});
}
return params;
}
/**
* 执行
* @param {[type]} http [description]
* @return {[type]} [description]
*/
App.exec = function(http){
'use strict';
var controller = this.getBaseController(http) || this.getCallController(http);
//controller不存在
if (!controller) {
var err = new Error('Controller `' + http.controller + '` not found. ' + http.pathname);
return getPromise(err, true);
}
var params;
var actionFn = controller[http.action + C('action_suffix')];
//参数绑定
if (C('url_params_bind') && isFunction(actionFn)) {
params = this.getActionParams(actionFn, http);
}
var promise = getPromise(controller.__initReturn);
var self = this;
return promise.then(function(){
return self.execAction(controller, http.action, params, true);
})
}
/**
* 发送错误信息
* @param {[type]} error [description]
* @return {[type]} [description]
*/
App.sendError = function(http, error){
'use strict';
var message = isError(error) ? error.stack : error;
console.log(message);
if (!http.res) {
return;
}
if (APP_DEBUG) {
http.res.statusCode = 500;
http.res.end(message);
}else{
http.res.statusCode = 500;
http.setHeader('Content-Type', 'text/html; charset=' + C('encoding'));
var readStream = fs.createReadStream(C('error_tpl_path'));
readStream.pipe(http.res);
readStream.on('end', function(){
http.res.end();
});
}
}
/**
* run
@ -254,26 +251,25 @@ App.listener = function(http){
http.res.end();
return getDefer().promise;
}
var instance = App(http);
var domainInstance = domain.create();
var deferred = getDefer();
domainInstance.on('error', function(err){
instance.sendError(err);
App.sendError(http, err);
deferred.reject(err);
});
domainInstance.run(function(){
return tag('app_init', http).then(function(){
return instance.dispatch();
return Dispatcher(http).run();
}).then(function(){
return tag('app_begin', http);
}).then(function(){
return tag('action_init', http);
}).then(function(){
return instance.exec();
return App.exec(http);
}).then(function(){
return tag('app_end', http);
}).catch(function(err){
instance.sendError(err);
App.sendError(http, err);
}).then(function(){
deferred.resolve();
})

View File

@ -80,7 +80,6 @@ var Dispatcher = module.exports = Class(function(){
}
};
});
/**
* 获取group
* @param {[type]} group [description]
@ -91,6 +90,12 @@ Dispatcher.getGroup = function(group){
group = group || C('default_group');
return ucfirst(group);
};
/**
* 检测Controller和Action是否合法的正则
* @type {RegExp}
*/
var nameReg = /^[A-Za-z\_](\w)*$/;
/**
* 获取controller
* @param {[type]} controller [description]
@ -98,7 +103,9 @@ Dispatcher.getGroup = function(group){
*/
Dispatcher.getController = function(controller){
'use strict';
controller = controller || C('default_controller');
if (!controller || !nameReg.test(controller)) {
return ucfirst(C('default_controller'));
}
return ucfirst(controller);
};
/**
@ -108,6 +115,8 @@ Dispatcher.getController = function(controller){
*/
Dispatcher.getAction = function(action){
'use strict';
action = action || C('default_action');
if (!action || !nameReg.test(action)) {
return C('default_action');
}
return action;
};