Coverage

68%
3295
2246
1049

/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 () {
23214 function T(args) {
24214 for(var name in cls.__prop){
25702 var val = cls.__prop[name];
26702 this[name] = isObject(val) ? extend({}, val) : val;
27 }
28 //自动执行init方法
29214 if(isFunction(this.init)){
30 //获取init返回值,如果返回一个promise,可以让后续执行在then之后
31214 this.__initReturn = this.init.apply(this, args);
32 }
33214 return this;
34 }
35214 T.prototype = cls.prototype;
36214 T.constructor = cls;
37214 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){
47334 var val = prop[name];
48334 if (isFunction(val)) {
49293 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方法
7451 if (!this[name]) {
751 return;
76 }
7750 var super_ = this.constructor.super_;
78 //如果父级没有这个方法,那么直接返回
7950 if (!isFunction(super_.prototype[name])) {
801 return;
81 }
82 //如果参数不是数组,自动转为数组
8349 if (!isArray(data)) {
8449 data = [data];
85 }
8649 while(1){
8750 if (this[name] === super_.prototype[name] && super_.super_) {
881 super_ = super_.super_;
89 }else{
9049 break;
91 }
92 }
9349 var method = super_.prototype[name];
9449 delete super_.prototype[name];
9549 var ret = method.apply(this, data);
9649 super_.prototype[name] = method;
9749 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(){
1091163 'use strict';
1101163 var args = [].slice.call(arguments);
1111163 var deep = true;
1121163 var target = args.shift();
1131163 if (isBoolean(target)) {
114511 deep = target;
115511 target = args.shift();
116 }
1171163 target = target || {};
1181163 var length = args.length;
1191163 var options, name, src, copy, copyAsArray, clone;
1201163 for(var i = 0; i < length; i++){
1211538 options = args[i] || {};
1221538 if (isFunction(options)) {
1231 options = options();
124 }
1251538 for(name in options){
1261988 src = target[name];
1271988 copy = options[name];
1281988 if (src === copy) {
129298 continue;
130 }
1311690 if (deep && copy && (isObject(copy) || (copyAsArray = isArray(copy) ))) {
132509 if (copyAsArray) {
133278 copyAsArray = false;
134278 clone = src && isArray(src) ? src : [];
135 }else{
136231 clone = src && isObject(src) ? src : {};
137 }
138509 target[name] = extend(deep, clone, copy);
1391181 }else if (copy !== undefined) {
1401181 target[name] = copy;
141 }
142 }
143 }
1441163 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){
1571401 'use strict';
1581401 return toString.call(obj) === '[object Boolean]';
159};
160/**
161 * 是否是数字
162 * @param {[type]} obj [description]
163 * @return {Boolean} [description]
164 */
1651global.isNumber = function(obj){
166572 'use strict';
167572 return toString.call(obj) === '[object Number]';
168};
169/**
170 * 是否是个对象
171 * @param {[type]} obj [description]
172 * @return {Boolean} [description]
173 */
1741global.isObject = function(obj){
1753843 'use strict';
1763843 if (isBuffer(obj)) {
1772 return false;
178 }
1793841 return toString.call(obj) === '[object Object]';
180};
181/**
182 * 是否是字符串
183 * @param {[type]} obj [description]
184 * @return {Boolean} [description]
185 */
1861global.isString = function(obj){
1872957 'use strict';
1882957 return toString.call(obj) === '[object String]';
189};
190/**
191 * 是否是个function
192 * @param {[type]} obj [description]
193 * @return {Boolean} [description]
194 */
1951global.isFunction = function(obj){
1962745 'use strict';
1972745 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){
21345 'use strict';
21445 return util.isRegExp(obj);
215};
216/**
217 * 是否是个错误
218 * @param {[type]} obj [description]
219 * @return {Boolean} [description]
220 */
2211global.isError = function(obj){
2224 'use strict';
2234 return util.isError(obj);
224};
225/**
226 * 判断对象是否为空
227 * @param {[type]} obj
228 * @return {Boolean}
229 */
2301global.isEmpty = function(obj){
231603 'use strict';
232603 if (isObject(obj)) {
233329 var key;
234329 for(key in obj){
235278 return false;
236 }
23751 return true;
238274 }else if (isArray(obj)) {
23996 return obj.length === 0;
240178 }else if (isString(obj)) {
2412 return obj.length === 0;
242176 }else if (isNumber(obj)) {
2434 return obj === 0;
244172 }else if (obj === null || obj === undefined) {
245169 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){
257147 'use strict';
258147 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){
278122 'use strict';
279122 if (!fs.existsSync(p)) {
28077 return false;
281 }
28245 var stats = fs.statSync(p);
28345 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){
319532 'use strict';
320532 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){
35183 'use strict';
35283 mode = mode || '0777';
35383 if (fs.existsSync(p)) {
35475 chmod(p, mode);
35575 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){
418116 'use strict';
419116 mode = mode || '0777';
420116 if (!fs.existsSync(p)) {
4211 return true;
422 }
423115 return fs.chmodSync(p, mode);
424};
425/**
426 * 获取文件内容
427 * @param {[type]} file [description]
428 * @return {[type]} [description]
429 */
4301global.getFileContent = function(file, encoding){
43118 'use strict';
43218 if (!fs.existsSync(file)) {
4333 return '';
434 }
43515 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){
4551849 'use strict';
4561849 name = (name || '') + '';
4571849 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){
46577 'use strict';
46677 var instance = crypto.createHash('md5');
46777 instance.update(str + '');
46877 return instance.digest('hex');
469};
470/**
471 * 生成一个promise,如果传入的参数是promise则直接返回
472 * @param {[type]} obj [description]
473 * @return {[type]} [description]
474 */
4751global.getPromise = function(obj, reject){
476527 'use strict';
477527 if (isPromise(obj)) {
47810 return obj;
479 }
480517 if (reject) {
48124 return Promise.reject(obj);
482 }
483493 return Promise.resolve(obj);
484};
485/**
486 * 生成一个defer对象
487 * @return {[type]} [description]
488 */
4891global.getDefer = function(){
49086 'use strict';
49186 var deferred = {};
49286 deferred.promise = new Promise(function(resolve, reject){
49386 deferred.resolve = resolve;
49486 deferred.reject = reject;
495 });
49686 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){
50531 'use strict';
50631 var obj = {};
50731 if (!isArray(key)) {
50822 obj[key] = value;
50922 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%
163
163
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){
13365 'use strict';
14365 if (_alias[name]) {
15319 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){
31314 'use strict';
32 //如果不是字符串则直接返回
33314 if (!isString(name)) {
341 return name;
35 }
36313 var path = name;
37313 if (path[0] !== '/') {
38313 path = getThinkRequirePath(name);
39 }
40313 if (path) {
41312 var obj = require(path);
42312 if (isFunction(obj)) {
43 //修正子类继承的方法获取到正确的文件名
44282 obj.prototype.__filename = path;
45 }
46312 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){
8971 'use strict';
9071 if (!name) {
911 return data;
92 }
9370 if (typeof name === 'function') {
943 return name(http, data);
95 }
9667 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){
133792 'use strict';
134 //获取所有的配置
135792 if (arguments.length === 0) {
13628 return _config;
137 }
138 //清除所有的配置
139764 if (name === null) {
1402 _config = {};
1412 return;
142 }
143762 if (isString(name)) {
144758 name = name.toLowerCase();
145 //name里不含. 一级
146758 if (name.indexOf('.') === -1) {
147720 if (value === undefined) {
148677 return _config[name];
149 }
15043 _config[name] = value;
15143 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){
22239 'use strict';
22339 if (name === undefined) {
2241 return thinkRequire('Model')(name, config);
225 }
22638 name = name.split(':');
22738 name[0] = name[0][0].toUpperCase() + name[0].slice(1);
22838 var path = getThinkRequirePath(name[0] + 'Model');
22938 if (path) {
23017 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){
25429 'use strict';
25529 if (isNumber(options)) {
2564 options = {timeout: options};
25725 }else if (options === true) {
2589 options = {type: true}
259 }
26029 options = options || {};
26129 var type = options.type === undefined ? C('cache_type') : options.type;
26229 var cls = (type === true ? '' : ucfirst(type)) + 'Cache';
26329 var instance = thinkRequire(cls)(options);
26429 if (value === undefined) {//获取缓存
26512 return instance.get(name);
26617 }else if (value === null) {
2673 return instance.rm(name); //删除缓存
26814 }else if (isFunction(value)) { //获取缓存,如果不存在,则自动从回调里获取
2691 var fromCache = false;
2701 var cacheData = null;
2711 return instance.get(name).then(function(data){
2721 fromCache = !isEmpty(data);
2731 return fromCache ? data : value();
274 }).then(function(data){
2751 cacheData = data;
2761 return fromCache ? data : S(name, data, options);
277 }).then(function(){
2781 return cacheData;
279 })
280 }else{
28113 return instance.set(name, value, options.timeout);
282 }
283};
284/**
285 * 语言
286 * @param {[type]} name [description]
287 */
2881global.L = function(name){
2892 'use strict';
2902 return name;
291};

/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 db_log_sql: false, //是否打印sql语句
83
84 tpl_content_type: 'text/html', //模版输出类型
85 tpl_file_suffix: '.html', //模版文件名后缀
86 tpl_file_depr: '_', //controller和action之间的分隔符
87 tpl_engine_type: 'ejs', //模版引擎名称
88 tpl_engine_config: {},
89
90 log_record: false, //是否记录日志,开启后会重写console.log等系列方法
91 log_file_path: LOG_PATH, //日志文件存在路径
92 log_console_type: ['error'], //默认只接管console.error日志
93
94 cache_type: 'File', //数据缓存类型
95 cache_timeout: 6 * 3600, //数据缓存有效期,单位: 秒
96 cache_path: CACHE_PATH, //缓存路径设置 (File缓存方式有效)
97 cache_file_suffix: '.json', //File缓存方式下文件后缀名
98 cache_gc_hour: [4], //缓存清除的时间点,数据为小时
99
100 html_cache_on: false, //HTML静态缓存
101 html_cache_timeout: 3600, //缓存时间,单位为秒
102 html_cache_rules: {}, //缓存规则
103 html_cache_path: CACHE_PATH + '/html',
104 html_cache_file_callback: undefined, //生成缓存文件的回调函数
105 html_cache_file_suffix: '.html', //缓存文件后缀名
106
107 memcache_host: '127.0.0.1', //memcache host
108 memcache_port: 11211, //memecache端口
109};

/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

100%
25
25
0
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(){
145 if (!RESOURCE_PATH || !this.options.url_resource_on || !this.http.pathname) {
151 return false;
16 }
174 var pathname = this.http.pathname;
184 if (pathname.indexOf('/') === 0) {
191 pathname = pathname.substr(1);
20 }
214 var reg = C('url_resource_reg');
22 //通过正则判断是否是静态资源请求
234 if (!reg.test(pathname)) {
241 return false;
25 }
26
273 var file = RESOURCE_PATH + '/' + pathname;
283 var res = this.http.res;
293 if (fs.existsSync(file)) {
302 var contentType = mime.lookup(file);
312 var fileStream = fs.createReadStream(file);
322 res.setHeader('Content-Type', contentType + '; charset=' + C('encoding'));
332 fileStream.pipe(res);
342 fileStream.on('end', function(){
352 res.end();
36 });
37 }else{
381 res.statusCode = 404;
391 res.end();
40 }
41 //返回一个pendding promise, 不让后续执行
422 return getDefer().promise;
43 }
44 };
45});

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

100%
108
108
0
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(){
1740 if (!this.options.url_route_on) {
181 return false;
19 }
2039 var routes = this.options.url_route_rules;
2139 var length = routes.length;
2239 if (length === 0) {
231 return false;
24 }
2538 var pathname = this.http.pathname;
2638 var match;
2738 for(var i = 0; i < length; i++){
2838 var route = routes[i];
2938 var rule = route[0];
30 //正则路由
3138 if (isRegexp(rule)) {
3228 match = pathname.match(rule);
3328 if (match) {
3426 var result = this.parseRegExp(match, route[1], pathname);
3526 if (result) {
3625 return result;
37 }
38 }
39 }else{
40 //字符串路由
4110 match = this.checkUrlMatch(pathname, rule);
4210 if (match) {
436 return this.parseRule(rule, route[1], pathname);
44 }
45 }
46 }
477 return false;
48 },
49 /**
50 * 分割pathname
51 * @param {[type]} pathname [description]
52 * @return {[type]} [description]
53 */
54 split: function(pathname){
5585 var ret = [];
5685 var j = 0;
5785 pathname = pathname.split('/');
5885 for(var i = 0, length = pathname.length, item; i < length; i++){
59178 item = pathname[i].trim();
60178 if (item) {
61153 ret[j++] = item;
62 }
63 }
6485 return ret;
65 },
66 /**
67 * 解析字符串路由
68 * @param {[type]} rule [description]
69 * @param {[type]} route [description]
70 * @param {[type]} pathname [description]
71 * @return {[type]} [description]
72 */
73 parseRule: function(rule, route, pathname){
746 route = this.getRoute(route);
756 if (!route) {
761 return false;
77 }
785 pathname = this.split(pathname);
795 rule = this.split(rule);
805 var matches = [];
815 var self = this;
825 rule.forEach(function(item){
8310 var pathitem = pathname.shift();
8410 if (item.indexOf(':') === 0) {
854 if (item.indexOf('\\') === -1) {
862 self.http.get[item.substr(1)] = pathitem;
87 }else{
882 matches.push(pathitem);
89 }
90 }
91 });
92 //将剩余的pathname分割为querystring
935 if (pathname.length) {
942 for(var i = 0,length = Math.ceil(pathname.length)/2; i < length; i++){
952 this.http.get[pathname[i * 2]] = pathname[i * 2 + 1] || '';
96 }
97 }
985 route = route.replace(/:(\d+)/g, function(a, b){
992 return matches[b - 1] || '';
100 });
1015 this.parseUrl(route);
1025 return true;
103 },
104 /**
105 * 检测URL是否匹配
106 * @param {[type]} pathname [description]
107 * @param {[type]} rule [description]
108 * @return {[type]} [description]
109 */
110 checkUrlMatch: function(pathname, rule){
11110 pathname = this.split(pathname);
11210 rule = this.split(rule);
11310 return rule.every(function(item, i){
11419 if (item.indexOf(':') === 0) {
1157 if (item.indexOf('\\') > -1) {
1165 var type = item.substr(-1);
1175 var reg;
1185 switch(type){
119 case 'd':
1202 reg = /^\d+$/;
1212 break;
122 case 'w':
1233 reg = /^\w+$/
1243 break;
125 }
1265 if (reg && !reg.test(pathname[i])) {
1272 return false;
128 }
129 }
130 }else{
13112 var pitem = pathname[i] || '';
13212 if (pitem.toLowerCase() !== item.toLowerCase()) {
1332 return false;
134 }
135 }
13615 return true;
137 });
138 },
139 /**
140 * 解析转化后的url
141 * @param {[type]} urlInfo [description]
142 * @return {[type]} [description]
143 */
144 parseUrl: function(urlInfo){
14530 urlInfo = url.parse(urlInfo, true);
14630 if (urlInfo.query) {
14730 for(var key in urlInfo.query){
14848 if (urlInfo.query[key] || !(key in this.http.get)) {
14945 this.http.get[key] = urlInfo.query[key];
150 }
151 }
152 }
15330 var pathname = urlInfo.pathname || '';
154 // 过滤调用pathname最后有/的情况
15530 pathname = this.split(pathname);
15630 this.http.action = Dispatcher.getAction(pathname.pop());
15730 this.http.controller = Dispatcher.getController(pathname.pop());
15830 this.http.group = Dispatcher.getGroup(pathname.pop());
159 },
160 /**
161 * 获取route
162 * @param {[type]} route [description]
163 * @return {[type]} [description]
164 */
165 getRoute: function(route, matches){
16632 if (isObject(route)) {
167 //对应的请求类型
1683 for(var method in route){
169 //由于请求类型没有包含关系,这里可以直接用indexOf判断
1703 if (method.toUpperCase().indexOf(this.http.method) > -1) {
1711 return route[method];
172 }
173 }
1742 return;
175 }
17629 var routeUpper = route.toUpperCase();
177 //RESTFUL API
17829 if (routeUpper === 'RESTFUL' || routeUpper.indexOf('RESTFUL:') === 0) {
17921 var group = route.split(':')[1] || C('restful_group');
18021 route = group + '/' + matches[1] + '/' + this.http.method.toLowerCase() + '?resource=' + matches[1];
18121 if (matches[2]) {
18213 route += '&id=' + matches[2];
183 }
184 //设置变量到http对象上,方便后续使用
18521 this.http.isRestful = true;
18621 return route;
187 }
1888 return route;
189 },
190 /**
191 * 正则匹配路由
192 * @param {[type]} matches [description]
193 * @param {[type]} route [description]
194 * @param {[type]} pathname [description]
195 * @return {[type]} [description]
196 */
197 parseRegExp: function(matches, route, pathname){
19826 route = this.getRoute(route, matches);
19926 if (!route) {
2001 return false;
201 }
202 //替换路由字符串里的:1, :2 匹配都的值
203 //如:group/detail?date=:1&groupId=:2&page=:3
20425 route = route.replace(/:(\d+)/g, function(a, b){
20512 return matches[b] || '';
206 });
20725 pathname = pathname.replace(matches[0], '');
20825 pathname = this.split(pathname);
209 //将剩余的pathname分割为querystring
21025 if (pathname.length) {
2111 for(var i = 0,length = Math.ceil(pathname.length)/2; i < length; i++){
2121 this.http.get[pathname[i * 2]] = pathname[i * 2 + 1] || '';
213 }
214 }
21525 this.parseUrl(route);
21625 return true;
217 }
218 };
219});

/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

100%
10
10
0
LineHitsSource
1/**
2 * 调用对应的模版引擎解析模版
3 * @return {[type]} [description]
4 */
51module.exports = Behavior(function(){
61 'use strict';
71 return {
8 run: function(data){
910 var file = data.file;
10 //将模版文件路径写入到http对象上,供writehtmlcache里使用
1110 this.http.tpl_file = file;
1210 var engine = C('tpl_engine_type');
13 //不使用模版引擎,直接返回文件内容
1410 if (!engine) {
152 return getFileContent(file);
16 }
178 var engineClass = ucfirst(engine) + 'Template';
188 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

51%
155
80
75
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 || !http.res) {
1590 return;
160 }
1610 var message = isError(error) ? error.stack : error;
1620 console.error(message);
1630 http.res.statusCode = 500;
1640 http.setHeader('Content-Type', 'text/html; charset=' + C('encoding'));
1650 if (APP_DEBUG) {
1660 http.res.end(message);
167 }else{
1680 var readStream = fs.createReadStream(C('error_tpl_path'));
1690 readStream.pipe(http.res);
1700 readStream.on('end', function(){
1710 http.res.end();
172 });
173 }
174}
175
176/**
177 * run
178 * @return {[type]} [description]
179 */
1801App.run = function(){
1811 'use strict';
1821 if (APP_MODE && App.mode[APP_MODE]) {
1831 return App.mode[APP_MODE]();
184 }
1850 return App.mode.http();
186};
187/**
188 * 不同模式下的run
189 * @type {Object}
190 */
1911App.mode = {
192 //命令行模式
193 cli: function(){
1941 'use strict';
1951 var defaultHttp = thinkHttp.getDefaultHttp(process.argv[2]);
1961 thinkHttp(defaultHttp.req, defaultHttp.res).run().then(App.listener);
197 },
198 //HTTP模式
199 http: function(){
2000 'use strict';
2010 var clusterNums = C('use_cluster');
202 //不使用cluster
2030 if (!clusterNums) {
2040 return App.createServer();
205 }
206 //使用cpu的个数
2070 if (clusterNums === true) {
2080 clusterNums = require('os').cpus().length;
209 }
2100 if (cluster.isMaster) {
2110 for (var i = 0; i < clusterNums; i++) {
2120 cluster.fork();
213 }
2140 cluster.on('exit', function(worker) {
2150 console.error('worker ' + worker.process.pid + ' died');
2160 process.nextTick(function(){
2170 cluster.fork();
218 });
219 });
220 }else {
2210 App.createServer();
222 }
223 }
224};
225/**
226 * 创建服务
227 * @return {[type]} [description]
228 */
2291App.createServer = function(){
2300 'use strict';
231 //自定义创建server
2320 var createServerFn = C('create_server_fn');
2330 if (createServerFn) {
2340 if (isFunction(createServerFn)) {
2350 return createServerFn(App);
2360 }else if (isFunction(global[createServerFn])) {
2370 return global[createServerFn](App);
238 }
239 }
2400 var server = require('http').createServer(function (req, res) {
2410 thinkHttp(req, res).run().then(App.listener);
242 });
2430 thinkRequire('WebSocket')(server, App).run();
2440 server.listen(C('port'));
2450 if (APP_DEBUG) {
2460 console.log('Server running at http://127.0.0.1:' + C('port') + '/');
247 }
248}
249/**
250 * 监听回调函数
251 * @param {[type]} http [description]
252 * @return {[type]} [description]
253 */
2541App.listener = function(http){
2551 'use strict';
256 //自动发送thinkjs和版本的header
2571 http.setHeader('X-Powered-By', 'thinkjs-' + THINK_VERSION);
258 //禁止远程直接用带端口的访问,websocket下允许
2591 if (C('use_proxy') && http.host !== http.hostname && !http.websocket) {
2600 http.res.statusCode = 403;
2610 http.res.end();
2620 return getDefer().promise;
263 }
2641 var domainInstance = domain.create();
2651 var deferred = getDefer();
2661 domainInstance.on('error', function(err){
2670 App.sendError(http, err);
2680 deferred.reject(err);
269 });
2701 domainInstance.run(function(){
2711 return tag('app_init', http).then(function(){
2721 return Dispatcher(http).run();
273 }).then(function(){
2741 return tag('app_begin', http);
275 }).then(function(){
2761 return tag('action_init', http);
277 }).then(function(){
2781 return App.exec(http);
279 }).then(function(){
2801 return tag('app_end', http);
281 }).catch(function(err){
2820 App.sendError(http, err);
283 }).then(function(){
2841 deferred.resolve();
285 })
286 });
2871 return deferred.promise;
288};

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

100%
152
152
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) {
1925 this.http = http;
2025 this.view = null;
21 //将http数据打到模版里
2225 this.assign('http', this.http);
23 //将配置信息打到模版里
2425 this.assign('config', C());
25 //设置变量别名
2625 this.set = this.assign;
27 //success别名
2825 this.ok = this.success;
29 //error别名
3025 this.fail = this.error;
31 },
32 /**
33 * 获取客户端的ip
34 * @return {[type]} [description]
35 */
36 ip: function() {
371 return this.http.ip();
38 },
39 /**
40 * 实例化View类
41 * @return {[type]} [description]
42 */
43 initView: function() {
4464 if (!this.view) {
4525 this.view = thinkRequire('View')(this.http);
46 }
4764 return this.view;
48 },
49 /**
50 * 是否是GET请求
51 * @return {Boolean} [description]
52 */
53 isGet: function() {
541 return this.http.method === 'GET';
55 },
56 /**
57 * 是否是POST请求
58 * @return {Boolean} [description]
59 */
60 isPost: function() {
611 return this.http.method === 'POST';
62 },
63 /**
64 * 是否是特定METHOD请求
65 * @param {[type]} method [description]
66 * @return {Boolean} [description]
67 */
68 isMethod: function(method) {
692 return this.http.method === method.toUpperCase();
70 },
71 /**
72 * 是否是AJAX请求
73 * @return {Boolean} [description]
74 */
75 isAjax: function(method) {
76 //请求类型判断
776 if (method && this.http.method !== method.toUpperCase()) {
782 return false;
79 }
804 return this.header('x-requested-with') === 'XMLHttpRequest';
81 },
82 /**
83 * 是否是websocket请求
84 * @return {Boolean} [description]
85 */
86 isWebSocket: function(){
872 return !!this.http.websocket;
88 },
89 /**
90 * 是否是命令行模式
91 * @return {Boolean} [description]
92 */
93 isCli: function(){
942 return APP_MODE === 'cli';
95 },
96 /**
97 * 是否是jsonp接口
98 * @return {Boolean} [description]
99 */
100 isJsonp: function(name){
1014 name = name || C('url_callback_name');
1024 return !!this.get(name);
103 },
104 /**
105 * 获取QUERY参数
106 * @param {[type]} name [description]
107 * @return {[type]} [description]
108 */
109 get: function(name) {
11044 if (name === undefined) {
1112 return this.http.get;
112 }
11342 return this.http.get[name] || '';
114 },
115 /**
116 * 获取POST参数
117 * @param {[type]} name [description]
118 * @return {[type]} [description]
119 */
120 post: function(name) {
12111 var http = this.http;
12211 return name ? (http.post[name] || '') : http.post;
123 },
124 /**
125 * 获取参数
126 * @param {[type]} name [description]
127 * @return {[type]} [description]
128 */
129 param: function(name) {
1304 if (name === undefined) {
1312 var post = this.post();
1322 return !isEmpty(post) ? post : this.get();
133 }
1342 return this.post(name) || this.get(name);
135 },
136 /**
137 * 获取上传的文件
138 * @param {[type]} name [description]
139 * @return {[type]} [description]
140 */
141 file: function(name) {
1423 var http = this.http;
1433 return name ? (http.file[name] || {}) : http.file;
144 },
145 /**
146 * header操作
147 * @param {[type]} name [description]
148 * @param {[type]} value [description]
149 * @return {[type]} [description]
150 */
151 header: function(name, value) {
15211 if (name === undefined) {
1531 return this.http.headers;
15410 }else if (isObject(name)) {
1551 for (var key in name) {
1562 this.header(key, name[key]);
157 }
1581 return this;
1599 }else if (value !== undefined) {
1603 this.http.setHeader(name, value);
1613 return this;
162 }else{
1636 return this.http.getHeader(name);
164 }
165 },
166 /**
167 * 获取userAgent
168 * @return {[type]} [description]
169 */
170 userAgent: function(){
1711 return this.http.headers['user-agent'] || '';
172 },
173 /**
174 * 获取referrer
175 * @return {[type]} [description]
176 */
177 referer: function(host){
1783 var referer = this.http.headers.referer || this.http.headers.referfer || '';
1793 if (!referer || !host) {
1802 return referer;
181 }
1821 var info = url.parse(referer);
1831 return info.hostname;
184 },
185 /**
186 * cookie操作
187 * @param {[type]} name [description]
188 * @param {[type]} value [description]
189 * @param {[type]} options [description]
190 * @return {[type]} [description]
191 */
192 cookie: function(name, value, options) {
1934 if (value !== undefined) {
1941 this.http.setCookie(name, value, options);
1951 return this;
196 }
1973 return name === undefined ? this.http.cookie : (this.http.cookie[name] || '');
198 },
199 /**
200 * session
201 * 如果是get操作,则返回一个promise
202 * @param {[type]} name [description]
203 * @param {[type]} value [description]
204 * @return {[type]} [description]
205 */
206 session: function(name, value) {
20711 thinkRequire('Session').start(this.http);
20811 var instance = this.http.session;
20911 if (name === undefined) {
2101 return instance.rm();
211 }
21210 if (value !== undefined) {
2135 return instance.set(name, value);
214 }
2155 return instance.get(name);
216 },
217 /**
218 * 跳转,返回一个pendding promise阻止后面继续执行
219 * @param {[type]} url [description]
220 * @param {[type]} code [description]
221 * @return {[type]} [description]
222 */
223 redirect: function(url, code) {
2242 this.http.redirect(url, code);
2252 return getDefer().promise;
226 },
227 /**
228 * 赋值变量到模版
229 * @param {[type]} name [description]
230 * @param {[type]} value [description]
231 * @return {[type]} [description]
232 */
233 assign: function(name, value) {
23457 if (arguments.length <= 1) {
2356 return this.initView().assign(name);
236 }
23751 return this.initView().assign(name, value);
238 },
239 /**
240 * 获取解析后的模版内容
241 * @param {[type]} templateFile [description]
242 * @param {[type]} content [description]
243 * @return {[type]} [description]
244 */
245 fetch: function(templateFile) {
2463 return this.initView().fetch(templateFile);
247 },
248 /**
249 * 输出模版内容
250 * @param {[type]} templateFile [description]
251 * @param {[type]} charset [description]
252 * @param {[type]} contentType [description]
253 * @param {[type]} content [description]
254 * @return {[type]} [description]
255 */
256 display: function(templateFile, charset, contentType) {
2573 return this.initView().display(templateFile, charset, contentType);
258 },
259 /**
260 * 调用另一个controll里的aciton
261 * 可以跨分组
262 * A('Admin/Test/index')
263 * @param {[type]} action [description]
264 * @return {[type]} [description]
265 */
266 action: function(action, data) {
267 //自动补group
2683 action = action.replace(/\//g, ':');
2693 if (action.split(':').length === 2) {
2703 action = this.http.group + ':' + action;
271 }
2723 return A(action, this.http, data);
273 },
274 /**
275 * jsonp格式输出
276 * @param {[type]} data [description]
277 * @param {[type]} jsonp [description]
278 * @return {[type]} [description]
279 */
280 jsonp: function(data) {
2816 this.type(C('json_content_type'));
2826 var callback = this.get(C('url_callback_name'));
283 //过滤callback值里的非法字符
2846 callback = callback.replace(/[^\w\.]/g, '');
2856 if (callback) {
2863 data = callback + '(' + (data !== undefined ? JSON.stringify(data) : '') + ')';
2873 this.end(data);
288 } else {
2893 this.end(data);
290 }
291 },
292 /**
293 * json格式输出
294 * @param {[type]} data [description]
295 * @return {[type]} [description]
296 */
297 json: function(data){
2982 this.type(C('json_content_type'));
2992 return this.end(data);
300 },
301 /**
302 * 设置http响应状态码
303 * @param {[type]} status [description]
304 * @return {[type]} [description]
305 */
306 status: function(status) {
3072 var res = this.http.res;
3082 if (!res.headersSent) {
3092 res.statusCode = status || 404;
310 }
3112 return this;
312 },
313 /**
314 * 阻止访问
315 * @param {[type]} status [description]
316 * @return {[type]} [description]
317 */
318 deny: function(status){
3192 var res = this.http.res;
3202 if (!res.headersSent) {
3212 res.statusCode = status || 403;
3222 this.http.end();
323 }
3242 return getDefer().promise;
325 },
326 /**
327 * 输出内容
328 * 自动JSON.stringify
329 * 自定将数字等转化为字符串
330 * @param {[type]} obj [description]
331 * @return {[type]} [description]
332 */
333 echo: function(obj, encoding) {
334 //自动发送Content-Type的header
33521 if (C('auto_send_content_type')) {
33621 this.type(C('tpl_content_type'));
337 }
33821 return this.http.echo(obj, encoding);
339 },
340 /**
341 * 结束输出,输出完成时一定要调用这个方法
342 * @param {[type]} obj [description]
343 * @return {[type]} [description]
344 */
345 end: function(obj, encoding) {
34618 if (obj !== undefined) {
34715 this.echo(obj, encoding);
348 }
34918 this.http.end();
350 },
351 /**
352 * 发送Content-Type
353 * @param {[type]} type [description]
354 * @return {[type]} [description]
355 */
356 type: function(ext){
35748 if (this.http.cthIsSend || !ext) {
35831 return;
359 }
36017 if (ext.indexOf('/') === -1) {
3613 ext = require('mime').lookup(ext);
362 }
36317 if (ext.toLowerCase().indexOf('charset=') === -1) {
36417 ext += '; charset=' + C('encoding');
365 }
366 //Content-Type Header has been Send
36717 this.http.cthIsSend = true;
36817 this.http.setHeader('Content-Type', ext);
369 },
370 /**
371 * 下载文件
372 * @return Promise [description]
373 */
374 download: function(file, contentType, filename) {
3755 if (isString(contentType) && contentType.indexOf('.') > -1) {
3761 filename = contentType;
3771 contentType = '';
378 }
3795 if (!contentType || contentType.indexOf('/') === -1) {
3804 contentType = require('mime').lookup(contentType || file);
381 }
3825 var http = this.http;
3835 var fileStream = fs.createReadStream(file);
3845 var deferred = getDefer();
3855 this.type(contentType);
3865 http.setHeader('Content-Disposition', 'attachment; filename="' + (filename || path.basename(file)) + '"');
3875 fileStream.pipe(http.res);
3885 fileStream.on('end', function() {
3895 http.end();
3905 deferred.resolve();
391 });
3925 return deferred.promise;
393 },
394 /**
395 * 正常json数据输出
396 * @param {[type]} data [description]
397 * @return {[type]} [description]
398 */
399 success: function(data){
4002 var obj = getObject([C('error_no_key'), C('error_msg_key')], [0, '']);
4012 if (data !== undefined) {
4021 obj.data = data;
403 }
4042 this.type(C('json_content_type'));
4052 this.end(obj);
4062 return getDefer().promise;
407 },
408 /**
409 * 异常json数据数据
410 * @param {[type]} errno [description]
411 * @param {[type]} errmsg [description]
412 * @param {[type]} extra [description]
413 * @return {[type]} [description]
414 */
415 error: function(errno, errmsg, data){
4167 var obj;
4177 if (isObject(errno)) {
4183 data = errmsg;
4193 obj = extend({}, errno);
420 }else{
4214 if (!isNumber(errno)) {
4221 data = errmsg;
4231 errmsg = errno;
4241 errno = C('error_no_default_value');
425 }
4264 obj = getObject([C('error_no_key'), C('error_msg_key')], [errno, errmsg || 'error']);
427 }
4287 if (data !== undefined) {
4292 obj.data = data;
430 }
4317 this.type(C('json_content_type'));
4327 this.end(obj);
4337 return getDefer().promise;
434 },
435 /**
436 * 关闭数据库连接
437 * @return {[type]} [description]
438 */
439 closeDb: function(){
4401 thinkRequire('Model').close();
441 },
442 /**
443 * 发送执行时间
444 * @param {[type]} name [description]
445 * @return {[type]} [description]
446 */
447 sendTime: function(name){
4482 return this.http.sendTime(name);
449 },
450 /**
451 * 对数据进行过滤
452 * @param {[type]} data [description]
453 * @param {[type]} type [description]
454 * @return {[type]} [description]
455 */
456 filter: function() {
4572 var filter = thinkRequire('Filter').filter;
4582 return filter.apply(null, arguments);
459 },
460 /**
461 * 校验一个值是否合法
462 * @param {[type]} data [description]
463 * @param {[type]} validType [description]
464 * @return {[type]} [description]
465 */
466 valid: function(data, validType) {
467 //单个值检测,只返回是否正常
4683 if (validType !== undefined) {
4691 data = [{
470 value: data,
471 valid: validType
472 }];
4731 var result = thinkRequire('Valid')(data);
4741 return isEmpty(result);
475 }
4762 return thinkRequire('Valid')(data);
477 }
478 };
479});

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

82%
363
299
64
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 };
24 //数据查询缓存
251 var dbCacheData = {};
26
271 return {
28 // 数据库类型
29 dbType: null,
30 // 当前操作所属的模型名
31 model: 'think',
32 // 当前SQL指令
33 sql: '',
34 // 操作的sql列表
35 modelSql: {},
36 // 当前连接ID
37 linkId: null,
38 // 数据库连接参数配置
39 config: '',
40 /**
41 * 初始化
42 * @return {[type]} [description]
43 */
44 init: function(){
45
46 },
47 /**
48 * 解析set集合
49 * @param {[type]} data [description]
50 * @return {[type]} [description]
51 */
52 parseSet: function(data){
5314 data = data || {};
5414 var set = [];
5514 for(var key in data){
5614 var value = this.parseValue(data[key]);
5714 if (isScalar(value)) {
5814 set.push(this.parseKey(key) + '=' + value);
59 }
60 }
6114 return ' SET ' + set.join(',');
62 },
63 /**
64 * 解析字段名,具体的数据库里实现
65 * @param {[type]} key [description]
66 * @return {[type]} [description]
67 */
68 parseKey: function(key){
690 return key;
70 },
71 /**
72 * value分析
73 * @param {[type]} value [description]
74 * @return {[type]} [description]
75 */
76 parseValue: function(value){
77163 if (isString(value)) {
7867 value = '\'' + this.escapeString(value) + '\'';
7996 }else if(isArray(value)){
8017 if ((value[0] + '').toLowerCase() === 'exp') {
818 value = this.escapeString(value[1]);
82 }else{
839 var self = this;
849 value = value.map(function(item){
8517 return self.parseValue(item);
86 });
87 }
8879 }else if(isBoolean(value)){
890 value = value ? '1' : '0';
9079 }else if (value === null) {
910 value = 'null';
92 }
93163 return value;
94 },
95 /**
96 * field分析
97 * parseField('name');
98 * parseField('name,email');
99 * parseField({
100 * xx_name: 'name',
101 * xx_email: 'email'
102 * })
103 * @return {[type]} [description]
104 */
105 parseField: function(fields){
106157 if (isString(fields) && fields.indexOf(',') > -1) {
1074 fields = fields.split(',');
108 }
109157 if (isArray(fields)) {
1104 var self = this;
1114 return fields.map(function(item){
11217 return self.parseKey(item);
113 }).join(',');
114153 }else if(isObject(fields)){
1150 var data = [];
1160 for(var key in fields){
1170 data.push(this.parseKey(key) + ' AS ' + this.parseKey(fields[key]));
118 }
1190 return data.join(',');
120153 }else if(isString(fields) && fields){
12117 return this.parseKey(fields);
122 }
123136 return '*';
124 },
125 /**
126 * table别名分析
127 * @param {[type]} tables [description]
128 * @return {[type]} [description]
129 */
130 parseTable: function(tables){
131184 if (isString(tables)) {
132184 tables = tables.split(',');
133 }
134184 if (isArray(tables)) {
135184 var self = this;
136184 return tables.map(function(item){
137184 return self.parseKey(item);
138 }).join(',');
1390 }else if (isObject(tables)) {
1400 var data = [];
1410 for(var key in tables){
1420 data.push(this.parseKey(key) + ' AS ' + this.parseKey(tables[key]));
143 }
1440 return data.join(',');
145 }
1460 return '';
147 },
148 /**
149 * where条件分析
150 * @param {[type]} where [description]
151 * @return {[type]} [description]
152 */
153 parseWhere: function(where){
154177 var whereStr = '';
155177 var self = this;
156177 where = where || {};
157177 if (isString(where)) {
1580 whereStr = where;
159 }else{
160 // 定义逻辑运算规则 例如 OR XOR AND NOT
161177 var oList = ['AND', 'OR', 'XOR'];
162177 var operate = (where._logic + '').toUpperCase();
163177 delete where._logic;
164177 operate = oList.indexOf(operate) > -1 ? ' ' + operate + ' ' : ' AND ';
165 //key值的安全检测正则
166177 var keySafeRegExp = /^[\w\|\&\-\.\(\)\,]+$/;
167177 var multi = where._multi;
168177 delete where._multi;
169
170177 var val;
171177 var fn = function(item, i){
1728 var v = multi ? val[i] : val;
1738 return '(' + self.parseWhereItem(self.parseKey(item), v) + ')';
174 };
175177 for(var key in where){
176105 key = key.trim();
177105 val = where[key];
178105 whereStr += '( ';
179105 if (key.indexOf('_') === 0) {
180 // 解析特殊条件表达式
1813 whereStr += this.parseThinkWhere(key, val);
182 }else{
183102 if (!keySafeRegExp.test(key)) {
1840 console.log(key + ' is not safe');
1850 continue;
186 }
187102 var arr;
188 // 支持 name|title|nickname 方式定义查询字段
189102 if (key.indexOf('|') > -1) {
1902 arr = key.split('|');
1912 whereStr += arr.map(fn).join(' OR ');
192100 }else if (key.indexOf('&') > -1) {
1932 arr = key.split('&');
1942 whereStr += arr.map(fn).join(' AND ');
195 }else{
19698 whereStr += this.parseWhereItem(this.parseKey(key), val);
197 }
198 }
199105 whereStr += ' )' + operate;
200 }
201177 whereStr = whereStr.substr(0, whereStr.length - operate.length);
202 }
203
204177 return whereStr ? (' WHERE ' + whereStr) : '';
205 },
206 /**
207 * 解析单个查询条件
208 * @param {[type]} key [description]
209 * @param {[type]} val [description]
210 * @return {[type]} [description]
211 */
212 parseWhereItem: function(key, val){
213106 if (isObject(val)) { // {id: {'<': 10, '>': 1}}
2147 var logic = (val._logic || 'AND').toUpperCase();
2157 delete val._logic;
2167 var result = [];
2177 for(var opr in val){
21814 var nop = opr.toUpperCase();
21914 nop = comparison[nop] || nop;
22014 result.push(key + ' ' + nop + ' ' + this.parseValue(val[opr]));
221 }
2227 return result.join(' ' + logic + ' ');
22399 }else if (!isArray(val)) {
224 //对字符串类型字段采用模糊匹配
22536 if (C('db_like_fields').indexOf(key) > -1) {
2260 return key + ' LIKE ' + this.parseValue('%' + val + '%');
227 }else{
22836 return key + ' = ' + this.parseValue(val);
229 }
230 }
23163 var whereStr = '';
23263 var data;
23363 if (isString(val[0])) {
23462 var val0 = val[0].toUpperCase();
23562 val0 = comparison[val0] || val0;
23662 if (/^(=|!=|>|>=|<|<=)$/.test(val0)) { // 比较运算
23722 whereStr += key + ' ' + val0 + ' ' + this.parseValue(val[1]);
23840 }else if (/^(NOT\s+LIKE|LIKE)$/.test(val0)) { // 模糊查找
23923 if (isArray(val[1])) { //多个like
2407 var likeLogic = (val[2] || 'OR').toUpperCase();
2417 var likesLogic = ['AND','OR','XOR'];
2427 var self = this;
2437 if (likesLogic.indexOf(likeLogic) > -1) {
2447 var like = val[1].map(function(item){
24513 return key + ' ' + val0 + ' ' + self.parseValue(item);
246 }).join(' ' + likeLogic + ' ');
2477 whereStr += '(' + like + ')';
248 }
249 }else{
25016 whereStr += key + ' ' + val0 + ' ' + this.parseValue(val[1]);
251 }
25217 }else if(val0 === 'EXP'){ // 使用表达式
2532 whereStr += '(' + key + ' ' + val[1] + ')';
25415 }else if(val0 === 'IN' || val0 === 'NOT IN'){ // IN 运算
25512 if (val[2] === 'exp') {
2563 whereStr += key + ' ' + val0 + ' ' + val[1];
257 }else{
2589 if (isString(val[1])) {
2594 val[1] = val[1].split(',');
260 }
261 //如果不是数组,自动转为数组
2629 if (!isArray(val[1])) {
2632 val[1] = [val[1]];
264 }
2659 val[1] = this.parseValue(val[1]);
266 //如果只有一个值,那么变成=或者!=
2679 if (val[1].length === 1) {
2682 whereStr += key + (val0 === 'IN' ? ' = ' : ' != ') + val[1];
269 }else{
2707 whereStr += key + ' ' + val0 + ' (' + val[1].join(',') + ')';
271 }
272 }
2733 }else if(val0 === 'BETWEEN'){ // BETWEEN运算
2743 data = isString(val[1]) ? val[1].split(',') : val[1];
2753 if (!isArray(data)) {
2762 data = [val[1], val[2]];
277 }
2783 whereStr += ' (' + key + ' ' + val0 + ' ' + this.parseValue(data[0]);
2793 whereStr += ' AND ' + this.parseValue(data[1]) + ')';
280 }else{
2810 console.log('_EXPRESS_ERROR_', key, val);
2820 return '';
283 }
284 }else{
2851 var length = val.length;
2861 var rule = 'AND';
2871 if (isString(val[length - 1])) {
2880 var last = val[length - 1].toUpperCase();
2890 if (last && ['AND', 'OR', 'XOR'].indexOf(last) > -1) {
2900 rule = last;
2910 length--;
292 }
293 }
2941 for(var i = 0; i < length; i++){
2953 var isArr = isArray(val[i]);
2963 data = isArr ? val[i][1] : val[i];
2973 var exp = ((isArr ? val[i][0] : '') + '').toUpperCase();
2983 if (exp === 'EXP') {
2991 whereStr += '(' + key + ' ' + data + ') ' + rule + ' ';
300 }else{
3012 var op = isArr ? (comparison[val[i][0].toUpperCase()] || val[i][0]) : '=';
3022 whereStr += '(' + key + ' ' + op + ' ' + this.parseValue(data) + ') ' + rule + ' ';
303 }
304 }
3051 whereStr = whereStr.substr(0, whereStr.length - 4);
306 }
30763 return whereStr;
308 },
309 /**
310 * 解析一些特殊的where条件
311 * @param {[type]} key [description]
312 * @param {[type]} val [description]
313 * @return {[type]} [description]
314 */
315 parseThinkWhere: function(key, val){
3163 switch(key){
317 // 字符串模式查询条件
318 case '_string':
3192 return val;
320 // 复合查询条件
321 case '_complex':
3221 return this.parseWhere(val).substr(6);
323 // 字符串模式查询条件
324 case '_query':
3250 var where = isString(val) ? querystring.parse(val) : val;
3260 var op = ' AND ';
3270 if ('_logic' in where) {
3280 op = ' ' + where._logic.toUpperCase() + ' ';
3290 delete where._logic;
330 }
3310 var arr = [];
3320 for(var name in where){
3330 val = where[name];
3340 val = this.parseKey(name) + ' = ' + this.parseValue(val);
3350 arr.push(val);
336 }
3370 return arr.join(op);
338 default:
3390 return '';
340 }
3410 return '';
342 },
343 /**
344 * 解析limit,对非法的limit进行过滤
345 * @param {[type]} limit [description]
346 * @return {[type]} [description]
347 */
348 parseLimit: function(limit){
349176 if (!limit) {
350151 return '';
351 }
35225 limit = (limit + '').split(',');
35325 var data = [];
35425 for(var i = 0; i < Math.min(2, limit.length); i++){
35533 data[i] = limit[i] | 0;
356 }
35725 return ' LIMIT ' + data.join(',');
358 },
359 /**
360 * 解析join
361 * @param {[type]} join [description]
362 * @return {[type]} [description]
363 */
364 parseJoin: function(join, options){
365157 if (!join) {
366140 return '';
367 }
36817 var joinStr = '';
36917 var defaultJoin = ' LEFT JOIN ';
37017 if (isArray(join)) {
37117 var joins = {
372 'left': ' LEFT JOIN ',
373 'right': ' RIGHT JOIN ',
374 'inner': ' INNER JOIN '
375 };
37617 join.forEach(function(val){
37719 if (isString(val)) {//字符串,直接拼接
3786 var hasJoin = val.toLowerCase().indexOf(' join ') > -1;
3796 joinStr += (hasJoin ? ' ' : defaultJoin) + val;
38013 }else if (isObject(val)) {
38113 var ret = [];
38213 if (!('on' in val)) {
3837 for(var key in val){
38415 var v = val[key];
38515 v.table = key;
38615 ret.push(v);
387 }
388 }else{
3896 ret.push(val);
390 }
39113 ret.forEach(function(item){
39221 var joinType = joins[item.join] || item.join || defaultJoin;
39321 var table = options.tablePrefix + item.table;
39421 joinStr += joinType + '`' + table + '`';
39521 if (item.as) {
39612 joinStr += ' AS ' + item.as;
397 }
398 //ON条件
39921 if (item.on) {
40021 var mTable = options.alias || options.table;
40121 var jTable = item.as || table;
402 //多个=条件
40321 if (isObject(item.on)) {
4042 var where = [];
4052 for(var key in item.on){
4064 where.push(mTable + '.`' + key + '`' + '=' + jTable + '.`' + item.on[key] + '`');
407 }
4082 joinStr += ' ON (' + where.join(' AND ') + ')';
409 }else{
41019 if (isString(item.on)) {
4113 item.on = item.on.split(/\s*,\s*/);
412 }
41319 joinStr += ' ON ' + mTable + '.`' + item.on[0] + '`';
41419 joinStr += '=' + jTable + '.`' + item.on[1] + '`';
415 }
416 }
417 })
418 }
419 });
420 }else{
4210 joinStr += defaultJoin + join;
422 }
42317 return joinStr;
424 },
425 /**
426 * 解析order
427 * @param {[type]} order [description]
428 * @return {[type]} [description]
429 */
430 parseOrder: function(order){
431176 var self = this;
432176 if (isArray(order)) {
4332 order = order.map(function(item){
4343 return self.parseKey(item);
435 }).join(',');
436174 }else if (isObject(order)) {
4372 var arr = [];
4382 for(var key in order){
4393 var val = order[key];
4403 val = this.parseKey(key) + ' ' + val;
4413 arr.push(val);
442 }
4432 order = arr.join(',');
444 }
445176 return order ? (' ORDER BY ' + order) : '';
446 },
447 /**
448 * 解析group
449 * @param {[type]} group [description]
450 * @return {[type]} [description]
451 */
452 parseGroup: function(group){
453157 return group ? (' GROUP BY `' + group + '`' ) : '';
454 },
455 /**
456 * 解析having
457 * @param {[type]} having [description]
458 * @return {[type]} [description]
459 */
460 parseHaving: function(having){
461157 return having ? (' HAVING ' + having) : '';
462 },
463 /**
464 * 解析注释,一般情况下用不到
465 * @param {[type]} comment [description]
466 * @return {[type]} [description]
467 */
468 parseComment: function(comment){
469180 return comment ? (' /* ' + comment + '*/') : '';
470 },
471 /**
472 * 解析Distinct
473 * @param {[type]} distinct [description]
474 * @return {[type]} [description]
475 */
476 parseDistinct: function(distinct){
477157 return distinct ? ' Distinct ' : '';
478 },
479 /**
480 * 解析Union
481 * @param {[type]} union [description]
482 * @return {[type]} [description]
483 */
484 parseUnion: function(union){
485157 if (!union) {
486153 return '';
487 }
4884 if (isArray(union)) {
4894 var self = this;
4904 var sql = '';
4914 union.forEach(function(item){
4925 sql += item.all ? 'UNION ALL ' : 'UNION ';
4935 sql += '(' + (isObject(item.union) ? self.buildSelectSql(item.union).trim() : item.union) + ') ';
494 })
4954 return sql;
496 }else{
4970 return 'UNION (' + (isObject(union) ? this.buildSelectSql(union).trim() : union) + ') ';
498 }
499 },
500 /**
501 * 解析Lock
502 * @param {[type]} lock [description]
503 * @return {[type]} [description]
504 */
505 parseLock: function(lock){
506180 if (!lock) {
507179 return '';
508 }
5091 return ' FOR UPDATE ';
510 },
511 /**
512 * 将page转化为sql里的limit
513 * @return {[type]} [description]
514 */
515 pageToLimit: function(options){
516157 options = options || {};
517 //根据page生成limit
518157 if ('page' in options) {
5196 var page = options.page + '';
5206 var listRows = 0;
5216 if (page.indexOf(',') > -1) {
5223 page = page.split(',');
5233 listRows = page[1] | 0;
5243 page = page[0];
525 }
5266 page = parseInt(page, 10) || 1;
5276 if (!listRows) {
5284 listRows = isNumberString(options.limit) ? options.limit : C('db_nums_per_page');
529 }
5306 var offset = listRows * (page - 1);
5316 options.limit = offset + ',' + listRows;
532 }
533157 return options;
534 },
535 /**
536 * 拼接select查询语句
537 * @param {[type]} options [description]
538 * @return {[type]} [description]
539 */
540 buildSelectSql: function(options){
541157 options = this.pageToLimit(options);
542157 var sql = this.parseSql(selectSql, options);
543157 sql += this.parseLock(options.lock);
544157 return sql;
545 },
546 /**
547 * 解析sql语句
548 * @param {[type]} sql [description]
549 * @param {[type]} options [description]
550 * @return {[type]} [description]
551 */
552 parseSql: function(sql, options){
553157 options = options || {};
554157 var self = this;
555157 return sql.replace(/\%([A-Z]+)\%/g, function(a, type){
5561727 type = type.toLowerCase();
5571727 return self['parse' + ucfirst(type)](options[type] || '', options);
558 }).replace(/__([A-Z_-]+)__/g, function(a, b){
5590 return '`' + C('db_prefix') + b.toLowerCase() + '`';
560 });
561 },
562 /**
563 * 插入一条记录
564 * @param {[type]} data [description]
565 * @param {[type]} options [description]
566 * @param {[type]} replace [description]
567 * @return {[type]} [description]
568 */
569 insert: function(data, options, replace){
5704 data = data || {};
5714 options = options || {};
5724 var values = [];
5734 var fields = [];
5744 this.model = options.model;
5754 for(var key in data){
5765 var val = data[key];
5775 val = this.parseValue(val);
5785 if (isScalar(val)) {
5795 values.push(val);
5805 fields.push(this.parseKey(key));
581 }
582 }
5834 var sql = (replace ? 'REPLACE' : 'INSERT') + ' INTO ';
5844 sql += this.parseTable(options.table) + ' (' + fields.join(',') + ') ';
5854 sql += 'VALUES(' + values.join(',') + ')';
5864 sql += this.parseLock(options.lock) + this.parseComment(options.comment);
5874 return this.execute(sql);
588 },
589 /**
590 * 插入多条记录
591 * @param {[type]} data [description]
592 * @param {[type]} options [description]
593 * @param {[type]} replace [description]
594 * @return {[type]} [description]
595 */
596 insertAll: function(data, options, replace){
5974 var fields = Object.keys(data[0]);
5984 var self = this;
5994 fields = fields.map(function(item){
6006 return self.parseKey(item);
601 }).join(',');
6024 var values = data.map(function(item){
6036 var value = [];
6046 for(var key in item){
6059 var val = item[key];
6069 val = self.parseValue(val);
6079 if (isScalar(val)) {
6089 value.push(val);
609 }
610 }
6116 return '(' + value.join(',') + ')';
612 }).join(',');
6134 var sql = replace ? 'REPLACE' : 'INSERT';
6144 sql += ' INTO ' + this.parseTable(options.table) + '(' + fields + ') VALUES ' + values;
6154 return this.execute(sql);
616 },
617 /**
618 * 从一个选择条件的结果插入记录
619 * @param {[type]} fields [description]
620 * @param {[type]} table [description]
621 * @param {[type]} options [description]
622 * @return {[type]} [description]
623 */
624 selectInsert: function(fields, table, options){
6250 options = options || {};
6260 this.model = options.model;
6270 if (isString(fields)) {
6280 fields = fields.split(',');
629 }
6300 var self = this;
6310 fields = fields.map(function(item){
6320 return self.parseKey(item);
633 });
6340 var sql = 'INSERT INTO ' + this.parseTable(options.table) + ' (' + fields.join(',') + ')';
6350 sql += this.buildSelectSql(options);
6360 return this.execute(sql);
637 },
638 /**
639 * 删除记录
640 * @param {[type]} options [description]
641 * @return {[type]} [description]
642 */
643 delete: function(options){
6445 options = options || {};
6455 this.model = options.model;
6465 var sql = [
647 'DELETE FROM ',
648 this.parseTable(options.table),
649 this.parseWhere(options.where),
650 this.parseOrder(options.order),
651 this.parseLimit(options.limit),
652 this.parseLock(options.lock),
653 this.parseComment(options.comment)
654 ].join('');
6555 return this.execute(sql);
656 },
657 /**
658 * 更新数据
659 * @param {[type]} data [description]
660 * @param {[type]} options [description]
661 * @return {[type]} [description]
662 */
663 update: function(data, options){
66414 options = options || {};
66514 this.model = options.model;
66614 var sql = [
667 'UPDATE ',
668 this.parseTable(options.table),
669 this.parseSet(data),
670 this.parseWhere(options.where),
671 this.parseOrder(options.order),
672 this.parseLimit(options.limit),
673 this.parseLock(options.lock),
674 this.parseComment(options.comment)
675 ].join('');
67614 return this.execute(sql);
677 },
678 /**
679 * 数据查询
680 * @todo 返回是个promise,缓存调用需要修改
681 * @param {[type]} options [description]
682 * @return {[type]} [description]
683 */
684 select: function(options){
685154 var sql, cache;
686154 if (isString(options) && options.indexOf('SELECT') > -1) {
6870 sql = options;
6880 cache = arguments[1];
689 }else{
690154 options = options || {};
691154 this.model = options.model;
692154 sql = this.buildSelectSql(options);
693154 cache = options.cache;
694 }
695154 var self = this;
696154 if (!isEmpty(cache) && C('db_cache_on')) {
697 //内存缓存
6980 if (cache.type === '') {
6990 cache.cacheData = dbCacheData;
700 }
7010 var key = cache.key || md5(sql);
7020 return S(key, function(){
7030 return self.query(sql);
704 }, cache);
705 }
706154 return this.query(sql);
707 },
708 /**
709 * 转义字符
710 * @param {[type]} str [description]
711 * @return {[type]} [description]
712 */
713 escapeString: function(str){
71475 if (!str) {
7150 return '';
716 }
71775 return str.replace(/[\0\n\r\b\t\\\'\"\x1a]/g, function(s) {
7186 switch(s) {
719 case '\0':
7200 return '\\0';
721 case '\n':
7223 return '\\n';
723 case '\r':
7240 return '\\r';
725 case '\b':
7260 return '\\b';
727 case '\t':
7280 return '\\t';
729 case '\x1a':
7300 return '\\Z';
731 default:
7323 return '\\'+s;
733 }
734 });
735 },
736 /**
737 * 获取上次的sql语句
738 * @param {[type]} model [description]
739 * @return {[type]} [description]
740 */
741 getLastSql: function(model){
742174 return model ? this.modelSql[model] : this.sql;
743 },
744 /**
745 * 设置当前操作的sql
746 * @param {[type]} sql [description]
747 */
748 setSql: function(sql){
749183 this.sql = sql;
750183 this.modelSql[this.model] = sql;
751 },
752 /**
753 * 设置模型
754 * @param {[type]} model [description]
755 */
756 setModel: function(model){
7570 this.model = model;
7580 return this;
759 }
760 };
761});
762/**
763 * 解析配置
764 * @param {[type]} config [description]
765 * @return {[type]} [description]
766 */
7671Db.parseConfig = function(config){
7681 'use strict';
7691 config = config || {};
7701 return {
771 type: config.db_type || C('db_type') || 'mysql',
772 username: config.db_user || C('db_user'),
773 password: config.db_pwd || C('db_pwd'),
774 hostname: config.db_host || C('db_host'),
775 port: config.db_port || C('db_port'),
776 database: config.db_name || C('db_name'),
777 charset: config.db_charset || C('db_charset')
778 };
779};
780/**
781 * 根据配置获取对应的数据库实例
782 * @param {[type]} config [description]
783 * @return {[type]} [description]
784 */
7851Db.getInstance = function(config){
7861 'use strict';
7871 config = this.parseConfig(config);
7881 var instance = thinkRequire(ucfirst(config.type) + 'Db')(config);
7891 instance.dbType = config.type.toUpperCase();
7901 return instance;
791};

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

88%
50
44
6
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){
8931 'use strict';
9031 group = group || C('default_group');
9131 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){
10531 'use strict';
10631 if (!controller || !nameReg.test(controller)) {
1071 return ucfirst(C('default_controller'));
108 }
10930 return ucfirst(controller);
110};
111/**
112 * 获取action
113 * @param {[type]} action [description]
114 * @return {[type]} [description]
115 */
1161Dispatcher.getAction = function(action){
11731 'use strict';
11831 if (!action || !nameReg.test(action)) {
1191 return C('default_action');
120 }
12130 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){
1610 this.req = req;
1710 this.res = res;
18 //http对象为EventEmitter的实例
1910 this.http = new EventEmitter();
20 //记录当前请求的开始时间
2110 this.http.startTime = Date.now();
22 },
23 /**
24 * 执行
25 * @param {Function} callback [description]
26 * @return Promise [description]
27 */
28 run: function(){
2910 this._request();
3010 this._response();
31 //数组的indexOf要比字符串的indexOf略快
3210 var methods = ['POST', 'PUT', 'PATCH'];
3310 if (methods.indexOf(this.req.method) > -1) {
340 return this.getPostData();
35 }
3610 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(){
14210 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 };
17110 extend(this.http, req);
172
173 //解析url中的参数
17410 var urlInfo = url.parse('//' + req.headers.host + this.req.url, true, true);
17510 this.http.pathname = urlInfo.pathname;
176 //query只记录?后面的参数
17710 this.http.query = urlInfo.query;
178 //get包含路由解析追加的参数
17910 this.http.get = extend({}, urlInfo.query);
180 //主机名,带端口
18110 this.http.host = urlInfo.host;
182 //主机名,不带端口
18310 this.http.hostname = urlInfo.hostname;
184 //将原生的request对象放在http上,方便后续在controller等地方使用
18510 this.http.req = this.req;
186 },
187 /**
188 * HttpResponse增强
189 * @return {[type]} [description]
190 */
191 _response: function(){
19210 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){
2165 options = options || {};
2175 if (typeof options === 'number') {
2180 options = {timeout: options};
219 }
2205 var timeout = options.timeout;
2215 if (timeout === undefined) {
2225 timeout = C('cookie_timeout');
223 }
2245 delete options.timeout;
225 //if value is null, remove cookie
2265 if (value === null) {
2270 timeout = -1000;
228 }
2295 var defaultOptions = {
230 path: C('cookie_path'),
231 domain: C('cookie_domain'),
232 expires: new Date (Date.now() + timeout * 1000)
233 };
2345 if (timeout === 0) {
2355 delete defaultOptions.expires;
236 }
2375 for(var key in options){
2380 defaultOptions[key.toLowerCase()] = options[key];
239 }
2405 defaultOptions.name = name;
2415 defaultOptions.value = encodeURIComponent(value + '');
2425 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 };
30810 extend(this.http, res);
309 //将原生的response对象放在http上,方便后续controller等地方使用
31010 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

68%
429
295
134
LineHitsSource
11var util = require('util');
21var querystring = require('querystring');
31var Db = thinkRequire('Db');
4
5//数据库实例化对象
61var dbInstances = {};
7//数据表的字段信息
81var tableFields = {};
9
10/**
11 * Model类
12 * @type {[type]}
13 */
141var Model = module.exports = Class(function(){
151 'use strict';
16 //解析page参数
171 var parsePage = function(options){
180 if ('page' in options) {
190 var page = options.page + '';
200 var num = 0;
210 if (page.indexOf(',') > -1) {
220 page = page.split(',');
230 num = parseInt(page[1], 10);
240 page = page[0];
25 }
260 num = num || C('db_nums_per_page');
270 page = parseInt(page, 10) || 1;
280 return {
29 page: page,
30 num: num
31 };
32 }
330 return {
34 page: 1,
35 num: C('db_nums_per_page')
36 };
37 };
38 /**
39 * 字符串命名风格转换
40 * @param {[type]} name [description]
41 * @param {[type]} type [description]
42 * @return {[type]} [description]
43 */
441 var parseName = function(name, type){
4528 name = (name + '').trim();
4628 if (type) {
470 name = name.replace(/_([a-zA-Z])/g, function(a, b){
480 return b.toUpperCase();
49 });
500 return name.substr(0, 1).toUpperCase() + name.substr(1);
51 } else {
52 //首字母如果是大写,不转义为_x
5328 if (name.length >= 1) {
5428 name = name.substr(0, 1).toLowerCase() + name.substr(1);
55 }
5628 return name.replace(/[A-Z]/g, function(a){
570 return '_' + a;
58 }).toLowerCase();
59 }
60 };
61
621 return {
63 // 当前数据库操作对象
64 db: null,
65 // 主键名称
66 pk: 'id',
67 // 数据库配置信息
68 config: null,
69 // 配置信息key
70 configKey: '',
71 // 模型名称
72 name: '',
73 // 数据表前缀
74 tablePrefix: '',
75 // 数据表名(不包含表前缀)
76 tableName: '',
77 // 实际数据表名(包含表前缀)
78 trueTableName: '',
79 // 数据表字段信息
80 fields: {},
81 // 数据信息
82 _data: {},
83 // 参数
84 _options: {},
85 /**
86 * 初始化
87 * @access public
88 * @param string $name 模型名称
89 * @param mixed config 数据库连接信息
90 */
91 init: function(name, config){
92 // 获取模型名称
9344 if (name) {
9426 this.name = name;
95 }
9644 if (isString(config)) {
970 config = {db_prefix: config};
98 }
9944 this.config = config || '';
100 //数据表前缀
10144 if (this.config.db_prefix) {
1020 this.tablePrefix = this.config.db_prefix;
10344 }else if(!this.tablePrefix) {
10444 this.tablePrefix = C('db_prefix');
105 }
106 },
107 /**
108 * 初始化数据库连接
109 * @return {[type]} [description]
110 */
111 initDb: function(){
112376 if (this.db) {
113348 return this.db;
114 }
11528 var config = this.config;
11628 var configKey = md5(JSON.stringify(config));
11728 if (!dbInstances[configKey]) {
1181 dbInstances[configKey] = Db.getInstance(config);
119 }
12028 this.db = dbInstances[configKey];
12128 this.configKey = configKey;
12228 return this.db;
123 },
124 /**
125 * 获取模型名
126 * @access public
127 * @return string
128 */
129 getModelName: function(){
130214 if (this.name) {
131203 return this.name;
132 }
13311 var filename = this.__filename || __filename;
13411 var last = filename.lastIndexOf('/');
13511 this.name = filename.substr(last + 1, filename.length - last - 9);
13611 return this.name;
137 },
138 /**
139 * 获取表名
140 * @return {[type]} [description]
141 */
142 getTableName: function(){
143195 if (!this.trueTableName) {
14428 var tableName = this.tablePrefix || '';
14528 tableName += this.tableName || parseName(this.getModelName());
14628 this.trueTableName = tableName.toLowerCase();
147 }
148195 return this.trueTableName;
149 },
150 /**
151 * 获取数据表信息
152 * @access protected
153 * @return Promise
154 */
155 getTableFields: function(table, all){
156196 this.initDb();
157196 if (table === true) {
1580 table = undefined;
1590 all = true;
160 }
161196 if (!isEmpty(this.fields)) {
162168 return getPromise(all ? this.fields : this.fields._field);
163 }
16428 var tableName = table || this.getTableName();
16528 var fields = tableFields[tableName];
16628 if (!isEmpty(fields)) {
16724 this.fields = fields;
16824 return getPromise(all ? fields : fields._field);
169 }
1704 var self = this;
171 //从数据表里查询字段信息
1724 return this.flushFields(tableName).then(function(fields){
1734 self.fields = fields;
1744 if (C('db_fields_cache')) {
1754 tableFields[tableName] = fields;
176 }
1774 return getPromise(all ? fields : fields._field);
178 });
179 },
180 /**
181 * 获取数据表信息
182 * @param {[type]} table [description]
183 * @return Promise [description]
184 */
185 flushFields: function(table){
1865 table = table || this.getTableName();
1875 return this.initDb().getFields(table).then(function(data){
1885 var fields = {
189 '_field': Object.keys(data || {}),
190 '_autoinc': false,
191 '_unique': []
192 };
1935 var types = {};
1945 for(var key in data){
19565 var val = data[key];
19665 types[key] = val.type;
19765 if (val.primary) {
1985 fields._pk = key;
1995 if (val.autoinc) {
2005 fields._autoinc = true;
201 }
20260 }else if (val.unique) {
2035 fields._unique.push(key);
204 }
205 }
2065 fields._type = types;
2075 return fields;
208 })
209 },
210 /**
211 * 获取类型为唯一的字段
212 * @return {[type]} [description]
213 */
214 // getUniqueField: function(data){
215 // var unqiueFileds = this.fields._unique;
216 // var unqiue = '';
217 // unqiueFileds.some(function(item){
218 // if (!data || data[item]) {
219 // unqiue = item;
220 // return unqiue;
221 // }
222 // });
223 // return unqiue;
224 // },
225 /**
226 * 获取上一次操作的sql
227 * @return {[type]} [description]
228 */
229 getLastSql: function(){
230174 return this.initDb().getLastSql();
231 },
232 /**
233 * 获取主键名称
234 * @access public
235 * @return string
236 */
237 getPk: function(){
238 //如果fields为空,那么异步去获取
23935 if (isEmpty(this.fields)) {
2409 var self = this;
2419 return this.getTableFields().then(function(){
2429 return self.fields_pk || self.pk;
243 })
244 }
24526 return this.fields._pk || this.pk;
246 },
247 /**
248 * 缓存
249 * @param {[type]} key [description]
250 * @param {[type]} expire [description]
251 * @param {[type]} type [description]
252 * @return {[type]} [description]
253 */
254 cache: function(key, timeout){
2550 if (key === undefined) {
2560 return this;
257 }
2580 var options = this._getCacheOptions(key, timeout);
2590 this._options.cache = options;
2600 return this;
261 },
262 /**
263 * 获取缓存的选项
264 * @param {[type]} key [description]
265 * @param {[type]} timeout [description]
266 * @return {[type]} [description]
267 */
268 _getCacheOptions: function(key, timeout, type){
2690 if (isObject(key)) {
2700 return key;
271 }
2720 if (isNumber(key)) {
2730 timeout = key;
2740 key = '';
275 }
2760 var cacheType = type === undefined ? C('db_cache_type') : type;
2770 var options = {
278 key: key,
279 timeout: timeout || C('db_cache_timeout'),
280 type: cacheType,
281 gcType: 'dbCache'
282 }
2830 if (cacheType === 'File') {
2840 options.cache_path = C('db_cache_path');
285 }
2860 return options;
287 },
288 /**
289 * 指定查询数量
290 * @param {[type]} offset [description]
291 * @param {[type]} length [description]
292 * @return {[type]} [description]
293 */
294 limit: function(offset, length){
2954 this._options.limit = length === undefined ? offset : offset + ',' + length;
2964 return this;
297 },
298 /**
299 * 指定分页
300 * @return {[type]} [description]
301 */
302 page: function(page, listRows){
3037 this._options.page = listRows === undefined ? page : page + ',' + listRows;
3047 return this;
305 },
306 /**
307 * where条件
308 * @return {[type]} [description]
309 */
310 where: function(where){
31196 if (!where) {
3122 return this;
313 }
31494 if (isString(where)) {
3153 where = {_string: where};
316 }
31794 this._options.where = extend(this._options.where || {}, where);
31894 return this;
319 },
320 /**
321 * 要查询的字段
322 * @param {[type]} field [description]
323 * @param {[type]} reverse [description]
324 * @return {[type]} [description]
325 */
326 field: function(field, reverse){
3275 if (isArray(field)) {
3282 field = field.join(',');
3293 }else if (!field) {
3301 field = '*';
331 }
3325 this._options.field = field;
3335 this._options.fieldReverse = reverse;
3345 return this;
335 },
336 /**
337 * 设置表名
338 * @param {[type]} table [description]
339 * @return {[type]} [description]
340 */
341 table: function(table, prefix){
3422 if (!table) {
3430 return this;
344 }
3452 this._options.table = prefix ? table : this.tablePrefix + table;
3462 return this;
347 },
348 /**
349 * 联合查询
350 * @return {[type]} [description]
351 */
352 union: function(union, all){
3535 if (!this._options.union) {
3544 this._options.union = [];
355 }
3565 this._options.union.push({
357 union: union,
358 all: all
359 });
3605 return this;
361 },
362 /**
363 * .join({
364 * 'xxx': {
365 * join: 'left',
366 * as: 'c',
367 * on: ['id', 'cid']
368 * }
369 * })
370 * 联合查询
371 * @param {[type]} join [description]
372 * @return {[type]} [description]
373 */
374 join: function(join){
37518 if (!this._options.join) {
37617 this._options.join = [];
377 }
37818 if (isArray(join)) {
3791 this._options.join = this._options.join.concat(join);
380 }else{
38117 this._options.join.push(join);
382 }
38318 return this;
384 },
385 /**
386 * 生成查询SQL 可用于子查询
387 * @param {[type]} options [description]
388 * @return {[type]} [description]
389 */
390 buildSql: function(options){
3911 var self = this;
3921 return this.parseOptions(options).then(function(options){
3931 return '( ' + self.db.buildSelectSql(options) + ' )';
394 });
395 },
396 /**
397 * 解析参数
398 * @param {[type]} options [description]
399 * @return promise [description]
400 */
401 parseOptions: function(options, extraOptions){
402185 options = extend({}, this._options, this.parseWhereOptions(options), extraOptions);
403 // 查询过后清空sql表达式组装 避免影响下次查询
404185 this._options = {};
405185 options.table = options.table || this.getTableName();
406 //表前缀,Db里会使用
407185 options.tablePrefix = this.tablePrefix;
408185 options.model = this.getModelName();
409185 var promise = this.getTableFields(options.table);
410 //数据表别名
411185 if (options.alias) {
4126 options.table += ' AS ' + options.alias;
413 }
414185 var self = this;
415185 return promise.then(function(fields){
416 // 字段类型验证
417185 if (isObject(options.where) && !isEmpty(fields)) {
41895 var keyReg = /[\.\|\&]/;
419 // 对数组查询条件进行字段类型检查
42095 for(var key in options.where){
421108 var val = options.where[key];
422108 key = key.trim();
423108 if (fields.indexOf(key) > -1) {
42494 if (isScalar(val)) {
42529 options.where[key] = self.parseType(options.where, key)[key];
426 }
42714 }else if(key[0] !== '_' && !keyReg.test(key)){
4281 delete options.where[key];
429 }
430 }
431 }
432 //field反选
433185 if (options.field && options.fieldReverse) {
4341 var optionsField = options.field.split(',');
4351 options.field = fields.filter(function(item){
43613 if (optionsField.indexOf(item) > -1) {
4372 return;
438 }
43911 return item;
440 }).join(',');
441 }
442185 return self._optionsFilter(options, fields);
443 });
444 },
445 /**
446 * 选项过滤器
447 * 具体的Model类里进行实现
448 * @param {[type]} options [description]
449 * @return {[type]} [description]
450 */
451 _optionsFilter: function(options){
452185 return options;
453 },
454 /**
455 * 数据类型检测
456 * @param {[type]} data [description]
457 * @param {[type]} key [description]
458 * @return {[type]} [description]
459 */
460 parseType: function(data, key){
46145 var fieldType = this.fields._type[key] || '';
46245 if (fieldType.indexOf('bigint') === -1 && fieldType.indexOf('int') > -1) {
46324 data[key] = parseInt(data[key], 10) || 0;
46421 }else if(fieldType.indexOf('double') > -1 || fieldType.indexOf('float') > -1){
4650 data[key] = parseFloat(data[key]) || 0.0;
46621 }else if(fieldType.indexOf('bool') > -1){
4670 data[key] = !! data[key];
468 }
46945 return data;
470 },
471 /**
472 * 对插入到数据库中的数据进行处理,要在parseOptions后执行
473 * @param {[type]} data [description]
474 * @return {[type]} [description]
475 */
476 parseData: function(data){
47721 data = extend({}, data);
47821 var key;
47921 if (!isEmpty(this.fields)) {
48021 for(key in data){
48125 var val = data[key];
48225 if (this.fields._field.indexOf(key) === -1) {
4831 delete data[key];
48424 }else if(isScalar(val)){
48516 data = this.parseType(data, key);
486 }
487 }
488 }
489 //安全过滤
49021 if (typeof this._options.filter === 'function') {
4910 for(key in data){
4920 data[key] = this._options.filter.call(this, key, data[key]);
493 }
4940 delete this._options.filter;
495 }
49621 data = this._dataFilter(data);
49721 return data;
498 },
499 /**
500 * 数据过滤器
501 * 具体的Model类里进行实现
502 * @param {[type]} data [description]
503 * @return {[type]} [description]
504 */
505 _dataFilter: function(data){
50621 return data;
507 },
508 /**
509 * 数据插入之前操作,可以返回一个promise
510 * @param {[type]} data [description]
511 * @param {[type]} options [description]
512 * @return {[type]} [description]
513 */
514 _beforeAdd: function(data){
5154 return data;
516 },
517 /**
518 * 数据插入之后操作,可以返回一个promise
519 * @param {[type]} data [description]
520 * @param {[type]} options [description]
521 * @return {[type]} [description]
522 */
523 _afterAdd: function(data){
5244 return data;
525 },
526 /**
527 * 添加一条数据
528 * @param {[type]} data [description]
529 * @param {[type]} options [description]
530 * @param int 返回插入的id
531 */
532 add: function(data, options, replace){
533 //copy data
5345 data = extend({}, this._data, data);
5355 this._data = {};
5365 if (isEmpty(data)) {
5371 return getPromise(new Error('_DATA_TYPE_INVALID_'), true);
538 }
5394 var self = this;
540 //解析后的选项
5414 var parsedOptions = {};
542 //解析后的数据
5434 var parsedData = {};
5444 return this.parseOptions(options).then(function(options){
5454 parsedOptions = options;
5464 return self._beforeAdd(data, parsedOptions);
547 }).then(function(data){
5484 parsedData = data;
5494 data = self.parseData(data);
5504 return self.db.insert(data, parsedOptions, replace);
551 }).then(function(){
5524 parsedData[self.getPk()] = self.db.getLastInsertId();
5534 return self._afterAdd(parsedData, parsedOptions);
554 }).then(function(){
5554 return parsedData[self.getPk()];
556 });
557 },
558 /**
559 * 如果当前条件的数据不存在,才添加
560 * @param {[type]} data 要插入的数据
561 * @param {[type]} where where条件
562 * @param boolean returnType 返回值是否包含type
563 * @return {[type]} promise
564 */
565 thenAdd: function(data, where, returnType){
5660 if (where === true) {
5670 returnType = true;
5680 where = '';
569 }
5700 var self = this;
5710 return this.where(where).find().then(function(findData){
5720 if (!isEmpty(findData)) {
5730 var idValue = findData[self.getPk()];
5740 return returnType ? {id: idValue, type: 'exist'} : idValue;
575 }
5760 return self.add(data).then(function(insertId){
5770 return returnType ? {id: insertId, type: 'add'} : insertId;
578 });
579 });
580 },
581 /**
582 * 插入多条数据
583 * @param {[type]} data [description]
584 * @param {[type]} options [description]
585 * @param {[type]} replace [description]
586 */
587 addAll: function(data, options, replace){
5886 if (!isArray(data) || !isObject(data[0])) {
5892 return getPromise(new Error('_DATA_TYPE_INVALID_'), true);
590 }
5914 var self = this;
5924 return this.parseOptions(options).then(function(options){
5934 return self.db.insertAll(data, options, replace);
594 }).then(function(){
5954 return self.db.getLastInsertId();
596 });
597 },
598 /**
599 * 删除后续操作
600 * @return {[type]} [description]
601 */
602 _afterDelete: function(data){
6034 return data;
604 },
605 /**
606 * 删除数据
607 * @return {[type]} [description]
608 */
609 delete: function(options){
6105 var self = this;
6115 var parsedOptions = {};
6125 var affectedRows = 0;
6135 return this.parseOptions(options).then(function(options){
6145 parsedOptions = options;
6155 return self.db.delete(options);
616 }).then(function(rows){
6174 affectedRows = rows;
6184 return self._afterDelete(parsedOptions.where || {}, parsedOptions);
619 }).then(function(){
6204 return affectedRows;
621 })
622 },
623 /**
624 * 更新前置操作
625 * @param {[type]} data [description]
626 * @param {[type]} options [description]
627 * @return {[type]} [description]
628 */
629 _beforeUpdate: function(data){
63017 return data;
631 },
632 /**
633 * 更新后置操作
634 * @param {[type]} data [description]
635 * @param {[type]} options [description]
636 * @return {[type]} [description]
637 */
638 _afterUpdate: function(data){
63914 return data;
640 },
641 /**
642 * 更新数据
643 * @return {[type]} [description]
644 */
645 update: function(data, options){
64618 data = extend({}, data);
64718 if (isEmpty(data)) {
6481 if (!isEmpty(this._data)) {
6490 data = this._data;
6500 this._data = {};
651 }else{
6521 return getPromise(new Error('_DATA_TYPE_INVALID_'), true);
653 }
654 }
65517 var self = this;
65617 var parsedOptions = {};
65717 var parsedData = {};
65817 var affectedRows = 0;
65917 return this.parseOptions(options).then(function(options){
66017 parsedOptions = options;
66117 return self._beforeUpdate(data, options);
662 }).then(function(data){
66317 var pk = self.getPk();
66417 parsedData = data;
66517 data = self.parseData(data);
66617 if (isEmpty(parsedOptions.where)) {
667 // 如果存在主键数据 则自动作为更新条件
6685 if (!isEmpty(data[pk])) {
6692 parsedOptions.where = getObject(pk, data[pk]);
6702 delete data[pk];
671 }else{
6723 return getPromise(new Error('_OPERATION_WRONG_'), true);
673 }
674 }else{
67512 parsedData[pk] = parsedOptions.where[pk];
676 }
67714 return self.db.update(data, parsedOptions);
678 }).then(function(rows){
67914 affectedRows = rows;
68014 return self._afterUpdate(parsedData, parsedOptions);
681 }).then(function(){
68214 return affectedRows;
683 });
684 },
685 /**
686 * 更新多个数据,自动用主键作为查询条件
687 * @param {[type]} dataList [description]
688 * @return {[type]} [description]
689 */
690 updateAll: function(dataList){
6914 if (!isArray(dataList) || !isObject(dataList[0])) {
6922 return getPromise(new Error('_DATA_TYPE_INVALID_'), true);
693 }
6942 var self = this;
6952 var promises = dataList.map(function(data){
6963 return self.update(data);
697 });
6982 return Promise.all(promises);
699 },
700 /**
701 * 更新某个字段的值
702 * @param {[type]} field [description]
703 * @param {[type]} value [description]
704 * @return {[type]} [description]
705 */
706 updateField: function(field, value){
70710 var data = {};
70810 if (isObject(field)) {
7090 data = field;
710 }else{
71110 data[field] = value;
712 }
71310 return this.update(data);
714 },
715 /**
716 * 字段值增长
717 * @return {[type]} [description]
718 */
719 updateInc: function(field, step){
7204 step = parseInt(step, 10) || 1;
7214 return this.updateField(field, ['exp', field + '+' + step]);
722 },
723 /**
724 * 字段值减少
725 * @return {[type]} [description]
726 */
727 updateDec: function(field, step){
7284 step = parseInt(step, 10) || 1;
7294 return this.updateField(field, ['exp', field + '-' + step]);
730 },
731 /**
732 * 解析options中简洁的where条件
733 * @return {[type]} [description]
734 */
735 parseWhereOptions: function(options){
736185 if (isNumber(options) || isString(options)) {
7370 var pk = this.getPk();
7380 options += '';
7390 var where = {};
7400 if (options.indexOf(',') > -1) {
7410 where[pk] = ['IN', options];
742 }else{
7430 where[pk] = options;
744 }
7450 options = {
746 where: where
747 };
748 }
749185 return options || {};
750 },
751 /**
752 * find查询后置操作
753 * @return {[type]} [description]
754 */
755 _afterFind: function(result){
7562 return result;
757 },
758 /**
759 * 查询一条数据
760 * @return 返回一个promise
761 */
762 find: function(options){
7633 var self = this;
7643 var parsedOptions = {};
7653 return this.parseOptions(options, {
766 limit: 1
767 }).then(function(options){
7683 parsedOptions = options;
7693 return self.db.select(options);
770 }).then(function(data){
7712 return self._afterFind(data[0] || {}, parsedOptions);
772 });
773 },
774 /**
775 * 查询后置操作
776 * @param {[type]} result [description]
777 * @param {[type]} options [description]
778 * @return {[type]} [description]
779 */
780 _afterSelect: function(result){
781136 return result;
782 },
783 /**
784 * 查询数据
785 * @return 返回一个promise
786 */
787 select: function(options){
788137 var self = this;
789137 var parsedOptions = {};
790137 return this.parseOptions(options).then(function(options){
791137 parsedOptions = options;
792137 return self.db.select(options);
793 }).then(function(result){
794136 return self._afterSelect(result, parsedOptions);
795 });
796 },
797 selectAdd: function(fields, table, options){
7980 var self = this;
7990 return this.parseOptions(options).then(function(options){
8000 fields = fields || options.field;
8010 table = table || self.getTableName();
8020 return self.db.selectInsert(fields, table, options);
803 });
804 },
805 /**
806 * 返回数据里含有count信息的查询
807 * @param options 查询选项
808 * @param pageFlag 当页面不合法时的处理方式,true为获取第一页,false为获取最后一页,undefined获取为空
809 * @return promise
810 */
811 countSelect: function(options, pageFlag){
8120 if (isBoolean(options)) {
8130 pageFlag = options;
8140 options = {};
815 }
8160 var self = this;
817 //解析后的options
8180 var parsedOptions = {};
8190 var result = {};
8200 return this.parseOptions(options).then(function(options){
8210 delete options.table;
8220 parsedOptions = options;
8230 return self.options({
824 where: options.where,
825 cache: options.cache,
826 join: options.join,
827 alias: options.alias
828 }).count((options.alias || self.getTableName()) + '.' + self.getPk());
829 }).then(function(count){
8300 var pageOptions = parsePage(parsedOptions);
8310 var totalPage = Math.ceil(count / pageOptions.num);
8320 if (isBoolean(pageFlag)) {
8330 if (pageOptions.page > totalPage) {
8340 pageOptions.page = pageFlag === true ? 1 : totalPage;
835 }
8360 parsedOptions.page = pageOptions.page + ',' + pageOptions.num;
837 }
8380 result = extend({count: count, total: totalPage}, pageOptions);
8390 return self.select(parsedOptions);
840 }).then(function(data){
8410 result.data = data;
8420 return result;
843 });
844 },
845 /**
846 * 获取某个字段下的记录
847 * @return {[type]} [description]
848 */
849 getField: function(field, one){
85014 var self = this;
85114 return this.parseOptions({'field': field}).then(function(options){
85214 if (isNumber(one)) {
8531 options.limit = one;
85413 }else if (one === true) {
85511 options.limit = 1;
856 }
85714 return self.db.select(options);
858 }).then(function(data){
85914 var multi = field.indexOf(',') > -1;
86014 if (multi) {
8611 var fields = field.split(/\s*,\s*/);
8621 var result = {};
8631 fields.forEach(function(item){
8642 result[item] = [];
865 })
8661 data.every(function(item){
8679 fields.forEach(function(fItem){
86818 if (one === true) {
8690 result[fItem] = item[fItem];
870 }else{
87118 result[fItem].push(item[fItem]);
872 }
873 })
8749 return one === true ? false : true;
875 })
8761 return result;
877 }else{
87813 data = data.map(function(item){
879117 return Object.values(item)[0];
880 })
88113 return one === true ? data[0] : data;
882 }
883 });
884 },
885 /**
886 * 根据某个字段值获取一条数据
887 * @param {[type]} name [description]
888 * @param {[type]} value [description]
889 * @return {[type]} [description]
890 */
891 getBy: function(name, value){
8920 var where = getObject(name, value);
8930 return this.where(where).find();
894 },
895 /**
896 * SQL查询
897 * @return {[type]} [description]
898 */
899 query: function(sql, parse){
9000 if (parse !== undefined && !isBoolean(parse) && !isArray(parse)) {
9010 parse = [].slice.call(arguments);
9020 parse.shift();
903 }
9040 var self = this;
9050 return this.parseSql(sql, parse).then(function(sql){
9060 return self.db.select(sql, self._options.cache);
907 }).then(function(data){
9080 self._options = {};
9090 return data;
910 })
911 },
912 /**
913 * 执行SQL语法,非查询类的SQL语句,返回值为影响的行数
914 * @param {[type]} sql [description]
915 * @param {[type]} parse [description]
916 * @return {[type]} [description]
917 */
918 execute: function(sql, parse){
9190 if (parse !== undefined && !isBoolean(parse) && !isArray(parse)) {
9200 parse = [].slice.call(arguments);
9210 parse.shift();
922 }
9230 var self = this;
9240 return this.parseSql(sql, parse).then(function(sql){
9250 return self.db.execute(sql);
926 });
927 },
928 /**
929 * 解析SQL语句
930 * @return promise [description]
931 */
932 parseSql: function(sql, parse){
9330 var promise = null;
9340 var self = this;
9350 if (parse === true) {
9360 promise = this.parseOptions().then(function(options){
9370 return self.db.parseSql(options);
938 });
939 }else{
9400 if (parse === undefined) {
9410 parse = [];
942 }else{
9430 parse = isArray(parse) ? parse : [parse];
944 }
9450 parse.unshift(sql);
9460 sql = util.format.apply(null, parse);
9470 var map = {
948 '__TABLE__': '`' + this.getTableName() + '`'
949 };
9500 sql = sql.replace(/__([A-Z]+)__/g, function(a, b){
9510 return map[a] || ('`' + self.tablePrefix + b.toLowerCase() + '`');
952 });
9530 promise = getPromise(sql);
954 }
9550 this.initDb().setModel(self.getModelName());
9560 return promise;
957 },
958 /**
959 * 设置数据对象值
960 * @return {[type]} [description]
961 */
962 data: function(data){
9630 if (data === true) {
9640 return this._data;
965 }
9660 if (isString(data)) {
9670 data = querystring.parse(data);
968 }
9690 this._data = data;
9700 return this;
971 },
972 /**
973 * 设置操作选项
974 * @param {[type]} options [description]
975 * @return {[type]} [description]
976 */
977 options: function(options){
9780 if (options === true) {
9790 return this._options;
980 }
9810 this._options = options;
9820 return this;
983 },
984 /**
985 * 关闭数据库连接
986 * @return {[type]} [description]
987 */
988 close: function(){
9890 delete dbInstances[this.configKey];
9900 if (this.db) {
9910 this.db.close();
9920 this.db = null;
993 }
994 }
995 };
996}).extend(function(){
9971 'use strict';
998 //追加的方法
9991 var methods = {};
1000 // 链操作方法列表
10011 var methodNameList = [
1002 'order','alias','having','group',
1003 'lock','auto','filter','validate'
1004 ];
10051 methodNameList.forEach(function(item){
10068 methods[item] = function(data){
100720 this._options[item] = data;
100820 return this;
1009 };
1010 });
10111 methods.distinct = function(data){
10122 this._options.distinct = data;
1013 //如果传过来一个字段,则映射到field上
10142 if (isString(data)) {
10152 this._options.field = data;
1016 }
10172 return this;
1018 };
10191 ['count','sum','min','max','avg'].forEach(function(item){
10205 methods[item] = function(field){
102110 field = field || this.pk;
102210 return this.getField(item.toUpperCase() + '(' + field + ') AS thinkjs_' + item, true);
1023 };
1024 });
1025 //方法别名
10261 var aliasMethodMap = {
1027 update: 'save',
1028 updateField: 'setField',
1029 updateInc: 'setInc',
1030 updateDec: 'setDec'
1031 };
10321 Object.keys(aliasMethodMap).forEach(function(key){
10334 var value = aliasMethodMap[key];
10344 methods[value] = function(){
10350 return this[key].apply(this, arguments);
1036 };
1037 });
10381 return methods;
1039});
1040/**
1041 * 关闭所有的数据库连接
1042 * @return {[type]} [description]
1043 */
10441Model.close = function(){
10451 'use strict';
10461 for(var key in dbInstances) {
10470 dbInstances[key].close();
1048 }
10491 dbInstances = {};
1050};

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

54%
174
94
80
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();
18 //加载文件
191 this.loadFiles();
20 //合并自动加载的路径
211 this.mergeAutoloadPath();
22 //thinkRequire的autoload
231 registerAutoload(this.autoload);
24 //debug模式
251 if (APP_DEBUG) {
260 this.debug();
27 }else{
281 this.processEvent();
29 }
30 //记录进程的id
311 this.logPid();
32 //记录日志
331 this.log();
34
351 thinkRequire('App').run();
36 },
37 /**
38 * 定义一些目录,加载框架的基础文件
39 * @return {[type]} [description]
40 */
41 init: function(){
421 'use strict';
43 //系统路径设置
441 global.THINK_LIB_PATH = THINK_PATH + '/Lib';
451 global.THINK_EXTEND_PATH = THINK_LIB_PATH + '/Extend';
46 //应用路径设置
471 var config = {
48 COMMON_PATH: APP_PATH + '/Common',
49 LIB_PATH: APP_PATH + '/Lib',
50 CONF_PATH: APP_PATH + '/Conf',
51 LANG_PATH: APP_PATH + '/Lang',
52 VIEW_PATH: APP_PATH + '/View',
53 //HTML_PATH: RUNTIME_PATH + '/Html',
54 LOG_PATH: RUNTIME_PATH + '/Log',
55 TEMP_PATH: RUNTIME_PATH + '/Temp',
56 DATA_PATH: RUNTIME_PATH + '/Data',
57 CACHE_PATH: RUNTIME_PATH + '/Cache'
58 };
591 for (var name in config) {
609 if (global[name] === undefined) {
619 global[name] = config[name];
62 }
63 }
641 require(THINK_PATH + '/Common/extend.js');
651 require(THINK_PATH + '/Common/common.js');
661 require(THINK_PATH + '/Common/function.js');
67 //别名导入
681 aliasImport(require(THINK_PATH + '/Conf/alias.js'));
69 },
70 /**
71 * 记录日志
72 * @return {[type]} [description]
73 */
74 log: function(){
751 'use strict';
761 if (APP_DEBUG || APP_MODE === 'cli' || !C('log_record')) {
771 return;
78 }
790 thinkRequire('Log')().run();
80 },
81 /**
82 * 安全方式加载文件
83 * @param {[type]} file [description]
84 * @return {[type]} [description]
85 */
86 safeRequire: function(file){
872 'use strict';
882 try{
892 return require(file);
90 }catch(e){
910 console.error(e.stack);
92 }
930 return {};
94 },
95 /**
96 * 注册异常处理
97 * @return {[type]} [description]
98 */
99 processEvent: function(){
1001 'use strict';
1011 process.on('uncaughtException', function(err) {
1020 console.error(isError(err) ? err.stack : err);
103 });
104 },
105 /**
106 * 加载项目下对应的文件
107 * @return {[type]} [description]
108 */
109 loadFiles: function(){
1101 'use strict';
1111 C(null); //移除之前的所有配置
112 //加载系统默认配置
1131 C(require(THINK_PATH + '/Conf/config.js'));
114 //加载用户配置
1151 var file = CONF_PATH + '/config.js';
1161 if (isFile(file)) {
1171 C(this.safeRequire(file));
118 }
119 //加载模式的配置文件
1201 if (APP_MODE) {
1211 var modeFiles = [
122 THINK_PATH + '/Conf/mode.js',
123 CONF_PATH + '/mode.js'
124 ];
1251 var self = this;
1261 modeFiles.forEach(function(file){
1272 if (isFile(file)) {
1281 var conf = self.safeRequire(file);
1291 if (conf[APP_MODE]) {
1301 C(conf[APP_MODE]);
131 }
132 }
133 });
134 }
135 //自定义路由
1361 if (C('url_route_on') && isFile(CONF_PATH + '/route.js')) {
1370 C('url_route_rules', this.safeRequire(CONF_PATH + '/route.js'));
138 }
139 //别名文件
1401 if (isFile(CONF_PATH + '/alias.js')) {
1410 aliasImport(this.safeRequire(CONF_PATH + '/alias.js'));
142 }
143 //common文件
1441 if (isFile(COMMON_PATH + '/common.js')) {
1451 require(COMMON_PATH + '/common.js');
146 }
1471 this.loadTag();
1481 this.loadExtConfig();
1491 this.loadExtFiles();
150 },
151 //加载标签行为
152 loadTag: function(){
1531 'use strict';
154 //系统标签
1551 var tag = require(THINK_PATH + '/Conf/tag.js');
156 //用户行为标签
1571 var tagFile = CONF_PATH + '/tag.js';
1581 if (!C('app_tag_on') || !isFile(tagFile)) {
1591 C('tag', tag);
1601 return;
161 }
1620 var mixTag = extend({}, tag);
1630 var userTag = extend({}, require(tagFile));
1640 for(var key in userTag){
1650 var value = userTag[key];
1660 if (!value.length) {
1670 continue;
168 }
1690 mixTag[key] = mixTag[key] || [];
1700 if (isBoolean(value[0])) {
1710 var flag = value.shift();
1720 if (flag) { //true为替换系统标签
1730 mixTag[key] = value;
174 }else{ //false为将自定义标签置为系统标签前面
1750 mixTag[key] = value.concat(mixTag[key]);
176 }
177 }else{// 默认将用户标签置为系统标签后面
1780 mixTag[key] = mixTag[key].concat(value);
179 }
180 }
181 //行为标签
1820 C('tag', mixTag);
183 },
184 //加载自定义外部文件
185 loadExtFiles: function(){
1861 'use strict';
1871 var files = C('load_ext_file');
1881 if (files) {
1891 if (isString(files)) {
1900 files = files.split(',');
191 }
1921 files.forEach(function(file){
1930 file = COMMON_PATH + '/' + file + '.js';
1940 if (isFile(file)) {
1950 require(file);
196 }
197 });
198 }
199 },
200 //加载额外的配置
201 loadExtConfig: function(){
2021 'use strict';
2031 var files = C('load_ext_config');
2041 if (files) {
2051 if (isString(files)) {
2060 files = files.split(',');
207 }
2081 files.forEach(function(file){
2090 file = CONF_PATH + '/' + file + '.js';
2100 if (isFile(file)) {
2110 C(require(file));
212 }
213 });
214 }
215 },
216 //加载debug模式配置文件
217 loadDebugFiles: function(){
2180 'use strict';
219 //加载debug模式下的配置
2200 C(require(THINK_PATH + '/Conf/debug.js'));
221 //debug下自定义状态的配置
2220 var status = C('app_status');
2230 if (status) {
2240 if (isFile(CONF_PATH + '/' + status + '.js')) {
2250 C(require(CONF_PATH + '/' + status + '.js'));
226 }
227 }else{
2280 if (isFile(CONF_PATH + '/debug.js')) {
2290 C(require(CONF_PATH + '/debug.js'));
230 }
231 }
2320 if (APP_MODE) {
2330 var modeFiles = [
234 THINK_PATH + '/Conf/mode.js',
235 CONF_PATH + '/mode.js'
236 ];
2370 modeFiles.forEach(function(file){
2380 if (isFile(file)) {
2390 var conf = require(file);
2400 var key = APP_MODE + '_debug';
2410 if (conf[key]) {
2420 C(conf[key]);
243 }
244 }
245 });
246 }
247 },
248 /**
249 * debug模式下一些特殊处理
250 * @return {[type]} [description]
251 */
252 debug: function(){
2530 'use strict';
2540 this.loadDebugFiles();
255 //清除require的缓存
2560 if (C('clear_require_cache')) {
257 //这些文件不清除缓存
2580 var retainFiles = C('debug_retain_files');
2590 var self = this;
2600 setInterval(function(){
2610 var fn = function(item){
262 //windows目录定界符为\
2630 if (process.platform === 'win32') {
2640 item = item.replace(/\//g, '\\');
265 }
2660 if (file.indexOf(item) > -1) {
2670 return true;
268 }
269 };
2700 for(var file in require.cache){
2710 var flag = retainFiles.some(fn);
2720 if (!flag) {
2730 delete require.cache[file];
274 }
275 }
2760 self.loadFiles();
2770 self.loadDebugFiles();
278 }, 100);
279 }
280 },
281 /**
282 * 记录当前进程的id
283 * 记录在Runtime/Data/app.pid文件里
284 * @return {[type]} [description]
285 */
286 logPid: function(){
2871 'use strict';
2881 if (C('log_process_pid') && cluster.isMaster) {
2890 mkdir(DATA_PATH);
2900 var pidFile = DATA_PATH + '/app.pid';
2910 fs.writeFileSync(pidFile, process.pid);
2920 chmod(pidFile);
293 //进程退出时删除该文件
2940 process.on('SIGTERM', function () {
2950 if (fs.existsSync(pidFile)) {
2960 fs.unlinkSync(pidFile);
297 }
2980 process.exit(0);
299 });
300 }
301 },
302 /**
303 * 合并autoload的path
304 * @return {[type]} [description]
305 */
306 mergeAutoloadPath: function(){
3071 'use strict';
3081 var file = '__CLASS__.js';
3091 var sysAutoloadPath = {
310 'Behavior': [
311 LIB_PATH + '/Behavior/' + file,
312 THINK_LIB_PATH + '/Behavior/' + file
313 ],
314 'Model': [
315 LIB_PATH + '/Model/' + file,
316 THINK_EXTEND_PATH + '/Model/' + file
317 ],
318 'Logic': [
319 LIB_PATH + '/Logic/' + file
320 ],
321 'Service': [
322 LIB_PATH + '/Service/' + file
323 ],
324 'Controller': [
325 LIB_PATH + '/Controller/' + file,
326 THINK_EXTEND_PATH + '/Controller/' + file
327 ],
328 'Cache': [
329 LIB_PATH + '/Driver/Cache/' + file,
330 THINK_LIB_PATH + '/Driver/Cache/' + file
331 ],
332 'Db': [
333 LIB_PATH + '/Driver/Db/' + file,
334 THINK_LIB_PATH + '/Driver/Db/' + file
335 ],
336 'Template': [
337 LIB_PATH + '/Driver/Template/' + file,
338 THINK_LIB_PATH + '/Driver/Template/' + file
339 ],
340 'Socket': [
341 LIB_PATH + '/Driver/Socket/' + file,
342 THINK_LIB_PATH + '/Driver/Socket/' + file
343 ],
344 'Session': [
345 LIB_PATH + '/Driver/Session/' + file,
346 THINK_LIB_PATH + '/Driver/Session/' + file
347 ]
348 };
3491 var autoloadPath = C('autoload_path');
3501 for(var type in autoloadPath){
3510 var paths = autoloadPath[type];
3520 var override = false;
3530 if (!isArray(paths)) {
3540 paths = [paths];
3550 }else if (isBoolean(paths[0])) {
3560 override = paths.shift();
357 }
3580 if (override) {
3590 sysAutoloadPath[type] = paths;
360 }else{
3610 paths.push.apply(paths, sysAutoloadPath[type]);
3620 sysAutoloadPath[type] = paths;
363 }
364 }
3651 autoloadPaths = sysAutoloadPath;
366 },
367 //thinkRequire的自动加载
368 autoload: function(cls){
36946 'use strict';
37046 var filepath = '';
37146 var fn = function(item){
37284 item = item.replace(/__CLASS__/g, cls);
37384 if (isFile(item)) {
37421 filepath = item;
37521 return true;
376 }
377 };
37846 for(var name in autoloadPaths){
379346 var length = name.length;
380346 if (cls.substr(0 - length) === name) {
38144 var list = autoloadPaths[name];
38244 list.some(fn);
38344 if (filepath) {
38421 if (!APP_DEBUG) {
38521 aliasImport(cls, filepath);
386 }
38721 return filepath;
388 }
389 }
390 }
391 }
392};
393

/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){
925 this.http = http;
1025 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){
1957 if (name === undefined) {
201 return this.tVar;
21 }
2256 if (isString(name) && arguments.length === 1) {
234 return this.tVar[name];
24 }
2552 if (isObject(name)) {
261 this.tVar = extend(this.tVar, name);
27 }else{
2851 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){
1123 this.options = extend({
12 cache_path: C('cache_path'), //缓存目录
13 cache_path_level: 2, //缓存子目录深度
14 cache_file_suffix: C('cache_file_suffix') //缓存文件后缀名
15 }, options);
1623 mkdir(this.options.cache_path);
1723 this.gcType += ':' + this.options.cache_path;
18
1923 this.super_('init', this.options);
20 },
21 /**
22 * 存储的缓存文件
23 * @param {[type]} name [description]
24 * @return {[type]} [description]
25 */
26 getStoredFile: function(name){
2747 name = md5(this.key || name);
2847 var dir = name.split('').slice(0, this.options.cache_path_level).join('/');
2947 mkdir(this.options.cache_path + '/' + dir);
3047 var path = this.options.cache_path + '/' + dir + '/' + name + this.options.cache_file_suffix;
3147 return path;
32 },
33 /**
34 * 获取缓存,返回promise
35 * @param {[type]} name [description]
36 * @return {[type]} [description]
37 */
38 getData: function(name){
399 var filePath = this.getStoredFile(name);
409 if (!isFile(filePath)) {
412 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){
728 return this.getData(name).then(function(data){
738 return (data || {})[name];
74 })
75 },
76 setData: function(name, value, timeout){
7736 if (isObject(name)) {
7829 timeout = value;
79 }
8036 if (timeout === undefined) {
8132 timeout = this.options.timeout;
82 }
8336 var filePath = this.getStoredFile(name);
8436 var data = {
85 data: isObject(name) ? name : getObject(name, value),
86 expire: Date.now() + timeout * 1000,
87 timeout: timeout
88 };
8936 var deferred = getDefer();
9036 fs.writeFile(filePath, JSON.stringify(data), function(){
91 //修改缓存文件权限,避免不同账号下启动时可能会出现无权限的问题
9236 chmod(filePath);
9336 deferred.resolve();
94 })
9536 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){
1047 return this.setData(name, value, timeout);
105 },
106 /**
107 * 删除缓存
108 * @param {[type]} name [description]
109 * @return {[type]} [description]
110 */
111 rm: function(name){
1122 var filePath = this.getStoredFile(name);
1132 if (isFile(filePath)) {
1142 var deferred = getDefer();
1152 fs.unlink(filePath, function(){
1162 deferred.resolve();
117 })
1182 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(){
27183 if (!this.linkId) {
281 this.linkId = mysqlSocket(this.config);
29 }
30183 return this.linkId;
31 },
32 /**
33 * 查询一条sql
34 * @param string str
35 * @return promise
36 */
37 query: function(str){
38157 this.setSql(str);
39157 var self = this;
40157 if (!(str in this.queryWaiting)) {
41157 this.queryWaiting[str] = [];
42157 return this.connect().query(str).then(function(data){
43157 process.nextTick(function(){
44157 self.queryWaiting[str].forEach(function(deferred){
450 deferred.resolve(data);
46 });
47157 delete self.queryWaiting[str];
48 })
49157 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){
6326 this.setSql(str);
6426 var self = this;
6526 return this.connect().query(str).then(function(data){
6626 self.lastInsertId = data.insertId;
6726 return data.affectedRows || 0;
68 });
69 },
70 /**
71 * 获取数据表字段信息
72 * @param string tableName 数据表名
73 * @return promise 返回一个promise
74 */
75 getFields: function(tableName){
765 var sql = 'SHOW COLUMNS FROM ' + this.parseKey(tableName);
775 return this.query(sql).then(function(data){
785 var ret = {};
795 data.forEach(function(item){
8065 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 });
905 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){
127360 key = (key || '').trim();
128360 if (!(/[,\'\"\*\(\)`.\s]/.test(key))) {
129339 key = '`' + key + '`';
130 }
131360 return key;
132 },
133 /**
134 * 获取最后插入的id
135 * @return {[type]} [description]
136 */
137 getLastInsertId: function(){
1388 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){
166 options = options || {};
176 options.cache_path = C('session_path') || (os.tmpdir() + '/thinkjs');
186 this.super_('init', options);
196 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 (C('db_log_sql')) {
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){
98 'use strict';
108 var content = getFileContent(templateFile);
118 var conf = extend({
12 filename: templateFile,
13 cache: true
14 }, C('tpl_engine_config'));
158 return ejs.compile(content, conf)(tVar);
16 }
17};

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

100%
46
46
0
LineHitsSource
1/**
2 * REST Controller
3 * @return {[type]} [description]
4 */
51module.exports = Controller(function(){
61 'use strict';
71 return {
8 init: function(http){
914 this.super('init', http);
10 //资源名
1114 this.resource = this.get('resource');
12 //资源id
1314 this.id = this.get('id') | 0;
14 //实例化对应的模型
1514 this.model = D(this.resource);
16 },
17 /**
18 * 获取
19 * @return {[type]} [description]
20 */
21 getAction: function(){
224 var self = this;
234 if (this.id) {
242 return getPromise(this.model.getPk()).then(function(pk){
252 return self.model.where(getObject(pk, self.id)).find();
26 }).then(function(data){
271 return self.success(data);
28 }).catch(function(err){
291 return self.error(err.message);
30 })
31 }
322 return this.model.select().then(function(data){
331 return self.success(data);
34 }).catch(function(err){
351 return self.error(err.message);
36 });
37 },
38 /**
39 * 新建
40 * @return {[type]} [description]
41 */
42 postAction: function(){
433 var self = this;
443 return getPromise(this.model.getPk()).then(function(pk){
453 var data = self.post();
463 delete data[pk];
473 if (isEmpty(data)) {
481 return self.error('data is empty');
49 }
502 return self.model.add(data);
51 }).then(function(insertId){
522 return self.success({id: insertId});
53 }).catch(function(err){
541 var msg = isError(err) ? err.message : err;
551 return self.error(msg);
56 });
57 },
58 /**
59 * 删除
60 * @return {[type]} [description]
61 */
62 deleteAction: function(){
633 if (!this.id) {
641 return this.error('params error');
65 }
662 var self = this;
672 return getPromise(this.model.getPk()).then(function(pk){
682 return self.model.where(getObject(pk, self.id)).delete();
69 }).then(function(affectedRows){
701 return self.success({affectedRows: affectedRows});
71 }).catch(function(err){
721 return self.error(err.message);
73 });
74 },
75 /**
76 * 更新
77 * @return {[type]} [description]
78 */
79 putAction: function(){
803 if (!this.id) {
811 return this.error('params error');
82 }
832 var self = this;
842 return getPromise(this.model.getPk()).then(function(pk){
852 var data = self.post();
862 delete data[pk];
872 if (isEmpty(data)) {
881 return self.error('data is empty');
89 }
901 return self.model.where(getObject(pk, self.id)).update(data);
91 }).then(function(affectedRows){
921 return self.success({affectedRows: affectedRows});
93 }).catch(function(err){
941 var msg = isError(err) ? err.message : err;
951 return self.error(msg);
96 });
97 },
98 __call: function(action){
991 return this.error('action `' + action + '` is not allowed');
100 }
101 }
102})

/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){
1167 this.http = http;
1267 for(var name in this.options){
1398 if (C(name) !== undefined) {
1497 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){
2036 'use strict';
2136 if (APP_DEBUG || APP_MODE === 'cli' || gcTimer[instance.gcType]) {
2236 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){
5136 options = options || {};
5236 if (options.cacheData) {
530 this.cacheData = options.cacheData;
54 }else{
5536 this.cacheData = cacheData;
56 }
5736 if (options.gcType) {
580 this.gcType = options.gcType;
59 }
6036 if (!options.timeout) {
6121 options.timeout = C('cache_timeout')
62 }
6336 this.options = options;
64 //操作的key
6536 this.key = '';
66 //是否更新expire值
6736 this.updateExpire = false;
6836 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){
1222 'use strict';
1322 var data = {};
1422 str.split(/; */).forEach(function(item) {
1544 var pos = item.indexOf('=');
1644 if (pos === -1) {
179 return;
18 }
1935 var key = item.substr(0, pos).trim();
2035 var val = item.substr(pos + 1).trim();
2135 if ('"' === val[0]) {
222 val = val.slice(1, -1);
23 }
24 // only assign once
2535 if (undefined === data[key]) {
2635 try {
2735 data[key] = decodeURIComponent(val);
28 } catch (e) {
292 data[key] = val;
30 }
31 }
32 });
3322 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

100%
57
57
0
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){
207 'use strict';
217 if (isString(value)) {
226 value = value.split(',');
23 }
247 if (!isArray(value)) {
251 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){
844 'use strict';
854 if (!isArray(arr)) {
862 arr = [arr];
87 }
884 if(arr.indexOf(value) > -1){
892 return value;
90 }
912 return '';
92 },
93 /**
94 * 将字符串切割为数组
95 * @param {[type]} value [description]
96 * @param {[type]} split [description]
97 * @return {[type]} [description]
98 */
99 strs: function(value, split){
1005 'use strict';
1015 if (isString(value)) {
1024 value = value.split(split || ',');
103 }
1045 if (!isArray(value)) {
1051 return [];
106 }
1074 return value.filter(function(item){
1087 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){
11934 'use strict';
12034 var fn = Filter[type];
12134 if (typeof fn === 'function') {
12233 var args = [].slice.call(arguments, 2);
12333 args.unshift(value);
12433 return Filter[type].apply(Filter, args);
125 }
1261 return false;
127};

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

100%
52
52
0
LineHitsSource
11var crypto = require('crypto');
2/**
3 * 生成uid
4 * @param int length
5 * @return string
6 */
71var uid = function(length){
84 'use strict';
94 var ratio = Math.log(64) / Math.log(256);
104 var numbytes = Math.ceil(length * ratio);
114 var str = crypto.randomBytes(numbytes).toString('base64').slice(0, length);
124 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){
218 'use strict';
228 secret = crypto.createHmac('sha256', secret).update(val).digest('base64');
238 secret = secret.replace(/\=+$/, '');
248 return val + '.' + secret;
25};
26/**
27 * 解析cookie签名
28 * @param {[type]} val
29 * @param {[type]} secret
30 * @return {[type]}
31 */
321var cookieUnsign = function(val, secret){
335 'use strict';
345 var str = val.slice(0, val.lastIndexOf('.'));
355 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){
5018 'use strict';
5118 if (http.session) {
5211 return http.session;
53 }
547 var name = C('session_name');
55 //是否使用签名
567 var secret = C('session_sign');
577 var cookie = http.cookie[name];
587 if (cookie && secret) {
595 cookie = cookieUnsign(cookie, secret);
605 if (cookie) {
612 http.cookie[name] = cookie;
62 }
63 }
647 var session_cookie = cookie;
657 if (!cookie) {
664 cookie = uid(32);
674 session_cookie = cookie;
684 if (secret) {
693 cookie = cookieSign(cookie, secret);
70 }
71 //将生成的cookie放在http.cookie对象上,方便程序内读取
724 http.cookie[name] = cookie;
734 http.setCookie(name, cookie, C('session_options'));
74 }
757 var type = C('session_type');
767 if (!type) {
773 if (APP_DEBUG || C('use_cluster')) {
782 type = 'File';
792 C('session_type', 'File');
802 console.log("in debug or cluster mode, session can't use memory for storage, convert to File");
81 }
82 }
837 name = type + 'Session';
84 //session类
857 var session = http.session = thinkRequire(name)({
86 cookie: session_cookie,
87 timeout: C('session_timeout')
88 });
89 //afterend时刷新缓存
907 http.on('afterEnd', function(){
91 //刷新session
9229 return session.flush && session.flush();
93 })
947 return cookie;
95};

/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

85%
20
17
3
LineHitsSource
11var path = require('path');
21var fs = require('fs');
3
41if (!global.APP_PATH) {
50 throw new Error('APP_PATH must be defined');
6}
71if (!global.RUNTIME_PATH) {
81 global.RUNTIME_PATH = APP_PATH + '/Runtime';
9}
10//DEBUG模式
111if (global.APP_DEBUG === undefined) {
121 global.APP_DEBUG = false;
13}
14//线上环境自动关闭debug模式
151if (process.argv[2] === 'online' && APP_DEBUG === true) {
160 process.argv[2] = '';
170 APP_DEBUG = false;
18}
19//静态资源文件的根目录
201global.RESOURCE_PATH = global.RESOURCE_PATH || '';
21//THINKJS的根目录
221global.THINK_PATH = __dirname;
23//默认为http模式
241global.APP_MODE = global.APP_MODE || '';
25//命令行模式
261if (process.argv[2]) {
271 APP_MODE = 'cli';
28}
29//从package.json文件里获取版本号
301var pkgPath = path.dirname(THINK_PATH) + '/package.json';
311var pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
321global.THINK_VERSION = pkg.version;
33//启动
341require(THINK_PATH + '/Lib/Core/Think.js').start();