Authored by 姜枫

删除library目录,使用yoho-node-lib公用库

1 -/**  
2 - * 接口公共方法  
3 - * @author: xuqi<qi.xu@yoho.cn>  
4 - * @date: 2016/4/25  
5 - */  
6 -  
7 -'use strict';  
8 -const rp = require('request-promise');  
9 -const qs = require('querystring');  
10 -const md5 = require('md5');  
11 -const _ = require('lodash');  
12 -const log = require('./logger');  
13 -const cache = require('./cache');  
14 -const Timer = require('./timer');  
15 -const sign = require('./sign');  
16 -const config = require('../config/common');  
17 -const api = config.domains.api;  
18 -const serviceApi = config.domains.service;  
19 -const searchApi = config.domains.search;  
20 -  
21 -// 错误返回  
22 -const API_BAD_RETSULT = {  
23 - code: 500,  
24 - message: 'API result is not JSON string or null.'  
25 -};  
26 -  
27 -// 调用失败  
28 -const API_CALL_FAIL = {  
29 - code: 500,  
30 - message: 'Call API failed.'  
31 -};  
32 -  
33 -// all 方法错误的传参  
34 -const API_ALL_METHOD_ERROR = 'the parameters of api all method should be Array!';  
35 -  
36 -// 获取缓存数据失败  
37 -const SLAVE_CACHE_FAIL = 'get slave cache fail';  
38 -const MASTER_CACHE_FAIL = 'get master cache fail';  
39 -  
40 -// 获取缓存数据成功  
41 -const SLAVE_CACHE_SUCCESS = 'get slave cache success';  
42 -const MASTER_CACHE_SUCCESS = 'get master cache success';  
43 -  
44 -class Http {  
45 -  
46 - constructor(baseUrl) {  
47 - this.ApiUrl = baseUrl;  
48 - }  
49 -  
50 - /**  
51 - * 获取请求 ID  
52 - */  
53 - _getReqId(options) {  
54 - return md5(`${options.url}?${qs.stringify(options.qs || options.form)}`);  
55 - }  
56 -  
57 - /**  
58 - * 调用接口  
59 - */  
60 - _requestFromAPI(options, cacheOption, reqId) {  
61 - const timer = new Timer();  
62 - const method = options.method || 'get';  
63 -  
64 - timer.put('getApi');// 统计时间开始  
65 - return rp(options).then((result) => {  
66 - const duration = timer.put('getApi');// 统计时间结束  
67 -  
68 - // 数据校验  
69 - if (!result) {  
70 - log.error(`error: ${API_BAD_RETSULT.message}`);  
71 - return Promise.reject(API_BAD_RETSULT);  
72 - }  
73 -  
74 - // 写缓存, 否则返回 Slave 缓存服务器的数据  
75 - if (config.useCache && cacheOption) {  
76 - const cacheTime = _.isNumber(cacheOption) ? cacheOption : 60;  
77 - const catchErr = (err) => {  
78 - log.error(`cache: ${err.toString()}`);  
79 - };  
80 -  
81 - reqId = reqId || this._getReqId(options);  
82 - cache.set(`apiCache:${reqId}`, result, cacheTime).catch(catchErr);  
83 - cache.setSlave(`apiCache:${reqId}`, result, 86400).catch(catchErr); // 二级缓存存储一天  
84 - }  
85 -  
86 - let reqData = options.qs || options.form;  
87 -  
88 - log.info(`use: ${duration}ms for ${method} api: ${options.url}?${qs.stringify(reqData)} `);  
89 - return result;  
90 - }).catch((err)=> {  
91 - const duration = timer.put('getApi');// 统计时间结束  
92 -  
93 - log.error(`${method} api fail: use: ${duration}ms, code:${err.statusCode}, error: ${err.message}`);  
94 - log.error(`API: ${options.url}?${qs.stringify(options.qs)}`);  
95 -  
96 - // 使用缓存的时候,读取二级缓存  
97 - if (config.useCache && cacheOption) {  
98 - return this._requestFromCache(options, true);  
99 - }  
100 - return Promise.resolve(API_CALL_FAIL);  
101 - });  
102 - }  
103 -  
104 - /**  
105 - * 读取缓存  
106 - * @param {[object]} options  
107 - * @param {[boolean]} slave true: 读取二级缓存  
108 - * @return {[type]}  
109 - */  
110 - _requestFromCache(options, slave) {  
111 - const reqId = this._getReqId(options);  
112 - const getCache = slave ? cache.getFromSlave : cache.get;  
113 -  
114 - log.info(`get ${slave ? 'slave' : 'master'} cache: ${reqId}, url: ${options.url}?${qs.stringify(options.qs)}`);  
115 - return getCache(`apiCache:${reqId}`).then((result) => {  
116 - if (!_.isNil(result)) {  
117 - try {  
118 - result = JSON.parse(result);  
119 - } finally {  
120 - log.info(slave ? SLAVE_CACHE_SUCCESS : MASTER_CACHE_SUCCESS);  
121 - return result;  
122 - }  
123 - }  
124 -  
125 - // 读取缓存失败,并且不是二级缓存的时候,调用 API  
126 - if (!slave) {  
127 - return this._requestFromAPI(options, true, reqId);  
128 - }  
129 - }).catch(() => {  
130 - log.error(slave ? SLAVE_CACHE_FAIL : MASTER_CACHE_FAIL);  
131 -  
132 - // 读取缓存失败,并且不是二级缓存的时候,调用 API  
133 - if (!slave) {  
134 - return this._requestFromAPI(options, true, reqId);  
135 - }  
136 -  
137 - return Promise.resolve(API_CALL_FAIL);  
138 - });  
139 - }  
140 -  
141 - /**  
142 - * 使用 get 请求获取接口  
143 - * @param {[string]} url  
144 - * @param {[object]} data  
145 - * @param {[bool or number]} cacheOption 使用数字时,数字表示缓存时间  
146 - * @return {[type]}  
147 - */  
148 - get(url, data, cacheOption) {  
149 - const options = {  
150 - url: `${this.ApiUrl}${url}`,  
151 - qs: data.client_secret ? data : sign.apiSign(data),  
152 - json: true,  
153 - gzip: true,  
154 - timeout: 3000  
155 - };  
156 -  
157 - // 从缓存获取数据  
158 - if (config.useCache && cacheOption) {  
159 - return this._requestFromCache(options);  
160 - }  
161 -  
162 - return this._requestFromAPI(options, cacheOption);  
163 - }  
164 -  
165 - /**  
166 - * post  
167 - * @param url String  
168 - * @param data Obejct  
169 - */  
170 - post(url, data) {  
171 - const options = {  
172 - url: `${this.ApiUrl}${url}`,  
173 - form: data.client_secret ? data : sign.apiSign(data),  
174 - method: 'post',  
175 - json: true,  
176 - timeout: 3000  
177 - };  
178 -  
179 - return this._requestFromAPI(options);  
180 - }  
181 -  
182 - all(list) {  
183 - if (_.isArray(list)) {  
184 - return Promise.all(list);  
185 - } else {  
186 - return Promise.reject(Error(API_ALL_METHOD_ERROR));  
187 - }  
188 - }  
189 -}  
190 -  
191 -class API extends Http {  
192 - constructor() {  
193 - super(api);  
194 - }  
195 -}  
196 -  
197 -class ServiceAPI extends Http {  
198 - constructor() {  
199 - super(serviceApi);  
200 - }  
201 -}  
202 -  
203 -class SearchAPI extends Http {  
204 - constructor() {  
205 - super(searchApi);  
206 - }  
207 -}  
208 -  
209 -exports.API = API;  
210 -exports.ServiceAPI = ServiceAPI;  
211 -exports.SearchAPI = SearchAPI;  
1 -/**  
2 - * 缓存封装  
3 - * 前期使用 memcache, 写方法的时候考虑一下如何转换为 redis  
4 - * @author bikai kai.bi@yoho.cn  
5 - * @date 2016/05/16  
6 - */  
7 -'use strict';  
8 -const Promise = require('bluebird');  
9 -const Memcached = require('memcached');  
10 -const _ = require('lodash');  
11 -const config = require('../config/common');  
12 -  
13 -let master = new Memcached(config.memcache.master, config.memcache);  
14 -let slave = new Memcached(config.memcache.slave, config.memcache);  
15 -  
16 -master = Promise.promisifyAll(master);  
17 -slave = Promise.promisifyAll(slave);  
18 -  
19 -/**  
20 - * 获取缓存  
21 - * @param {[string]} key 键  
22 - * @return {[type]}  
23 - */  
24 -exports.get = (key) => {  
25 - if (_.isString(key)) {  
26 - return master.getAsync(key);  
27 - }  
28 -  
29 - return Promise.resolve();  
30 -};  
31 -  
32 -/**  
33 - * 批量获取缓存  
34 - * @param {[array]} list 字符串数组  
35 - * @return {[type]}  
36 - */  
37 -exports.getMulti = (list) => {  
38 - if (_.isArray(list)) {  
39 - return master.getMultiAsync(list);  
40 - }  
41 - return Promise.resolve();  
42 -};  
43 -  
44 -/**  
45 - * 获取缓存(从 Slave 服务器)  
46 - * @param {[string]} key 键  
47 - * @return {[type]}  
48 - */  
49 -exports.getFromSlave = (key) => {  
50 - if (_.isString(key)) {  
51 - return slave.getAsync(key);  
52 - }  
53 - return Promise.resolve();  
54 -};  
55 -  
56 -/**  
57 - * 批量获取缓存(从 Slave 服务器)  
58 - * @param {[array]} list 字符串数组  
59 - * @return {[type]}  
60 - */  
61 -exports.getMultiFromSlave = (list) => {  
62 - if (_.isArray(list)) {  
63 - return slave.getMultiAsync(list);  
64 - }  
65 - return Promise.resolve();  
66 -};  
67 -  
68 -/**  
69 - * 写缓存  
70 - * @param {[type]} key 键  
71 - * @param {[type]} value 值  
72 - * @param {[type]} lifetime 生命周期  
73 - * @return {[type]}  
74 - */  
75 -exports.set = (key, value, lifetime) => {  
76 - lifetime = lifetime || 86400;  
77 -  
78 - if (_.isObject(value)) {  
79 - value = JSON.stringify(value);  
80 - }  
81 -  
82 - if (_.isString(key)) {  
83 - return master.setAsync(key, value, lifetime);  
84 - }  
85 - return Promise.resolve();  
86 -};  
87 -  
88 -/**  
89 - * 写缓存(到 Slave 服务器)  
90 - * @param {[type]} key 键  
91 - * @param {[type]} value 值  
92 - * @param {[type]} lifetime 生命周期  
93 - * @return {[type]}  
94 - */  
95 -exports.setSlave = (key, value, lifetime) => {  
96 - lifetime = lifetime || 86400;  
97 -  
98 - if (_.isObject(value)) {  
99 - value = JSON.stringify(value);  
100 - }  
101 -  
102 - if (_.isString(key)) {  
103 - return slave.setAsync(key, value, lifetime);  
104 - }  
105 - return Promise.resolve();  
106 -};  
107 -  
108 -/**  
109 - * 删除缓存  
110 - * @param {[string]} key 键  
111 - * @return {[type]}  
112 - */  
113 -exports.del = (key) => {  
114 - if (_.isString(key)) {  
115 - return master.delAsync(key);  
116 - }  
117 - return Promise.resolve();  
118 -};  
1 -/**  
2 - * 对象键名驼峰化  
3 - * @author: Bi Kai<kai.bi@yoho.cn>  
4 - * @date: 2016/05/09  
5 - */  
6 -'use strict';  
7 -const _ = require('lodash');  
8 -  
9 -let camelCase,  
10 - camelCaseObject,  
11 - camelCaseArray;  
12 -  
13 -camelCaseObject = (obj) => {  
14 - _.forEach(Object.keys(obj), (k) => {  
15 - obj[k] = camelCase(obj[k]);  
16 - if (/[_-]/.test(k)) {  
17 - obj[_.camelCase(k)] = obj[k];  
18 - delete obj[k];  
19 - }  
20 - });  
21 - return obj;  
22 -};  
23 -  
24 -camelCaseArray = (list) => {  
25 - _.forEach(list, (k) => {  
26 - k = camelCase(k);  
27 - });  
28 - return list;  
29 -};  
30 -  
31 -camelCase = (data) => {  
32 - if (_.isArray(data)) {  
33 - data = camelCaseArray(data);  
34 - } else if (_.isObject(data)) {  
35 - data = camelCaseObject(data);  
36 - }  
37 -  
38 - return data;  
39 -};  
40 -  
41 -module.exports = camelCase;  
1 -/**  
2 - * 获取 UID  
3 - * @param {[object]} req  
4 - * @return {[string]}  
5 - */  
6 -'use strict';  
7 -const sign = require('./sign');  
8 -  
9 -exports.getUid = (req) => {  
10 - const cookie = req.cookies._UID;  
11 - let _uid = 0;  
12 - let cookieList;  
13 -  
14 - if (req.isApp) {  
15 - return req.query.uid || 0;  
16 - }  
17 -  
18 - if (cookie) {  
19 - cookieList = cookie.split('::');  
20 - if (cookieList[1] && !isNaN(cookieList[1])) {  
21 - _uid = cookieList[1];  
22 - }  
23 - }  
24 -  
25 - // 校验 cookie 的 uid 有没有被修改  
26 - if (req.cookies._TOKEN !== sign.makeToken(_uid)) {  
27 - _uid = 0;  
28 - }  
29 -  
30 - return _uid;  
31 -};  
32 -  
33 -exports.getShoppingKey = (req) => {  
34 - return req.cookies['_SPK'] ? req.cookies['_SPK'] : ''; // eslint-disable-line  
35 -};  
1 -/**  
2 - * Handlebars helpers  
3 - * bikai kai.bi@yoho.cn  
4 - * 2016-05-10  
5 - */  
6 -'use strict';  
7 -const querystring = require('querystring');  
8 -const _ = require('lodash');  
9 -const moment = require('moment');  
10 -const config = require('../config/common');  
11 -  
12 -/**  
13 - * 七牛图片路径处理  
14 - * @param {[string]} url  
15 - * @param {[string]} width  
16 - * @param {[string]} height  
17 - * @param {[string]} mode  
18 - * @return {[string]}  
19 - */  
20 -exports.image = (url, width, height, mode) => {  
21 - mode = _.isNumber(mode) ? mode : 2;  
22 - url = url || '';  
23 - url = url.replace(/{width}/g, width).replace(/{height}/g, height).replace(/{mode}/g, mode);  
24 -  
25 - return url.replace('http:', '');  
26 -};  
27 -  
28 -/**  
29 - * 条件判断  
30 - * @param {[string]} v1  
31 - * @param {[string]} v2  
32 - * @param {[object]} options 上下文环境,一般不手动传  
33 - * @return {[boolen]}  
34 - */  
35 -exports.isEqual = (v1, v2, _options) => {  
36 - if (_.isEqual(v1, v2)) {  
37 - return _options.fn(this); // eslint-disable-line  
38 - }  
39 -  
40 - return _options.inverse(this); // eslint-disable-line  
41 -};  
42 -  
43 -/**  
44 - * 站内地址格式化  
45 - * @param {[string]} uri 路径  
46 - * @param {[object]} qs 查询字符串  
47 - * @param {[string]} module 模块  
48 - * @return {[string]}  
49 - */  
50 -exports.urlFormat = (uri, qs, module) => {  
51 - const subDomain = '.m.yohobuy.com';  
52 - const subName = {  
53 - default: config.siteUrl,  
54 - guang: `//guang${subDomain}`,  
55 - list: `//list${subDomain}`,  
56 - search: `//search${subDomain}`,  
57 - huodong: `//huodong${subDomain}`,  
58 - activity: '//activity.yohobuy.com',  
59 - index: config.siteUrl  
60 - };  
61 - let url;  
62 -  
63 - module = module || 'default';  
64 - if (subName[module]) {  
65 - url = subName[module];  
66 - } else {  
67 - url = `//${module}${subDomain}`; // 规则没匹配到就把模块当作子域名  
68 - }  
69 -  
70 - url += uri;  
71 - if (qs) {  
72 - url += `?${querystring.stringify(qs)}`;  
73 - }  
74 -  
75 - return url;  
76 -};  
77 -  
78 -/**  
79 - * 大写转小写处理  
80 - * @param {[string]} str 转换字符  
81 - */  
82 -exports.lowerCase = (str) => {  
83 - str = str || '';  
84 - return str.toLowerCase();  
85 -};  
86 -  
87 -/**  
88 - * 小写转大写处理  
89 - * @param {[string]} str 转换字符  
90 - */  
91 -exports.upperCase = (str) => {  
92 - str = str || '';  
93 - return str.toUpperCase();  
94 -};  
95 -  
96 -  
97 -/**  
98 - * 四舍五入  
99 - * @param {[type]} num 数字  
100 - * @param {[type]} precision 精度  
101 - * @return {[type]}  
102 - */  
103 -exports.round = (num, precision) => {  
104 - precision = _.isNumber(precision) ? precision : 2;  
105 - num = _.isInteger(num) ? (+num).toFixed(precision) : _.round(num, precision);  
106 - return num;  
107 -};  
108 -  
109 -/**  
110 - * 链接改成自适应链接  
111 - * @return {[type]}  
112 - */  
113 -exports.https = (url) => {  
114 - return url.replace('http:', '');  
115 -};  
116 -  
117 -/**  
118 - * 时间格式化  
119 - * @param format 格式化token @see{http://momentjs.cn/docs/#/displaying/format/}  
120 - * @param date 日期或者数字  
121 - * @return string  
122 - *  
123 - */  
124 -exports.dateFormat = (format, date) => {  
125 - if (typeof format !== 'string' || typeof date === 'undefined') {  
126 - return '';  
127 - } else {  
128 - if (date instanceof Date) {  
129 - return moment(date).format(format);  
130 - } else {  
131 - const d = moment.unix(date);  
132 -  
133 - return moment(d).utc().format(format);  
134 - }  
135 - }  
136 -};  
137 -  
138 -/**  
139 - * 时间差格式化  
140 - * @param {[string]} format 格式化字符串  
141 - * @param {[number]} diff 相差值  
142 - * @param {[string]} type diff时间类型 默认ms  
143 - *  
144 - * Key Shorthand  
145 - * years y  
146 - * quarters Q  
147 - * months M  
148 - * weeks w  
149 - * days d  
150 - * hours h  
151 - * minutes m  
152 - * seconds s  
153 - * milliseconds ms  
154 - *  
155 - * @example  
156 - * let diff = 60 * 60 * 24 * (1.3) + 2;  
157 - *  
158 - * let s = helpers.dateDiffFormat('{d}天{h}小时', diff, 's');  
159 - * >>> 1天7小时  
160 - */  
161 -exports.dateDiffFormat = (format, diff, type) => {  
162 - if (typeof format !== 'string' || typeof diff === 'undefined') {  
163 - return '';  
164 - } else {  
165 - type = type || 'ms';  
166 - const m = moment.duration(diff, type);  
167 -  
168 - format.match(/(\{.*?\})/g).forEach((s) => {  
169 - format = format.replace(s, m.get(s.substring(1, s.length - 1)));  
170 - });  
171 -  
172 - return format;  
173 - }  
174 -};  
175 -  
176 -/**  
177 - * 验证邮箱是否合法  
178 - *  
179 - * @param string email  
180 - * @return boolean  
181 - */  
182 -exports.verifyEmail = (email) => {  
183 - if (!email) {  
184 - return false;  
185 - }  
186 -  
187 - const emailRegExp = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;  
188 -  
189 - return emailRegExp.test(email);  
190 -};  
191 -  
192 -/**  
193 - * 各国手机号规则  
194 - */  
195 -function areaMobileVerify(phone, area) {  
196 - area = area || '86';  
197 - phone = phone.trim();  
198 -  
199 - let verify = {  
200 - 86: {  
201 - name: '中国',  
202 - match: /^1[3|4|5|8|7][0-9]{9}$/.test(phone)  
203 - },  
204 - 852: {  
205 - name: '中国香港',  
206 - match: /^[9|6|5][0-9]{7}$/.test(phone)  
207 - },  
208 - 853: {  
209 - name: '中国澳门',  
210 - match: /^[0-9]{8}$/.test(phone)  
211 - },  
212 - 886: {  
213 - name: '中国台湾',  
214 - match: /^[0-9]{10}$/.test(phone)  
215 - },  
216 - 65: {  
217 - name: '新加坡',  
218 - match: /^[9|8][0-9]{7}$/.test(phone)  
219 - },  
220 - 60: {  
221 - name: '马来西亚',  
222 - match: /^1[1|2|3|4|6|7|9][0-9]{8}$/.test(phone)  
223 - },  
224 - 1: {  
225 - name: '加拿大&美国',  
226 - match: /^[0-9]{10}$/.test(phone)  
227 - },  
228 - 82: {  
229 - name: '韩国',  
230 - match: /^01[0-9]{9}$/.test(phone)  
231 - },  
232 - 44: {  
233 - name: '英国',  
234 - match: /^7[7|8|9][0-9]{8}$/.test(phone)  
235 - },  
236 - 81: {  
237 - name: '日本',  
238 - match: /^0[9|8|7][0-9]{9}$/.test(phone)  
239 - },  
240 - 61: {  
241 - name: '澳大利亚',  
242 - match: /^[0-9]{11}$/.test(phone)  
243 - }  
244 - };  
245 -  
246 - if (verify[area]) {  
247 - return verify[area].match;  
248 - } else {  
249 - return false;  
250 - }  
251 -}  
252 -  
253 -/**  
254 - * 验证国际手机号是否合法  
255 - */  
256 -exports.verifyAreaMobile = (areaMobile) => {  
257 - if (!areaMobile) {  
258 - return false;  
259 - }  
260 -  
261 - let mobile = {  
262 - area: '86',  
263 - phone: ''  
264 - };  
265 -  
266 - let splitMobile = areaMobile.split('-');  
267 -  
268 - if (splitMobile.length === 2) {  
269 - mobile.area = splitMobile[0];  
270 - mobile.phone = splitMobile[1];  
271 - } else {  
272 - mobile.phone = splitMobile[0];  
273 - }  
274 -  
275 - return areaMobileVerify(mobile.phone, mobile.area);  
276 -};  
277 -  
278 -/**  
279 - * 验证手机是否合法  
280 - */  
281 -exports.verifyMobile = (phone) => {  
282 - if (!phone) {  
283 - return false;  
284 - }  
285 -  
286 - return /^1[3|4|5|8|7][0-9]{9}$/.test(phone);  
287 -};  
288 -  
289 -/**  
290 - * 验证密码规则  
291 - */  
292 -exports.verifyPassword = (password) => {  
293 - if (!password) {  
294 - return false;  
295 - }  
296 -  
297 - return /^([a-zA-Z0-9\-\+_!@\#$%\^&\*\(\)\:\;\.=\[\]\\\',\?]){6,20}$/.test(password);  
298 -};  
1 -/**  
2 - * 日志工具类  
3 - * @author: hbomb<qiqi.zhou@yoho.cn>  
4 - * @date: 2016/05/06  
5 - */  
6 -'use strict';  
7 -  
8 -const winston = require('winston');  
9 -const config = require('../config/common');  
10 -const FileTransport = require('winston-daily-rotate-file');  
11 -  
12 -require('influxdb-winston');  
13 -  
14 -const logger = new(winston.Logger)({  
15 - transports: [  
16 - new(FileTransport)(config.loggers.infoFile),  
17 - new(FileTransport)(config.loggers.errorFile),  
18 - new(winston.transports.UdpTransport)(config.loggers.udp),  
19 - new(winston.transports.Console)(config.loggers.console)  
20 - ],  
21 - exitOnError: false  
22 -});  
23 -  
24 -module.exports = logger;  
1 -/**  
2 - * 签名  
3 - * @author: bikai  
4 - * @date: 2016/5/6  
5 - */  
6 -  
7 -'use strict';  
8 -const _ = require('lodash');  
9 -const md5 = require('md5');  
10 -  
11 -const privateKey = {  
12 - android: 'fd4ad5fcfa0de589ef238c0e7331b585',  
13 - iphone: 'a85bb0674e08986c6b115d5e3a4884fa',  
14 - ipad: 'ad9fcda2e679cf9229e37feae2cdcf80',  
15 - web: '0ed29744ed318fd28d2c07985d3ba633',  
16 - yoho: 'fd4ad5fcsa0de589af23234ks1923ks',  
17 - h5: 'fd4ad5fcfa0de589ef238c0e7331b585'  
18 -};  
19 -  
20 -/**  
21 - * 排序参数  
22 - * @param {Object} argument 需要排序的参数对象  
23 - * @return {Object} 排序之后的参数对象  
24 - */  
25 -const packageSort = argument => {  
26 - const newObj = {};  
27 -  
28 - for (const k of Object.keys(argument).sort()) {  
29 - newObj[k] = argument[k];  
30 - }  
31 -  
32 - return newObj;  
33 -};  
34 -  
35 -/**  
36 - * 生成签名  
37 - * @param {Object} argument 需要签名的数据  
38 - * @return {string} 生成的签名字符串  
39 - */  
40 -const makeSign = argument => {  
41 - const qs = [];  
42 -  
43 - _.forEach(argument, (value, key) => {  
44 - qs.push(`${key}=${_.trim(value)}`);  
45 - });  
46 -  
47 - return md5(qs.join('&')).toLowerCase();  
48 -};  
49 -  
50 -// 生成API签名,调用后端接口的时候有私钥校验  
51 -exports.apiSign = (params) => {  
52 - const clientType = params.client_type || 'h5';  
53 -  
54 - /* eslint-disable */  
55 - let sign = packageSort(Object.assign({  
56 - client_type: clientType,  
57 - private_key: privateKey[clientType],  
58 - app_version: '4.6.0',  
59 - os_version: 'yohobuy:h5',  
60 - screen_size: '720x1280',  
61 - v: '7'  
62 - }, params));  
63 - /* eslint-enable */  
64 -  
65 - sign = Object.assign(sign, {  
66 - client_secret: makeSign(sign) // eslint-disable-line camelcase  
67 - });  
68 - delete sign.private_key;  
69 - return sign;  
70 -};  
71 -  
72 -// 检查签名,APP 访问 H5 页面的时候需要检查  
73 -exports.checkSign = (params) => {  
74 - const // eslint-disable-line camelcase  
75 - clientSecret = params.client_secret;  
76 -  
77 - let sortedParams;  
78 -  
79 - // 忽略部分参数  
80 - delete params.client_secret;  
81 - delete params.q;  
82 - delete params.debug_data;  
83 - delete params['/api'];  
84 -  
85 - params.private_key = privateKey[params.client_type]; // eslint-disable-line camelcase  
86 - sortedParams = packageSort(params);  
87 -  
88 - return clientSecret === makeSign(sortedParams);  
89 -};  
90 -  
91 -// 检查签名,APP 访问 H5 页面的时候需要检查, 有可能不同于上边的签名方式  
92 -exports.webSign = (params) => {  
93 - const webPrivateKey = 'yohobuyapp';  
94 -  
95 - return params.key === md5(md5(webPrivateKey) + params.uid);  
96 -};  
97 -  
98 -// 生成 token  
99 -exports.makeToken = (string) => {  
100 - return md5(md5(string + '#@!@#'));  
101 -};  
102 -  
103 -// 校验 token  
104 -exports.verifyToken = (string, token) => {  
105 - return exports.makeToken(string) === token;  
106 -};  
1 -/**  
2 - * 计时类  
3 - * @example  
4 - * let timer = new Timer();  
5 - * timer.put('profile');  
6 - * timer.put('proflie'); // console output: 12.14  
7 - *  
8 - * @author: hbomb<qiqi.zhou@yoho.cn>  
9 - * @date: 2016/05/07  
10 - */  
11 -'use strict';  
12 -class Timer {  
13 - constructor() {  
14 - this.timers = {};  
15 - }  
16 -  
17 - /**  
18 - * 打点计时  
19 - */  
20 - put(label) {  
21 - const labelTime = this.timers[label];  
22 -  
23 - if (labelTime) {  
24 - const duration = process.hrtime(labelTime);  
25 -  
26 - return this._round(duration[0], duration[1]);  
27 - } else {  
28 - this.timers[label] = process.hrtime();  
29 - }  
30 - }  
31 -  
32 - /**  
33 - * 格式化成毫秒  
34 - * @param {Number} value 纳秒  
35 - */  
36 - _round(seconds, nanoseconds) {  
37 - return Math.round((seconds * 1e9 + nanoseconds) / 10000) / 100;  
38 - }  
39 -  
40 -}  
41 -  
42 -module.exports = Timer;