Coverage

62%
3267
2054
1213

/Users/welefen/Develop/git/thinkjs/lib/Common/common.js

100%
270
270
0
LineHitsSource
11var fs = require('fs');
21var path = require('path');
31var util = require('util');
41var crypto = require('crypto');
51var net = require('net');
6
7/**
8 * Promise,后续Node.js会默认支持Promise,所以这里加个判断
9 * @type {[type]}
10 */
111if (!global.Promise) {
121 global.Promise = require('es6-promise').Promise;
13}
14
15/**
16 * 动态创建一个类
17 * 提供了继承、扩展、调用父级别方法等方法
18 * @return {[type]} [description]
19 */
201global.Class = function (prop, superCls) {
2136 'use strict';
2236 var cls = function () {
23116 function T(args) {
24116 for(var name in cls.__prop){
25435 var val = cls.__prop[name];
26435 this[name] = isObject(val) ? extend({}, val) : val;
27 }
28 //自动执行init方法
29116 if(isFunction(this.init)){
30 //获取init返回值,如果返回一个promise,可以让后续执行在then之后
31116 this.__initReturn = this.init.apply(this, args);
32 }
33116 return this;
34 }
35116 T.prototype = cls.prototype;
36116 T.constructor = cls;
37116 return new T(arguments);
38 };
39 //类的属性,不放在原型上,实例化的时候调用
4036 cls.__prop = {};
4136 cls.extend = function(prop){
4237 if (isFunction(prop)) {
4332 prop = prop();
44 }
4537 if (isObject(prop)) {
4635 for(var name in prop){
47333 var val = prop[name];
48333 if (isFunction(val)) {
49292 this.prototype[name] = val;
50 }else{
5141 cls.__prop[name] = isObject(val) ? extend({}, val) : val;
52 }
53 }
54 }
5537 return this;
56 };
5736 cls.inherits = function(superCls){
5825 util.inherits(this, superCls);
59 //将父级的属性复制到当前类上
6025 extend(cls.__prop, superCls.__prop);
6125 return this;
62 };
6336 if (superCls === true && isFunction(prop)) {
641 superCls = prop;
651 prop = undefined;
66 }
6736 if (isFunction(superCls)) {
6825 cls.inherits(superCls);
69 }
70 //调用父级方法
7136 cls.prototype.super = cls.prototype.super_ = function(name, data){
72 //如果当前类没有这个方法,则直接返回。
73 //用于在a方法调用父级的b方法
7430 if (!this[name]) {
751 return;
76 }
7729 var super_ = this.constructor.super_;
78 //如果父级没有这个方法,那么直接返回
7929 if (!isFunction(super_.prototype[name])) {
801 return;
81 }
82 //如果参数不是数组,自动转为数组
8328 if (!isArray(data)) {
8428 data = [data];
85 }
8628 while(1){
8729 if (this[name] === super_.prototype[name] && super_.super_) {
881 super_ = super_.super_;
89 }else{
9028 break;
91 }
92 }
9328 var method = super_.prototype[name];
9428 delete super_.prototype[name];
9528 var ret = method.apply(this, data);
9628 super_.prototype[name] = method;
9728 return ret;
98 };
9936 if (prop) {
10035 cls.extend(prop);
101 }
10236 return cls;
103};
104/**
105 * extend, from jquery,具有深度复制功能
106 * @return {[type]} [description]
107 */
1081global.extend = function(){
109969 'use strict';
110969 var args = [].slice.call(arguments);
111969 var deep = true;
112969 var target = args.shift();
113969 if (isBoolean(target)) {
114445 deep = target;
115445 target = args.shift();
116 }
117969 target = target || {};
118969 var length = args.length;
119969 var options, name, src, copy, copyAsArray, clone;
120969 for(var i = 0; i < length; i++){
1211324 options = args[i] || {};
1221324 if (isFunction(options)) {
1231 options = options();
124 }
1251324 for(name in options){
1261705 src = target[name];
1271705 copy = options[name];
1281705 if (src === copy) {
129257 continue;
130 }
1311448 if (deep && copy && (isObject(copy) || (copyAsArray = isArray(copy) ))) {
132443 if (copyAsArray) {
133237 copyAsArray = false;
134237 clone = src && isArray(src) ? src : [];
135 }else{
136206 clone = src && isObject(src) ? src : {};
137 }
138443 target[name] = extend(deep, clone, copy);
1391005 }else if (copy !== undefined) {
1401005 target[name] = copy;
141 }
142 }
143 }
144969 return target;
145};
146
147
148//Object上toString方法
1491var toString = Object.prototype.toString;
150
151/**
152 * 是否是boolean
153 * @param {[type]} obj
154 * @return {Boolean}
155 */
1561global.isBoolean = function(obj){
1571191 'use strict';
1581191 return toString.call(obj) === '[object Boolean]';
159};
160/**
161 * 是否是数字
162 * @param {[type]} obj [description]
163 * @return {Boolean} [description]
164 */
1651global.isNumber = function(obj){
166543 'use strict';
167543 return toString.call(obj) === '[object Number]';
168};
169/**
170 * 是否是个对象
171 * @param {[type]} obj [description]
172 * @return {Boolean} [description]
173 */
1741global.isObject = function(obj){
1753231 'use strict';
1763231 if (isBuffer(obj)) {
1772 return false;
178 }
1793229 return toString.call(obj) === '[object Object]';
180};
181/**
182 * 是否是字符串
183 * @param {[type]} obj [description]
184 * @return {Boolean} [description]
185 */
1861global.isString = function(obj){
1872453 'use strict';
1882453 return toString.call(obj) === '[object String]';
189};
190/**
191 * 是否是个function
192 * @param {[type]} obj [description]
193 * @return {Boolean} [description]
194 */
1951global.isFunction = function(obj){
1962294 'use strict';
1972294 return typeof obj === 'function';
198};
199/**
200 * 是否是日期
201 * @return {Boolean} [description]
202 */
2031global.isDate = function(obj){
2045 'use strict';
2055 return util.isDate(obj);
206};
207/**
208 * 是否是正则
209 * @param {[type]} reg [description]
210 * @return {Boolean} [description]
211 */
2121global.isRegexp = function(obj){
2137 'use strict';
2147 return util.isRegExp(obj);
215};
216/**
217 * 是否是个错误
218 * @param {[type]} obj [description]
219 * @return {Boolean} [description]
220 */
2211global.isError = function(obj){
2222 'use strict';
2232 return util.isError(obj);
224};
225/**
226 * 判断对象是否为空
227 * @param {[type]} obj
228 * @return {Boolean}
229 */
2301global.isEmpty = function(obj){
231538 'use strict';
232538 if (isObject(obj)) {
233275 var key;
234275 for(key in obj){
235246 return false;
236 }
23729 return true;
238263 }else if (isArray(obj)) {
23991 return obj.length === 0;
240172 }else if (isString(obj)) {
2412 return obj.length === 0;
242170 }else if (isNumber(obj)) {
2434 return obj === 0;
244166 }else if (obj === null || obj === undefined) {
245163 return true;
2463 }else if (isBoolean(obj)) {
2472 return !obj;
248 }
2491 return false;
250};
251/**
252 * 是否是个标量
253 * @param {[type]} obj [description]
254 * @return {Boolean} [description]
255 */
2561global.isScalar = function(obj){
257136 'use strict';
258136 return isBoolean(obj) || isNumber(obj) || isString(obj);
259};
260/**
261 * 是否是个数组
262 * @type {Boolean}
263 */
2641global.isArray = Array.isArray;
265/**
266 * 是否是IP
267 * @type {Boolean}
268 */
2691global.isIP = net.isIP;
2701global.isIP4 = net.isIP4;
2711global.isIP6 = net.isIP6;
272/**
273 * 是否是个文件
274 * @param {[type]} p [description]
275 * @return {Boolean} [description]
276 */
2771global.isFile = function(p){
278120 'use strict';
279120 if (!fs.existsSync(p)) {
28076 return false;
281 }
28244 var stats = fs.statSync(p);
28344 return stats.isFile();
284};
285/**
286 * 是否是个目录
287 * @param {[type]} p [description]
288 * @return {Boolean} [description]
289 */
2901global.isDir = function(p){
29116 'use strict';
29216 if (!fs.existsSync(p)) {
2932 return false;
294 }
29514 var stats = fs.statSync(p);
29614 return stats.isDirectory();
297};
298/**
299 * 是否是buffer
300 * @type {Boolean}
301 */
3021global.isBuffer = Buffer.isBuffer;
303/**
304 * 是否是个数字的字符串
305 * @param {[type]} obj [description]
306 * @return {Boolean} [description]
307 */
3081var numberReg = /^((\-?\d*\.?\d*(?:e[+-]?\d*(?:\d?\.?|\.?\d?)\d*)?)|(0[0-7]+)|(0x[0-9a-f]+))$/i;
3091global.isNumberString = function(obj){
31014 'use strict';
31114 return numberReg.test(obj);
312};
313/**
314 * 判断是否是个promise
315 * @param {[type]} obj [description]
316 * @return {Boolean} [description]
317 */
3181global.isPromise = function(obj){
319480 'use strict';
320480 return !!(obj && typeof obj.then === 'function');
321};
322
323/**
324 * 判断一个文件或者目录是否可写
325 * @param {[type]} p [description]
326 * @return {Boolean} [description]
327 */
3281global.isWritable = function(p){
3293 'use strict';
3303 if (!fs.existsSync(p)) {
3311 return false;
332 }
3332 var stats = fs.statSync(p);
3342 var mode = stats.mode;
3352 var uid = process.getuid ? process.getuid() : 0;
3362 var gid = process.getgid ? process.getgid() : 0;
3372 var owner = uid === stats.uid;
3382 var group = gid === stats.gid;
3392 return !!(owner && (mode & parseInt('00200', 8)) ||
340 group && (mode & parseInt('00020', 8)) ||
341 (mode & parseInt('00002', 8)));
342};
343
344/**
345 * 递归创建目录,同步模式
346 * @param {[type]} p [description]
347 * @param {[type]} mode [description]
348 * @return {[type]} [description]
349 */
3501global.mkdir = function(p, mode){
35175 'use strict';
35275 mode = mode || '0777';
35375 if (fs.existsSync(p)) {
35467 chmod(p, mode);
35567 return true;
356 }
3578 var pp = path.dirname(p);
3588 if (fs.existsSync(pp)) {
3597 fs.mkdirSync(p, mode);
360 }else{
3611 mkdir(pp, mode);
3621 mkdir(p, mode);
363 }
3648 return true;
365};
366/**
367 * 递归的删除目录,返回promise
368 * @param string p 要删除的目录
369 * @param boolean reserve 是否保留当前目录,只删除子目录
370 * @return Promise
371 */
3721global.rmdir = function(p, reserve){
3739 'use strict';
3749 if (!isDir(p)) {
3751 return getPromise();
376 }
3778 var deferred = getDefer();
3788 fs.readdir(p, function(err, files){
3798 if (err) {
3801 return deferred.reject(err);
381 }
3827 var promises = files.map(function(item){
3832 var filepath = path.normalize(p + '/' + item);
3842 if (isDir(filepath)) {
3851 return rmdir(filepath, false);
386 }else{
3871 var deferred = getDefer();
3881 fs.unlink(filepath, function(err){
3891 return err ? deferred.reject(err) : deferred.resolve();
390 })
3911 return deferred.promise;
392 }
393 })
3947 var promise = files.length === 0 ? getPromise() : Promise.all(promises);
3957 return promise.then(function(){
3967 if (!reserve) {
3977 var deferred = getDefer();
3987 fs.rmdir(p, function(err){
3997 return err ? deferred.reject(err) : deferred.resolve();
400 })
4017 return deferred.promise;
402 }
403 }).then(function(){
4046 deferred.resolve();
405 }).catch(function(err){
4061 deferred.reject(err);
407 })
408 })
4098 return deferred.promise;
410}
411/**
412 * 修改目录或者文件权限
413 * @param {[type]} p [description]
414 * @param {[type]} mode [description]
415 * @return {[type]} [description]
416 */
4171global.chmod = function(p, mode){
418107 'use strict';
419107 mode = mode || '0777';
420107 if (!fs.existsSync(p)) {
4211 return true;
422 }
423106 return fs.chmodSync(p, mode);
424};
425/**
426 * 获取文件内容
427 * @param {[type]} file [description]
428 * @return {[type]} [description]
429 */
4301global.getFileContent = function(file, encoding){
43114 'use strict';
43214 if (!fs.existsSync(file)) {
4331 return '';
434 }
43513 return fs.readFileSync(file, encoding || 'utf8');
436};
437/**
438 * 设置文件内容
439 * @param {[type]} file [description]
440 * @param {[type]} data [description]
441 * @return {[type]} [description]
442 */
4431global.setFileContent = function(file, data){
4442 'use strict';
4452 var filepath = path.dirname(file);
4462 mkdir(filepath);
4472 return fs.writeFileSync(file, data);
448};
449/**
450 * 大写首字符
451 * @param {[type]} name [description]
452 * @return {[type]} [description]
453 */
4541global.ucfirst = function(name){
4551740 'use strict';
4561740 name = (name || '') + '';
4571740 return name.substr(0,1).toUpperCase() + name.substr(1).toLowerCase();
458};
459/**
460 * 获取字符串的md5
461 * @param {[type]} str [description]
462 * @return {[type]} [description]
463 */
4641global.md5 = function(str){
46563 'use strict';
46663 var instance = crypto.createHash('md5');
46763 instance.update(str + '');
46863 return instance.digest('hex');
469};
470/**
471 * 生成一个promise,如果传入的参数是promise则直接返回
472 * @param {[type]} obj [description]
473 * @return {[type]} [description]
474 */
4751global.getPromise = function(obj, reject){
476475 'use strict';
477475 if (isPromise(obj)) {
4781 return obj;
479 }
480474 if (reject) {
48111 return Promise.reject(obj);
482 }
483463 return Promise.resolve(obj);
484};
485/**
486 * 生成一个defer对象
487 * @return {[type]} [description]
488 */
4891global.getDefer = function(){
49082 'use strict';
49182 var deferred = {};
49282 deferred.promise = new Promise(function(resolve, reject){
49382 deferred.resolve = resolve;
49482 deferred.reject = reject;
495 });
49682 return deferred;
497};
498/**
499 * 快速生成一个object
500 * @param {[type]} key [description]
501 * @param {[type]} value [description]
502 * @return {[type]} [description]
503 */
5041global.getObject = function(key, value){
50525 'use strict';
50625 var obj = {};
50725 if (!isArray(key)) {
50816 obj[key] = value;
50916 return obj;
510 }
5119 key.forEach(function(item, i){
51217 obj[item] = value[i];
513 });
5149 return obj;
515};
516/**
517 * 将数组变成对象
518 * @param {[type]} arr [description]
519 * @param {[type]} key [description]
520 * @param {[type]} valueKeys [description]
521 * @return {[type]} [description]
522 */
5231global.arrToObj = function(arr, key, valueKey){
5244 'use strict';
5254 var result = {};
5264 var arrResult = [];
5274 arr.forEach(function(item){
5288 var keyValue = item[key];
5298 if (valueKey === null) {
5304 arrResult.push(keyValue);
5314 }else if (valueKey) {
5322 result[keyValue] = item[valueKey];
533 }else{
5342 result[keyValue] = item;
535 }
536 })
5374 return valueKey === null ? arrResult : result;
538}

/Users/welefen/Develop/git/thinkjs/lib/Common/extend.js

100%
13
13
0
LineHitsSource
1//该文件内容为原生对象的扩展
2
3/**
4 * 获取对象的值
5 * @param {[type]} obj [description]
6 * @return {[type]} [description]
7 */
81Object.values = function(obj){
9173 'use strict';
10173 var values = [];
11173 for(var key in obj){
121574 if (obj.hasOwnProperty(key)) {
131574 values.push(obj[key])
14 }
15 }
16173 return values;
17};
18/**
19 * 数组求和
20 * @return {[type]} [description]
21 */
221Array.prototype.sum = function(){
237 'use strict';
247 var count = 0;
257 this.forEach(function(item){
2623 count += parseFloat(item) || 0;
27 });
287 return count;
29};
30

/Users/welefen/Develop/git/thinkjs/lib/Common/function.js

100%
154
154
0
LineHitsSource
11var fs = require('fs');
21var path = require('path');
3
4
51var _alias = {};
61var _autoload_callbacks = [];
7/**
8 * thinkRequire获取到的路径
9 * @param {[type]} name [description]
10 * @return {[type]} [description]
11 */
121global.getThinkRequirePath = function(name){
13248 'use strict';
14248 if (_alias[name]) {
15202 return _alias[name];
16 }
1746 var result = '';
1846 _autoload_callbacks.some(function(callback){
1946 result = callback && callback(name);
2046 if (result) {
2121 return true;
22 }
23 });
2446 return result;
25}
26/**
27 * 自定义的require, 加入别名功能
28 * @type {[type]}
29 */
301global.thinkRequire = function(name){
31211 'use strict';
32 //如果不是字符串则直接返回
33211 if (!isString(name)) {
341 return name;
35 }
36210 var path = name;
37210 if (path[0] !== '/') {
38210 path = getThinkRequirePath(name);
39 }
40210 if (path) {
41209 var obj = require(path);
42209 if (isFunction(obj)) {
43 //修正子类继承的方法获取到正确的文件名
44181 obj.prototype.__filename = path;
45 }
46209 return obj;
47 }
481 return require(name);
49};
50/**
51 * 注册require
52 * @param {Function} callback [description]
53 * @return {[type]} [description]
54 */
551global.registerAutoload = function(callback){
561 'use strict';
571 _autoload_callbacks.push(callback);
58};
59/**
60 * 别名
61 * @return {[type]} [description]
62 */
631global.aliasImport = function(alias, classFile){
6422 'use strict';
6522 if (isString(alias)) {
6621 _alias[alias] = classFile;
67 }else{
681 _alias = extend(_alias, alias);
69 }
70};
71
72//常用类的基类
731['Cache', 'Behavior', 'Controller', 'Session', 'Model', 'Db'].forEach(function(item){
746 'use strict';
756 global[item] = function(super_, obj){
7620 if (isString(super_)) {
771 return Class(obj, thinkRequire(super_));
78 }
7919 return Class(super_, thinkRequire(item));
80 };
81});
82
83
84/**
85 * 调用一个指定的行为
86 * @param {[type]} name [description]
87 */
881global.B = function(name, http, data){
8924 'use strict';
9024 if (!name) {
911 return data;
92 }
9323 if (typeof name === 'function') {
943 return name(http, data);
95 }
9620 return thinkRequire(name + 'Behavior')(http).run(data);
97};
98
99/**
100 * 处理标签扩展
101 * @return {[type]} [description]
102 */
1031global.tag = function(name, http, data){
10435 'use strict';
10535 var tags = (C('tag.' + name) || []).slice();
106 //tag处理的数据
10735 http.tag_data = data;
10835 if (!tags.length) {
10915 return getPromise(http.tag_data);
110 }
11120 var index = 0;
11220 function runBehavior(){
11340 var behavior = tags[index++];
11440 if (!behavior) {
11520 return getPromise(http.tag_data);
116 }
11720 var result = B(behavior, http, http.tag_data);
11820 return getPromise(result).then(function(data){
119 //如果返回值不是undefined,那么认为有返回值
12020 if (data !== undefined) {
12118 http.tag_data = data;
122 }
12320 return runBehavior();
124 })
125 }
12620 return runBehavior();
127};
128/**
129 * 配置读取和写入
130 */
1311var _config = {};
1321global.C = function(name, value){
133487 'use strict';
134 //获取所有的配置
135487 if (arguments.length === 0) {
13614 return _config;
137 }
138 //清除所有的配置
139473 if (name === null) {
1402 _config = {};
1412 return;
142 }
143471 if (isString(name)) {
144467 name = name.toLowerCase();
145 //name里不含. 一级
146467 if (name.indexOf('.') === -1) {
147429 if (value === undefined) {
148422 return _config[name];
149 }
1507 _config[name] = value;
1517 return;
152 }
153 //name中含有. 二级
15438 name = name.split('.');
15538 if (value === undefined) {
15637 value = _config[name[0]] || {};
15737 return value[name[1]];
158 }
1591 if (!_config[name[0]]) {
1601 _config[name[0]] = {};
161 }
1621 _config[name[0]][name[1]] = value;
163 }else{
1644 _config = extend(_config, name);
165 }
166};
167/**
168 * 实例化Controller类,可以调用一个具体的Action
169 * A('Home/Index'), A('Admin/Index/test')
170 * @param {[type]} name [description]
171 */
1721global.A = function(name, http, data){
17311 'use strict';
174 //将/转为:,兼容之前的方式
17511 name = name.replace(/\//g, ':').split(':');
17611 http.group = name[0];
17711 http.controller = name[1];
17811 var App = thinkRequire('App');
17911 var instance = App.getBaseController(http);
18011 if (!instance) {
1812 return instance;
182 }
1839 var action = name[2];
1849 if (!action) {
1851 return instance;
186 }
1878 http.action = action;
1888 return getPromise(instance.__initReturn).then(function(){
1898 if (data && !isArray(data)) {
1901 data = [data];
191 }
1928 return App.execAction(instance, action, data);
193 })
194};
195
196/**
197 * 快速文件读取和写入
198 * 默认写入到App/Runtime/Data目录下
199 */
2001global.F = function(name, value, rootPath){
2019 'use strict';
2029 rootPath = rootPath || DATA_PATH;
2039 var filePath = rootPath + '/' + name + '.json';
2049 if (value !== undefined) {
2054 mkdir(path.dirname(filePath));
2064 fs.writeFileSync(filePath, JSON.stringify(value));
2074 chmod(filePath);
2084 return;
209 }
2105 if (isFile(filePath)) {
2114 var content = getFileContent(filePath);
2124 if (content) {
2134 return JSON.parse(content);
214 }
215 }
2161 return false;
217};
218/**
219 * 实例化模型
220 */
2211global.D = function(name, config){
22225 'use strict';
22325 if (name === undefined) {
2241 return thinkRequire('Model')(name, config);
225 }
22624 name = name.split(':');
22724 name[0] = name[0][0].toUpperCase() + name[0].slice(1);
22824 var path = getThinkRequirePath(name[0] + 'Model');
22924 if (path) {
2303 return thinkRequire(name[0] + 'Model')(name[1], config);
231 }else{
23221 return thinkRequire(name[1] === 'AdvModel' ? 'AdvModel' : 'Model')(name[0], config);
233 }
234};
235/**
236 * 实例化模型基类
237 * @param {[type]} name [description]
238 * @param {[type]} config [description]
239 */
2401global.M = function(name, config){
2415 'use strict';
2425 if (name === undefined) {
2431 return thinkRequire('Model')(name, config);
244 }
2454 name = name.split(':');
2464 var model = name[1] === 'AdvModel' ? 'AdvModel' : 'Model';
2474 return thinkRequire(model)(name[0], config)
248}
249/**
250 * 缓存的设置和读取
251 * 获取返回的是一个promise
252 */
2531global.S = function(name, value, options){
25426 'use strict';
25526 if (isNumber(options)) {
2563 options = {timeout: options};
25723 }else if (options === true) {
2589 options = {type: true}
259 }
26026 options = options || {};
26126 var type = options.type === undefined ? C('cache_type') : options.type;
26226 var cls = (type === true ? '' : ucfirst(type)) + 'Cache';
26326 var instance = thinkRequire(cls)(options);
264 //获取缓存
26526 if (value === undefined) {
26612 return instance.get(name);
267 }
268 //移除缓存
26914 if (value === null) {
2702 return instance.rm(name);
271 }
27212 return instance.set(name, value, options.timeout);
273};
274/**
275 * 语言
276 * @param {[type]} name [description]
277 */
2781global.L = function(name){
2792 'use strict';
2802 return name;
281};

/Users/welefen/Develop/git/thinkjs/lib/Conf/alias.js

100%
1
1
0
LineHitsSource
1/**
2 * 模块别名,模块名到具体的路径,模块名不能有重复
3 * 使用thinkRequire加载模块时有效
4 * @type {Object}
5 */
61module.exports = {
7 Controller: THINK_LIB_PATH + '/Core/Controller.js',
8 App: THINK_LIB_PATH + '/Core/App.js',
9 Behavior: THINK_LIB_PATH + '/Util/Behavior.js',
10 Cache: THINK_LIB_PATH + '/Util/Cache.js',
11 Db: THINK_LIB_PATH + '/Core/Db.js',
12 Dispatcher: THINK_LIB_PATH + '/Core/Dispatcher.js',
13 Filter: THINK_LIB_PATH + '/Util/Filter.js',
14 Http: THINK_LIB_PATH + '/Core/Http.js',
15 Log: THINK_LIB_PATH + '/Util/Log.js',
16 Model: THINK_LIB_PATH + '/Core/Model.js',
17 Session: THINK_LIB_PATH + '/Util/Session.js',
18 Think: THINK_LIB_PATH + '/Core/Think.js',
19 Valid: THINK_LIB_PATH + '/Util/Valid.js',
20 View: THINK_LIB_PATH + '/Core/View.js',
21 Cookie: THINK_LIB_PATH + '/Util/Cookie.js',
22 WebSocket: THINK_LIB_PATH + '/Util/WebSocket.js',
23 Auth: THINK_LIB_PATH + '/Util/Auth.js'
24};

/Users/welefen/Develop/git/thinkjs/lib/Conf/config.js

100%
1
1
0
LineHitsSource
1 /**
2 * 框架默认配置
3 * 可以在App/Conf/config.js里修改下面的配置值
4 * @type {Object}
5 */
61module.exports = {
7 port: 8360, //监听端口
8 use_proxy: false, //是否使用代理访问,如:nginx。开启后不能通过ip+端口直接访问
9 encoding: 'utf8', //输出数据的编码
10 url_pathname_prefix: '', //不解析的pathname前缀
11 url_pathname_suffix: '.html', //不解析的pathname后缀,这样利于seo
12 app_tag_on: true, //是否支持标签功能
13 url_resource_on: true, //是否监听静态资源类请求
14 url_resource_reg: /^(resource\/|static\/|favicon\.ico)/, //判断是否是静态资源的正则
15 url_route_on: true, //是否开启自定义路由功能
16
17 post_json_content_type: ['application/json'], //post数据为json时的content-type
18 post_max_file_size: 1024 * 1024 * 1024, //上传文件大小限制,默认1G
19 post_max_fields: 100, //最大表单数,默认为100
20 post_max_fields_size: 2 * 1024 * 1024, //单个表单长度最大值,默认为2MB
21
22 app_group_list: ['Home', 'Admin', 'Restful'], //分组列表
23 default_group: 'Home', //默认分组
24 default_controller: 'Index', //默认模块
25 default_action: 'index', //默认Action
26 call_controller: 'Home:Index:_404', //controller不存在时执行方法,此配置表示调用Home分组下IndexController的_404Action方法
27 call_method: '__call', //当找不到方法时调用什么方法,这个方法存在时才有效
28 before_action: '__before', //调用一个action前调用的方法,会将action名传递进去
29 after_action: '__after', //调用一个action之后调用的方法,会将action名传递进去
30 url_params_bind: true, //方法参数绑定,将URL参数值绑定到action的参数上
31 action_suffix: 'Action', //action后缀
32 url_callback_name: 'callback', //jsonp格式的callback名字
33 json_content_type: 'application/json', //发送json时的content-type
34 auto_send_content_type: true, //是否自动发送Content-Type,默认值为`tpl_content_type`配置值
35 log_process_pid: true, //记录进程的id,方便其他脚本处理。
36 use_cluster: false, //是否使用cluster,默认不使用,0:为cpu的数量,可以自定义值
37 autoload_path: {}, //autoload查找的path,用于thinkRequire加载自定义库的时候查找
38 create_server_fn: '', //自定义create server全局函数名,可以在Common/common.js里实现
39
40 restful_group: 'Restful', //RESTFUL API默认分组
41
42 load_ext_config: [], //加载额外的配置文件 CONF_PATH
43 load_ext_file: [], //加载额外的文件 COMMON_PATH
44
45 use_websocket: false, //是否使用websocket
46 websocket_allow_origin: '', //允许从那里发送过来的websocket,可以是字符串、数组、回调函数,为空表示不检测
47 websocket_sub_protocal: '', //websocket子协议,可以是个字符串也可以是回调函数
48 websocket_message_handle: undefined, //websocket消息处理函数
49
50 error_tpl_path: THINK_PATH + '/View/error.html', //错误页模版
51 error_no_key: 'errno', //错误number的key
52 error_no_default_value: 1000, //错误号默认值
53 error_msg_key: 'errmsg', //错误消息的key
54
55 cookie_domain: '', //cookie有效域名
56 cookie_path: '/', //cookie路径
57 cookie_timeout: 0, //cookie失效时间,0为浏览器关闭,单位:秒
58
59 session_name: 'thinkjs', //session对应的cookie名称
60 session_type: 'File', //session存储类型, 空为内存,还可以为File
61 session_path: '', //File类型下文件存储位置,默认为系统的tmp目录
62 session_options: {}, //session对应的cookie选项
63 session_sign: '', //session对应的cookie使用签名
64 session_timeout: 24 * 3600, //服务器上session失效时间,单位:秒
65
66 db_type: 'mysql', // 数据库类型
67 db_host: '127.0.0.1', // 服务器地址
68 db_port: '', // 端口
69 db_name: '', // 数据库名
70 db_user: 'root', // 用户名
71 db_pwd: '', // 密码
72 db_prefix: 'think_', // 数据库表前缀
73 db_fieldtype_check: false, // 是否进行字段类型检查
74 db_fields_cache: true, // 启用字段缓存
75 db_charset: 'utf8', // 数据库编码默认采用utf8
76 db_nums_per_page: 20, //默认每页显示的条数
77 db_like_fields: [], //自动进行模糊查询,|连接,如: ['title', 'content']
78 db_cache_on: true, //是否启用查询缓存,如果关闭那么cache方法则无效
79 db_cache_type: '', //缓存类型,默认为内存缓存
80 db_cache_path: CACHE_PATH + '/db', //缓存路径,File类型下有效
81 db_cache_timeout: 3600, //缓存时间,默认为1个小时
82
83 tpl_content_type: 'text/html', //模版输出类型
84 tpl_file_suffix: '.html', //模版文件名后缀
85 tpl_file_depr: '_', //controller和action之间的分隔符
86 tpl_engine_type: 'ejs', //模版引擎名称
87 tpl_engine_config: {},
88
89 log_record: false, //是否记录日志,开启后会重写console.log等系列方法
90 log_file_path: LOG_PATH, //日志文件存在路径
91 log_console_type: ['error'], //默认只接管console.error日志
92
93 cache_type: 'File', //数据缓存类型
94 cache_timeout: 6 * 3600, //数据缓存有效期,单位: 秒
95 cache_path: CACHE_PATH, //缓存路径设置 (File缓存方式有效)
96 cache_file_suffix: '.json', //File缓存方式下文件后缀名
97 cache_gc_hour: [4], //缓存清除的时间点,数据为小时
98
99 html_cache_on: false, //HTML静态缓存
100 html_cache_timeout: 3600, //缓存时间,单位为秒
101 html_cache_rules: {}, //缓存规则
102 html_cache_path: CACHE_PATH + '/html',
103 html_cache_file_callback: undefined, //生成缓存文件的回调函数
104 html_cache_file_suffix: '.html', //缓存文件后缀名
105
106 memcache_host: '127.0.0.1', //memcache host
107 memcache_port: 11211, //memecache端口
108};

/Users/welefen/Develop/git/thinkjs/lib/Conf/mode.js

100%
1
1
0
LineHitsSource
1/**
2 * 不同模式下的配置文件
3 * 由于每个模式下的配置可能都比较少,所以放在一个文件里
4 * @type {Object}
5 */
61module.exports = {
7 cli: {
8 use_cluster: false, //使用cluster
9 html_cache_on: false,
10 log_process_pid: false,
11 clear_require_cache: false,
12 auto_close_db: false //自动关闭数据库连接
13 },
14 cli_debug: {
15 clear_require_cache: false
16 }
17};

/Users/welefen/Develop/git/thinkjs/lib/Conf/tag.js

75%
12
9
3
LineHitsSource
1/**
2 * 系统标签配置
3 * 可以在App/Conf/tag.js里进行修改
4 * @type {Object}
5 */
6
7/**
8 * 命令行模式下执行后自动关闭数据库连接
9 * @return {[type]} [description]
10 */
111var closeDbConnect = function(){
121 'use strict';
131 if(C('auto_close_db') && APP_MODE === 'cli'){
140 thinkRequire('Model').close();
15 }
16}
17/**
18 * 解析提交的json数据
19 * @param {[type]} http [description]
20 * @return {[type]} [description]
21 */
221var jsonParse = function(http){
231 'use strict';
241 var jsonConentType = C('post_json_content_type');
251 if (!isArray(jsonConentType)) {
260 jsonConentType = [jsonConentType];
27 }
281 if (jsonConentType.indexOf(http.contentType) > -1) {
290 http.post = JSON.parse(http.payload) || {};
30 }
31}
32
331module.exports = {
34 //应用初始化
35 app_init: [],
36 //表单数据解析
37 form_parse: [jsonParse],
38 //pathinfo解析
39 path_info: [],
40 //静态资源请求检测
41 resource_check: ['CheckResource'],
42 //路由检测
43 route_check: ['CheckRoute'],
44 //应用开始
45 app_begin: ['ReadHtmlCache'],
46 //action执行初始化
47 action_init: [],
48 //模版解析初始化
49 view_init: [],
50 //定位模版文件
51 view_template: ['LocationTemplate'],
52 //模版解析
53 view_parse: ['ParseTemplate'],
54 //模版内容过滤
55 view_filter: [],
56 //模版解析结束
57 view_end: ['WriteHtmlCache'],
58 //action结束
59 action_end: [],
60 //应用结束
61 app_end: [closeDbConnect]
62};

/Users/welefen/Develop/git/thinkjs/lib/Lib/Behavior/CheckResourceBehavior.js

48%
25
12
13
LineHitsSource
11var fs = require('fs');
21var mime = require('mime');
3/**
4 * 静态资源请求
5 * @return {[type]} [description]
6 */
71module.exports = Behavior(function(){
81 'use strict';
91 return {
10 options: {
11 'url_resource_on': false
12 },
13 run: function(){
141 if (!RESOURCE_PATH || !this.options.url_resource_on || !this.http.pathname) {
150 return false;
16 }
171 var pathname = this.http.pathname;
181 if (pathname.indexOf('/') === 0) {
191 pathname = pathname.substr(1);
20 }
211 var reg = C('url_resource_reg');
22 //通过正则判断是否是静态资源请求
231 if (!reg.test(pathname)) {
241 return false;
25 }
26
270 var file = RESOURCE_PATH + '/' + pathname;
280 var res = this.http.res;
290 if (fs.existsSync(file)) {
300 var contentType = mime.lookup(file);
310 var fileStream = fs.createReadStream(file);
320 res.setHeader('Content-Type', contentType + '; charset=' + C('encoding'));
330 fileStream.pipe(res);
340 fileStream.on('end', function(){
350 res.end();
36 });
37 }else{
380 res.statusCode = 404;
390 res.end();
40 }
41 //返回一个pendding promise, 不让后续执行
420 return getDefer().promise;
43 }
44 };
45});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Behavior/CheckRouteBehavior.js

10%
98
10
88
LineHitsSource
1/**
2 * 检测路由行为
3 * 通过自定义路由识别到对应的URL上
4 * @return {[type]} [description]
5 */
61var url = require('url');
71var Dispatcher = thinkRequire('Dispatcher');
8
91module.exports = Behavior(function(){
101 'use strict';
111 return {
12 options: {
13 'url_route_on': false, //是否开启自定义URL路由
14 'url_route_rules': [] //自定义URL路由规则
15 },
16 run: function(){
171 if (!this.options.url_route_on) {
180 return false;
19 }
201 var routes = this.options.url_route_rules;
211 var length = routes.length;
221 if (length === 0) {
231 return false;
24 }
250 var pathname = this.http.pathname;
260 var match;
270 for(var i = 0; i < length; i++){
280 var route = routes[i];
290 var rule = route[0];
30 //正则路由
310 if (isRegexp(rule)) {
320 match = pathname.match(rule);
330 if (match) {
340 var result = this.parseRegExp(match, route[1], pathname);
350 if (result) {
360 return result;
37 }
38 }
39 }else{
40 //字符串路由
410 match = this.checkUrlMatch(pathname, rule);
420 if (match) {
430 return this.parseRule(rule, route[1], pathname);
44 }
45 }
46 }
470 return false;
48 },
49 /**
50 * 解析字符串路由
51 * @param {[type]} rule [description]
52 * @param {[type]} route [description]
53 * @param {[type]} pathname [description]
54 * @return {[type]} [description]
55 */
56 parseRule: function(rule, route, pathname){
570 route = this.getRoute(route);
580 if (!route) {
590 return false;
60 }
610 pathname = pathname.split('/').filter(function(item){
620 return item.trim();
63 });
640 rule = rule.split('/').filter(function(item){
650 return item.trim();
66 });
670 var matches = {};
680 rule.forEach(function(item){
690 var pathitem = pathname.shift();
700 if (item.indexOf(':') === 0) {
710 matches[item] = pathitem;
72 }
73 });
74 //将剩余的pathname分割为querystring
750 if (pathname.length) {
760 for(var i = 0,length = Math.ceil(pathname.length)/2; i < length; i++){
770 this.http.get[pathname[i * 2]] = pathname[i * 2 + 1] || '';
78 }
79 }
800 var values = Object.values(matches);
810 route = route.replace(/:(\d+)/g, function(a, b){
820 return values[b - 1] || '';
83 });
840 this.parseUrl(route);
850 return true;
86 },
87 /**
88 * 检测URL是否匹配
89 * @param {[type]} pathname [description]
90 * @param {[type]} rule [description]
91 * @return {[type]} [description]
92 */
93 checkUrlMatch: function(pathname, rule){
940 pathname = pathname.split('/').filter(function(item){
950 return item.trim();
96 });
970 rule = rule.split('/').filter(function(item){
980 return item.trim();
99 });
1000 return rule.every(function(item, i){
1010 if (item.indexOf(':') === 0) {
1020 if (item.indexOf('\\') > -1) {
1030 var type = item.substr(-1);
1040 if (type === 'd' && !isNumberString(pathname[i])) {
1050 return false;
106 }
107 }
108 }else{
1090 var pitem = pathname[i] || '';
1100 if (pitem.toLowerCase() !== item.toLowerCase()) {
1110 return false;
112 }
113 }
1140 return true;
115 });
116 },
117 /**
118 * 解析转化后的url
119 * @param {[type]} urlInfo [description]
120 * @return {[type]} [description]
121 */
122 parseUrl: function(urlInfo){
1230 urlInfo = url.parse(urlInfo, true);
1240 if (urlInfo.query) {
1250 for(var key in urlInfo.query){
1260 if (urlInfo.query[key] || !(key in this.http.get)) {
1270 this.http.get[key] = urlInfo.query[key];
128 }
129 }
130 }
1310 var pathname = urlInfo.pathname || '';
132 // 过滤调用pathname最后有/的情况
1330 pathname = pathname.split('/').filter(function(item){
1340 return item.trim();
135 });
1360 this.http.action = Dispatcher.getAction(pathname.pop());
1370 this.http.controller = Dispatcher.getController(pathname.pop());
1380 this.http.group = Dispatcher.getGroup(pathname.pop());
139 },
140 /**
141 * 获取route
142 * @param {[type]} route [description]
143 * @return {[type]} [description]
144 */
145 getRoute: function(route, matches){
1460 if (isObject(route)) {
147 //对应的请求类型
1480 for(var method in route){
149 //由于请求类型没有包含关系,这里可以直接用indexOf判断
1500 if (method.toUpperCase().indexOf(this.http.method) > -1) {
1510 return route[method];
152 }
153 }
1540 return;
155 }
1560 var routeUpper = route.toUpperCase();
157 //RESTFUL API
1580 if (routeUpper === 'RESTFUL' || routeUpper.indexOf('RESTFUL:') === 0) {
1590 var group = route.split(':')[1] || C('restful_group');
1600 route = group + '/' + matches[1] + '/' + this.http.method.toLowerCase() + '?resource=' + matches[1];
1610 if (matches[2]) {
1620 route += '&id=' + matches[2];
163 }
164 //设置变量到http对象上,方便后续使用
1650 this.http.isRestful = true;
1660 return route;
167 }
1680 return route;
169 },
170 /**
171 * 正则匹配路由
172 * @param {[type]} matches [description]
173 * @param {[type]} route [description]
174 * @param {[type]} pathname [description]
175 * @return {[type]} [description]
176 */
177 parseRegExp: function(matches, route, pathname){
1780 route = this.getRoute(route, matches);
1790 if (!route) {
1800 return false;
181 }
1820 route = route.replace(/:(\d+)/g, function(a, b){
1830 return matches[b] || '';
184 });
1850 pathname = pathname.replace(matches[0], '');
1860 pathname = pathname.split('/').filter(function(item){
1870 return item;
188 });
189 //将剩余的pathname分割为querystring
1900 if (pathname.length) {
1910 for(var i = 0,length = Math.ceil(pathname.length)/2; i < length; i++){
1920 this.http.get[pathname[i * 2]] = pathname[i * 2 + 1] || '';
193 }
194 }
1950 this.parseUrl(route);
1960 return true;
197 }
198 };
199});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Behavior/DenyIpBehavior.js

93%
15
14
1
LineHitsSource
1/**
2 * 阻止ip来源访问
3 * @return {[type]} [description]
4 */
51module.exports = Behavior(function(){
61 'use strict';
71 return {
8 options: {
9 deny_ip: [] //阻止的ip列表
10 },
11 run: function(){
122 if (this.options.deny_ip.length === 0) {
131 return true;
14 }
151 var clientIps = this.http.ip().split('.');
161 var flag = this.options.deny_ip.some(function(item){
171 return item.split('.').every(function(num, i){
184 if (num === '*' || num === clientIps[i]) {
194 return true;
20 }
21 });
22 });
23 //如果在阻止的ip在列表里,则返回一个pendding promise,让后面的代码不执行
241 if (flag) {
251 this.http.res.statusCode = 403;
261 this.http.res.end();
271 return getDefer().promise;
28 }
290 return true;
30 }
31 };
32});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Behavior/LocationTemplateBehavior.js

100%
15
15
0
LineHitsSource
1/**
2 * 定位模版路径
3 * @return {[type]} [description]
4 */
5
61module.exports = Behavior(function(){
71 'use strict';
81 return {
9 run: function(templateFile){
10 //templateFile = templateFile || '';
116 if (!templateFile) {
12 //根据group, controller, action自动生成
131 templateFile = [
14 VIEW_PATH, '/', this.http.group, '/',
15 this.http.controller.toLowerCase(),
16 C('tpl_file_depr'),
17 this.http.action.toLowerCase(),
18 C('tpl_file_suffix')
19 ].join('');
205 }else if(templateFile.indexOf('/') > -1){
21 //自动追加VIEW_PATH
221 if (templateFile.indexOf('/') !== 0) {
231 templateFile = VIEW_PATH + '/' + templateFile;
24 }
254 }else if(templateFile.indexOf(C('tpl_file_suffix')) === -1){
264 var path = templateFile.split(':');
274 var action = path.pop();
284 var controller = path.pop() || this.http.controller.toLowerCase();
294 var group = ucfirst(path.pop()) || this.http.group;
304 templateFile = [
31 VIEW_PATH, '/', group, '/',
32 controller,
33 C('tpl_file_depr'),
34 action,
35 C('tpl_file_suffix')
36 ].join('');
37 }
386 return templateFile;
39 }
40 };
41});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Behavior/ParseTemplateBehavior.js

90%
10
9
1
LineHitsSource
1/**
2 * 调用对应的模版引擎解析模版
3 * @return {[type]} [description]
4 */
51module.exports = Behavior(function(){
61 'use strict';
71 return {
8 run: function(data){
96 var file = data.file;
10 //将模版文件路径写入到http对象上,供writehtmlcache里使用
116 this.http.tpl_file = file;
126 var engine = C('tpl_engine_type');
13 //不使用模版引擎,直接返回文件内容
146 if (!engine) {
150 return getFileContent(file);
16 }
176 var engineClass = ucfirst(engine) + 'Template';
186 return thinkRequire(engineClass).fetch(file, data.var);
19 }
20 };
21});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Behavior/ReadHtmlCacheBehavior.js

10%
64
7
57
LineHitsSource
1//获取模版文件
21var getViewFile = thinkRequire('WriteHtmlCacheBehavior').getViewFile;
31var fs = require('fs');
4/**
5 * 读取HTML缓存
6 * @return {[type]} [description]
7 */
81module.exports = Behavior(function(){
91 'use strict';
101 return {
11 options:{
12 'html_cache_on': false, //是否开启缓存
13 'html_cache_timeout': 3600, //缓存时间
14 'html_cache_rules': {}, //缓存规则
15 'html_cache_path': '',
16 'html_cache_file_callback': undefined, //生成缓存文件的回调函数
17 'html_cache_file_suffix': '.html', //缓存文件扩展名
18 },
19 run: function(){
201 if (!this.options.html_cache_on || isEmpty(this.options.html_cache_rules)) {
211 return false;
22 }
230 var cacheTime = this.getCacheTime();
240 if (cacheTime === false) {
250 return false;
26 }
270 if (this.checkCacheTime(cacheTime)) {
280 this.responseCacheContent();
29 //return a pending promise
300 return getDefer().promise;
31 }
320 return false;
33 },
34 /**
35 * 返回缓存内容
36 * @return {[type]} [description]
37 */
38 responseCacheContent: function(){
390 var http = this.http;
400 var fileStream = fs.createReadStream(this.options.html_cache_path + '/' + http.html_filename);
410 http.setHeader('Content-Type', 'text/html');
420 http.sendTime('Exec-Time');
430 http.sendCookie();
440 fileStream.pipe(http.res);
450 fileStream.on('end', function(){
460 http.end();
47 });
48 },
49 /**
50 * 获取缓存时间
51 * @return {[type]} [description]
52 */
53 getCacheTime: function(){
54 /**
55 * rules数据格式
56 * {
57 * 'index:index': ['index_home', 1800, html_cache_callback]
58 * }
59 * @type {[type]}
60 */
610 var rules = this.options.html_cache_rules;
620 var group = this.http.group.toLowerCase();
630 var controller = this.http.controller.toLowerCase();
640 var action = this.http.action.toLowerCase();
650 var list = [
66 group + ':' + controller + ':' + action,
67 controller + ':' + action,
68 action,
69 '*'
70 ];
710 var html = [];
720 list.some(function(item){
730 if (item in rules) {
740 html = rules[item];
750 return true;
76 }
77 });
780 if (isEmpty(html)) {
790 return false;
80 }
810 if (!isArray(html)) {
820 html = [html];
83 }
840 var rule = html[0];
85 //将cookie变量传递进去
860 var cookiePars = {};
870 for(var name in this.http.cookie){
880 cookiePars['cookie.' + name] = this.http.cookie[name];
89 }
900 var pars = extend({}, this.http.get, cookiePars, {
91 ':group': group,
92 ':controller': controller,
93 ':action': action
94 });
950 rule = rule.replace(/\{([\w\:]+)\}/g, function(a, name){
960 return pars[name] || '';
97 });
980 var callback = html[2] || C('html_cache_file_callback') || this.getCacheFilename;
990 var filename = callback(rule, this.http) + this.options.html_cache_file_suffix;
100 //静态缓存文件名
1010 this.http.html_filename = filename;
1020 var cacheTime = html[1] || this.options.html_cache_timeout;
1030 return cacheTime;
104 },
105 /**
106 *
107 * @param {[type]} key [description]
108 * @return {[type]} [description]
109 */
110 getCacheFilename: function(key){
1110 var value = md5(key);
1120 return value.substr(0, 1) + '/' + value;
113 },
114 /**
115 * [checkCacheTime description]
116 * @return {[type]} [description]
117 */
118 checkCacheTime: function(cacheTime){
1190 var cacheFile = this.options.html_cache_path + '/' + this.http.html_filename;
1200 if (!isFile(cacheFile)) {
1210 return false;
122 }
1230 var cacheFileMtime = fs.statSync(cacheFile).mtime.getTime();
1240 var tplFile = getViewFile(this.http);
1250 if (tplFile) {
1260 if (!isFile(tplFile)) {
1270 return false;
128 }
1290 var tplFileMtime = fs.statSync(tplFile).mtime.getTime();
130 //模版文件有更新
1310 if (tplFileMtime > cacheFileMtime) {
1320 return false;
133 }
134 }
1350 if (Date.now() > (cacheFileMtime + cacheTime * 1000)) {
1360 return false;
137 }
1380 return true;
139 }
140 };
141});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Behavior/WriteHtmlCacheBehavior.js

45%
20
9
11
LineHitsSource
1/**
2 * 模版文件列表
3 * @type {Object}
4 */
51var path = require('path');
61var fs = require('fs');
7
81var tplFiles = {};
9/**
10 * 写入html缓存
11 * @return {[type]} [description]
12 */
131module.exports = Behavior(function(){
141 'use strict';
151 return {
16 options: {
17 'html_cache_on': false, //是否开启缓存
18 'html_cache_path': ''
19 },
20 run: function(content){
213 if (!this.options.html_cache_on || !this.http.html_filename) {
223 return content;
23 }
240 this.recordViewFile();
250 var file = this.options.html_cache_path + '/' + this.http.html_filename;
260 mkdir(path.dirname(file));
27 //异步方式写入缓存
280 fs.writeFile(file, content);
290 return content;
30 },
31 /**
32 * 记录模版文件名
33 * @return {[type]} [description]
34 */
35 recordViewFile: function(){
360 var tplFile = this.http.tpl_file;
370 var key = this.http.group + ':' + this.http.controller + ':' + this.http.action;
380 tplFiles[key] = tplFile;
39 }
40 };
41});
42/**
43 * 获取模版文件
44 * @param {[type]} http [description]
45 * @return {[type]} [description]
46 */
471module.exports.getViewFile = function(http){
480 'use strict';
490 var key = http.group + ':' + http.controller + ':' + http.action;
500 return tplFiles[key];
51};

/Users/welefen/Develop/git/thinkjs/lib/Lib/Core/App.js

50%
158
80
78
LineHitsSource
11var cluster = require('cluster');
21var fs = require('fs');
31var domain = require('domain');
4
51var thinkHttp = thinkRequire('Http');
61var Dispatcher = thinkRequire('Dispatcher');
7
8
91var App = module.exports = {};
10/**
11 * 根据http里的group和controller获取对应的controller实例
12 * @param {[type]} http [description]
13 * @return {[type]} [description]
14 */
151App.getBaseController = function(http){
1612 'use strict';
1712 var gc = ucfirst(http.group) + '/' + ucfirst(http.controller) + 'Controller';
1812 var path = getThinkRequirePath(gc);
1912 if (path) {
2010 return require(path)(http);
21 }
22}
23/**
24 * controller不存在时调用的默认controller
25 * @return {[type]} [description]
26 */
271App.getCallController = function(http){
280 'use strict';
29 //如果是RESTFUL API,则调用RestController
300 if (http.isRestful) {
310 return thinkRequire('RestController')(http);
32 }
330 var config = C('call_controller');
340 if (!config) {
350 return;
36 }
370 if (isString(config)) {
380 config = config.split(':');
39 }
400 var action = Dispatcher.getAction(config.pop());
410 var controller = Dispatcher.getController(config.pop());
420 var group = Dispatcher.getGroup(config.pop());
430 var instance = this.getBaseController({
44 group: group,
45 controller: controller
46 })
470 if (instance && isFunction(instance[action + C('action_suffix')])) {
480 http.group = group;
490 http.controller = controller;
500 http.action = action;
51 }
520 return instance;
53}
54
55/**
56 * 执行具体的action,调用前置和后置操作
57 * @return {[type]} [description]
58 */
591App.execAction = function(controller, action, data, callMethod){
609 'use strict';
61 //action操作
629 var act = action + C('action_suffix');
639 var flag = false;
64 //action不存在时执行魔术方法
659 if (callMethod && !isFunction(controller[act])) {
660 var call = C('call_method');
670 if (call && isFunction(controller[call])) {
680 flag = true;
690 act = call;
70 }
71 }
72 //action不存在
739 if (!isFunction(controller[act])) {
740 return getPromise(new Error('action `' + action + '` not found. '), true);
75 }
769 var promise = getPromise();
77 //action前置操作
789 var before = C('before_action');
799 if (before && isFunction(controller[before])) {
800 promise = getPromise(controller[before](action));
81 }
829 promise = promise.then(function(){
83 //action魔术方法只传递action参数
849 if (flag) {
850 return controller[act](action);
86 }
879 if (data) {
885 return controller[act].apply(controller, data);
89 }else{
904 return controller[act]();
91 }
92 });
93 //action后置操作
949 var after = C('after_action');
959 if (after && isFunction(controller[after])) {
960 promise = promise.then(function(){
970 return controller[after](action);
98 })
99 }
1009 return promise;
101}
102
103/**
104 * 获取action的形参
105 * @return {[type]} [description]
106 */
1071App.getActionParams = function(fn, http){
1081 'use strict';
109 //注释的正则
1101 var commentReg = /((\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s))/mg;
111 //获取形参的正则
1121 var parsReg = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
1131 var toString = fn.toString().replace(commentReg, '');
1141 var match = toString.match(parsReg)[1].split(/\s*,\s*/);
115 //匹配到形参
1161 var params;
1171 if (match && match.length) {
1181 params = match.map(function(item){
1191 return http.post[item] || http.get[item] || '';
120 });
121 }
1221 return params;
123}
124/**
125 * 执行
126 * @param {[type]} http [description]
127 * @return {[type]} [description]
128 */
1291App.exec = function(http){
1301 'use strict';
1311 var controller = this.getBaseController(http) || this.getCallController(http);
132 //controller不存在
1331 if (!controller) {
1340 var err = new Error('Controller `' + http.controller + '` not found. ' + http.pathname);
1350 return getPromise(err, true);
136 }
137 //controller类实例
1381 http.controllerInstance = controller;
1391 var params;
1401 var actionFn = controller[http.action + C('action_suffix')];
141 //参数绑定
1421 if (C('url_params_bind') && isFunction(actionFn)) {
1431 params = this.getActionParams(actionFn, http);
144 }
1451 var promise = getPromise(controller.__initReturn);
1461 var self = this;
1471 return promise.then(function(){
1481 return self.execAction(controller, http.action, params, true);
149 })
150}
151/**
152 * 发送错误信息
153 * @param {[type]} error [description]
154 * @return {[type]} [description]
155 */
1561App.sendError = function(http, error){
1570 'use strict';
1580 if (!error) {
1590 return;
160 }
1610 var message = isError(error) ? error.stack : error;
1620 console.error(message);
1630 if (!http.res) {
1640 return;
165 }
1660 if (APP_DEBUG) {
1670 http.res.statusCode = 500;
1680 http.res.end(message);
169 }else{
1700 http.res.statusCode = 500;
1710 http.setHeader('Content-Type', 'text/html; charset=' + C('encoding'));
1720 var readStream = fs.createReadStream(C('error_tpl_path'));
1730 readStream.pipe(http.res);
1740 readStream.on('end', function(){
1750 http.res.end();
176 });
177 }
178}
179
180/**
181 * run
182 * @return {[type]} [description]
183 */
1841App.run = function(){
1851 'use strict';
1861 if (APP_MODE && App.mode[APP_MODE]) {
1871 return App.mode[APP_MODE]();
188 }
1890 return App.mode.http();
190};
191/**
192 * 不同模式下的run
193 * @type {Object}
194 */
1951App.mode = {
196 //命令行模式
197 cli: function(){
1981 'use strict';
1991 var defaultHttp = thinkHttp.getDefaultHttp(process.argv[2]);
2001 thinkHttp(defaultHttp.req, defaultHttp.res).run().then(App.listener);
201 },
202 //HTTP模式
203 http: function(){
2040 'use strict';
2050 var clusterNums = C('use_cluster');
206 //不使用cluster
2070 if (!clusterNums) {
2080 return App.createServer();
209 }
210 //使用cpu的个数
2110 if (clusterNums === true) {
2120 clusterNums = require('os').cpus().length;
213 }
2140 if (cluster.isMaster) {
2150 for (var i = 0; i < clusterNums; i++) {
2160 cluster.fork();
217 }
2180 cluster.on('exit', function(worker) {
2190 console.log('worker ' + worker.process.pid + ' died');
2200 process.nextTick(function(){
2210 cluster.fork();
222 });
223 });
224 }else {
2250 App.createServer();
226 }
227 }
228};
229/**
230 * 创建服务
231 * @return {[type]} [description]
232 */
2331App.createServer = function(){
2340 'use strict';
235 //自定义创建server
2360 var createServerFn = C('create_server_fn');
2370 if (createServerFn) {
2380 if (isFunction(createServerFn)) {
2390 return createServerFn(App);
2400 }else if (isFunction(global[createServerFn])) {
2410 return global[createServerFn](App);
242 }
243 }
2440 var server = require('http').createServer(function (req, res) {
2450 thinkHttp(req, res).run().then(App.listener);
246 });
2470 thinkRequire('WebSocket')(server, App).run();
2480 server.listen(C('port'));
2490 if (APP_DEBUG) {
2500 console.log('Server running at http://127.0.0.1:' + C('port') + '/');
251 }
252}
253/**
254 * 监听回调函数
255 * @param {[type]} http [description]
256 * @return {[type]} [description]
257 */
2581App.listener = function(http){
2591 'use strict';
260 //自动发送thinkjs和版本的header
2611 http.setHeader('X-Powered-By', 'thinkjs-' + THINK_VERSION);
262 //禁止远程直接用带端口的访问,websocket下允许
2631 if (C('use_proxy') && http.host !== http.hostname && !http.websocket) {
2640 http.res.statusCode = 403;
2650 http.res.end();
2660 return getDefer().promise;
267 }
2681 var domainInstance = domain.create();
2691 var deferred = getDefer();
2701 domainInstance.on('error', function(err){
2710 App.sendError(http, err);
2720 deferred.reject(err);
273 });
2741 domainInstance.run(function(){
2751 return tag('app_init', http).then(function(){
2761 return Dispatcher(http).run();
277 }).then(function(){
2781 return tag('app_begin', http);
279 }).then(function(){
2801 return tag('action_init', http);
281 }).then(function(){
2821 return App.exec(http);
283 }).then(function(){
2841 return tag('app_end', http);
285 }).catch(function(err){
2860 App.sendError(http, err);
287 }).then(function(){
2881 deferred.resolve();
289 })
290 });
2911 return deferred.promise;
292};

/Users/welefen/Develop/git/thinkjs/lib/Lib/Core/Controller.js

100%
151
151
0
LineHitsSource
1/**
2 * Controller 基类
3 * @return {[type]} [description]
4 */
51var fs = require('fs');
61var path = require('path');
71var url = require('url');
8
91module.exports = Class(function() {
101 'use strict';
11
121 return {
13 /**
14 * 初始化执行方法
15 * @param {[type]} http [description]
16 * @return {[type]} [description]
17 */
18 init: function(http) {
1911 this.http = http;
2011 this.view = null;
21 //将http数据打到模版里
2211 this.assign('http', this.http);
23 //将配置信息打到模版里
2411 this.assign('config', C());
25 //设置变量别名
2611 this.set = this.assign;
27 //success别名
2811 this.ok = this.success;
29 },
30 /**
31 * 获取客户端的ip
32 * @return {[type]} [description]
33 */
34 ip: function() {
351 return this.http.ip();
36 },
37 /**
38 * 实例化View类
39 * @return {[type]} [description]
40 */
41 initView: function() {
4236 if (!this.view) {
4311 this.view = thinkRequire('View')(this.http);
44 }
4536 return this.view;
46 },
47 /**
48 * 是否是GET请求
49 * @return {Boolean} [description]
50 */
51 isGet: function() {
521 return this.http.method === 'GET';
53 },
54 /**
55 * 是否是POST请求
56 * @return {Boolean} [description]
57 */
58 isPost: function() {
591 return this.http.method === 'POST';
60 },
61 /**
62 * 是否是特定METHOD请求
63 * @param {[type]} method [description]
64 * @return {Boolean} [description]
65 */
66 isMethod: function(method) {
672 return this.http.method === method.toUpperCase();
68 },
69 /**
70 * 是否是AJAX请求
71 * @return {Boolean} [description]
72 */
73 isAjax: function(method) {
74 //请求类型判断
756 if (method && this.http.method !== method.toUpperCase()) {
762 return false;
77 }
784 return this.header('x-requested-with') === 'XMLHttpRequest';
79 },
80 /**
81 * 是否是websocket请求
82 * @return {Boolean} [description]
83 */
84 isWebSocket: function(){
852 return !!this.http.websocket;
86 },
87 /**
88 * 是否是命令行模式
89 * @return {Boolean} [description]
90 */
91 isCli: function(){
922 return APP_MODE === 'cli';
93 },
94 /**
95 * 是否是jsonp接口
96 * @return {Boolean} [description]
97 */
98 isJsonp: function(name){
994 name = name || C('url_callback_name');
1004 return !!this.get(name);
101 },
102 /**
103 * 获取QUERY参数
104 * @param {[type]} name [description]
105 * @return {[type]} [description]
106 */
107 get: function(name) {
10816 if (name === undefined) {
1092 return this.http.get;
110 }
11114 return this.http.get[name] || '';
112 },
113 /**
114 * 获取POST参数
115 * @param {[type]} name [description]
116 * @return {[type]} [description]
117 */
118 post: function(name) {
1196 var http = this.http;
1206 return name ? (http.post[name] || '') : http.post;
121 },
122 /**
123 * 获取参数
124 * @param {[type]} name [description]
125 * @return {[type]} [description]
126 */
127 param: function(name) {
1284 if (name === undefined) {
1292 var post = this.post();
1302 return !isEmpty(post) ? post : this.get();
131 }
1322 return this.post(name) || this.get(name);
133 },
134 /**
135 * 获取上传的文件
136 * @param {[type]} name [description]
137 * @return {[type]} [description]
138 */
139 file: function(name) {
1403 var http = this.http;
1413 return name ? (http.file[name] || {}) : http.file;
142 },
143 /**
144 * header操作
145 * @param {[type]} name [description]
146 * @param {[type]} value [description]
147 * @return {[type]} [description]
148 */
149 header: function(name, value) {
15011 if (name === undefined) {
1511 return this.http.headers;
15210 }else if (isObject(name)) {
1531 for (var key in name) {
1542 this.header(key, name[key]);
155 }
1561 return this;
1579 }else if (value !== undefined) {
1583 this.http.setHeader(name, value);
1593 return this;
160 }else{
1616 return this.http.getHeader(name);
162 }
163 },
164 /**
165 * 获取userAgent
166 * @return {[type]} [description]
167 */
168 userAgent: function(){
1691 return this.http.headers['user-agent'] || '';
170 },
171 /**
172 * 获取referrer
173 * @return {[type]} [description]
174 */
175 referer: function(host){
1763 var referer = this.http.headers.referer || this.http.headers.referfer || '';
1773 if (!referer || !host) {
1782 return referer;
179 }
1801 var info = url.parse(referer);
1811 return info.hostname;
182 },
183 /**
184 * cookie操作
185 * @param {[type]} name [description]
186 * @param {[type]} value [description]
187 * @param {[type]} options [description]
188 * @return {[type]} [description]
189 */
190 cookie: function(name, value, options) {
1914 if (value !== undefined) {
1921 this.http.setCookie(name, value, options);
1931 return this;
194 }
1953 return name === undefined ? this.http.cookie : (this.http.cookie[name] || '');
196 },
197 /**
198 * session
199 * 如果是get操作,则返回一个promise
200 * @param {[type]} name [description]
201 * @param {[type]} value [description]
202 * @return {[type]} [description]
203 */
204 session: function(name, value) {
20511 thinkRequire('Session').start(this.http);
20611 var instance = this.http.session;
20711 if (name === undefined) {
2081 return instance.rm();
209 }
21010 if (value !== undefined) {
2115 return instance.set(name, value);
212 }
2135 return instance.get(name);
214 },
215 /**
216 * 跳转,返回一个pendding promise阻止后面继续执行
217 * @param {[type]} url [description]
218 * @param {[type]} code [description]
219 * @return {[type]} [description]
220 */
221 redirect: function(url, code) {
2222 this.http.redirect(url, code);
2232 return getDefer().promise;
224 },
225 /**
226 * 赋值变量到模版
227 * @param {[type]} name [description]
228 * @param {[type]} value [description]
229 * @return {[type]} [description]
230 */
231 assign: function(name, value) {
23229 if (arguments.length <= 1) {
2336 return this.initView().assign(name);
234 }
23523 return this.initView().assign(name, value);
236 },
237 /**
238 * 获取解析后的模版内容
239 * @param {[type]} templateFile [description]
240 * @param {[type]} content [description]
241 * @return {[type]} [description]
242 */
243 fetch: function(templateFile) {
2443 return this.initView().fetch(templateFile);
245 },
246 /**
247 * 输出模版内容
248 * @param {[type]} templateFile [description]
249 * @param {[type]} charset [description]
250 * @param {[type]} contentType [description]
251 * @param {[type]} content [description]
252 * @return {[type]} [description]
253 */
254 display: function(templateFile, charset, contentType) {
2553 return this.initView().display(templateFile, charset, contentType);
256 },
257 /**
258 * 调用另一个controll里的aciton
259 * 可以跨分组
260 * A('Admin/Test/index')
261 * @param {[type]} action [description]
262 * @return {[type]} [description]
263 */
264 action: function(action, data) {
265 //自动补group
2663 action = action.replace(/\//g, ':');
2673 if (action.split(':').length === 2) {
2683 action = this.http.group + ':' + action;
269 }
2703 return A(action, this.http, data);
271 },
272 /**
273 * jsonp格式输出
274 * @param {[type]} data [description]
275 * @param {[type]} jsonp [description]
276 * @return {[type]} [description]
277 */
278 jsonp: function(data) {
2796 this.type(C('json_content_type'));
2806 var callback = this.get(C('url_callback_name'));
281 //过滤callback值里的非法字符
2826 callback = callback.replace(/[^\w\.]/g, '');
2836 if (callback) {
2843 data = callback + '(' + (data !== undefined ? JSON.stringify(data) : '') + ')';
2853 this.end(data);
286 } else {
2873 this.end(data);
288 }
289 },
290 /**
291 * json格式输出
292 * @param {[type]} data [description]
293 * @return {[type]} [description]
294 */
295 json: function(data){
2962 this.type(C('json_content_type'));
2972 return this.end(data);
298 },
299 /**
300 * 设置http响应状态码
301 * @param {[type]} status [description]
302 * @return {[type]} [description]
303 */
304 status: function(status) {
3052 var res = this.http.res;
3062 if (!res.headersSent) {
3072 res.statusCode = status || 404;
308 }
3092 return this;
310 },
311 /**
312 * 阻止访问
313 * @param {[type]} status [description]
314 * @return {[type]} [description]
315 */
316 deny: function(status){
3172 var res = this.http.res;
3182 if (!res.headersSent) {
3192 res.statusCode = status || 403;
3202 this.http.end();
321 }
3222 return getDefer().promise;
323 },
324 /**
325 * 输出内容
326 * 自动JSON.stringify
327 * 自定将数字等转化为字符串
328 * @param {[type]} obj [description]
329 * @return {[type]} [description]
330 */
331 echo: function(obj, encoding) {
332 //自动发送Content-Type的header
33321 if (C('auto_send_content_type')) {
33421 this.type(C('tpl_content_type'));
335 }
33621 return this.http.echo(obj, encoding);
337 },
338 /**
339 * 结束输出,输出完成时一定要调用这个方法
340 * @param {[type]} obj [description]
341 * @return {[type]} [description]
342 */
343 end: function(obj, encoding) {
34418 if (obj !== undefined) {
34515 this.echo(obj, encoding);
346 }
34718 this.http.end();
348 },
349 /**
350 * 发送Content-Type
351 * @param {[type]} type [description]
352 * @return {[type]} [description]
353 */
354 type: function(ext){
35548 if (this.http.cthIsSend || !ext) {
35631 return;
357 }
35817 if (ext.indexOf('/') === -1) {
3593 ext = require('mime').lookup(ext);
360 }
36117 if (ext.toLowerCase().indexOf('charset=') === -1) {
36217 ext += '; charset=' + C('encoding');
363 }
364 //Content-Type Header has been Send
36517 this.http.cthIsSend = true;
36617 this.http.setHeader('Content-Type', ext);
367 },
368 /**
369 * 下载文件
370 * @return Promise [description]
371 */
372 download: function(file, contentType, filename) {
3735 if (isString(contentType) && contentType.indexOf('.') > -1) {
3741 filename = contentType;
3751 contentType = '';
376 }
3775 if (!contentType || contentType.indexOf('/') === -1) {
3784 contentType = require('mime').lookup(contentType || file);
379 }
3805 var http = this.http;
3815 var fileStream = fs.createReadStream(file);
3825 var deferred = getDefer();
3835 this.type(contentType);
3845 http.setHeader('Content-Disposition', 'attachment; filename="' + (filename || path.basename(file)) + '"');
3855 fileStream.pipe(http.res);
3865 fileStream.on('end', function() {
3875 http.end();
3885 deferred.resolve();
389 });
3905 return deferred.promise;
391 },
392 /**
393 * 正常json数据输出
394 * @param {[type]} data [description]
395 * @return {[type]} [description]
396 */
397 success: function(data){
3982 var obj = getObject([C('error_no_key'), C('error_msg_key')], [0, '']);
3992 if (data !== undefined) {
4001 obj.data = data;
401 }
4022 this.type(C('json_content_type'));
4032 this.end(obj);
4042 return getDefer().promise;
405 },
406 /**
407 * 异常json数据数据
408 * @param {[type]} errno [description]
409 * @param {[type]} errmsg [description]
410 * @param {[type]} extra [description]
411 * @return {[type]} [description]
412 */
413 error: function(errno, errmsg, data){
4147 var obj;
4157 if (isObject(errno)) {
4163 data = errmsg;
4173 obj = extend({}, errno);
418 }else{
4194 if (!isNumber(errno)) {
4201 data = errmsg;
4211 errmsg = errno;
4221 errno = C('error_no_default_value');
423 }
4244 obj = getObject([C('error_no_key'), C('error_msg_key')], [errno, errmsg || 'error']);
425 }
4267 if (data !== undefined) {
4272 obj.data = data;
428 }
4297 this.type(C('json_content_type'));
4307 this.end(obj);
4317 return getDefer().promise;
432 },
433 /**
434 * 关闭数据库连接
435 * @return {[type]} [description]
436 */
437 closeDb: function(){
4381 thinkRequire('Model').close();
439 },
440 /**
441 * 发送执行时间
442 * @param {[type]} name [description]
443 * @return {[type]} [description]
444 */
445 sendTime: function(name){
4462 return this.http.sendTime(name);
447 },
448 /**
449 * 对数据进行过滤
450 * @param {[type]} data [description]
451 * @param {[type]} type [description]
452 * @return {[type]} [description]
453 */
454 filter: function() {
4552 var filter = thinkRequire('Filter').filter;
4562 return filter.apply(null, arguments);
457 },
458 /**
459 * 校验一个值是否合法
460 * @param {[type]} data [description]
461 * @param {[type]} validType [description]
462 * @return {[type]} [description]
463 */
464 valid: function(data, validType) {
465 //单个值检测,只返回是否正常
4663 if (validType !== undefined) {
4671 data = [{
468 value: data,
469 valid: validType
470 }];
4711 var result = thinkRequire('Valid')(data);
4721 return isEmpty(result);
473 }
4742 return thinkRequire('Valid')(data);
475 }
476 };
477});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Core/Db.js

82%
366
303
63
LineHitsSource
11var querystring = require('querystring');
2/**
3 * 数据库基类
4 * @return {[type]} [description]
5 */
61var Db = module.exports = Class(function(){
71 'use strict';
8 //用于查询的sql语句,所有select语句根据该语句解析
91 var selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%COMMENT%';
10 //where条件里的表达式
111 var comparison = {
12 'EQ': '=',
13 'NEQ': '!=',
14 '<>': '!=',
15 'GT': '>',
16 'EGT': '>=',
17 'LT': '<',
18 'ELT': '<=',
19 'NOTLIKE': 'NOT LIKE',
20 'LIKE': 'LIKE',
21 'IN': 'IN',
22 'NOTIN': 'NOT IN'
23 };
241 return {
25 // 数据库类型
26 dbType: null,
27 // 当前操作所属的模型名
28 model: 'think',
29 // 当前SQL指令
30 sql: '',
31 // 操作的sql列表
32 modelSql: {},
33 // 当前连接ID
34 linkId: null,
35 // 数据库连接参数配置
36 config: '',
37 /**
38 * 初始化
39 * @return {[type]} [description]
40 */
41 init: function(){
42
43 },
44 /**
45 * 解析set集合
46 * @param {[type]} data [description]
47 * @return {[type]} [description]
48 */
49 parseSet: function(data){
5013 data = data || {};
5113 var set = [];
5213 for(var key in data){
5313 var value = this.parseValue(data[key]);
5413 if (isScalar(value)) {
5513 set.push(this.parseKey(key) + '=' + value);
56 }
57 }
5813 return ' SET ' + set.join(',');
59 },
60 /**
61 * 解析字段名,具体的数据库里实现
62 * @param {[type]} key [description]
63 * @return {[type]} [description]
64 */
65 parseKey: function(key){
660 return key;
67 },
68 /**
69 * value分析
70 * @param {[type]} value [description]
71 * @return {[type]} [description]
72 */
73 parseValue: function(value){
74155 if (isString(value)) {
7564 value = '\'' + this.escapeString(value) + '\'';
7691 }else if(isArray(value)){
7717 if ((value[0] + '').toLowerCase() === 'exp') {
788 value = this.escapeString(value[1]);
79 }else{
809 var self = this;
819 value = value.map(function(item){
8217 return self.parseValue(item);
83 });
84 }
8574 }else if(isBoolean(value)){
860 value = value ? '1' : '0';
8774 }else if (value === null) {
880 value = 'null';
89 }
90155 return value;
91 },
92 /**
93 * field分析
94 * parseField('name');
95 * parseField('name,email');
96 * parseField({
97 * xx_name: 'name',
98 * xx_email: 'email'
99 * })
100 * @return {[type]} [description]
101 */
102 parseField: function(fields){
103153 if (isString(fields) && fields.indexOf(',') > -1) {
1044 fields = fields.split(',');
105 }
106153 if (isArray(fields)) {
1074 var self = this;
1084 return fields.map(function(item){
10917 return self.parseKey(item);
110 }).join(',');
111149 }else if(isObject(fields)){
1120 var data = [];
1130 for(var key in fields){
1140 data.push(this.parseKey(key) + ' AS ' + this.parseKey(fields[key]));
115 }
1160 return data.join(',');
117149 }else if(isString(fields) && fields){
11817 return this.parseKey(fields);
119 }
120132 return '*';
121 },
122 /**
123 * table别名分析
124 * @param {[type]} tables [description]
125 * @return {[type]} [description]
126 */
127 parseTable: function(tables){
128175 if (isString(tables)) {
129175 tables = tables.split(',');
130 }
131175 if (isArray(tables)) {
132175 var self = this;
133175 return tables.map(function(item){
134175 return self.parseKey(item);
135 }).join(',');
1360 }else if (isObject(tables)) {
1370 var data = [];
1380 for(var key in tables){
1390 data.push(this.parseKey(key) + ' AS ' + this.parseKey(tables[key]));
140 }
1410 return data.join(',');
142 }
1430 return '';
144 },
145 /**
146 * where条件分析
147 * @param {[type]} where [description]
148 * @return {[type]} [description]
149 */
150 parseWhere: function(where){
151170 var whereStr = '';
152170 var self = this;
153170 where = where || {};
154170 if (isString(where)) {
1550 whereStr = where;
156 }else{
157 // 定义逻辑运算规则 例如 OR XOR AND NOT
158170 var oList = ['AND', 'OR', 'XOR'];
159170 var operate = (where._logic + '').toUpperCase();
160170 delete where._logic;
161170 operate = oList.indexOf(operate) > -1 ? ' ' + operate + ' ' : ' AND ';
162 //key值的安全检测正则
163170 var keySafeRegExp = /^[\w\|\&\-\.\(\)\,]+$/;
164170 var multi = where._multi;
165170 delete where._multi;
166
167170 var val;
168170 var fn = function(item, i){
1698 var v = multi ? val[i] : val;
1708 return '(' + self.parseWhereItem(self.parseKey(item), v) + ')';
171 };
172170 for(var key in where){
173100 key = key.trim();
174100 val = where[key];
175100 whereStr += '( ';
176100 if (key.indexOf('_') === 0) {
177 // 解析特殊条件表达式
1783 whereStr += this.parseThinkWhere(key, val);
179 }else{
18097 if (!keySafeRegExp.test(key)) {
1810 console.log(key + ' is not safe');
1820 continue;
183 }
18497 var arr;
185 // 支持 name|title|nickname 方式定义查询字段
18697 if (key.indexOf('|') > -1) {
1872 arr = key.split('|');
1882 whereStr += arr.map(fn).join(' OR ');
18995 }else if (key.indexOf('&') > -1) {
1902 arr = key.split('&');
1912 whereStr += arr.map(fn).join(' AND ');
192 }else{
19393 whereStr += this.parseWhereItem(this.parseKey(key), val);
194 }
195 }
196100 whereStr += ' )' + operate;
197 }
198170 whereStr = whereStr.substr(0, whereStr.length - operate.length);
199 }
200
201170 return whereStr ? (' WHERE ' + whereStr) : '';
202 },
203 /**
204 * 解析单个查询条件
205 * @param {[type]} key [description]
206 * @param {[type]} val [description]
207 * @return {[type]} [description]
208 */
209 parseWhereItem: function(key, val){
210101 if (isObject(val)) { // {id: {'<': 10, '>': 1}}
2117 var logic = (val._logic || 'AND').toUpperCase();
2127 delete val._logic;
2137 var result = [];
2147 for(var opr in val){
21514 var nop = opr.toUpperCase();
21614 nop = comparison[nop] || nop;
21714 result.push(key + ' ' + nop + ' ' + this.parseValue(val[opr]));
218 }
2197 return result.join(' ' + logic + ' ');
22094 }else if (!isArray(val)) {
221 //对字符串类型字段采用模糊匹配
22231 if (C('db_like_fields').indexOf(key) > -1) {
2230 return key + ' LIKE ' + this.parseValue('%' + val + '%');
224 }else{
22531 return key + ' = ' + this.parseValue(val);
226 }
227 }
22863 var whereStr = '';
22963 var data;
23063 if (isString(val[0])) {
23162 var val0 = val[0].toUpperCase();
23262 val0 = comparison[val0] || val0;
23362 if (/^(=|!=|>|>=|<|<=)$/.test(val0)) { // 比较运算
23422 whereStr += key + ' ' + val0 + ' ' + this.parseValue(val[1]);
23540 }else if (/^(NOT\s+LIKE|LIKE)$/.test(val0)) { // 模糊查找
23623 if (isArray(val[1])) { //多个like
2377 var likeLogic = (val[2] || 'OR').toUpperCase();
2387 var likesLogic = ['AND','OR','XOR'];
2397 var self = this;
2407 if (likesLogic.indexOf(likeLogic) > -1) {
2417 var like = val[1].map(function(item){
24213 return key + ' ' + val0 + ' ' + self.parseValue(item);
243 }).join(' ' + likeLogic + ' ');
2447 whereStr += '(' + like + ')';
245 }
246 }else{
24716 whereStr += key + ' ' + val0 + ' ' + this.parseValue(val[1]);
248 }
24917 }else if(val0 === 'EXP'){ // 使用表达式
2502 whereStr += '(' + key + ' ' + val[1] + ')';
25115 }else if(val0 === 'IN' || val0 === 'NOT IN'){ // IN 运算
25212 if (val[2] === 'exp') {
2533 whereStr += key + ' ' + val0 + ' ' + val[1];
254 }else{
2559 if (isString(val[1])) {
2564 val[1] = val[1].split(',');
257 }
258 //如果不是数组,自动转为数组
2599 if (!isArray(val[1])) {
2602 val[1] = [val[1]];
261 }
2629 val[1] = this.parseValue(val[1]);
263 //如果只有一个值,那么变成=或者!=
2649 if (val[1].length === 1) {
2652 whereStr += key + (val0 === 'IN' ? ' = ' : ' != ') + val[1];
266 }else{
2677 whereStr += key + ' ' + val0 + ' (' + val[1].join(',') + ')';
268 }
269 }
2703 }else if(val0 === 'BETWEEN'){ // BETWEEN运算
2713 data = isString(val[1]) ? val[1].split(',') : val[1];
2723 if (!isArray(data)) {
2732 data = [val[1], val[2]];
274 }
2753 whereStr += ' (' + key + ' ' + val0 + ' ' + this.parseValue(data[0]);
2763 whereStr += ' AND ' + this.parseValue(data[1]) + ')';
277 }else{
2780 console.log('_EXPRESS_ERROR_', key, val);
2790 return '';
280 }
281 }else{
2821 var length = val.length;
2831 var rule = 'AND';
2841 if (isString(val[length - 1])) {
2850 var last = val[length - 1].toUpperCase();
2860 if (last && ['AND', 'OR', 'XOR'].indexOf(last) > -1) {
2870 rule = last;
2880 length--;
289 }
290 }
2911 for(var i = 0; i < length; i++){
2923 var isArr = isArray(val[i]);
2933 data = isArr ? val[i][1] : val[i];
2943 var exp = ((isArr ? val[i][0] : '') + '').toUpperCase();
2953 if (exp === 'EXP') {
2961 whereStr += '(' + key + ' ' + data + ') ' + rule + ' ';
297 }else{
2982 var op = isArr ? (comparison[val[i][0].toUpperCase()] || val[i][0]) : '=';
2992 whereStr += '(' + key + ' ' + op + ' ' + this.parseValue(data) + ') ' + rule + ' ';
300 }
301 }
3021 whereStr = whereStr.substr(0, whereStr.length - 4);
303 }
30463 return whereStr;
305 },
306 /**
307 * 解析一些特殊的where条件
308 * @param {[type]} key [description]
309 * @param {[type]} val [description]
310 * @return {[type]} [description]
311 */
312 parseThinkWhere: function(key, val){
3133 switch(key){
314 // 字符串模式查询条件
315 case '_string':
3162 return val;
317 // 复合查询条件
318 case '_complex':
3191 return this.parseWhere(val).substr(6);
320 // 字符串模式查询条件
321 case '_query':
3220 var where = isString(val) ? querystring.parse(val) : val;
3230 var op = ' AND ';
3240 if ('_logic' in where) {
3250 op = ' ' + where._logic.toUpperCase() + ' ';
3260 delete where._logic;
327 }
3280 var arr = [];
3290 for(var name in where){
3300 val = where[name];
3310 val = this.parseKey(name) + ' = ' + this.parseValue(val);
3320 arr.push(val);
333 }
3340 return arr.join(op);
335 default:
3360 return '';
337 }
3380 return '';
339 },
340 /**
341 * 解析limit,对非法的limit进行过滤
342 * @param {[type]} limit [description]
343 * @return {[type]} [description]
344 */
345 parseLimit: function(limit){
346169 if (!limit) {
347146 return '';
348 }
34923 limit = (limit + '').split(',');
35023 var data = [];
35123 for(var i = 0; i < Math.min(2, limit.length); i++){
35231 data[i] = limit[i] | 0;
353 }
35423 return ' LIMIT ' + data.join(',');
355 },
356 /**
357 * 解析join
358 * @param {[type]} join [description]
359 * @return {[type]} [description]
360 */
361 parseJoin: function(join, options){
362153 if (!join) {
363136 return '';
364 }
36517 var joinStr = '';
36617 var defaultJoin = ' LEFT JOIN ';
36717 if (isArray(join)) {
36817 var joins = {
369 'left': ' LEFT JOIN ',
370 'right': ' RIGHT JOIN ',
371 'inner': ' INNER JOIN '
372 };
37317 join.forEach(function(val){
37419 if (isString(val)) {//字符串,直接拼接
3756 var hasJoin = val.toLowerCase().indexOf(' join ') > -1;
3766 joinStr += (hasJoin ? ' ' : defaultJoin) + val;
37713 }else if (isObject(val)) {
37813 var ret = [];
37913 if (!('on' in val)) {
3807 for(var key in val){
38115 var v = val[key];
38215 v.table = key;
38315 ret.push(v);
384 }
385 }else{
3866 ret.push(val);
387 }
38813 ret.forEach(function(item){
38921 var joinType = joins[item.join] || item.join || defaultJoin;
39021 var table = options.tablePrefix + item.table;
39121 joinStr += joinType + '`' + table + '`';
39221 if (item.as) {
39312 joinStr += ' AS ' + item.as;
394 }
395 //ON条件
39621 if (item.on) {
39721 var mTable = options.alias || options.table;
39821 var jTable = item.as || table;
399 //多个=条件
40021 if (isObject(item.on)) {
4012 var where = [];
4022 for(var key in item.on){
4034 where.push(mTable + '.`' + key + '`' + '=' + jTable + '.`' + item.on[key] + '`');
404 }
4052 joinStr += ' ON (' + where.join(' AND ') + ')';
406 }else{
40719 if (isString(item.on)) {
4083 item.on = item.on.split(/\s*,\s*/);
409 }
41019 joinStr += ' ON ' + mTable + '.`' + item.on[0] + '`';
41119 joinStr += '=' + jTable + '.`' + item.on[1] + '`';
412 }
413 }
414 })
415 }
416 });
417 }else{
4180 joinStr += defaultJoin + join;
419 }
42017 return joinStr;
421 },
422 /**
423 * 解析order
424 * @param {[type]} order [description]
425 * @return {[type]} [description]
426 */
427 parseOrder: function(order){
428169 var self = this;
429169 if (isArray(order)) {
4302 order = order.map(function(item){
4313 return self.parseKey(item);
432 }).join(',');
433167 }else if (isObject(order)) {
4342 var arr = [];
4352 for(var key in order){
4363 var val = order[key];
4373 val = this.parseKey(key) + ' ' + val;
4383 arr.push(val);
439 }
4402 order = arr.join(',');
441 }
442169 return order ? (' ORDER BY ' + order) : '';
443 },
444 /**
445 * 解析group
446 * @param {[type]} group [description]
447 * @return {[type]} [description]
448 */
449 parseGroup: function(group){
450153 return group ? (' GROUP BY `' + group + '`' ) : '';
451 },
452 /**
453 * 解析having
454 * @param {[type]} having [description]
455 * @return {[type]} [description]
456 */
457 parseHaving: function(having){
458153 return having ? (' HAVING ' + having) : '';
459 },
460 /**
461 * 解析注释,一般情况下用不到
462 * @param {[type]} comment [description]
463 * @return {[type]} [description]
464 */
465 parseComment: function(comment){
466171 return comment ? (' /* ' + comment + '*/') : '';
467 },
468 /**
469 * 解析Distinct
470 * @param {[type]} distinct [description]
471 * @return {[type]} [description]
472 */
473 parseDistinct: function(distinct){
474153 return distinct ? ' Distinct ' : '';
475 },
476 /**
477 * 解析Union
478 * @param {[type]} union [description]
479 * @return {[type]} [description]
480 */
481 parseUnion: function(union){
482153 if (!union) {
483149 return '';
484 }
4854 if (isArray(union)) {
4864 var self = this;
4874 var sql = '';
4884 union.forEach(function(item){
4895 sql += item.all ? 'UNION ALL ' : 'UNION ';
4905 sql += '(' + (isObject(item.union) ? self.buildSelectSql(item.union).trim() : item.union) + ') ';
491 })
4924 return sql;
493 }else{
4940 return 'UNION (' + (isObject(union) ? this.buildSelectSql(union).trim() : union) + ') ';
495 }
496 },
497 /**
498 * 解析Lock
499 * @param {[type]} lock [description]
500 * @return {[type]} [description]
501 */
502 parseLock: function(lock){
503171 if (!lock) {
504170 return '';
505 }
5061 return ' FOR UPDATE ';
507 },
508 /**
509 * 将page转化为sql里的limit
510 * @return {[type]} [description]
511 */
512 pageToLimit: function(options){
513153 options = options || {};
514 //根据page生成limit
515153 if ('page' in options) {
5166 var page = options.page + '';
5176 var listRows = 0;
5186 if (page.indexOf(',') > -1) {
5193 page = page.split(',');
5203 listRows = page[1] | 0;
5213 page = page[0];
522 }
5236 page = parseInt(page, 10) || 1;
5246 if (!listRows) {
5254 listRows = isNumberString(options.limit) ? options.limit : C('db_nums_per_page');
526 }
5276 var offset = listRows * (page - 1);
5286 options.limit = offset + ',' + listRows;
529 }
530153 return options;
531 },
532 /**
533 * 拼接select查询语句
534 * @param {[type]} options [description]
535 * @return {[type]} [description]
536 */
537 buildSelectSql: function(options){
538153 options = this.pageToLimit(options);
539153 var sql = this.parseSql(selectSql, options);
540153 sql += this.parseLock(options.lock);
541153 return sql;
542 },
543 /**
544 * 解析sql语句
545 * @param {[type]} sql [description]
546 * @param {[type]} options [description]
547 * @return {[type]} [description]
548 */
549 parseSql: function(sql, options){
550153 options = options || {};
551153 var self = this;
552153 return sql.replace(/\%([A-Z]+)\%/g, function(a, type){
5531683 type = type.toLowerCase();
5541683 return self['parse' + ucfirst(type)](options[type] || '', options);
555 }).replace(/__([A-Z_-]+)__/g, function(a, b){
5560 return '`' + C('db_prefix') + b.toLowerCase() + '`';
557 });
558 },
559 /**
560 * 插入一条记录
561 * @param {[type]} data [description]
562 * @param {[type]} options [description]
563 * @param {[type]} replace [description]
564 * @return {[type]} [description]
565 */
566 insert: function(data, options, replace){
5672 data = data || {};
5682 options = options || {};
5692 var values = [];
5702 var fields = [];
5712 this.model = options.model;
5722 for(var key in data){
5733 var val = data[key];
5743 val = this.parseValue(val);
5753 if (isScalar(val)) {
5763 values.push(val);
5773 fields.push(this.parseKey(key));
578 }
579 }
5802 var sql = (replace ? 'REPLACE' : 'INSERT') + ' INTO ';
5812 sql += this.parseTable(options.table) + ' (' + fields.join(',') + ') ';
5822 sql += 'VALUES(' + values.join(',') + ')';
5832 sql += this.parseLock(options.lock) + this.parseComment(options.comment);
5842 return this.execute(sql);
585 },
586 /**
587 * 插入多条记录
588 * @param {[type]} data [description]
589 * @param {[type]} options [description]
590 * @param {[type]} replace [description]
591 * @return {[type]} [description]
592 */
593 insertAll: function(data, options, replace){
5944 var fields = Object.keys(data[0]);
5954 var self = this;
5964 fields = fields.map(function(item){
5976 return self.parseKey(item);
598 }).join(',');
5994 var values = data.map(function(item){
6006 var value = [];
6016 for(var key in item){
6029 var val = item[key];
6039 val = self.parseValue(val);
6049 if (isScalar(val)) {
6059 value.push(val);
606 }
607 }
6086 return '(' + value.join(',') + ')';
609 }).join(',');
6104 var sql = replace ? 'REPLACE' : 'INSERT';
6114 sql += ' INTO ' + this.parseTable(options.table) + '(' + fields + ') VALUES ' + values;
6124 return this.execute(sql);
613 },
614 /**
615 * 从一个选择条件的结果插入记录
616 * @param {[type]} fields [description]
617 * @param {[type]} table [description]
618 * @param {[type]} options [description]
619 * @return {[type]} [description]
620 */
621 selectInsert: function(fields, table, options){
6220 options = options || {};
6230 this.model = options.model;
6240 if (isString(fields)) {
6250 fields = fields.split(',');
626 }
6270 var self = this;
6280 fields = fields.map(function(item){
6290 return self.parseKey(item);
630 });
6310 var sql = 'INSERT INTO ' + this.parseTable(options.table) + ' (' + fields.join(',') + ')';
6320 sql += this.buildSelectSql(options);
6330 return this.execute(sql);
634 },
635 /**
636 * 删除记录
637 * @param {[type]} options [description]
638 * @return {[type]} [description]
639 */
640 delete: function(options){
6413 options = options || {};
6423 this.model = options.model;
6433 var sql = [
644 'DELETE FROM ',
645 this.parseTable(options.table),
646 this.parseWhere(options.where),
647 this.parseOrder(options.order),
648 this.parseLimit(options.limit),
649 this.parseLock(options.lock),
650 this.parseComment(options.comment)
651 ].join('');
6523 return this.execute(sql);
653 },
654 /**
655 * 更新数据
656 * @param {[type]} data [description]
657 * @param {[type]} options [description]
658 * @return {[type]} [description]
659 */
660 update: function(data, options){
66113 options = options || {};
66213 this.model = options.model;
66313 var sql = [
664 'UPDATE ',
665 this.parseTable(options.table),
666 this.parseSet(data),
667 this.parseWhere(options.where),
668 this.parseOrder(options.order),
669 this.parseLimit(options.limit),
670 this.parseLock(options.lock),
671 this.parseComment(options.comment)
672 ].join('');
67313 return this.execute(sql);
674 },
675 /**
676 * 数据查询
677 * @todo 返回是个promise,缓存调用需要修改
678 * @param {[type]} options [description]
679 * @return {[type]} [description]
680 */
681 select: function(options){
682150 var sql, cache;
683150 if (isString(options) && options.indexOf('SELECT') > -1) {
6840 sql = options;
6850 cache = arguments[1];
686 }else{
687150 options = options || {};
688150 this.model = options.model;
689150 sql = this.buildSelectSql(options);
690150 cache = options.cache;
691 }
692150 var self = this;
693150 var cacheOn = !isEmpty(cache) && C('db_cache_on');
694 //获取数据
695150 function queryData(){
696150 return self.query(sql).then(function(data){
697150 if (cacheOn) {
6980 S(key, data, cache);
699 }
700150 return data;
701 });
702 }
703150 if (cacheOn) {
7040 var key = isString(cache.key) && cache.key ? cache.key : md5(sql);
7050 return S(key, undefined, cache).then(function(value){
7060 return value || queryData();
707 });
708 }
709150 return queryData();
710 },
711 /**
712 * 转义字符
713 * @param {[type]} str [description]
714 * @return {[type]} [description]
715 */
716 escapeString: function(str){
71772 if (!str) {
7180 return '';
719 }
72072 return str.replace(/[\0\n\r\b\t\\\'\"\x1a]/g, function(s) {
7216 switch(s) {
722 case '\0':
7230 return '\\0';
724 case '\n':
7253 return '\\n';
726 case '\r':
7270 return '\\r';
728 case '\b':
7290 return '\\b';
730 case '\t':
7310 return '\\t';
732 case '\x1a':
7330 return '\\Z';
734 default:
7353 return '\\'+s;
736 }
737 });
738 },
739 /**
740 * 获取上次的sql语句
741 * @param {[type]} model [description]
742 * @return {[type]} [description]
743 */
744 getLastSql: function(model){
745170 return model ? this.modelSql[model] : this.sql;
746 },
747 /**
748 * 设置当前操作的sql
749 * @param {[type]} sql [description]
750 */
751 setSql: function(sql){
752176 this.sql = sql;
753176 this.modelSql[this.model] = sql;
754 },
755 /**
756 * 设置模型
757 * @param {[type]} model [description]
758 */
759 setModel: function(model){
7600 this.model = model;
7610 return this;
762 }
763 };
764});
765/**
766 * 解析配置
767 * @param {[type]} config [description]
768 * @return {[type]} [description]
769 */
7701Db.parseConfig = function(config){
7711 'use strict';
7721 config = config || {};
7731 return {
774 type: config.db_type || C('db_type') || 'mysql',
775 username: config.db_user || C('db_user'),
776 password: config.db_pwd || C('db_pwd'),
777 hostname: config.db_host || C('db_host'),
778 port: config.db_port || C('db_port'),
779 database: config.db_name || C('db_name'),
780 charset: config.db_charset || C('db_charset')
781 };
782};
783/**
784 * 根据配置获取对应的数据库实例
785 * @param {[type]} config [description]
786 * @return {[type]} [description]
787 */
7881Db.getInstance = function(config){
7891 'use strict';
7901 config = this.parseConfig(config);
7911 var instance = thinkRequire(ucfirst(config.type) + 'Db')(config);
7921 instance.dbType = config.type.toUpperCase();
7931 return instance;
794};

/Users/welefen/Develop/git/thinkjs/lib/Lib/Core/Dispatcher.js

84%
50
42
8
LineHitsSource
1/**
2 * 路由识别
3 * @type {Object}
4 */
51var Dispatcher = module.exports = Class(function(){
61 'use strict';
71 return {
8 /**
9 * 初始化
10 * @param {[type]} http [description]
11 * @return {[type]} [description]
12 */
13 init: function(http){
141 this.http = http;
15 },
16 /**
17 * 准备pathanem
18 * @return {[type]} [description]
19 */
20 preparePathName: function(){
211 var pathname = this.http.pathname.split('/').filter(function(item){
222 return item.trim();
23 }).join('/');
24 //去除pathname前缀
251 var prefix = C('url_pathname_prefix');
261 if (prefix && pathname.indexOf(prefix) === 0) {
270 pathname = pathname.substr(prefix.length);
28 }
29 //判断URL后缀
301 var suffix = C('url_pathname_suffix');
311 if (suffix && pathname.substr(0 - suffix.length) === suffix) {
320 pathname = pathname.substr(0, pathname.length - suffix.length);
33 }
341 this.http.pathname = pathname;
35 },
36 /**
37 * 解析pathname
38 * @return {[type]} [description]
39 */
40 parsePathName: function(){
411 if (this.http.group) {
420 return true;
43 }
441 var paths = this.http.pathname.split('/');
45 //将group list变为小写
461 var groupList = C('app_group_list').map(function(item){
473 return item.toLowerCase();
48 });
491 var group = '';
501 if (groupList.length && paths[0] && groupList.indexOf(paths[0].toLowerCase()) > -1) {
510 group = paths.shift();
52 }
531 var controller = paths.shift();
541 var action = paths.shift();
55 //解析剩余path的参数
561 if (paths.length) {
570 for(var i = 0,length = Math.ceil(paths.length) / 2; i < length; i++){
580 this.http.get[paths[i * 2]] = paths[i * 2 + 1] || '';
59 }
60 }
611 this.http.group = Dispatcher.getGroup(group);
621 this.http.controller = Dispatcher.getController(controller);
631 this.http.action = Dispatcher.getAction(action);
64 },
65 /**
66 * run
67 * @return {[type]} [description]
68 */
69 run: function(){
701 var self = this;
711 return tag('resource_check', this.http).then(function(){
721 return self.preparePathName();
73 }).then(function(){
741 return tag('path_info', self.http);
75 }).then(function(){
761 return tag('route_check', self.http);
77 }).then(function(){
781 return self.parsePathName();
79 });
80 }
81 };
82});
83/**
84 * 获取group
85 * @param {[type]} group [description]
86 * @return {[type]} [description]
87 */
881Dispatcher.getGroup = function(group){
891 'use strict';
901 group = group || C('default_group');
911 return ucfirst(group);
92};
93
94/**
95 * 检测Controller和Action是否合法的正则
96 * @type {RegExp}
97 */
981var nameReg = /^[A-Za-z\_](\w)*$/;
99/**
100 * 获取controller
101 * @param {[type]} controller [description]
102 * @return {[type]} [description]
103 */
1041Dispatcher.getController = function(controller){
1051 'use strict';
1061 if (!controller || !nameReg.test(controller)) {
1071 return ucfirst(C('default_controller'));
108 }
1090 return ucfirst(controller);
110};
111/**
112 * 获取action
113 * @param {[type]} action [description]
114 * @return {[type]} [description]
115 */
1161Dispatcher.getAction = function(action){
1171 'use strict';
1181 if (!action || !nameReg.test(action)) {
1191 return C('default_action');
120 }
1210 return action;
122};

/Users/welefen/Develop/git/thinkjs/lib/Lib/Core/Http.js

59%
142
84
58
LineHitsSource
1/**
2 * 对HttpRequest和HttpResponse 2个对象重新包装
3 * @type {Object}
4 */
51var querystring = require('querystring');
61var url = require('url');
71var cookie = thinkRequire('Cookie');
81var EventEmitter = require('events').EventEmitter;
91var multiparty = require('multiparty');
10
111var localIp = '127.0.0.1';
121module.exports = Class(function(){
131 'use strict';
141 return {
15 init: function(req, res){
166 this.req = req;
176 this.res = res;
18 //http对象为EventEmitter的实例
196 this.http = new EventEmitter();
20 //记录当前请求的开始时间
216 this.http.startTime = Date.now();
22 },
23 /**
24 * 执行
25 * @param {Function} callback [description]
26 * @return Promise [description]
27 */
28 run: function(){
296 this._request();
306 this._response();
31 //数组的indexOf要比字符串的indexOf略快
326 var methods = ['POST', 'PUT', 'PATCH'];
336 if (methods.indexOf(this.req.method) > -1) {
340 return this.getPostData();
35 }
366 return getPromise(this.http);
37 },
38 /**
39 * 检测是否含有post数据
40 * @return {Boolean} [description]
41 */
42 hasPostData: function(){
430 if ('transfer-encoding' in this.req.headers) {
440 return true;
45 }
460 var contentLength = this.req.headers['content-length'] | 0;
470 return contentLength > 0;
48 },
49 /**
50 * 含有文件的表单上传
51 * @return {[type]} [description]
52 */
53 _filePost: function(){
540 var deferred = getDefer();
550 var self = this;
560 var form = new multiparty.Form({
57 maxFieldsSize: C('post_max_fields_size'),
58 maxFields: C('post_max_fields'),
59 maxFilesSize: C('post_max_file_size')
60 });
610 form.on('file', function(name, value){
620 self.http.file[name] = value;
63 });
640 form.on('field', function(name, value){
650 self.http.post[name] = value;
66 });
670 form.on('close', function(){
680 deferred.resolve(self.http);
69 });
70 //有错误后直接拒绝当前请求
710 form.on('error', function(){
720 self.res.statusCode = 413;
730 self.res.end();
74 });
750 form.parse(this.req);
760 return deferred.promise;
77 },
78 /**
79 * 普通的表单上传
80 * @return {[type]} [description]
81 */
82 _commonPost: function(){
830 var buffers = [];
840 var length = 0;
850 var self = this;
860 var deferred = getDefer();
870 this.req.on('data', function(chunk){
880 buffers.push(chunk);
890 length += chunk.length;
90 });
910 this.req.on('end', function(){
920 self.http.payload = Buffer.concat(buffers).toString();
930 tag('form_parse', self.http).then(function(){
94 //默认使用querystring.parse解析
950 if (isEmpty(self.http.post) && self.http.payload) {
960 self.http.post = querystring.parse(self.http.payload) || {}
97 }
980 var post = self.http.post;
990 var length = Object.keys(post);
100 //最大表单数超过限制
1010 if (length > C('post_max_fields')) {
1020 self.res.statusCode = 413;
1030 self.res.end();
1040 return;
105 }
1060 for(var name in post){
107 //单个表单值长度超过限制
1080 if (post[name].length > C('post_max_fields_size')) {
1090 self.res.statusCode = 413;
1100 self.res.end();
1110 return;
112 }
113 }
1140 deferred.resolve(self.http);
115 })
116 });
1170 return deferred.promise;
118 },
119 /**
120 * 获取POST过来的数据,包含上传的文件
121 * 依赖multiparty库
122 * @return {[type]} [description]
123 */
124 getPostData: function(){
125 //没有post数据,直接返回
1260 if (!this.hasPostData()) {
1270 return getPromise(this.http);
128 }
129 //上传的数据中是否含有文件的检测正则
1300 var multiReg = /^multipart\/(form-data|related);\s*boundary=(?:"([^"]+)"|([^;]+))$/i;
1310 if (multiReg.test(this.req.headers['content-type'])) {
1320 return this._filePost();
133 }else{
1340 return this._commonPost();
135 }
136 },
137 /**
138 * HttpRequest增强
139 * @return {[type]} [description]
140 */
141 _request: function(){
1426 var req = {
143 //http版本号
144 version: this.req.httpVersion,
145 //请求方法
146 method: this.req.method,
147 //请求头
148 headers: this.req.headers,
149 getHeader: function(name){
1509 return this.headers[name] || '';
151 },
152 //请求的Content-Type
153 contentType: (this.req.headers['content-type'] || '').split(';')[0].trim(),
154 //post信息
155 post: {},
156 //上传的文件信息
157 file: {},
158 //请求用户的ip
159 ip: function(){
1602 var connection = this.req.connection;
1612 var socket = this.req.socket;
1622 var ip = (connection && connection.remoteAddress) || (socket && socket.remoteAddress);
1632 if (ip && ip !== localIp) {
1640 return ip;
165 }
1662 return this.headers['x-forwarded-for'] || this.headers['x-real-ip'] || localIp;
167 },
168 //请求的cookie
169 cookie: cookie.parse(this.req.headers.cookie || '')
170 };
1716 extend(this.http, req);
172
173 //解析url中的参数
1746 var urlInfo = url.parse('//' + req.headers.host + this.req.url, true, true);
1756 this.http.pathname = urlInfo.pathname;
176 //query只记录?后面的参数
1776 this.http.query = urlInfo.query;
178 //get包含路由解析追加的参数
1796 this.http.get = extend({}, urlInfo.query);
180 //主机名,带端口
1816 this.http.host = urlInfo.host;
182 //主机名,不带端口
1836 this.http.hostname = urlInfo.hostname;
184 //将原生的request对象放在http上,方便后续在controller等地方使用
1856 this.http.req = this.req;
186 },
187 /**
188 * HttpResponse增强
189 * @return {[type]} [description]
190 */
191 _response: function(){
1926 var res = {
193 /**
194 * 一次请求下,可能会发送多个Cookie,所以这里不能立即发送
195 * 需要临时存起来,到输出内容前统一发送
196 * @type {Object}
197 */
198 _cookie: {},
199 /**
200 * 发送header
201 * @param {[type]} name [description]
202 * @param {[type]} value [description]
203 */
204 setHeader: function(name, value){
20585 if (!this.res.headersSent) {
20662 this.res.setHeader(name, value);
207 }
208 },
209 /**
210 * 设置cookie
211 * @param {[type]} name [description]
212 * @param {[type]} value [description]
213 * @param {[type]} options [description]
214 */
215 setCookie: function(name, value, options){
2164 options = options || {};
2174 if (typeof options === 'number') {
2180 options = {timeout: options};
219 }
2204 var timeout = options.timeout;
2214 if (timeout === undefined) {
2224 timeout = C('cookie_timeout');
223 }
2244 delete options.timeout;
225 //if value is null, remove cookie
2264 if (value === null) {
2270 timeout = -1000;
228 }
2294 var defaultOptions = {
230 path: C('cookie_path'),
231 domain: C('cookie_domain'),
232 expires: new Date (Date.now() + timeout * 1000)
233 };
2344 if (timeout === 0) {
2354 delete defaultOptions.expires;
236 }
2374 for(var key in options){
2380 defaultOptions[key.toLowerCase()] = options[key];
239 }
2404 defaultOptions.name = name;
2414 defaultOptions.value = encodeURIComponent(value + '');
2424 this._cookie[name] = defaultOptions;
243 },
244 /**
245 * 将队列中的cookie发送出去
246 * @return {[type]} [description]
247 */
248 sendCookie: function(){
24954 var cookies = Object.values(this._cookie).map(function(item){
25052 return cookie.stringify(item.name, item.value, item);
251 });
25254 if (cookies.length) {
25352 this.setHeader('Set-Cookie', cookies);
254 //发送Cookie后不清除_cookie内容,websocket里需要读取
255 //this._cookie = {};
256 }
257 },
258 /**
259 * url跳转
260 * @param {[type]} url [description]
261 * @param {[type]} code [description]
262 * @return {[type]} [description]
263 */
264 redirect: function(url, code){
2652 this.res.statusCode = code || 302;
2662 this.setHeader('Location', url || '/');
2672 this.end();
268 },
269 /**
270 * 发送执行时间
271 * @param {[type]} name [description]
272 * @return {[type]} [description]
273 */
274 sendTime: function(name){
2752 var time = Date.now() - this.startTime;
2762 this.setHeader('X-' + (name || 'EXEC-TIME'), time + 'ms');
277 },
278 /**
279 * 输出内容
280 * @param {[type]} obj [description]
281 * @param {[type]} encoding [description]
282 * @return {[type]} [description]
283 */
284 echo: function(obj, encoding){
28524 this.sendCookie();
28624 if (obj === undefined) {
2872 return;
288 }
28922 if (isArray(obj) || isObject(obj)) {
29014 obj = JSON.stringify(obj);
291 }
29222 if (!isString(obj) && !(obj instanceof Buffer)) {
2930 obj += '';
294 }
29522 this.res.write(obj, encoding || C('encoding'));
296 },
297 /**
298 * 结束URL
299 * @return {[type]} [description]
300 */
301 end: function(){
30230 this.emit('beforeEnd', this);
30330 this.sendCookie();
30430 this.res.end();
30530 this.emit('afterEnd', this);
306 }
307 };
3086 extend(this.http, res);
309 //将原生的response对象放在http上,方便后续controller等地方使用
3106 this.http.res = this.res;
311 }
312 };
313});
314/**
315 * 获取默认的http信息
316 * @param {[type]} data [description]
317 * @return {[type]} [description]
318 */
3191module.exports.getDefaultHttp = function(data){
3204 'use strict';
3214 data = data || {};
3224 if (isString(data)) {
3234 if (data[0] === '{') {
3240 data = JSON.parse(data);
3254 }else if (/^[\w]+\=/.test(data)) {
3260 data = querystring.parse(data);
327 }else{
3284 data = {url: data};
329 }
330 }
3314 var fn = function(){
3324 return '';
333 };
3344 var url = data.url || '';
3354 if (url.indexOf('/') !== 0) {
3360 url = '/' + url;
337 }
3384 return {
339 req: {
340 httpVersion: '1.1',
341 method: data.method || 'GET',
342 url: url,
343 headers: extend({
344 host: data.host || localIp
345 }, data.headers || {}),
346 connection: {
347 remoteAddress: data.ip || localIp
348 }
349 },
350 res: {
351 end: data.end || data.close || fn,
352 write: data.write || data.send || fn,
353 setHeader: fn
354 }
355 };
356};

/Users/welefen/Develop/git/thinkjs/lib/Lib/Core/Model.js

67%
429
288
141
LineHitsSource
11var util = require('util');
21var querystring = require('querystring');
31var Db = thinkRequire('Db');
4
5//数据库实例化对象
61var dbInstances = {};
7//数据表的字段信息
81var tableFields = {};
9//db缓存数据
101var dbCacheData = {};
11
12/**
13 * Model类
14 * @type {[type]}
15 */
161var Model = module.exports = Class(function(){
171 'use strict';
18 //解析page参数
191 var parsePage = function(options){
200 if ('page' in options) {
210 var page = options.page + '';
220 var num = 0;
230 if (page.indexOf(',') > -1) {
240 page = page.split(',');
250 num = parseInt(page[1], 10);
260 page = page[0];
27 }
280 num = num || C('db_nums_per_page');
290 page = parseInt(page, 10) || 1;
300 return {
31 page: page,
32 num: num
33 };
34 }
350 return {
36 page: 1,
37 num: C('db_nums_per_page')
38 };
39 };
40 /**
41 * 字符串命名风格转换
42 * @param {[type]} name [description]
43 * @param {[type]} type [description]
44 * @return {[type]} [description]
45 */
461 var parseName = function(name, type){
4717 name = (name + '').trim();
4817 if (type) {
490 name = name.replace(/_([a-zA-Z])/g, function(a, b){
500 return b.toUpperCase();
51 });
520 return name.substr(0, 1).toUpperCase() + name.substr(1);
53 } else {
54 //首字母如果是大写,不转义为_x
5517 if (name.length >= 1) {
5617 name = name.substr(0, 1).toLowerCase() + name.substr(1);
57 }
5817 return name.replace(/[A-Z]/g, function(a){
590 return '_' + a;
60 }).toLowerCase();
61 }
62 };
63
641 return {
65 // 当前数据库操作对象
66 db: null,
67 // 主键名称
68 pk: 'id',
69 // 数据库配置信息
70 config: null,
71 // 配置信息key
72 configKey: '',
73 // 模型名称
74 name: '',
75 // 数据表前缀
76 tablePrefix: '',
77 // 数据表名(不包含表前缀)
78 tableName: '',
79 // 实际数据表名(包含表前缀)
80 trueTableName: '',
81 // 数据表字段信息
82 fields: {},
83 // 数据信息
84 _data: {},
85 // 参数
86 _options: {},
87 /**
88 * 初始化
89 * @access public
90 * @param string $name 模型名称
91 * @param mixed config 数据库连接信息
92 */
93 init: function(name, config){
94 // 获取模型名称
9530 if (name) {
9626 this.name = name;
97 }
9830 if (isString(config)) {
990 config = {db_prefix: config};
100 }
10130 this.config = config || '';
102 //数据表前缀
10330 if (this.config.db_prefix) {
1040 this.tablePrefix = this.config.db_prefix;
10530 }else if(!this.tablePrefix) {
10630 this.tablePrefix = C('db_prefix');
107 }
108 },
109 /**
110 * 初始化数据库连接
111 * @return {[type]} [description]
112 */
113 initDb: function(){
114353 if (this.db) {
115336 return this.db;
116 }
11717 var config = this.config;
11817 var configKey = md5(JSON.stringify(config));
11917 if (!dbInstances[configKey]) {
1201 dbInstances[configKey] = Db.getInstance(config);
121 }
12217 this.db = dbInstances[configKey];
12317 this.configKey = configKey;
12417 return this.db;
125 },
126 /**
127 * 获取模型名
128 * @access public
129 * @return string
130 */
131 getModelName: function(){
132194 if (this.name) {
133194 return this.name;
134 }
1350 var filename = this.__filename || __filename;
1360 var last = filename.lastIndexOf('/');
1370 this.name = filename.substr(last + 1, filename.length - last - 9);
1380 return this.name;
139 },
140 /**
141 * 获取表名
142 * @return {[type]} [description]
143 */
144 getTableName: function(){
145177 if (!this.trueTableName) {
14617 var tableName = this.tablePrefix || '';
14717 tableName += this.tableName || parseName(this.getModelName());
14817 this.trueTableName = tableName.toLowerCase();
149 }
150177 return this.trueTableName;
151 },
152 /**
153 * 获取数据表信息
154 * @access protected
155 * @return Promise
156 */
157 getTableFields: function(table, all){
158178 this.initDb();
159178 if (table === true) {
1600 table = undefined;
1610 all = true;
162 }
163178 if (!isEmpty(this.fields)) {
164161 return getPromise(all ? this.fields : this.fields._field);
165 }
16617 var tableName = table || this.getTableName();
16717 var fields = tableFields[tableName];
16817 if (!isEmpty(fields)) {
16914 this.fields = fields;
17014 return getPromise(all ? fields : fields._field);
171 }
1723 var self = this;
173 //从数据表里查询字段信息
1743 return this.flushFields(tableName).then(function(fields){
1753 self.fields = fields;
1763 if (C('db_fields_cache')) {
1773 tableFields[tableName] = fields;
178 }
1793 return getPromise(all ? fields : fields._field);
180 });
181 },
182 /**
183 * 获取数据表信息
184 * @param {[type]} table [description]
185 * @return Promise [description]
186 */
187 flushFields: function(table){
1884 table = table || this.getTableName();
1894 return this.initDb().getFields(table).then(function(data){
1904 var fields = {
191 '_field': Object.keys(data || {}),
192 '_autoinc': false,
193 '_unique': []
194 };
1954 var types = {};
1964 for(var key in data){
19752 var val = data[key];
19852 types[key] = val.type;
19952 if (val.primary) {
2004 fields._pk = key;
2014 if (val.autoinc) {
2024 fields._autoinc = true;
203 }
20448 }else if (val.unique) {
2054 fields._unique.push(key);
206 }
207 }
2084 fields._type = types;
2094 return fields;
210 })
211 },
212 /**
213 * 获取类型为唯一的字段
214 * @return {[type]} [description]
215 */
216 // getUniqueField: function(data){
217 // var unqiueFileds = this.fields._unique;
218 // var unqiue = '';
219 // unqiueFileds.some(function(item){
220 // if (!data || data[item]) {
221 // unqiue = item;
222 // return unqiue;
223 // }
224 // });
225 // return unqiue;
226 // },
227 /**
228 * 获取上一次操作的sql
229 * @return {[type]} [description]
230 */
231 getLastSql: function(){
232170 return this.initDb().getLastSql();
233 },
234 /**
235 * 获取主键名称
236 * @access public
237 * @return string
238 */
239 getPk: function(){
240 //如果fields为空,那么异步去获取
24121 if (isEmpty(this.fields)) {
2420 var self = this;
2430 return this.getTableFields().then(function(){
2440 return self.fields_pk || self.pk;
245 })
246 }
24721 return this.fields._pk || this.pk;
248 },
249 /**
250 * 缓存
251 * @param {[type]} key [description]
252 * @param {[type]} expire [description]
253 * @param {[type]} type [description]
254 * @return {[type]} [description]
255 */
256 cache: function(key, timeout){
2570 if (key === undefined) {
2580 return this;
259 }
2600 var options = this._getCacheOptions(key, timeout);
2610 this._options.cache = options;
2620 return this;
263 },
264 /**
265 * 获取缓存的选项
266 * @param {[type]} key [description]
267 * @param {[type]} timeout [description]
268 * @return {[type]} [description]
269 */
270 _getCacheOptions: function(key, timeout, type){
2710 if (isObject(key)) {
2720 return key;
273 }
2740 if (isNumber(key)) {
2750 timeout = key;
2760 key = '';
277 }
2780 var cacheType = type === undefined ? C('db_cache_type') : type;
2790 var options = {
280 key: key,
281 timeout: timeout || C('db_cache_timeout'),
282 type: cacheType,
283 gcType: 'dbCache'
284 }
2850 if (cacheType === 'File') {
2860 options.cache_path = C('db_cache_path');
287 }else{
2880 options.cacheData = dbCacheData;
289 }
2900 return options;
291 },
292 /**
293 * 指定查询数量
294 * @param {[type]} offset [description]
295 * @param {[type]} length [description]
296 * @return {[type]} [description]
297 */
298 limit: function(offset, length){
2994 this._options.limit = length === undefined ? offset : offset + ',' + length;
3004 return this;
301 },
302 /**
303 * 指定分页
304 * @return {[type]} [description]
305 */
306 page: function(page, listRows){
3077 this._options.page = listRows === undefined ? page : page + ',' + listRows;
3087 return this;
309 },
310 /**
311 * where条件
312 * @return {[type]} [description]
313 */
314 where: function(where){
31591 if (!where) {
3162 return this;
317 }
31889 if (isString(where)) {
3193 where = {_string: where};
320 }
32189 this._options.where = extend(this._options.where || {}, where);
32289 return this;
323 },
324 /**
325 * 要查询的字段
326 * @param {[type]} field [description]
327 * @param {[type]} reverse [description]
328 * @return {[type]} [description]
329 */
330 field: function(field, reverse){
3315 if (isArray(field)) {
3322 field = field.join(',');
3333 }else if (!field) {
3341 field = '*';
335 }
3365 this._options.field = field;
3375 this._options.fieldReverse = reverse;
3385 return this;
339 },
340 /**
341 * 设置表名
342 * @param {[type]} table [description]
343 * @return {[type]} [description]
344 */
345 table: function(table, prefix){
3462 if (!table) {
3470 return this;
348 }
3492 this._options.table = prefix ? table : this.tablePrefix + table;
3502 return this;
351 },
352 /**
353 * 联合查询
354 * @return {[type]} [description]
355 */
356 union: function(union, all){
3575 if (!this._options.union) {
3584 this._options.union = [];
359 }
3605 this._options.union.push({
361 union: union,
362 all: all
363 });
3645 return this;
365 },
366 /**
367 * .join({
368 * 'xxx': {
369 * join: 'left',
370 * as: 'c',
371 * on: ['id', 'cid']
372 * }
373 * })
374 * 联合查询
375 * @param {[type]} join [description]
376 * @return {[type]} [description]
377 */
378 join: function(join){
37918 if (!this._options.join) {
38017 this._options.join = [];
381 }
38218 if (isArray(join)) {
3831 this._options.join = this._options.join.concat(join);
384 }else{
38517 this._options.join.push(join);
386 }
38718 return this;
388 },
389 /**
390 * 生成查询SQL 可用于子查询
391 * @param {[type]} options [description]
392 * @return {[type]} [description]
393 */
394 buildSql: function(options){
3951 var self = this;
3961 return this.parseOptions(options).then(function(options){
3971 return '( ' + self.db.buildSelectSql(options) + ' )';
398 });
399 },
400 /**
401 * 解析参数
402 * @param {[type]} options [description]
403 * @return promise [description]
404 */
405 parseOptions: function(options, extraOptions){
406176 options = extend({}, this._options, this.parseWhereOptions(options), extraOptions);
407 // 查询过后清空sql表达式组装 避免影响下次查询
408176 this._options = {};
409176 options.table = options.table || this.getTableName();
410 //表前缀,Db里会使用
411176 options.tablePrefix = this.tablePrefix;
412176 options.model = this.getModelName();
413176 var promise = this.getTableFields(options.table);
414 //数据表别名
415176 if (options.alias) {
4166 options.table += ' AS ' + options.alias;
417 }
418176 var self = this;
419176 return promise.then(function(fields){
420 // 字段类型验证
421176 if (isObject(options.where) && !isEmpty(fields)) {
42290 var keyReg = /[\.\|\&]/;
423 // 对数组查询条件进行字段类型检查
42490 for(var key in options.where){
425103 var val = options.where[key];
426103 key = key.trim();
427103 if (fields.indexOf(key) > -1) {
42889 if (isScalar(val)) {
42924 options.where[key] = self.parseType(options.where, key)[key];
430 }
43114 }else if(key[0] !== '_' && !keyReg.test(key)){
4321 delete options.where[key];
433 }
434 }
435 }
436 //field反选
437176 if (options.field && options.fieldReverse) {
4381 var optionsField = options.field.split(',');
4391 options.field = fields.filter(function(item){
44013 if (optionsField.indexOf(item) > -1) {
4412 return;
442 }
44311 return item;
444 }).join(',');
445 }
446176 return self._optionsFilter(options, fields);
447 });
448 },
449 /**
450 * 选项过滤器
451 * 具体的Model类里进行实现
452 * @param {[type]} options [description]
453 * @return {[type]} [description]
454 */
455 _optionsFilter: function(options){
456176 return options;
457 },
458 /**
459 * 数据类型检测
460 * @param {[type]} data [description]
461 * @param {[type]} key [description]
462 * @return {[type]} [description]
463 */
464 parseType: function(data, key){
46537 var fieldType = this.fields._type[key] || '';
46637 if (fieldType.indexOf('bigint') === -1 && fieldType.indexOf('int') > -1) {
46719 data[key] = parseInt(data[key], 10) || 0;
46818 }else if(fieldType.indexOf('double') > -1 || fieldType.indexOf('float') > -1){
4690 data[key] = parseFloat(data[key]) || 0.0;
47018 }else if(fieldType.indexOf('bool') > -1){
4710 data[key] = !! data[key];
472 }
47337 return data;
474 },
475 /**
476 * 对插入到数据库中的数据进行处理,要在parseOptions后执行
477 * @param {[type]} data [description]
478 * @return {[type]} [description]
479 */
480 parseData: function(data){
48118 data = extend({}, data);
48218 var key;
48318 if (!isEmpty(this.fields)) {
48418 for(key in data){
48521 var val = data[key];
48621 if (this.fields._field.indexOf(key) === -1) {
4870 delete data[key];
48821 }else if(isScalar(val)){
48913 data = this.parseType(data, key);
490 }
491 }
492 }
493 //安全过滤
49418 if (typeof this._options.filter === 'function') {
4950 for(key in data){
4960 data[key] = this._options.filter.call(this, key, data[key]);
497 }
4980 delete this._options.filter;
499 }
50018 data = this._dataFilter(data);
50118 return data;
502 },
503 /**
504 * 数据过滤器
505 * 具体的Model类里进行实现
506 * @param {[type]} data [description]
507 * @return {[type]} [description]
508 */
509 _dataFilter: function(data){
51018 return data;
511 },
512 /**
513 * 数据插入之前操作,可以返回一个promise
514 * @param {[type]} data [description]
515 * @param {[type]} options [description]
516 * @return {[type]} [description]
517 */
518 _beforeAdd: function(data){
5192 return data;
520 },
521 /**
522 * 数据插入之后操作,可以返回一个promise
523 * @param {[type]} data [description]
524 * @param {[type]} options [description]
525 * @return {[type]} [description]
526 */
527 _afterAdd: function(data){
5282 return data;
529 },
530 /**
531 * 添加一条数据
532 * @param {[type]} data [description]
533 * @param {[type]} options [description]
534 * @param int 返回插入的id
535 */
536 add: function(data, options, replace){
537 //copy data
5383 data = extend({}, this._data, data);
5393 this._data = {};
5403 if (isEmpty(data)) {
5411 return getPromise(new Error('_DATA_TYPE_INVALID_'), true);
542 }
5432 var self = this;
544 //解析后的选项
5452 var parsedOptions = {};
546 //解析后的数据
5472 var parsedData = {};
5482 return this.parseOptions(options).then(function(options){
5492 parsedOptions = options;
5502 return self._beforeAdd(data, parsedOptions);
551 }).then(function(data){
5522 parsedData = data;
5532 data = self.parseData(data);
5542 return self.db.insert(data, parsedOptions, replace);
555 }).then(function(){
5562 parsedData[self.getPk()] = self.db.getLastInsertId();
5572 return self._afterAdd(parsedData, parsedOptions);
558 }).then(function(){
5592 return parsedData[self.getPk()];
560 });
561 },
562 /**
563 * 如果当前条件的数据不存在,才添加
564 * @param {[type]} data 要插入的数据
565 * @param {[type]} where where条件
566 * @param boolean returnType 返回值是否包含type
567 * @return {[type]} promise
568 */
569 thenAdd: function(data, where, returnType){
5700 if (where === true) {
5710 returnType = true;
5720 where = '';
573 }
5740 var self = this;
5750 return this.where(where).find().then(function(findData){
5760 if (!isEmpty(findData)) {
5770 var idValue = findData[self.getPk()];
5780 return returnType ? {id: idValue, type: 'exist'} : idValue;
579 }
5800 return self.add(data).then(function(insertId){
5810 return returnType ? {id: insertId, type: 'add'} : insertId;
582 });
583 });
584 },
585 /**
586 * 插入多条数据
587 * @param {[type]} data [description]
588 * @param {[type]} options [description]
589 * @param {[type]} replace [description]
590 */
591 addAll: function(data, options, replace){
5926 if (!isArray(data) || !isObject(data[0])) {
5932 return getPromise(new Error('_DATA_TYPE_INVALID_'), true);
594 }
5954 var self = this;
5964 return this.parseOptions(options).then(function(options){
5974 return self.db.insertAll(data, options, replace);
598 }).then(function(){
5994 return self.db.getLastInsertId();
600 });
601 },
602 /**
603 * 删除后续操作
604 * @return {[type]} [description]
605 */
606 _afterDelete: function(data){
6073 return data;
608 },
609 /**
610 * 删除数据
611 * @return {[type]} [description]
612 */
613 delete: function(options){
6143 var self = this;
6153 var parsedOptions = {};
6163 var affectedRows = 0;
6173 return this.parseOptions(options).then(function(options){
6183 parsedOptions = options;
6193 return self.db.delete(options);
620 }).then(function(rows){
6213 affectedRows = rows;
6223 return self._afterDelete(parsedOptions.where || {}, parsedOptions);
623 }).then(function(){
6243 return affectedRows;
625 })
626 },
627 /**
628 * 更新前置操作
629 * @param {[type]} data [description]
630 * @param {[type]} options [description]
631 * @return {[type]} [description]
632 */
633 _beforeUpdate: function(data){
63416 return data;
635 },
636 /**
637 * 更新后置操作
638 * @param {[type]} data [description]
639 * @param {[type]} options [description]
640 * @return {[type]} [description]
641 */
642 _afterUpdate: function(data){
64313 return data;
644 },
645 /**
646 * 更新数据
647 * @return {[type]} [description]
648 */
649 update: function(data, options){
65017 data = extend({}, data);
65117 if (isEmpty(data)) {
6521 if (!isEmpty(this._data)) {
6530 data = this._data;
6540 this._data = {};
655 }else{
6561 return getPromise(new Error('_DATA_TYPE_INVALID_'), true);
657 }
658 }
65916 var self = this;
66016 var parsedOptions = {};
66116 var parsedData = {};
66216 var affectedRows = 0;
66316 return this.parseOptions(options).then(function(options){
66416 parsedOptions = options;
66516 return self._beforeUpdate(data, options);
666 }).then(function(data){
66716 var pk = self.getPk();
66816 parsedData = data;
66916 data = self.parseData(data);
67016 if (isEmpty(parsedOptions.where)) {
671 // 如果存在主键数据 则自动作为更新条件
6725 if (!isEmpty(data[pk])) {
6732 parsedOptions.where = getObject(pk, data[pk]);
6742 delete data[pk];
675 }else{
6763 return getPromise(new Error('_OPERATION_WRONG_'), true);
677 }
678 }else{
67911 parsedData[pk] = parsedOptions.where[pk];
680 }
68113 return self.db.update(data, parsedOptions);
682 }).then(function(rows){
68313 affectedRows = rows;
68413 return self._afterUpdate(parsedData, parsedOptions);
685 }).then(function(){
68613 return affectedRows;
687 });
688 },
689 /**
690 * 更新多个数据,自动用主键作为查询条件
691 * @param {[type]} dataList [description]
692 * @return {[type]} [description]
693 */
694 updateAll: function(dataList){
6954 if (!isArray(dataList) || !isObject(dataList[0])) {
6962 return getPromise(new Error('_DATA_TYPE_INVALID_'), true);
697 }
6982 var self = this;
6992 var promises = dataList.map(function(data){
7003 return self.update(data);
701 });
7022 return Promise.all(promises);
703 },
704 /**
705 * 更新某个字段的值
706 * @param {[type]} field [description]
707 * @param {[type]} value [description]
708 * @return {[type]} [description]
709 */
710 updateField: function(field, value){
71110 var data = {};
71210 if (isObject(field)) {
7130 data = field;
714 }else{
71510 data[field] = value;
716 }
71710 return this.update(data);
718 },
719 /**
720 * 字段值增长
721 * @return {[type]} [description]
722 */
723 updateInc: function(field, step){
7244 step = parseInt(step, 10) || 1;
7254 return this.updateField(field, ['exp', field + '+' + step]);
726 },
727 /**
728 * 字段值减少
729 * @return {[type]} [description]
730 */
731 updateDec: function(field, step){
7324 step = parseInt(step, 10) || 1;
7334 return this.updateField(field, ['exp', field + '-' + step]);
734 },
735 /**
736 * 解析options中简洁的where条件
737 * @return {[type]} [description]
738 */
739 parseWhereOptions: function(options){
740176 if (isNumber(options) || isString(options)) {
7410 var pk = this.getPk();
7420 options += '';
7430 var where = {};
7440 if (options.indexOf(',') > -1) {
7450 where[pk] = ['IN', options];
746 }else{
7470 where[pk] = options;
748 }
7490 options = {
750 where: where
751 };
752 }
753176 return options || {};
754 },
755 /**
756 * find查询后置操作
757 * @return {[type]} [description]
758 */
759 _afterFind: function(result){
7601 return result;
761 },
762 /**
763 * 查询一条数据
764 * @return 返回一个promise
765 */
766 find: function(options){
7671 var self = this;
7681 var parsedOptions = {};
7691 return this.parseOptions(options, {
770 limit: 1
771 }).then(function(options){
7721 parsedOptions = options;
7731 return self.db.select(options);
774 }).then(function(data){
7751 return self._afterFind(data[0] || {}, parsedOptions);
776 });
777 },
778 /**
779 * 查询后置操作
780 * @param {[type]} result [description]
781 * @param {[type]} options [description]
782 * @return {[type]} [description]
783 */
784 _afterSelect: function(result){
785135 return result;
786 },
787 /**
788 * 查询数据
789 * @return 返回一个promise
790 */
791 select: function(options){
792135 var self = this;
793135 var parsedOptions = {};
794135 return this.parseOptions(options).then(function(options){
795135 parsedOptions = options;
796135 return self.db.select(options);
797 }).then(function(result){
798135 return self._afterSelect(result, parsedOptions);
799 });
800 },
801 selectAdd: function(fields, table, options){
8020 var self = this;
8030 return this.parseOptions(options).then(function(options){
8040 fields = fields || options.field;
8050 table = table || self.getTableName();
8060 return self.db.selectInsert(fields, table, options);
807 });
808 },
809 /**
810 * 返回数据里含有count信息的查询
811 * @param options 查询选项
812 * @param pageFlag 当页面不合法时的处理方式,true为获取第一页,false为获取最后一页,undefined获取为空
813 * @return promise
814 */
815 countSelect: function(options, pageFlag){
8160 if (isBoolean(options)) {
8170 pageFlag = options;
8180 options = {};
819 }
8200 var self = this;
821 //解析后的options
8220 var parsedOptions = {};
8230 var result = {};
8240 return this.parseOptions(options).then(function(options){
8250 delete options.table;
8260 parsedOptions = options;
8270 return self.options({
828 where: options.where,
829 cache: options.cache,
830 join: options.join,
831 alias: options.alias
832 }).count((options.alias || self.getTableName()) + '.' + self.getPk());
833 }).then(function(count){
8340 var pageOptions = parsePage(parsedOptions);
8350 var totalPage = Math.ceil(count / pageOptions.num);
8360 if (isBoolean(pageFlag)) {
8370 if (pageOptions.page > totalPage) {
8380 pageOptions.page = pageFlag === true ? 1 : totalPage;
839 }
8400 parsedOptions.page = pageOptions.page + ',' + pageOptions.num;
841 }
8420 result = extend({count: count, total: totalPage}, pageOptions);
8430 return self.select(parsedOptions);
844 }).then(function(data){
8450 result.data = data;
8460 return result;
847 });
848 },
849 /**
850 * 获取某个字段下的记录
851 * @return {[type]} [description]
852 */
853 getField: function(field, one){
85414 var self = this;
85514 return this.parseOptions({'field': field}).then(function(options){
85614 if (isNumber(one)) {
8571 options.limit = one;
85813 }else if (one === true) {
85911 options.limit = 1;
860 }
86114 return self.db.select(options);
862 }).then(function(data){
86314 var multi = field.indexOf(',') > -1;
86414 if (multi) {
8651 var fields = field.split(/\s*,\s*/);
8661 var result = {};
8671 fields.forEach(function(item){
8682 result[item] = [];
869 })
8701 data.every(function(item){
8719 fields.forEach(function(fItem){
87218 if (one === true) {
8730 result[fItem] = item[fItem];
874 }else{
87518 result[fItem].push(item[fItem]);
876 }
877 })
8789 return one === true ? false : true;
879 })
8801 return result;
881 }else{
88213 data = data.map(function(item){
883117 return Object.values(item)[0];
884 })
88513 return one === true ? data[0] : data;
886 }
887 });
888 },
889 /**
890 * 根据某个字段值获取一条数据
891 * @param {[type]} name [description]
892 * @param {[type]} value [description]
893 * @return {[type]} [description]
894 */
895 getBy: function(name, value){
8960 var where = getObject(name, value);
8970 return this.where(where).find();
898 },
899 /**
900 * SQL查询
901 * @return {[type]} [description]
902 */
903 query: function(sql, parse){
9040 if (parse !== undefined && !isBoolean(parse) && !isArray(parse)) {
9050 parse = [].slice.call(arguments);
9060 parse.shift();
907 }
9080 var self = this;
9090 return this.parseSql(sql, parse).then(function(sql){
9100 return self.db.query(sql);
911 });
912 },
913 /**
914 * 执行SQL语法,非查询类的SQL语句,返回值为影响的行数
915 * @param {[type]} sql [description]
916 * @param {[type]} parse [description]
917 * @return {[type]} [description]
918 */
919 execute: function(sql, parse){
9200 if (parse !== undefined && !isBoolean(parse) && !isArray(parse)) {
9210 parse = [].slice.call(arguments);
9220 parse.shift();
923 }
9240 var self = this;
9250 return this.parseSql(sql, parse).then(function(sql){
9260 return self.db.execute(sql);
927 });
928 },
929 /**
930 * 解析SQL语句
931 * @return promise [description]
932 */
933 parseSql: function(sql, parse){
9340 var promise = null;
9350 var self = this;
9360 if (parse === true) {
9370 promise = this.parseOptions().then(function(options){
9380 return self.db.parseSql(options);
939 });
940 }else{
9410 if (parse === undefined) {
9420 parse = [];
943 }else{
9440 parse = isArray(parse) ? parse : [parse];
945 }
9460 parse.unshift(sql);
9470 sql = util.format.apply(null, parse);
9480 var map = {
949 '__TABLE__': '`' + this.getTableName() + '`'
950 };
9510 sql = sql.replace(/__([A-Z]+)__/g, function(a, b){
9520 return map[a] || ('`' + self.tablePrefix + b.toLowerCase() + '`');
953 });
9540 promise = getPromise(sql);
955 }
9560 this.initDb().setModel(self.getModelName());
9570 return promise;
958 },
959 /**
960 * 设置数据对象值
961 * @return {[type]} [description]
962 */
963 data: function(data){
9640 if (data === true) {
9650 return this._data;
966 }
9670 if (isString(data)) {
9680 data = querystring.parse(data);
969 }
9700 this._data = data;
9710 return this;
972 },
973 /**
974 * 设置操作选项
975 * @param {[type]} options [description]
976 * @return {[type]} [description]
977 */
978 options: function(options){
9790 if (options === true) {
9800 return this._options;
981 }
9820 this._options = options;
9830 return this;
984 },
985 /**
986 * 关闭数据库连接
987 * @return {[type]} [description]
988 */
989 close: function(){
9900 delete dbInstances[this.configKey];
9910 if (this.db) {
9920 this.db.close();
9930 this.db = null;
994 }
995 }
996 };
997}).extend(function(){
9981 'use strict';
999 //追加的方法
10001 var methods = {};
1001 // 链操作方法列表
10021 var methodNameList = [
1003 'order','alias','having','group',
1004 'lock','auto','filter','validate'
1005 ];
10061 methodNameList.forEach(function(item){
10078 methods[item] = function(data){
100820 this._options[item] = data;
100920 return this;
1010 };
1011 });
10121 methods.distinct = function(data){
10132 this._options.distinct = data;
1014 //如果传过来一个字段,则映射到field上
10152 if (isString(data)) {
10162 this._options.field = data;
1017 }
10182 return this;
1019 };
10201 ['count','sum','min','max','avg'].forEach(function(item){
10215 methods[item] = function(field){
102210 field = field || this.pk;
102310 return this.getField(item.toUpperCase() + '(' + field + ') AS thinkjs_' + item, true);
1024 };
1025 });
1026 //方法别名
10271 var aliasMethodMap = {
1028 update: 'save',
1029 updateField: 'setField',
1030 updateInc: 'setInc',
1031 updateDec: 'setDec'
1032 };
10331 Object.keys(aliasMethodMap).forEach(function(key){
10344 var value = aliasMethodMap[key];
10354 methods[value] = function(){
10360 return this[key].apply(this, arguments);
1037 };
1038 });
10391 return methods;
1040});
1041/**
1042 * 关闭所有的数据库连接
1043 * @return {[type]} [description]
1044 */
10451Model.close = function(){
10461 'use strict';
10471 for(var key in dbInstances) {
10480 dbInstances[key].close();
1049 }
10501 dbInstances = {};
1051};

/Users/welefen/Develop/git/thinkjs/lib/Lib/Core/Think.js

53%
168
90
78
LineHitsSource
11var fs = require('fs');
21var cluster = require('cluster');
3
4//自动加载进行识别的路径
51var autoloadPaths = {};
6/**
7 * [exports description]
8 * @type {Object}
9 */
101module.exports = {
11 /**
12 * [start description]
13 * @return {[type]} [description]
14 */
15 start: function(){
161 'use strict';
171 this.init();
181 this.processEvent();
19 //加载文件
201 this.loadFiles();
21 //合并自动加载的路径
221 this.mergeAutoloadPath();
23 //thinkRequire的autoload
241 registerAutoload(this.autoload);
25 //debug模式
261 if (APP_DEBUG) {
270 this.debug();
28 }
29 //记录进程的id
301 this.logPid();
31 //记录日志
321 this.log();
33
341 thinkRequire('App').run();
35 },
36 /**
37 * 定义一些目录,加载框架的基础文件
38 * @return {[type]} [description]
39 */
40 init: function(){
411 'use strict';
42 //系统路径设置
431 global.THINK_LIB_PATH = THINK_PATH + '/Lib';
441 global.THINK_EXTEND_PATH = THINK_LIB_PATH + '/Extend';
45 //应用路径设置
461 var config = {
47 COMMON_PATH: APP_PATH + '/Common',
48 LIB_PATH: APP_PATH + '/Lib',
49 CONF_PATH: APP_PATH + '/Conf',
50 LANG_PATH: APP_PATH + '/Lang',
51 VIEW_PATH: APP_PATH + '/View',
52 //HTML_PATH: RUNTIME_PATH + '/Html',
53 LOG_PATH: RUNTIME_PATH + '/Log',
54 TEMP_PATH: RUNTIME_PATH + '/Temp',
55 DATA_PATH: RUNTIME_PATH + '/Data',
56 CACHE_PATH: RUNTIME_PATH + '/Cache'
57 };
581 for (var name in config) {
599 if (global[name] === undefined) {
609 global[name] = config[name];
61 }
62 }
631 require(THINK_PATH + '/Common/extend.js');
641 require(THINK_PATH + '/Common/common.js');
651 require(THINK_PATH + '/Common/function.js');
66 //别名导入
671 aliasImport(require(THINK_PATH + '/Conf/alias.js'));
68 },
69 /**
70 * 记录日志
71 * @return {[type]} [description]
72 */
73 log: function(){
741 'use strict';
751 if (APP_DEBUG || APP_MODE === 'cli' || !C('log_record')) {
761 return;
77 }
780 thinkRequire('Log')().run();
79 },
80 /**
81 * 注册异常处理
82 * @return {[type]} [description]
83 */
84 processEvent: function(){
851 'use strict';
861 process.on('uncaughtException', function(err) {
870 console.error(isError(err) ? err.stack : err);
88 });
89 },
90 /**
91 * 加载项目下对应的文件
92 * @return {[type]} [description]
93 */
94 loadFiles: function(){
951 'use strict';
961 C(null); //移除之前的所有配置
97 //加载系统默认配置
981 C(require(THINK_PATH + '/Conf/config.js'));
99 //加载用户配置
1001 var file = CONF_PATH + '/config.js';
1011 if (isFile(file)) {
1021 C(require(file));
103 }
104 //加载模式的配置文件
1051 if (APP_MODE) {
1061 var modeFiles = [
107 THINK_PATH + '/Conf/mode.js',
108 CONF_PATH + '/mode.js'
109 ];
1101 modeFiles.forEach(function(file){
1112 if (isFile(file)) {
1121 var conf = require(file);
1131 if (conf[APP_MODE]) {
1141 C(conf[APP_MODE]);
115 }
116 }
117 });
118 }
119 //自定义路由
1201 if (C('url_route_on') && isFile(CONF_PATH + '/route.js')) {
1210 C('url_route_rules', require(CONF_PATH + '/route.js'));
122 }
123 //common文件
1241 if (isFile(COMMON_PATH + '/common.js')) {
1251 require(COMMON_PATH + '/common.js');
126 }
127 //别名文件
1281 if (isFile(COMMON_PATH + '/alias.js')) {
1290 aliasImport(require(COMMON_PATH + '/alias.js'));
130 }
1311 this.loadTag();
1321 this.loadExtConfig();
1331 this.loadExtFiles();
134 },
135 //加载标签行为
136 loadTag: function(){
1371 'use strict';
138 //系统标签
1391 var tag = require(THINK_PATH + '/Conf/tag.js');
140 //用户行为标签
1411 var tagFile = CONF_PATH + '/tag.js';
1421 if (!C('app_tag_on') || !isFile(tagFile)) {
1431 C('tag', tag);
1441 return;
145 }
1460 var mixTag = extend({}, tag);
1470 var userTag = extend({}, require(tagFile));
1480 for(var key in userTag){
1490 var value = userTag[key];
1500 if (!value.length) {
1510 continue;
152 }
1530 mixTag[key] = mixTag[key] || [];
1540 if (isBoolean(value[0])) {
1550 var flag = value.shift();
1560 if (flag) { //true为替换系统标签
1570 mixTag[key] = value;
158 }else{ //false为将自定义标签置为系统标签前面
1590 mixTag[key] = value.concat(mixTag[key]);
160 }
161 }else{// 默认将用户标签置为系统标签后面
1620 mixTag[key] = mixTag[key].concat(value);
163 }
164 }
165 //行为标签
1660 C('tag', mixTag);
167 },
168 //加载自定义外部文件
169 loadExtFiles: function(){
1701 'use strict';
1711 var files = C('load_ext_file');
1721 if (files) {
1731 if (isString(files)) {
1740 files = files.split(',');
175 }
1761 files.forEach(function(file){
1770 file = COMMON_PATH + '/' + file + '.js';
1780 if (isFile(file)) {
1790 require(file);
180 }
181 });
182 }
183 },
184 //加载额外的配置
185 loadExtConfig: function(){
1861 'use strict';
1871 var files = C('load_ext_config');
1881 if (files) {
1891 if (isString(files)) {
1900 files = files.split(',');
191 }
1921 files.forEach(function(file){
1930 file = CONF_PATH + '/' + file + '.js';
1940 if (isFile(file)) {
1950 C(require(file));
196 }
197 });
198 }
199 },
200 //加载debug模式配置文件
201 loadDebugFiles: function(){
2020 'use strict';
203 //加载debug模式下的配置
2040 C(require(THINK_PATH + '/Conf/debug.js'));
205 //debug下自定义状态的配置
2060 var status = C('app_status');
2070 if (status) {
2080 if (isFile(CONF_PATH + '/' + status + '.js')) {
2090 C(require(CONF_PATH + '/' + status + '.js'));
210 }
211 }else{
2120 if (isFile(CONF_PATH + '/debug.js')) {
2130 C(require(CONF_PATH + '/debug.js'));
214 }
215 }
2160 if (APP_MODE) {
2170 var modeFiles = [
218 THINK_PATH + '/Conf/mode.js',
219 CONF_PATH + '/mode.js'
220 ];
2210 modeFiles.forEach(function(file){
2220 if (isFile(file)) {
2230 var conf = require(file);
2240 var key = APP_MODE + '_debug';
2250 if (conf[key]) {
2260 C(conf[key]);
227 }
228 }
229 });
230 }
231 },
232 /**
233 * debug模式下一些特殊处理
234 * @return {[type]} [description]
235 */
236 debug: function(){
2370 'use strict';
2380 this.loadDebugFiles();
239 //清除require的缓存
2400 if (C('clear_require_cache')) {
241 //这些文件不清除缓存
2420 var retainFiles = C('debug_retain_files');
2430 var self = this;
2440 setInterval(function(){
2450 var fn = function(item){
246 //windows目录定界符为\
2470 if (process.platform === 'win32') {
2480 item = item.replace(/\//g, '\\');
249 }
2500 if (file.indexOf(item) > -1) {
2510 return true;
252 }
253 };
2540 for(var file in require.cache){
2550 var flag = retainFiles.some(fn);
2560 if (!flag) {
2570 delete require.cache[file];
258 }
259 }
2600 self.loadFiles();
2610 self.loadDebugFiles();
262 }, 100);
263 }
264 },
265 /**
266 * 记录当前进程的id
267 * 记录在Runtime/Data/app.pid文件里
268 * @return {[type]} [description]
269 */
270 logPid: function(){
2711 'use strict';
2721 if (C('log_process_pid') && cluster.isMaster) {
2730 mkdir(DATA_PATH);
2740 var pidFile = DATA_PATH + '/app.pid';
2750 fs.writeFileSync(pidFile, process.pid);
2760 chmod(pidFile);
277 //进程退出时删除该文件
2780 process.on('SIGTERM', function () {
2790 if (fs.existsSync(pidFile)) {
2800 fs.unlinkSync(pidFile);
281 }
2820 process.exit(0);
283 });
284 }
285 },
286 /**
287 * 合并autoload的path
288 * @return {[type]} [description]
289 */
290 mergeAutoloadPath: function(){
2911 'use strict';
2921 var file = '__CLASS__.js';
2931 var sysAutoloadPath = {
294 'Behavior': [
295 LIB_PATH + '/Behavior/' + file,
296 THINK_LIB_PATH + '/Behavior/' + file
297 ],
298 'Model': [
299 LIB_PATH + '/Model/' + file,
300 THINK_EXTEND_PATH + '/Model/' + file
301 ],
302 'Logic': [
303 LIB_PATH + '/Logic/' + file
304 ],
305 'Service': [
306 LIB_PATH + '/Service/' + file
307 ],
308 'Controller': [
309 LIB_PATH + '/Controller/' + file,
310 THINK_EXTEND_PATH + '/Controller/' + file
311 ],
312 'Cache': [
313 LIB_PATH + '/Driver/Cache/' + file,
314 THINK_LIB_PATH + '/Driver/Cache/' + file
315 ],
316 'Db': [
317 LIB_PATH + '/Driver/Db/' + file,
318 THINK_LIB_PATH + '/Driver/Db/' + file
319 ],
320 'Template': [
321 LIB_PATH + '/Driver/Template/' + file,
322 THINK_LIB_PATH + '/Driver/Template/' + file
323 ],
324 'Socket': [
325 LIB_PATH + '/Driver/Socket/' + file,
326 THINK_LIB_PATH + '/Driver/Socket/' + file
327 ],
328 'Session': [
329 LIB_PATH + '/Driver/Session/' + file,
330 THINK_LIB_PATH + '/Driver/Session/' + file
331 ]
332 };
3331 var autoloadPath = C('autoload_path');
3341 for(var type in autoloadPath){
3350 var paths = autoloadPath[type];
3360 var override = false;
3370 if (!isArray(paths)) {
3380 paths = [paths];
3390 }else if (isBoolean(paths[0])) {
3400 override = paths.shift();
341 }
3420 if (override) {
3430 sysAutoloadPath[type] = paths;
344 }else{
3450 paths.push.apply(paths, sysAutoloadPath[type]);
3460 sysAutoloadPath[type] = paths;
347 }
348 }
3491 autoloadPaths = sysAutoloadPath;
350 },
351 //thinkRequire的自动加载
352 autoload: function(cls){
35346 'use strict';
35446 var filepath = '';
35546 var fn = function(item){
35684 item = item.replace(/__CLASS__/g, cls);
35784 if (isFile(item)) {
35821 filepath = item;
35921 return true;
360 }
361 };
36246 for(var name in autoloadPaths){
363346 var length = name.length;
364346 if (cls.substr(0 - length) === name) {
36544 var list = autoloadPaths[name];
36644 list.some(fn);
36744 if (filepath) {
36821 if (!APP_DEBUG) {
36921 aliasImport(cls, filepath);
370 }
37121 return filepath;
372 }
373 }
374 }
375 }
376};
377

/Users/welefen/Develop/git/thinkjs/lib/Lib/Core/View.js

89%
37
33
4
LineHitsSource
1/**
2 * view
3 * @return {[type]} [description]
4 */
51module.exports = Class(function(){
61 'use strict';
71 return {
8 init: function(http){
911 this.http = http;
1011 this.tVar = {};
11 },
12 /**
13 * 给变量赋值
14 * @param {[type]} name [description]
15 * @param {[type]} value [description]
16 * @return {[type]} [description]
17 */
18 assign: function(name, value){
1929 if (name === undefined) {
201 return this.tVar;
21 }
2228 if (isString(name) && arguments.length === 1) {
234 return this.tVar[name];
24 }
2524 if (isObject(name)) {
261 this.tVar = extend(this.tVar, name);
27 }else{
2823 this.tVar[name] = value;
29 }
30 },
31 /**
32 * 输出模版文件内容
33 * @param {[type]} templateFile [description]
34 * @param {[type]} charset [description]
35 * @param {[type]} contentType [description]
36 * @param {[type]} content [description]
37 * @return {[type]} [description]
38 */
39 display: function(templateFile, charset, contentType){
403 var self = this;
413 return tag('view_init', this.http).then(function(){
423 return self.fetch(templateFile);
43 }).then(function(content){
443 self.render(content, charset, contentType);
453 return tag('view_end', self.http, content);
46 }).then(function(){
473 return self.http.end();
48 }).catch(function(){
490 return self.http.end();
50 });
51 },
52 /**
53 * 渲染模版
54 * @param {[type]} content [description]
55 * @param {[type]} charset [description]
56 * @param {[type]} contentType [description]
57 * @return {[type]} [description]
58 */
59 render: function(content, charset, contentType){
603 if (!this.http.cthIsSend) {
613 charset = charset || C('encoding');
623 contentType = contentType || C('tpl_content_type');
633 this.http.setHeader('Content-Type', contentType + '; charset=' + charset);
64 }
653 if (C('show_exec_time')) {
660 this.http.sendTime('Exec-Time');
67 }
683 this.http.echo(content || '', charset || C('encoding'));
69 },
70 /**
71 * 获取模版文件内容
72 * @param {[type]} templateFile [description]
73 * @param {[type]} content [description]
74 * @return {[type]} [description]
75 */
76 fetch: function(templateFile){
776 var self = this;
786 var promise = getPromise(templateFile);
796 if (!templateFile || !isFile(templateFile)) {
806 promise = tag('view_template', this.http, templateFile).then(function(file){
816 if (isFile(file)) {
826 templateFile = file;
83 }else{
840 return getPromise(new Error("can't find template file"), true);
85 }
86 });
87 }
886 return promise.then(function(){
896 return tag('view_parse', self.http, {
90 'var': self.tVar,
91 'file': templateFile
92 });
93 }).then(function(content){
946 return tag('view_filter', self.http, content);
95 }).catch(function(err){
96 //输出模版解析异常
970 console.log(isError(err) ? err.stack : err);
98 });
99 }
100 };
101});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Driver/Cache/FileCache.js

71%
67
48
19
LineHitsSource
11var fs = require('fs');
2/**
3 * 基于文件的缓存
4 * @return {[type]} [description]
5 */
61module.exports = Cache(function(){
71 'use strict';
81 return {
9 gcType: 'FileCache',
10 init: function(options){
1118 this.options = extend({
12 cache_path: C('cache_path'), //缓存目录
13 cache_path_level: 2, //缓存子目录深度
14 cache_file_suffix: C('cache_file_suffix') //缓存文件后缀名
15 }, options);
1618 mkdir(this.options.cache_path);
1718 this.gcType += ':' + this.options.cache_path;
18
1918 this.super_('init', this.options);
20 },
21 /**
22 * 存储的缓存文件
23 * @param {[type]} name [description]
24 * @return {[type]} [description]
25 */
26 getStoredFile: function(name){
2744 name = md5(this.key || name);
2844 var dir = name.split('').slice(0, this.options.cache_path_level).join('/');
2944 mkdir(this.options.cache_path + '/' + dir);
3044 var path = this.options.cache_path + '/' + dir + '/' + name + this.options.cache_file_suffix;
3144 return path;
32 },
33 /**
34 * 获取缓存,返回promise
35 * @param {[type]} name [description]
36 * @return {[type]} [description]
37 */
38 getData: function(name){
398 var filePath = this.getStoredFile(name);
408 if (!isFile(filePath)) {
411 return getPromise();
42 }
437 var deferred = getDefer();
447 fs.exists(filePath, function(exists){
457 if (!exists) {
460 return deferred.resolve();
47 }
487 fs.readFile(filePath, {encoding: 'utf8'}, function(error, content){
497 if (error || !content) {
500 return deferred.resolve();
51 }
527 try{
537 var data = JSON.parse(content);
547 if (Date.now() > data.expire) {
552 fs.unlink(filePath, function(){
562 return deferred.resolve();
57 });
58 }else{
595 deferred.resolve(data.data);
60 }
61 }catch(e){
62 //异常时删除该文件
630 fs.unlink(filePath, function(){
640 return deferred.resolve();
65 });
66 }
67 });
68 });
697 return deferred.promise;
70 },
71 get: function(name){
727 return this.getData(name).then(function(data){
737 return (data || {})[name];
74 })
75 },
76 setData: function(name, value, timeout){
7735 if (isObject(name)) {
7829 timeout = value;
79 }
8035 if (timeout === undefined) {
8132 timeout = this.options.timeout;
82 }
8335 var filePath = this.getStoredFile(name);
8435 var data = {
85 data: isObject(name) ? name : getObject(name, value),
86 expire: Date.now() + timeout * 1000,
87 timeout: timeout
88 };
8935 var deferred = getDefer();
9035 fs.writeFile(filePath, JSON.stringify(data), function(){
91 //修改缓存文件权限,避免不同账号下启动时可能会出现无权限的问题
9235 chmod(filePath);
9335 deferred.resolve();
94 })
9535 return deferred.promise;
96 },
97 /**
98 * 设置缓存
99 * @param {[type]} name [description]
100 * @param {[type]} value [description]
101 * @param {[type]} expire [description]
102 */
103 set: function(name, value, timeout){
1046 return this.setData(name, value, timeout);
105 },
106 /**
107 * 删除缓存
108 * @param {[type]} name [description]
109 * @return {[type]} [description]
110 */
111 rm: function(name){
1121 var filePath = this.getStoredFile(name);
1131 if (isFile(filePath)) {
1141 var deferred = getDefer();
1151 fs.unlink(filePath, function(){
1161 deferred.resolve();
117 })
1181 return deferred.promise;
119 }
1200 return getPromise();
121 },
122 /**
123 * gc
124 * @param {[type]} now [description]
125 * @return {[type]} [description]
126 */
127 gc: function(now, path){
1280 path = path || this.options.cache_path;
1290 var self = this;
1300 var files = fs.readdirSync(path);
1310 files.forEach(function(item){
1320 var filePath = path + '/' + item;
1330 var stat = fs.statSync(filePath);
1340 if (stat.isDirectory()) {
1350 self.gc(now, filePath);
1360 }else if (stat.isFile()) {
1370 var data = getFileContent(filePath);
1380 try{
1390 data = JSON.parse(data);
1400 if (now > data.expire) {
1410 fs.unlink(filePath, function(){});
142 }
143 }catch(e){}
144 }
145 });
146 }
147 };
148});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Driver/Cache/MemcacheCache.js

35%
14
5
9
LineHitsSource
11var memcache = thinkRequire('MemcacheSocket');
21module.exports = Cache(function(){
31 'use strict';
41 var instance = null;
51 return {
6 namePrefix: '__thinkjs__',
7 init: function(options){
80 this.super_('init', options);
90 if (!instance) {
100 instance = memcache(C('memcache_port'), C('memcache_host'));
11 }
120 this.handle = instance;
13 },
14 get: function(name){
150 return this.handle.get(this.namePrefix + name).then(function(value){
160 return value ? JSON.parse(value) : value;
17 })
18 },
19 set: function(name, value, timeout){
200 timeout = timeout || this.options.timeout;
210 return this.handle.set(this.namePrefix + name, JSON.stringify(value), timeout);
22 },
23 rm: function(name){
240 return this.handle.delete(this.namePrefix + name);
25 }
26 };
27});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Driver/Db/MysqlDb.js

72%
51
37
14
LineHitsSource
1/**
2 * mysql数据库
3 * @return {[type]} [description]
4 */
51var mysqlSocket = thinkRequire('MysqlSocket');
61module.exports = Db(function(){
71 'use strict';
8
91 return {
10 init: function(config){
111 this.super_('init');
121 if (config) {
131 this.config = config;
14 }
15 //最后插入id
161 this.lastInsertId = 0;
17 //查询等待
181 this.queryWaiting = {};
19 },
20 /**
21 * 连接数据库
22 * @param {[type]} config [description]
23 * @param {[type]} linknum [description]
24 * @return {[type]} [description]
25 */
26 connect: function(){
27176 if (!this.linkId) {
281 this.linkId = mysqlSocket(this.config);
29 }
30176 return this.linkId;
31 },
32 /**
33 * 查询一条sql
34 * @param string str
35 * @return promise
36 */
37 query: function(str){
38154 this.setSql(str);
39154 var self = this;
40154 if (!(str in this.queryWaiting)) {
41154 this.queryWaiting[str] = [];
42154 return this.connect().query(str).then(function(data){
43154 process.nextTick(function(){
44154 self.queryWaiting[str].forEach(function(deferred){
450 deferred.resolve(data);
46 });
47154 delete self.queryWaiting[str];
48 })
49154 return data;
50 });
51 }else{
520 var deferred = getDefer();
530 this.queryWaiting[str].push(deferred);
540 return deferred.promise;
55 }
56 },
57 /**
58 * 执行一条sql, 返回影响的行数
59 * @param {[type]} str [description]
60 * @return {[type]} [description]
61 */
62 execute: function(str){
6322 this.setSql(str);
6422 var self = this;
6522 return this.connect().query(str).then(function(data){
6622 self.lastInsertId = data.insertId;
6722 return data.affectedRows || 0;
68 });
69 },
70 /**
71 * 获取数据表字段信息
72 * @param string tableName 数据表名
73 * @return promise 返回一个promise
74 */
75 getFields: function(tableName){
764 var sql = 'SHOW COLUMNS FROM ' + this.parseKey(tableName);
774 return this.query(sql).then(function(data){
784 var ret = {};
794 data.forEach(function(item){
8052 ret[item.Field] = {
81 'name': item.Field,
82 'type': item.Type,
83 'notnull': item.Null === '',
84 'default': item.Default,
85 'primary': item.Key === 'PRI',
86 'unique': item.Key === 'UNI',
87 'autoinc': item.Extra.toLowerCase() === 'auto_increment'
88 };
89 });
904 return ret;
91 });
92 },
93 /**
94 * 获取数据库的表信息
95 * @param {[type]} dbName [description]
96 * @return {[type]} [description]
97 */
98 getTables: function(dbName){
990 var sql = 'SHOW TABLES';
1000 if (dbName) {
1010 sql += ' FROM ' + dbName;
102 }
1030 return this.query(sql).then(function(data){
1040 return data.map(function(item){
1050 for(var key in item){
1060 return item[key];
107 }
108 });
109 });
110 },
111 /**
112 * 关闭连接
113 * @return {[type]} [description]
114 */
115 close: function(){
1160 if (this.linkId) {
1170 this.linkId.close();
1180 this.linkId = null;
119 }
120 },
121 /**
122 * 解析key
123 * @param {[type]} key [description]
124 * @return {[type]} [description]
125 */
126 parseKey: function(key){
127342 key = (key || '').trim();
128342 if (!(/[,\'\"\*\(\)`.\s]/.test(key))) {
129321 key = '`' + key + '`';
130 }
131342 return key;
132 },
133 /**
134 * 获取最后插入的id
135 * @return {[type]} [description]
136 */
137 getLastInsertId: function(){
1386 return this.lastInsertId;
139 }
140 };
141});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Driver/Session/DbSession.js

9%
33
3
30
LineHitsSource
1/**
2 * DbSession
3 * 需要在数据库中建立对应的数据表
4 *
5 * DROP TABLE IF EXISTS `think_session`;
6 CREATE TABLE `think_session` (
7 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
8 `key` varchar(255) NOT NULL DEFAULT '',
9 `data` text,
10 `expire` bigint(11) NOT NULL,
11 PRIMARY KEY (`id`),
12 UNIQUE KEY `cookie` (`key`),
13 KEY `expire` (`expire`)
14 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
15 *
16 *
17 * @return {[type]} [description]
18 */
191module.exports = Cache(function(){
201 'use strict';
211 return {
22 /**
23 * gc类型
24 * @type {String}
25 */
26 gcType: 'DbSession',
27 /**
28 * [init description]
29 * @param {[type]} options [description]
30 * @return {[type]} [description]
31 */
32 init: function(options){
330 this.super_('init', options);
340 this.key = this.options.cookie;
350 this.data = {};
360 this.initData();
37 },
38 /**
39 * 初始化数据
40 * @return {[type]} [description]
41 */
42 initData: function(){
430 if (!this.promise) {
440 var model = D('Session');
450 var self = this;
460 this.promise = model.where({key: this.key}).find().then(function(data){
470 self.data = {};
480 if (isEmpty(data)) {
490 return model.add({
50 key: self.key,
51 expire: Date.now() + self.options.timeout * 1000
52 });
53 }
540 if (Date.now() > data.expire) {
550 return;
56 }
570 self.data = JSON.parse(data.data || '{}');
58 });
59 }
600 return this.promise;
61 },
62 /**
63 * 获取
64 * @param {[type]} name [description]
65 * @return {[type]} [description]
66 */
67 get: function(name){
680 var self = this;
690 return this.initData().then(function(){
700 return self.data[name];
71 });
72 },
73 /**
74 * 设置
75 * @param {[type]} name [description]
76 * @param {[type]} value [description]
77 */
78 set: function(name, value){
790 var self = this;
800 return this.initData().then(function(){
810 self.data[name] = value;
82 });
83 },
84 /**
85 * 删除
86 * @param {[type]} name [description]
87 * @return {[type]} [description]
88 */
89 rm: function(name){
900 if (this.data) {
910 delete this.data[name];
92 }
930 return getPromise();
94 },
95 /**
96 * 将数据保存到数据库中
97 * @return {[type]} [description]
98 */
99 flush: function(){
1000 var model = D('Session');
1010 var self = this;
1020 var data = {
103 expire: Date.now() + self.options.timeout * 1000,
104 data: JSON.stringify(self.data)
105 };
1060 return this.initData().then(function(){
1070 return model.where({key: self.key}).update(data);
108 });
109 },
110 /**
111 * [gc description]
112 * @param {[type]} now [description]
113 * @return {[type]} [description]
114 */
115 gc: function(now){
1160 return D('Session').where({
117 expire: ['<', now]
118 }).delete();
119 }
120 };
121});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Driver/Session/FileSession.js

96%
26
25
1
LineHitsSource
1/**
2 * 文件Session
3 * @return {[type]} [description]
4 */
5
61var os = require('os');
71module.exports = Class(function(){
81 'use strict';
91 return {
10 gcType: 'FileSession',
11 /**
12 * 差异化的init
13 * @return {[type]} [description]
14 */
15 init: function(options){
164 options = options || {};
174 options.cache_path = C('session_path') || (os.tmpdir() + '/thinkjs');
184 this.super_('init', options);
194 this.key = options.cookie;
20 },
21 initData: function(){
2239 if (!this.promise) {
231 var self = this;
241 this.promise = this.getData().then(function(data){
251 self.sessionData = data || {};
26 })
27 }
2839 return this.promise;
29 },
30 get: function(name){
315 var self = this;
325 return this.initData().then(function(){
335 return self.sessionData[name];
34 });
35 },
36 set: function(name, value, timeout){
375 var self = this;
385 return this.initData().then(function(){
395 self.sessionData[name] = value;
405 if (timeout) {
410 self.options.timeout = timeout;
42 }
43 });
44 },
45 rm: function(){
461 this.sessionData = {};
471 return getPromise();
48 },
49 /**
50 * 将数据写入到文件中
51 * @return {[type]} [description]
52 */
53 flush: function(){
5429 var self = this;
5529 return this.initData().then(function(){
5629 return self.setData(self.sessionData);
57 })
58 }
59 };
60}, thinkRequire('FileCache'));

/Users/welefen/Develop/git/thinkjs/lib/Lib/Driver/Socket/MemcacheSocket.js

12%
124
15
109
LineHitsSource
11var net = require('net');
21var EventEmitter = require('events').EventEmitter;
3
41var CRLF = '\r\n'; //换行符
51var CRLF_LENGTH = CRLF.length;
61var ERRORS = ['ERROR', 'NOT_FOUND', 'CLIENT_ERROR', 'SERVER_ERROR']; //错误
71var ERRORS_LENGTH = ERRORS.length;
8
9//读取一行数据
101function readLine(string){
110 'use strict';
120 var pos = string.indexOf(CRLF);
130 if (pos > -1) {
140 return string.substr(0, pos);
15 }
160 return string;
17}
18/**
19 * memcache类
20 * @return {[type]} [description]
21 */
221module.exports = Class(function(){
231 'use strict';
241 return {
25 init: function(port, hostname){
260 EventEmitter.call(this);
270 this.port = port || 11211;
280 this.hostname = hostname || 'localhost';
290 this.buffer = '';
300 this.callbacks = []; //回调函数
310 this.handle = null; //socket连接句柄
32 },
33 /**
34 * 建立连接
35 * @return {[type]} [description]
36 */
37 connect: function(){
380 if (this.handle) {
390 return this;
40 }
410 var self = this;
420 var deferred = getDefer();
430 this.handle = net.createConnection(this.port, this.host);
440 this.handle.on('connect', function(){
450 this.setTimeout(0);
460 this.setNoDelay();
470 self.emit('connect');
480 deferred.resolve();
49 });
500 this.handle.on('data', function(data){
510 self.buffer += data.toString();
520 self.handleData();
53 });
540 this.handle.on('end', function(){
550 self.handle.end();
560 self.handle = null;
57 });
580 this.handle.on('close', function(){
590 self.handle = null;
600 self.emit('close');
61 });
620 this.handle.on('timeout', function(){
630 self.handle = null;
640 self.emit('timeout');
65 });
660 this.handle.on('error', function(error){
670 self.handle = null;
680 self.emit('error', error);
69 });
700 this.promise = deferred.promise;
710 return this;
72 },
73 /**
74 * 处理接收的数据
75 * @return {[type]} [description]
76 */
77 handleData: function(){
780 while(this.buffer.length > 0){
790 var result = this.getHandleResult(this.buffer);
800 if(result === false){
810 break;
82 }
830 var value = result[0];
840 var pos = result[1];
850 var error = result[2];
860 if (pos > this.buffer.length) {
870 break;
88 }
890 this.buffer = this.buffer.substring(pos);
900 var callback = this.callbacks.shift();
910 if (callback && callback.callback) {
920 callback.callback(error, value);
93 }
94 }
95 },
96 getHandleResult: function(buffer){
970 if (buffer.indexOf(CRLF) === -1) {
980 return false;
99 }
1000 for(var i = 0; i < ERRORS_LENGTH; i++){
1010 var item = ERRORS[i];
1020 if (buffer.indexOf(item) > -1) {
1030 return this.handleError(buffer);
104 }
105 }
1060 var callback = this.callbacks[0];
1070 if (callback && callback.type) {
1080 return this['handle' + ucfirst(callback.type)](buffer);
109 }
1100 return false;
111 },
112 /**
113 * 处理错误
114 * @param {[type]} buffer [description]
115 * @return {[type]} [description]
116 */
117 handleError: function(buffer){
1180 var line = readLine(buffer);
1190 return [null, line.length + CRLF_LENGTH, line];
120 },
121 /**
122 * 处理获取数据
123 * @param {[type]} buffer [description]
124 * @return {[type]} [description]
125 */
126 handleGet: function(buffer){
1270 var value = null;
1280 var end = 3;
1290 var resultLen = 0;
1300 var firstPos;
1310 if (buffer.indexOf('END') === 0) {
1320 return [value, end + CRLF_LENGTH];
1330 }else if (buffer.indexOf('VALUE') === 0 && buffer.indexOf('END') > -1) {
1340 firstPos = buffer.indexOf(CRLF) + CRLF_LENGTH;
1350 var endPos = buffer.indexOf('END');
1360 resultLen = endPos - firstPos - CRLF_LENGTH;
1370 value = buffer.substr(firstPos, resultLen);
1380 return [value, firstPos + parseInt(resultLen, 10) + CRLF_LENGTH + end + CRLF_LENGTH];
139 }else{
1400 firstPos = buffer.indexOf(CRLF) + CRLF_LENGTH;
1410 resultLen = buffer.substr(0, firstPos).split(' ')[3];
1420 value = buffer.substr(firstPos, resultLen);
1430 return [value, firstPos + parseInt(resultLen) + CRLF_LENGTH + end + CRLF_LENGTH];
144 }
145 },
146 /**
147 * 处理简单数据
148 * @param {[type]} buffer [description]
149 * @return {[type]} [description]
150 */
151 handleSimple: function(buffer){
1520 var line = readLine(buffer);
1530 return [line, line.length + CRLF_LENGTH, null];
154 },
155 /**
156 * 版本号
157 * @param {[type]} buffer [description]
158 * @return {[type]} [description]
159 */
160 handleVersion: function(buffer){
1610 var pos = buffer.indexOf(CRLF);
162 //8 is length of 'VERSION '
1630 var value = buffer.substr(8, pos - 8);
1640 return [value, pos + CRLF_LENGTH, null];
165 },
166 /**
167 * 查询
168 * @param {[type]} query [description]
169 * @param {[type]} type [description]
170 * @param {Function} callback [description]
171 * @return {[type]} [description]
172 */
173 query: function(query, type){
1740 this.connect();
1750 var self = this;
1760 var deferred = getDefer();
1770 var callback = function(error, value){
1780 return error ? deferred.reject(error) : deferred.resolve(value);
179 }
1800 this.promise.then(function(){
1810 self.callbacks.push({type: type, callback: callback});
1820 self.handle.write(query + CRLF);
183 });
1840 return deferred.promise;
185 },
186 /**
187 * 获取
188 * @param {[type]} key [description]
189 * @param {Function} callback [description]
190 * @return {[type]} [description]
191 */
192 get: function(key){
1930 return this.query('get ' + key, 'get');
194 },
195 /**
196 * 存储
197 * @return {[type]} [description]
198 */
199 store: function(key, value, type, lifetime, flags){
2000 lifetime = lifetime || 0;
2010 flags = flags || 0;
2020 var length = Buffer.byteLength(value.toString());
2030 var query = [type, key, flags, lifetime, length].join(' ') + CRLF + value;
2040 return this.query(query, 'simple');
205 },
206 /**
207 * 删除
208 * @param {[type]} key [description]
209 * @param {Function} callback [description]
210 * @return {[type]} [description]
211 */
212 delete: function(key){
2130 return this.query('delete ' + key, 'simple');
214 },
215 /**
216 * 获取版本号
217 * @param {Function} callback [description]
218 * @return {[type]} [description]
219 */
220 version: function(){
2210 return this.query('version', 'version');
222 },
223 /**
224 * 增长
225 * @param {[type]} key [description]
226 * @param {[type]} step [description]
227 * @param {Function} callback [description]
228 * @return {[type]} [description]
229 */
230 increment: function(key, step){
2310 step = step || 1;
2320 return this.query('incr ' + key + ' ' + step, 'simple');
233 },
234 /**
235 * 减少
236 * @param {[type]} key [description]
237 * @param {[type]} step [description]
238 * @param {Function} callback [description]
239 * @return {[type]} [description]
240 */
241 decrement: function(key, step){
2420 step = step || 1;
2430 return this.query('decr ' + key + ' ' + step, 'simple');
244 },
245 /**
246 * 关闭
247 * @return {[type]} [description]
248 */
249 close: function(){
2500 if (this.handle && this.handle.readyState === 'open') {
2510 this.handle.end();
2520 this.handle = null;
253 }
254 }
255 }
256}, EventEmitter).extend(function(){
2571 'use strict';
2581 var result = {};
2591 ['set', 'add', 'replace', 'append', 'prepend'].forEach(function(item){
2605 result[item] = function(key, value, callback, lifetime, flags){
2610 return this.store(key, value, item, callback, lifetime, flags);
262 }
263 });
2641 return result;
265});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Driver/Socket/MysqlSocket.js

17%
45
8
37
LineHitsSource
1/**
2 * mysql socket
3 * @return {[type]} [description]
4 */
5
6//暂时使用mysql库
71var mysql = require('mysql');
81module.exports = Class(function(){
91 'use strict';
101 return {
11 init: function(config){
121 this.handle = null;
131 this.config = config;
141 this.deferred = null;
151 this.tryTimes = 0;
16 },
17 /**
18 * 建立数据库连接
19 * @return {[type]} [description]
20 */
21 connect: function(){
220 if (this.handle) {
230 return this.deferred.promise;
24 }
250 var self = this;
260 var deferred = getDefer();
27 //创建连接
280 var connection = mysql.createConnection({
29 host : this.config.hostname || '127.0.0.1',
30 port : this.config.port || 3306,
31 user : this.config.username || 'root',
32 password : this.config.password || '',
33 database : this.config.database || '',
34 charset : this.config.charset
35 });
36 //连接
370 connection.connect(function(err){
38 //连接失败
390 if (err) {
400 deferred.reject(err);
410 self.close();
42 }else{
430 deferred.resolve();
44 }
45 });
46 //错误时关闭当前连接
470 connection.on('error', function(){
480 self.close();
49 });
50 //PROTOCOL_CONNECTION_LOST
510 connection.on('end', function(){
520 self.close();
53 })
54 //连接句柄
550 this.handle = connection;
56 //把上一次的promise reject
570 if (this.deferred) {
580 this.deferred.reject(new Error('connection closed'));
59 }
600 this.deferred = deferred;
610 return this.deferred.promise;
62 },
63 /**
64 * 查询sql语句,返回一个promise
65 * @param {[type]} sql [description]
66 * @return {[type]} [description]
67 */
68 query: function(sql){
690 if (APP_DEBUG) {
700 console.log('sql: ' + sql);
71 }
720 var self = this;
730 return this.connect().then(function(){
740 var deferred = getDefer();
750 self.handle.query(sql, function(err, rows){
760 if (err) {
77 //当数据量非常大时,可能会出现连接丢失,这里进行重连
780 if (err.code === 'PROTOCOL_CONNECTION_LOST' && self.tryTimes < 3) {
790 self.tryTimes++;
800 self.close();
810 return self.query(sql);
82 }
830 return deferred.reject(err);
84 }
850 self.tryTimes = 0;
860 return deferred.resolve(rows || []);
87 });
880 return deferred.promise;
89 });
90 },
91 /**
92 * 关闭连接
93 * @return {[type]} [description]
94 */
95 close: function(){
960 if (this.handle) {
970 this.handle.destroy();
980 this.handle = null;
99 }
100 }
101 };
102});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Driver/Template/EjsTemplate.js

100%
6
6
0
LineHitsSource
1/**
2 * ejs
3 * https://github.com/visionmedia/ejs
4 * @type {[type]}
5 */
61var ejs = require('ejs');
71module.exports = {
8 fetch: function(templateFile, tVar){
96 'use strict';
106 var content = getFileContent(templateFile);
116 var conf = extend({
12 filename: templateFile,
13 cache: true
14 }, C('tpl_engine_config'));
156 return ejs.compile(content, conf)(tVar);
16 }
17};

/Users/welefen/Develop/git/thinkjs/lib/Lib/Extend/Controller/RestController.js

6%
44
3
41
LineHitsSource
1/**
2 * REST Controller
3 * @return {[type]} [description]
4 */
51module.exports = Controller(function(){
61 'use strict';
71 return {
8 init: function(http){
90 this.super('init', http);
10 //资源名
110 this.resource = this.get('resource');
12 //资源id
130 this.id = this.get('id') | 0;
14 //实例化对应的模型
150 this.model = D(this.resource);
16 },
17 /**
18 * 获取
19 * @return {[type]} [description]
20 */
21 getAction: function(){
220 var self = this;
230 if (this.id) {
240 return this.model.getPk().then(function(pk){
250 return self.model.where(getObject(pk, self.id)).find();
26 }).then(function(data){
270 return self.success(data);
28 }).catch(function(err){
290 return self.error(err.message);
30 })
31 }
320 return this.model.select().then(function(data){
330 return self.success(data);
34 }).catch(function(err){
350 return self.error(err.message);
36 });
37 },
38 /**
39 * 新建
40 * @return {[type]} [description]
41 */
42 postAction: function(){
430 var self = this;
440 return this.model.getPk().then(function(pk){
450 var data = self.post();
460 if (isEmpty(data)) {
470 return self.error('data is empty');
48 }
490 delete data[pk];
500 return self.model.add(data);
51 }).then(function(insertId){
520 return self.success({id: insertId});
53 }).catch(function(err){
540 return self.error(err.message);
55 });
56 },
57 /**
58 * 删除
59 * @return {[type]} [description]
60 */
61 deleteAction: function(){
620 if (!this.id) {
630 return this.error('params error');
64 }
650 var self = this;
660 return this.model.getPk().then(function(pk){
670 return self.model.where(getObject(pk, self.id)).delete();
68 }).then(function(){
690 return self.success();
70 }).catch(function(err){
710 return self.error(err.message);
72 });
73 },
74 /**
75 * 更新
76 * @return {[type]} [description]
77 */
78 putAction: function(){
790 if (!this.id) {
800 return this.error('params error');
81 }
820 var self = this;
830 return this.model.getPk().then(function(pk){
840 var data = self.post();
850 if (isEmpty(data)) {
860 return self.error('data is empty');
87 }
880 delete data[pk];
890 return self.model.where(getObject(pk, self.id)).update(data);
90 }).then(function(){
910 return self.success();
92 }).catch(function(err){
930 return self.error(err.message);
94 });
95 },
96 __call: function(action){
970 return this.error('action `' + action + '` is not allowed');
98 }
99 }
100})

/Users/welefen/Develop/git/thinkjs/lib/Lib/Extend/Model/AdvModel.js

5%
230
12
218
LineHitsSource
1/**
2 * 高级模型
3 * @return {[type]} [description]
4 */
51module.exports = Model(function(){
61 'use strict';
7 //关联类型
81 global.HAS_ONE = 1;
91 global.BELONGS_TO = 2;
101 global.HAS_MANY = 3;
111 global.MANY_TO_MANY = 4;
12
13 //post的操作类型
141 var ADD = 'ADD';
151 var UPDATE = 'UPDATE';
161 var DELETE = 'DELETE';
17
18 //get时不同的type对应的回调
191 var mapTypeGetFn = {
20 1: '_getHasOneRelation',
21 2: '_getBelongsToRelation',
22 3: '_getHasManyRelation',
23 4: '_getManyToManyRelation'
24 };
25
26 //post时不同的type对应的回调
271 var mapTypePostFn = {
28 1: '_postHasOneRelation',
29 2: '_postBelongsToRelation',
30 3: '_postHasManyRelation',
31 4: '_postManyToManyRelation'
32 };
33
341 return {
35 /**
36 * 关联定义
37 * 数据格式:
38 * 'Profile': {
39 type: 1,
40 model: 'Profile',
41 name: 'Profile',
42 key: 'id',
43 fKey: 'user_id',
44 field: 'id,name',
45 where: 'name=xx',
46 order: '',
47 limit: ''
48 * }
49 * @type {Object}
50 */
51 relation: {},
52 /**
53 * 本次使用的关联名称,默认是全部使用
54 * @type {Boolean}
55 */
56 _relationName: true,
57 /**
58 * 只读字段
59 * @type {String}
60 */
61 readonlyField: '',
62 /**
63 * 保存时对数据进行校验
64 * @type {Boolean}
65 */
66 _validateField: true,
67 /**
68 * 字段类型
69 * @type {Object}
70 */
71 fieldType: {},
72 /**
73 * 设置本次使用的relation
74 * @param {[type]} name [description]
75 */
76 setRelation: function(name, value){
770 if (isObject(name) || !isEmpty(value)) {
780 var obj = isObject(name) ? name : getObject(name, value);
790 extend(this.relation, obj);
800 return this;
81 }
820 if (isString(name)) {
830 name = name.split(',');
84 }
850 this._relationName = name;
860 return this;
87 },
88 /**
89 * find后置操作
90 * @param {[type]} data [description]
91 * @return {[type]} [description]
92 */
93 _afterFind: function(data, parsedOptions){
940 return this.getRelation(data, parsedOptions);
95 },
96 /**
97 * select后置操作
98 * @param {[type]} data [description]
99 * @return {[type]} [description]
100 */
101 _afterSelect: function(data, parsedOptions){
1020 return this.getRelation(data, parsedOptions);
103 },
104 /**
105 * 获取关联的数据
106 * @param {[type]} data [description]
107 * @param Boolean isDataList 是否是数据列表
108 * @return {[type]}
109 */
110 getRelation: function(data, parsedOptions){
1110 if (isEmpty(data) || isEmpty(this.relation) || isEmpty(this._relationName)) {
1120 return data;
113 }
1140 var self = this;
1150 var promises = Object.keys(this.relation).map(function(key){
1160 var mapName, mapType, model, mapKey, mapfKey;
1170 var value = self.relation[key];
1180 if (!isObject(value)) {
1190 value = {type: value};
120 }
1210 mapName = value.name || key;
122 //如果不在开启的relation内,则直接返回
1230 if (self._relationName !== true && self._relationName.indexOf(mapName) === -1) {
1240 return;
125 }
1260 mapType = value.type || HAS_ONE;
1270 mapKey = value.key || self.getPk();
1280 mapfKey = value.fKey || (self.name.toLowerCase() + '_id');
1290 model = D(value.model || key);
1300 model.where(value.where).cache(parsedOptions.cache).field(value.field).order(value.order).limit(value.limit);
131 //调用不同的类型解析
1320 return self[mapTypeGetFn[mapType]](data, value, {
133 model: model,
134 mapName: mapName,
135 mapKey: mapKey,
136 mapfKey: mapfKey
137 }, parsedOptions);
138 });
1390 return Promise.all(promises).then(function(){
1400 return data;
141 });
142 },
143 _getHasOneRelation: function(data, value, mapOptions){
1440 var self = this;
1450 var where = self.parseRelationWhere(data, mapOptions.mapKey, mapOptions.mapfKey);
1460 if (where === false) {
1470 return {};
148 }
1490 mapOptions.model.where(where);
1500 return mapOptions.model.select().then(function(mapData){
1510 return self.parseRelationData(data, mapData, mapOptions.mapName, mapOptions.mapKey, mapOptions.mapfKey);
152 });
153 },
154 _getBelongsToRelation: function(data, value, mapOptions){
1550 var self = this;
1560 var mapKey, mapfKey;
1570 return mapOptions.model.getTableFields().then(function(){
1580 mapKey = mapOptions.model.getModelName().toLowerCase() + '_id';
1590 mapfKey = mapOptions.model.getPk();
1600 var where = self.parseRelationWhere(data, mapKey, mapfKey);
1610 if (where === false) {
1620 return {};
163 }
1640 mapOptions.model.where(where);
1650 return mapOptions.model.select().then(function(mapData){
1660 return self.parseRelationData(data, mapData, mapOptions.mapName, mapKey, mapfKey);
167 })
168 })
169 },
170 _getHasManyRelation: function(data, value, mapOptions){
1710 var self = this;
1720 var where = self.parseRelationWhere(data, mapOptions.mapKey, mapOptions.mapfKey);
1730 if (where === false) {
1740 return [];
175 }
1760 mapOptions.model.where(where);
1770 return mapOptions.model.select().then(function(mapData){
1780 return self.parseRelationData(data, mapData, mapOptions.mapName, mapOptions.mapKey, mapOptions.mapfKey, true);
179 });
180 },
181 _getManyToManyRelation: function(data, value, mapOptions, parsedOptions){
1820 var self = this;
1830 return mapOptions.model.getTableFields().then(function(){
1840 var where = self.parseRelationWhere(data, mapOptions.mapKey, mapOptions.mapfKey);
1850 if (where === false) {
1860 return [];
187 }
1880 var whereStr = self.db.parseWhere(where);
189 //关联的实体表和关系表联合查询
1900 var sql = 'SELECT b.%s, a.%s FROM %s as a, %s as b %s AND a.%s=b.%s %s';
1910 var queryData = [
192 value.field || '*',
193 mapOptions.mapfKey,
194 value.rTable || self.getRelationTableName(mapOptions.model),
195 mapOptions.model.getTableName(),
196 whereStr || 'WHERE ',
197 value.rfKey || (mapOptions.model.getModelName().toLowerCase() + '_id'),
198 mapOptions.model.getPk(),
199 value.where ? (' AND ' + value.where) : ''
200 ];
2010 return self.parseSql(sql, queryData).then(function(sql){
2020 return self.db.select(sql, parsedOptions.cache);
203 }).then(function(mapData){
2040 return self.parseRelationData(data, mapData, mapOptions.mapName, mapOptions.mapKey, mapOptions.mapfKey, true);
205 });
206 });
207 },
208 /**
209 * 多对多关系下,获取对应的关联表
210 * @return {[type]} [description]
211 */
212 getRelationTableName: function(model){
2130 var table = [
214 this.tablePrefix,
215 this.tableName || this.name,
216 '_',
217 model.getModelName()
218 ].join('');
2190 return table.toLowerCase();
220 },
221 /**
222 * 多堆垛关系下,回去对应关联表的模型
223 * @param {[type]} model [description]
224 * @return {[type]} [description]
225 */
226 getRelationModel: function(model){
2270 var name = ucfirst(this.tableName || this.name) + ucfirst(model.getModelName());
2280 return D(name);
229 },
230 /**
231 * 解析relation的where条件
232 * @param {[type]} data [description]
233 * @param {[type]} mapKey [description]
234 * @param {[type]} mapfKey [description]
235 * @return {[type]} [description]
236 */
237 parseRelationWhere: function(data, mapKey, mapfKey){
2380 if (isArray(data)) {
2390 var keys = {};
2400 data.forEach(function(item){
2410 keys[item[mapKey]] = 1;
242 })
2430 var value = Object.keys(keys);
2440 if (value.length === 0) {
2450 return false;
246 }
2470 return getObject(mapfKey, ['IN', value]);
248 }
2490 return getObject(mapfKey, data[mapKey]);
250 },
251 /**
252 * 解析查询后的数据
253 * @param {[type]} data [description]
254 * @param {[type]} mapData [description]
255 * @param {[type]} mapName [description]
256 * @param {[type]} mapKey [description]
257 * @param {[type]} mapfKey [description]
258 * @param {Boolean} isArrMap [description]
259 * @return {[type]} [description]
260 */
261 parseRelationData: function(data, mapData, mapName, mapKey, mapfKey, isArrMap){
2620 if (isArray(data)) {
263 //提前初始化,防止mapData为空导致data里的数据没有初始化的情况
2640 data.forEach(function(item, i){
2650 data[i][mapName] = isArrMap ? [] : {};
266 });
2670 mapData.forEach(function(mapItem){
2680 data.forEach(function(item, i){
2690 if (mapItem[mapfKey] !== item[mapKey]) {
2700 return;
271 }
2720 if (isArrMap) {
2730 data[i][mapName].push(mapItem);
274 }else{
2750 data[i][mapName] = mapItem;
276 }
277 });
278 });
279 }else{
2800 data[mapName] = isArrMap ? (mapData || []) : (mapData[0] || {});
281 }
2820 return data;
283 },
284 /**
285 * 添加后置操作
286 * @param {[type]} data [description]
287 * @param {[type]} parsedOptions [description]
288 * @return {[type]} [description]
289 */
290 _afterAdd: function(data, parsedOptions){
2910 return this.postRelation(ADD, data, parsedOptions);
292 },
293 /**
294 * 删除后置操作
295 * @param {[type]} data [description]
296 * @param {[type]} parsedOptions [description]
297 * @return {[type]} [description]
298 */
299 _afterDelete: function(data, parsedOptions){
3000 return this.postRelation(DELETE, data, parsedOptions);
301 },
302 /**
303 * 更新前置操作
304 * @param {[type]} data [description]
305 * @param {[type]} parsedOptions [description]
306 * @return {[type]} [description]
307 */
308 _beforeUpdate: function(data){
309 //只读字段处理
3100 if (!isEmpty(this.readonlyField)) {
3110 if (isString(this.readonlyField)) {
3120 this.readonlyField = this.readonlyField.split(',');
313 }
3140 this.readonlyField.forEach(function(field){
3150 delete data[field];
316 });
317 }
3180 return data;
319 },
320 /**
321 * 更新后置操作
322 * @param {[type]} data [description]
323 * @param {[type]} parsedOptions [description]
324 * @return {[type]} [description]
325 */
326 _afterUpdate: function(data, parsedOptions){
3270 return this.postRelation(UPDATE, data, parsedOptions);
328 },
329 /**
330 * 提交类关联操作
331 * @param {[type]} postType [description]
332 * @param {[type]} data [description]
333 * @param {[type]} parsedOptions [description]
334 * @return {[type]} [description]
335 */
336 postRelation: function(postType, data, parsedOptions){
3370 if (isEmpty(data) || isEmpty(this.relation) || isEmpty(this._relationName)) {
3380 return data;
339 }
3400 var self = this;
3410 var promises = [];
3420 Object.keys(this.relation).forEach(function(key){
3430 var promise, mapName, mapType, model, mapKey, mapfKey, mapData;
3440 var value = self.relation[key];
3450 if (!isObject(value)) {
3460 value = {type: value};
347 }
3480 mapName = value.name || key;
349 //如果没有开启对应的relation,则直接返回
3500 if (self._relationName !== true && self._relationName.indexOf(mapName) === -1) {
3510 return;
352 }
3530 mapData = data[mapName];
354 //如果没有对应的数据,则直接返回
3550 if (isEmpty(mapData) && postType !== DELETE) {
3560 return;
357 }
3580 mapKey = value.key || self.getPk();
3590 if (isEmpty(data[mapKey])) {
3600 return;
361 }
3620 mapType = value.type || HAS_ONE;
3630 mapfKey = value.fKey || (self.name.toLowerCase() + '_id');
3640 model = D(value.model || key);
3650 model.where(value.where);
366 //调用不同的类型解析
3670 promise = self[mapTypePostFn[mapType]](data, value, {
368 model: model,
369 mapName: mapName,
370 mapKey: mapKey,
371 mapfKey: mapfKey,
372 mapData: mapData,
373 type: postType
374 }, parsedOptions);
375
3760 promises.push(promise);
377 });
3780 return Promise.all(promises).then(function(){
3790 return data;
380 });
381 },
382 /**
383 * 一对一提交
384 * @param {[type]} data [description]
385 * @param {[type]} value [description]
386 * @param {[type]} mapOptions [description]
387 * @param {[type]} parsedOptions [description]
388 * @return {[type]} [description]
389 */
390 _postHasOneRelation: function(data, value, mapOptions){
3910 var promise = null;
3920 var where;
3930 switch(mapOptions.type){
394 case ADD:
3950 mapOptions.mapData[mapOptions.mapfKey] = data[mapOptions.mapKey];
3960 promise = mapOptions.model.add(mapOptions.mapData);
3970 break;
398 case DELETE:
3990 where = getObject(mapOptions.mapfKey, data[mapOptions.mapKey]);
4000 promise = mapOptions.model.where(where).delete();
4010 break;
402 case UPDATE:
4030 where = getObject(mapOptions.mapfKey, data[mapOptions.mapKey]);
4040 promise = mapOptions.model.where(where).update(mapOptions.mapData);
4050 break;
406 default:
4070 break;
408 }
4090 return promise;
410 },
411 _postBelongsToRelation: function(data){
4120 return data;
413 },
414 /**
415 * 一对多提交
416 * @param {[type]} data [description]
417 * @param {[type]} value [description]
418 * @param {[type]} mapOptions [description]
419 * @param {[type]} parsedOptions [description]
420 * @return {[type]} [description]
421 */
422 _postHasManyRelation: function(data, value, mapOptions){
4230 var type = mapOptions.type;
4240 var mapData = mapOptions.mapData;
4250 var model = mapOptions.model;
4260 var promise;
4270 if (!isArray(mapData)) {
4280 mapData = [mapData];
429 }
4300 switch(type){
431 case ADD:
4320 mapData = mapData.map(function(item){
4330 item[mapOptions.mapfKey] = data[mapOptions.mapKey];
434 });
4350 promise = model.addAll(mapData);
4360 break;
437 case UPDATE:
4380 promise = model.getTableFields().then(function(){
4390 var promises = [];
4400 var pk = model.getPk();
4410 mapData.forEach(function(item){
4420 var pro;
4430 if (item[pk]) {
4440 pro = model.update(item);
445 }else{
4460 item[mapOptions.mapfKey] = data[mapOptions.mapKey];
4470 pro = model.add(item);
448 }
4490 promises.push(pro);
450 });
4510 return Promise.all(promises);
452 });
4530 break;
454 case DELETE:
4550 var where = getObject(mapOptions.mapfKey, data[mapOptions.mapKey]);
4560 promise = model.where(where).delete();
4570 break;
458 }
4590 return promise;
460 },
461 /**
462 * 多对多提交
463 * @param Object data [description]
464 * @param object value [description]
465 * @param {[type]} mapOptions [description]
466 * @param {[type]} parsedOptions [description]
467 * @return {[type]} [description]
468 */
469 _postManyToManyRelation: function(data, value, mapOptions){
4700 var self = this;
4710 var model = mapOptions.model;
4720 var promise = model.getTableFields();
4730 var rfKey = value.rfKey || (model.getModelName().toLowerCase() + '_id');
474 //var relationTable = value.rTable || self.getRelationTableName(model);
4750 var where;
4760 var type = mapOptions.type;
4770 var mapData = mapOptions.mapData;
4780 var relationModel = self.getRelationModel(model);
4790 if (type === DELETE || type === UPDATE) {
4800 where = getObject(mapOptions.mapfKey, data[mapOptions.mapKey]);
4810 promise = promise.then(function(){
4820 return relationModel.where(where).delete();
483 });
484 }
4850 if (type === ADD || type === UPDATE) {
4860 promise = promise.then(function(){
4870 if (!isArray(mapData)) {
4880 mapData = isString(mapData) ? mapData.split(',') : [mapData];
489 }
4900 var firstItem = mapData[0];
491 //关系数据
4920 if (isNumberString(firstItem) || (isObject(firstItem) && (rfKey in firstItem))) {
493 //生成要更新的数据
4940 var postData = mapData.map(function(item){
4950 var key = [mapOptions.mapfKey, rfKey];
4960 var val = [data[mapOptions.mapKey], item[rfKey] || item];
4970 return getObject(key, val);
498 });
4990 return relationModel.addAll(postData);
500 }else{ //实体数据
5010 var unqiueField = model.getUniqueField();
5020 if (!unqiueField) {
5030 return getPromise(model.getTableName() + ' table has no unqiue field', true);
504 }
5050 return self._getRalationAddIds(mapData, model, unqiueField).then(function(ids){
5060 var postData = ids.map(function(id){
5070 var key = [mapOptions.mapfKey, rfKey];
5080 var val = [data[mapOptions.mapKey], id];
5090 return getObject(key, val);
510 });
5110 return relationModel.addAll(postData);
512 });
513 }
514 });
515 }
5160 return promise;
517 },
518 /**
519 * 插入数据,并获取插入的id集合
520 * @param {[type]} dataList [description]
521 * @param {[type]} model [description]
522 * @param {[type]} unqiueField [description]
523 * @return {[type]} [description]
524 */
525 _getRalationAddIds: function(dataList, model, unqiueField){
5260 var promises = [];
5270 var ids = [];
5280 dataList.forEach(function(item){
5290 if (!isObject(item)) {
5300 item = getObject(unqiueField, item);
531 }
5320 var value = item[unqiueField];
5330 if (!value) {
5340 return true;
535 }
5360 var where = getObject(unqiueField, value);
5370 var promise = model.where(where).field(model.getPk()).find().then(function(data){
5380 if (isEmpty(data)) {
5390 return model.add(item).then(function(insertId){
5400 ids.push(insertId);
541 });
542 }else{
5430 ids.push(data[model.getPk()]);
544 }
545 });
5460 promises.push(promise);
547 });
5480 return Promise.all(promises).then(function(){
5490 return ids;
550 });
551 },
552 /**
553 * 设置是否对数据进行校验
554 * @param {[type]} validate [description]
555 * @return {[type]} [description]
556 */
557 validate: function(validate){
5580 this._validateField = validate;
559 }
560 };
561});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Util/Behavior.js

100%
7
7
0
LineHitsSource
1/**
2 * 行为类
3 * @return {[type]} [description]
4 */
51module.exports = Class(function(){
61 'use strict';
71 return {
8 options: {}, //行为选项
9 http: null,
10 init: function(http){
1120 this.http = http;
1220 for(var name in this.options){
1316 if (C(name) !== undefined) {
1414 this.options[name] = C(name);
15 }
16 }
17 },
18 run: function(){
19
20 }
21 };
22});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Util/Cache.js

66%
54
36
18
LineHitsSource
1/**
2 * 缓存基类
3 * @return {[type]} [description]
4 */
5/**
6 * 缓存数据
7 * @type {Object}
8 */
91var cacheData = {};
10/**
11 * 定时器
12 * @type {Number}
13 */
141var gcTimer = {};
15/**
16 * 清除已经过期的Cache
17 * @return {[type]} [description]
18 */
191var gc = function(instance){
2031 'use strict';
2131 if (APP_DEBUG || APP_MODE === 'cli' || gcTimer[instance.gcType]) {
2231 return;
23 }
240 gcTimer[instance.gcType] = setInterval(function(){
250 var hour = (new Date()).getHours();
260 if (C('cache_gc_hour').indexOf(hour) === -1) {
270 return;
28 }
290 var now = Date.now();
300 if (instance.gc) {
310 console.log('gc clean: ', instance.gcType, (new Date()).toUTCString());
320 instance.gc(now);
33 }
34 }, 3600 * 1000);
35};
36
371module.exports = Class(function(){
381 'use strict';
391 return {
40 /**
41 * gc的类型,用于定时器类型判断
42 * @type {String}
43 */
44 gcType: 'Cache',
45 /**
46 * 初始化
47 * @param {[type]} options [description]
48 * @return {[type]} [description]
49 */
50 init: function(options){
5131 options = options || {};
5231 if (options.cacheData) {
530 this.cacheData = options.cacheData;
54 }else{
5531 this.cacheData = cacheData;
56 }
5731 if (options.gcType) {
580 this.gcType = options.gcType;
59 }
6031 if (!options.timeout) {
6120 options.timeout = C('cache_timeout')
62 }
6331 this.options = options;
64 //操作的key
6531 this.key = '';
66 //是否更新expire值
6731 this.updateExpire = false;
6831 gc(this);
69 },
70 /**
71 * 获取缓存值,返回一个promise
72 * @param {[type]} name [description]
73 * @return {[type]} [description]
74 */
75 get: function(name){
765 var key = this.key || name;
775 if (!(key in this.cacheData)) {
780 return getPromise();
79 }
805 var value = this.cacheData[key];
815 if (Date.now() > value.expire) {
822 delete this.cacheData[key];
832 return getPromise();
84 }
853 if (this.updateExpire) {
860 this.cacheData[key].expire = Date.now() + value.timeout * 1000;
87 }
883 return getPromise(value.data[name]);
89 },
90 /**
91 * 设置缓存值
92 * @param {[type]} name [description]
93 * @param {[type]} value [description]
94 */
95 set: function(name, value, timeout){
966 if (timeout === undefined) {
970 timeout = this.options.timeout;
98 }
996 var key = this.key || name;
1006 if (key in this.cacheData) {
1010 this.cacheData[key].data[name] = value;
102 }else{
1036 this.cacheData[key] = {
104 data: getObject(name, value),
105 timeout: timeout,
106 expire: Date.now() + timeout * 1000
107 };
108 }
1096 return getPromise();
110 },
111 /**
112 * 移除缓存值
113 * @param {[type]} name [description]
114 * @return {[type]} [description]
115 */
116 rm: function(name){
1171 var key = this.key || name;
1181 if (key in this.cacheData) {
1191 delete this.cacheData[key].data[name];
120 }
1211 return getPromise();
122 },
123 /**
124 * gc
125 * @param {[type]} now [description]
126 * @return {[type]} [description]
127 */
128 gc: function(now){
1290 for(var key in this.cacheData){
1300 var item = this.cacheData[key] || {};
1310 if (now > item.expire) {
1320 delete this.cacheData[key];
133 }
134 }
135 }
136 };
137});

/Users/welefen/Develop/git/thinkjs/lib/Lib/Util/Cookie.js

100%
35
35
0
LineHitsSource
1/**
2 * cookie操作
3 * @type {Object}
4 */
51module.exports = {
6 /**
7 * 解析
8 * @param {[type]} str [description]
9 * @return {[type]} [description]
10 */
11 parse: function(str){
1218 'use strict';
1318 var data = {};
1418 str.split(/; */).forEach(function(item) {
1535 var pos = item.indexOf('=');
1635 if (pos === -1) {
176 return;
18 }
1929 var key = item.substr(0, pos).trim();
2029 var val = item.substr(pos + 1).trim();
2129 if ('"' === val[0]) {
222 val = val.slice(1, -1);
23 }
24 // only assign once
2529 if (undefined === data[key]) {
2629 try {
2729 data[key] = decodeURIComponent(val);
28 } catch (e) {
292 data[key] = val;
30 }
31 }
32 });
3318 return data;
34 },
35 /**
36 * 格式化
37 * @param {[type]} name [description]
38 * @param {[type]} val [description]
39 * @param {[type]} options [description]
40 * @return {[type]} [description]
41 */
42 stringify: function(name, value, options){
4363 'use strict';
4463 options = options || {};
4563 var item = [name + '=' + encodeURIComponent(value)];
4663 if (options.maxage) {
471 item.push('Max-Age=' + options.maxage);
48 }
4963 if (options.domain) {
501 item.push('Domain=' + options.domain);
51 }
5263 if (options.path) {
5353 item.push('Path=' + options.path);
54 }
5563 var expires = options.expires;
5663 if (expires){
572 if (!isDate(expires)) {
581 expires = new Date(expires);
59 }
602 item.push('Expires=' + expires.toUTCString());
61 }
6263 if (options.httponly) {
631 item.push('HttpOnly');
64 }
6563 if (options.secure) {
661 item.push('Secure');
67 }
6863 return item.join('; ');
69 }
70}

/Users/welefen/Develop/git/thinkjs/lib/Lib/Util/Filter.js

80%
57
46
11
LineHitsSource
1/**
2 * 过滤器
3 * @return {[type]} [description]
4 */
51var Filter = module.exports = {
6 /**
7 * 分页
8 * @param {[type]} value [description]
9 * @return {[type]} [description]
10 */
11 page: function(value){
126 'use strict';
136 return this.id(value) || 1;
14 },
15 /**
16 * xxx asc,yyy desc
17 * @return {[type]} [description]
18 */
19 order: function(value){
206 'use strict';
216 if (isString(value)) {
226 value = value.split(',');
23 }
246 if (!isArray(value)) {
250 return '';
26 }
276 return value.filter(function(item){
288 item = item.trim().split(' ');
298 var field = item[0];
308 var type = item[1];
318 if (/^(ASC|DESC)$/i.test(type) && /^[\w]+$/.test(field)) {
326 return field + ' ' + type;
33 }
34 }).join(',');
35 },
36 /**
37 * 大于0
38 * @return {[type]} [description]
39 */
40 id: function(value){
4114 'use strict';
4214 value = parseInt(value + '', 10);
4314 if (value > 0) {
447 return value;
45 }
467 return 0;
47 },
48 /**
49 * id列表
50 * @return {[type]} [description]
51 */
52 ids: function(value, split){
535 'use strict';
545 if (isNumber(value)) {
552 value = this.id(value);
562 if (value) {
571 return [value];
58 }
591 return [];
60 }
613 if (isString(value)) {
622 value = value.split(split || ',');
63 }
643 if (!isArray(value)) {
651 return [];
66 }
672 var ret = [];
682 for(var i = 0, length = value.length; i < length; i++){
693 var item = (value[i] + '').trim();
703 item = parseInt(item, 10);
713 if (item > 0) {
723 ret.push(item);
73 }
74 }
752 return ret;
76 },
77 /**
78 * 是否在一个中
79 * @param {[type]} value [description]
80 * @param {[type]} arr [description]
81 * @return {[type]} [description]
82 */
83 in: function(value, arr){
841 'use strict';
851 if (!isArray(arr)) {
860 arr = [arr];
87 }
881 if(arr.indexOf(value) > -1){
890 return value;
90 }
911 return '';
92 },
93 /**
94 * 将字符串切割为数组
95 * @param {[type]} value [description]
96 * @param {[type]} split [description]
97 * @return {[type]} [description]
98 */
99 strs: function(value, split){
1000 'use strict';
1010 if (isString(value)) {
1020 value = value.split(split || ',');
103 }
1040 if (!isArray(value)) {
1050 return [];
106 }
1070 return value.filter(function(item){
1080 return (item + '').trim();
109 });
110 }
111};
112/**
113 * 调用一个过滤器
114 * @param {[type]} data [description]
115 * @param {[type]} type [description]
116 * @return {[type]} [description]
117 */
1181Filter.filter = function(value, type){
11924 'use strict';
12024 var fn = Filter[type];
12124 if (typeof fn === 'function') {
12224 var args = [].slice.call(arguments, 2);
12324 args.unshift(value);
12424 return Filter[type].apply(Filter, args);
125 }
1260 return false;
127};

/Users/welefen/Develop/git/thinkjs/lib/Lib/Util/Session.js

92%
54
50
4
LineHitsSource
11var crypto = require('crypto');
2/**
3 * 生成uid
4 * @param int length
5 * @return string
6 */
71var uid = function(length){
83 'use strict';
93 var ratio = Math.log(64) / Math.log(256);
103 var numbytes = Math.ceil(length * ratio);
113 var str = crypto.randomBytes(numbytes).toString('base64').slice(0, length);
123 return str.replace(/\+/g, '_').replace(/\//g, '-');
13};
14/**
15 * 生成cookie签名
16 * @param string val
17 * @param string secret
18 * @return string
19 */
201var cookieSign = function(val, secret){
215 'use strict';
225 secret = crypto.createHmac('sha256', secret).update(val).digest('base64');
235 secret = secret.replace(/\=+$/, '');
245 return val + '.' + secret;
25};
26/**
27 * 解析cookie签名
28 * @param {[type]} val
29 * @param {[type]} secret
30 * @return {[type]}
31 */
321var cookieUnsign = function(val, secret){
333 'use strict';
343 var str = val.slice(0, val.lastIndexOf('.'));
353 return cookieSign(str, secret) === val ? str : '';
36};
37
381var Session = module.exports = Cache(function(){
391 'use strict';
401 return {
41 init: function(options){
421 this.super_('init', options);
431 this.key = this.options.cookie;
441 this.updateExpire = true;
45 }
46 };
47});
48
491Session.start = function(http){
5016 'use strict';
5116 if (http.session) {
5211 return http.session;
53 }
545 var name = C('session_name');
55 //是否使用签名
565 var secret = C('session_sign');
575 var cookie = http.cookie[name];
585 if (cookie && secret) {
593 cookie = cookieUnsign(cookie, secret);
603 if (cookie) {
611 http.cookie[name] = cookie;
62 }
63 }
645 var session_cookie = cookie;
655 if (!cookie) {
663 cookie = uid(32);
673 session_cookie = cookie;
683 if (secret) {
692 cookie = cookieSign(cookie, secret);
70 }
71 //将生成的cookie放在http.cookie对象上,方便程序内读取
723 http.cookie[name] = cookie;
733 http.setCookie(name, cookie, C('session_options'));
74 }
755 var type = C('session_type');
765 if (!type) {
771 if (APP_DEBUG) {
780 type = 'File';
790 console.log("in debug mode, session can't use memory type for storage, convert to File type");
801 }else if (C('use_cluster')) {
810 type = 'File';
820 console.log("in cluster mode, session can't use memory type for storage, convert to File type");
83 }
84 }
855 name = type + 'Session';
86 //session类
875 var session = http.session = thinkRequire(name)({
88 cookie: session_cookie,
89 timeout: C('session_timeout')
90 });
91 //afterend时刷新缓存
925 http.on('afterEnd', function(){
93 //刷新session
9429 return session.flush && session.flush();
95 })
965 return cookie;
97};

/Users/welefen/Develop/git/thinkjs/lib/Lib/Util/Valid.js

100%
101
101
0
LineHitsSource
1/**
2 * Valid
3 * @return {[type]} [description]
4 */
51var net = require('net');
6
71var Valid = {
8 /**
9 * 长度区域
10 * @param {[type]} min [description]
11 * @param {[type]} max [description]
12 * @return {[type]} [description]
13 */
14 length: function(value, min, max){
156 'use strict';
166 min = min | 0;
176 var length = ((value || '') + '').length;
186 if (length < min) {
192 return false;
20 }
214 if (max && length > max) {
221 return false;
23 }
243 return true;
25 },
26 /**
27 * 必填
28 * @return {[type]} [description]
29 */
30 required: function(value){
3113 'use strict';
3213 return ((value || '') + '').length > 0;
33 },
34 /**
35 * 自定义正则校验
36 * @param {[type]} reg [description]
37 * @return {[type]} [description]
38 */
39 regexp: function(value, reg){
4017 'use strict';
4117 return reg.test(value);
42 },
43 /**
44 * 邮箱
45 * @return {[type]} [description]
46 */
47 email: function(value){
484 'use strict';
494 var reg = /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/;
504 return this.regexp(value, reg);
51 },
52 /**
53 * 时间戳
54 * @return {[type]} [description]
55 */
56 time: function(value){
572 'use strict';
582 var reg = /^[1-5]\d{12}$/;
592 return this.regexp(value, reg);
60 },
61 /**
62 * 中文名
63 * @return {[type]} [description]
64 */
65 cnname: function(value){
663 'use strict';
673 var reg = /^[\u4e00-\u9fa5\u3002\u2022]{2,32}$/;
683 return this.regexp(value, reg);
69 },
70 /**
71 * 身份证号码
72 * @return {[type]} [description]
73 */
74 idnumber: function(value){
753 'use strict';
763 if (/^\d{15}$/.test(value)) {
771 return true;
78 }
792 if ((/^\d{17}[0-9xX]$/).test(value)) {
801 var vs = '1,0,x,9,8,7,6,5,4,3,2'.split(','),
81 ps = '7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2'.split(','),
82 ss = value.toLowerCase().split(''),
83 r = 0;
841 for (var i = 0; i < 17; i++) {
8517 r += ps[i] * ss[i];
86 }
871 var isOk = (vs[r % 11] === ss[17]);
881 return isOk;
89 }
901 return false;
91 },
92 /**
93 * 手机号
94 * @return {[type]} [description]
95 */
96 mobile: function(value){
972 'use strict';
982 var reg = /^(13|15|18|14|17)\d{9}$/;
992 return this.regexp(value, reg);
100 },
101 /**
102 * 邮编
103 * @return {[type]} [description]
104 */
105 zipcode: function(value){
1062 'use strict';
1072 var reg = /^\d{6}$/;
1082 return this.regexp(value, reg);
109 },
110 /**
111 * 2次值是否一致
112 * @param {[type]} field [description]
113 * @return {[type]} [description]
114 */
115 confirm: function(value, cvalue){
1162 'use strict';
1172 return value === cvalue;
118 },
119 /**
120 * url
121 * @return {[type]} [description]
122 */
123 url: function(value){
1242 'use strict';
1252 var reg = /^http(s?):\/\/(?:[A-za-z0-9-]+\.)+[A-za-z]{2,4}(?:[\/\?#][\/=\?%\-&~`@[\]\':+!\.#\w]*)?$/;
1262 return this.regexp(value, reg);
127 },
128 /**
129 * 整数
130 * @param {[type]} o [description]
131 * @return {[type]} [description]
132 */
133 int: function(value){
1346 'use strict';
1356 var val = parseInt(value, 10);
1366 if (isNaN(val)) {
1371 return false;
138 }
1395 return (val + '').length === value.length;
140 },
141 /**
142 * 浮点数
143 * @return {[type]} [description]
144 */
145 float: function(value){
1462 'use strict';
1472 return isNumberString(value);
148 },
149 /**
150 * 整数范围
151 * @param {[type]} min [description]
152 * @param {[type]} max [description]
153 * @return {[type]} [description]
154 */
155 range: function(value, min, max){
1564 'use strict';
1574 value = parseInt(value, 10);
1584 min = min | 0;
1594 if (isNaN(value) || value < min) {
1601 return false;
161 }
1623 if (max && value > max) {
1631 return false;
164 }
1652 return true;
166 },
167 /**
168 * ip4校验
169 * @return {[type]} [description]
170 */
171 ip4: function(value){
1722 'use strict';
1732 return net.isIPv4(value);
174 },
175 /**
176 * ip6校验
177 * @return {[type]} [description]
178 */
179 ip6: function(value){
1801 'use strict';
1811 return net.isIPv6(value);
182 },
183 /**
184 * ip校验
185 * @return {[type]} [description]
186 */
187 ip: function(value){
1881 'use strict';
1891 return net.isIP(value);
190 },
191 /**
192 * 日期校验
193 * @return {[type]} [description]
194 */
195 date: function(value){
1962 'use strict';
1972 var reg = /^\d{4}-\d{1,2}-\d{1,2}$/;
1982 return this.regexp(value, reg);
199 },
200 /**
201 * 在一个范围内
202 * @param {[type]} value [description]
203 * @param {[type]} arr [description]
204 * @return {[type]} [description]
205 */
206 in: function(value, arr){
2071 'use strict';
2081 return arr.indexOf(value) > -1;
209 }
210};
211/**
212 * data格式
213 * [{
214 * value: xxx,
215 * name: '',
216 * valid: ['required', 'range'],
217 * range_args: [],
218 * msg:{
219 * required: '',
220 * range: ''
221 * }
222 * },{
223 * value: xxx,
224 * name: '',
225 * valid: ['required', 'range'],
226 * range_args: [],
227 * msg:{
228 * required: '',
229 * range: ''
230 * }
231 * }]
232 * @param {[type]} data [description]
233 * @return {[type]} [description]
234 */
2351module.exports = function(data){
23657 'use strict';
23757 if (!data) {
2381 return true;
239 }
24056 if (!isArray(data)) {
24148 data = [data];
242 }
24356 var result = {};
24456 data.forEach(function(item){
24561 var valid = item.valid;
24661 if (!isArray(valid)) {
24753 valid = [valid];
248 }
24961 valid.some(function(validItem){
25063 var flag = true;
251 //自定义检测方法
25263 if (isFunction(validItem)) {
2534 flag = validItem(item.value, item);
2544 if (isString(flag)) {
2553 result[item.name] = flag;
2563 flag = false;
257 }
25859 }else if(!isFunction(Valid[validItem])){
2591 throw new Error(validItem + ' is not valid');
260 }else{
26158 var args = item[validItem + '_args'] || [];
26258 if (!isArray(args)) {
2633 args = [args];
264 }
26558 args = [item.value].concat(args);
26658 flag = Valid[validItem].apply(Valid, args);
26758 if (flag === false) {
26833 var msg = (isObject(item.msg) ? item.msg[validItem] : item.msg) || '';
26933 msg = msg.replace('{name}', item.name).replace('{value}', item.value);
27033 result[item.name] = msg;
271 }
272 }
27362 return !flag;
274 });
275 });
27655 return result;
277};

/Users/welefen/Develop/git/thinkjs/lib/Lib/Util/WebSocket.js

8%
107
9
98
LineHitsSource
11var thinkHttp = thinkRequire('Http');
21var url = require('url');
31var websocket = require('websocket').server;
41var querystring = require('querystring');
5
61var WebSocket = module.exports = Class(function(){
71 'use strict';
8 /**
9 * socket初始化id
10 * @type {Number}
11 */
121 var socketId = 1000;
131 return {
14 init: function(httpServer, app){
150 this.httpServer = httpServer;
160 this.app = app;
17 },
18 /**
19 * 检测origin是否合法
20 * @param {[type]} origin [description]
21 * @return {[type]} [description]
22 */
23 originIsAllowed: function(origin){
240 var allowOrigins = C('websocket_allow_origin');
250 if (!allowOrigins) {
260 return true;
27 }
280 var info = url.parse(origin);
290 var hostname = info.hostname;
300 if (isString(allowOrigins) && allowOrigins === hostname) {
310 return true;
320 }else if (isArray(allowOrigins) && allowOrigins.indexOf(hostname) > -1) {
330 return true;
340 }else if (isFunction(allowOrigins)) {
350 return allowOrigins(hostname, info);
36 }
370 return false;
38 },
39 /**
40 * 选择子协议
41 * @param {[type]} protocolFullCaseMap [description]
42 * @return {[type]} [description]
43 */
44 getSubProtocal: function(protocolFullCaseMap){
450 var selectedProtocal = C('websocket_sub_protocal');
460 if (isFunction(selectedProtocal)) {
470 var subProtocals = Object.values(protocolFullCaseMap);
480 selectedProtocal = selectedProtocal(subProtocals);
49 }
500 return selectedProtocal;
51 },
52 /**
53 * 建立连接处理
54 * @param {[type]} request [description]
55 * @return {[type]} [description]
56 */
57 openHandle: function(request, protocal){
580 var req = request.httpRequest;
590 if (req.url === '/') {
600 return getPromise([]);
61 }
620 var deferred = getDefer();
630 var fn = function(){};
640 var res = {setHeader: fn, end: fn, write: fn};
650 var self = this;
660 thinkHttp(req, res).run(function(http){
670 http.websocket = request.socket;
68 //子协议
690 http.websocket_sub_protocal = protocal;
700 self.app.listener(http).then(function(){
710 deferred.resolve({
72 cookie: Object.values(http._cookie),
73 http: http
74 });
75 }).catch(function(err){
760 deferred.reject(err);
77 })
78 });
790 return deferred.promise;
80 },
81 /**
82 * 消息处理
83 * @return {[type]} [description]
84 */
85 messageHandle: function(message, connection, app, type){
860 if (type !== 'utf8') {
870 connection.socket.send(WebSocket.ERROR_MESSAGE.TYPE_ERROR, message + ' is not valid json');
880 return;
89 }
90 //解析数据
910 try{
920 message = JSON.parse(message);
93 }catch(e){
940 connection.socket.send(WebSocket.ERROR_MESSAGE.INVALID_JSON, message + ' is not valid json');
950 return;
96 }
970 if (message.jsonrpc !== '2.0') {
980 connection.socket.send(WebSocket.ERROR_MESSAGE.INVALID_JSONRPC, 'data.jsonrpc must be 2.0');
990 return;
100 }
1010 var method = message.method + '';
1020 if (!method) {
1030 connection.socket.send(WebSocket.ERROR_MESSAGE.INVALID_METHOD, 'data.method is not valid');
1040 return;
105 }
1060 var pars = message.params;
1070 var headers = {};
1080 if (isObject(message.params.headers)) {
1090 headers = message.params.headers;
1100 pars = message.params.data;
111 }
1120 if (isObject(pars)) {
1130 method += (method.indexOf('?') > -1 ? '&' : '?') + querystring.stringify(pars)
114 }
1150 var self = this;
1160 var data = {
117 host: '',
118 url: method,
119 headers: headers,
120 write: function(data, encoding, errMsg){
1210 var pars = self.getRPCData(JSON.parse(data), errMsg);
1220 pars.id = message.id;
1230 connection.send(JSON.stringify(pars));
124 },
125 end: function(data){
1260 if (data) {
1270 this.write(data);
128 }
1290 connection.close();
130 }
131 }
1320 var defaultHttp = thinkHttp.getDefaultHttp(data);
1330 var httpInstance = thinkHttp(defaultHttp.req, defaultHttp.res);
134 //将websocket实例添加到http对象上
1350 httpInstance.http.websocket = connection.socket;
1360 httpInstance.run(app.listener);
137 },
138 /**
139 * 获取rpc数据对象
140 * @param {[type]} data [description]
141 * @param {[type]} errMsg [description]
142 * @return {[type]} [description]
143 */
144 getRPCData: function(data, errMsg){
1450 var pars = {jsonrpc: '2.0'};
1460 if (errMsg) {
1470 pars.error = {code: data, message: errMsg};
148 }else{
1490 pars.result = data;
150 }
1510 return pars;
152 },
153 run: function(){
1540 var instance = new websocket({
155 httpServer: this.httpServer,
156 autoAcceptConnections: false
157 });
1580 var self = this;
1590 instance.on('request', function(request){
160 //检测origin
1610 if (!self.originIsAllowed(request.origin)) {
1620 return request.reject();
163 }
1640 var socket = request.socket;
1650 socket.id = socketId++;
1660 socket.activeTime = Date.now();
167 //选择子协议
1680 var protocal = self.getSubProtocal(request.protocolFullCaseMap);
1690 return self.openHandle(request, protocal).then(function(data){
1700 var connection = socket.connection = request.accept(protocal, request.origin, data.cookie);
1710 socket.close = function(){
1720 connection.close();
173 }
1740 if (!socket.send) {
1750 socket.send = function(data, errMsg){
1760 var pars = self.getRPCData(data, errMsg);
1770 connection.send(JSON.stringify(pars));
178 }
179 }
1800 var messageHandle = C('websocket_message_handle');
1810 connection.on('message', function(message) {
1820 socket.activeTime = Date.now();
1830 var data = message.type === 'utf8' ? message.utf8Data : message.binaryData;
1840 if (isFunction(messageHandle)) {
1850 messageHandle(data, connection, self.app, message.type);
186 }else{
1870 self.messageHandle(data, connection, self.app, message.type);
188 }
189 });
1900 connection.on('close', function() {
1910 data.http.emit('websocket.close');
192 });
193 }).catch(function(err){
1940 request.reject(err);
195 })
196 })
197 }
198 }
199});
200/**
201 * 错误信息
202 * @type {Object}
203 */
2041WebSocket.ERROR_MESSAGE = {
205 TYPE_ERROR: -100001, //数据类型错误
206 INVALID_JSON: -100002, //不是合法的json
207 INVALID_JSONRPC: -100003, //不是jsonrpc数据格式
208 INVALID_METHOD: -100004 //请求方法不合法
209}

/Users/welefen/Develop/git/thinkjs/lib/think.js

100%
12
12
0
LineHitsSource
11var path = require('path');
21var fs = require('fs');
3
4//APP根目錄
51global.APP_PATH = global.APP_PATH ? path.normalize(global.APP_PATH) : path.dirname(__dirname) + '/App';
6//RUNTIME目录
71global.RUNTIME_PATH = global.RUNTIME_PATH ? path.normalize(global.RUNTIME_PATH) : global.APP_PATH + '/Runtime';
8//DEBUG模式
91global.APP_DEBUG = global.APP_DEBUG || false;
10//静态资源文件的根目录
111global.RESOURCE_PATH = global.RESOURCE_PATH || '';
12//THINKJS的根目录
131global.THINK_PATH = __dirname;
14//默认为http模式
151global.APP_MODE = global.APP_MODE || '';
16//命令行模式
171if (process.argv[2]) {
181 APP_MODE = 'cli';
19}
20//从package.json文件里获取版本号
211global.THINK_VERSION = JSON.parse(fs.readFileSync(global.THINK_PATH + '/../package.json', 'utf8')).version;
22//启动
231require(global.THINK_PATH + '/Lib/Core/Think.js').start();