UNPKG

24.1 kBJavaScriptView Raw
1'use strict';
2
3/**
4 * lei-utils
5 *
6 * @author Zongmin Lei <leizongmin@gmail.com>
7 */
8
9const fs = require('fs');
10const util = require('util');
11const events = require('events');
12const crypto = require('crypto');
13const stream = require('stream');
14const utils = exports;
15
16
17const BUG_FREE = require('./bugfree');
18
19/**
20 * 佛祖保佑,用无Bug
21 * 图像来源于 https://github.com/ottomao/bugfreejs
22 *
23 * @param {Boolean} doNotOutput 设置为true时不自动打印,仅返回字符串
24 * @return {String}
25 */
26exports.bugfree = function bugfree(doNotOutput) {
27 if (doNotOutput) {
28 return BUG_FREE;
29 }
30 console.log(BUG_FREE);
31};
32
33/**
34 * format
35 *
36 * @param {String} str
37 * @param {Mixed} param1
38 * @param {Mixed} param2
39 * @return {String}
40 */
41exports.format = util.format;
42
43/**
44 * 40位SHA1值
45 *
46 * @param {String} text 文本
47 * @return {String}
48 */
49exports.sha1 = function sha1(text) {
50 return crypto.createHash('sha1').update(utils.toBuffer(text)).digest('hex');
51};
52
53/**
54 * 32位MD5值
55 *
56 * @param {String} text 文本
57 * @return {String}
58 */
59exports.md5 = function md5(text) {
60 return crypto.createHash('md5').update(utils.toBuffer(text)).digest('hex');
61};
62
63/**
64 * 取文件内容的SHA1
65 *
66 * @param {String} filename
67 * @param {Function} callback
68 */
69exports.fileSha1 = function fileSha1(filename, callback) {
70 fs.readFile(filename, function (err, data) {
71 if (err) return callback(err);
72 callback(null, utils.sha1(data));
73 });
74};
75
76/**
77 * 取文件内容的MD5
78 *
79 * @param {String} filename
80 * @param {Function} callback
81 */
82exports.fileMd5 = function fileMd5(filename, callback) {
83 fs.readFile(filename, function (err, data) {
84 if (err) return callback(err);
85 callback(null, utils.md5(data));
86 });
87};
88
89/**
90 * 取哈希值
91 *
92 * @param {String} method 方法,如 md5, sha1, sha256
93 * @param {String|Buffer} text 数据
94 * @return {String}
95 */
96exports.hash = function hash(method, text) {
97 return crypto.createHash(method).update(utils.toBuffer(text)).digest('hex');
98};
99
100/**
101 * 加密密码
102 *
103 * @param {String} password
104 * @return {String}
105 */
106exports.encryptPassword = function encryptPassword(password) {
107 const random = utils.md5(Math.random() + '' + Math.random()).toUpperCase();
108 const left = random.substr(0, 2);
109 const right = random.substr(-2);
110 const newpassword = utils.md5(left + password + right).toUpperCase();
111 return [ left, newpassword, right ].join(':');
112};
113
114/**
115 * 验证密码
116 *
117 * @param {String} password 待验证的密码
118 * @param {String} encrypted 密码加密字符串
119 * @return {Boolean}
120 */
121exports.validatePassword = function validatePassword(password, encrypted) {
122 const random = encrypted.toUpperCase().split(':');
123 if (random.length < 3) return false;
124 const left = random[0];
125 const right = random[2];
126 const main = random[1];
127 const newpassword = utils.md5(left + password + right).toUpperCase();
128 return newpassword === main;
129};
130
131/**
132 * 加密信息
133 *
134 * @param {Mixed} data
135 * @param {String} secret
136 * @return {String}
137 */
138exports.encryptData = function encryptData(data, secret) {
139 const str = JSON.stringify(data);
140 const cipher = crypto.createCipher('aes192', secret);
141 let enc = cipher.update(str, 'utf8', 'hex');
142 enc += cipher.final('hex');
143 return enc;
144};
145
146/**
147 * 解密信息
148 *
149 * @param {String} str
150 * @param {String} secret
151 * @return {Mixed}
152 */
153exports.decryptData = function decryptData(str, secret) {
154 const decipher = crypto.createDecipher('aes192', secret);
155 let dec = decipher.update(str, 'hex', 'utf8');
156 dec += decipher.final('utf8');
157 const data = JSON.parse(dec);
158 return data;
159};
160
161/**
162 * 产生随机字符串
163 *
164 * @param {Integer} size
165 * @param {String} chars
166 * @return {String}
167 */
168exports.randomString = function randomString(size, chars) {
169 size = size || 6;
170 chars = chars || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
171 const max = chars.length;
172 let ret = '';
173 for (let i = 0; i < size; i++) {
174 ret += chars.charAt(Math.floor(Math.random() * max));
175 }
176 return ret;
177};
178
179/**
180 * 产生随机数字字符串
181 *
182 * @param {Integer} size
183 * @return {String}
184 */
185exports.randomNumber = function randomNumber(size) {
186 return utils.randomString(size, '0123456789');
187};
188
189/**
190 * 产生随机字母字符串
191 *
192 * @param {Integer} size
193 * @return {String}
194 */
195exports.randomLetter = function randomLetter(size) {
196 return utils.randomString(size, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz');
197};
198
199/**
200 * 格式化日期时间
201 *
202 * @param {String} format
203 * @param {String|Number|Date} timestamp
204 * @return {String}
205 */
206exports.date = function date(format, timestamp) {
207 // discuss at: http://phpjs.org/functions/date/
208 // original by: Carlos R. L. Rodrigues (http://www.jsfromhell.com)
209 // original by: gettimeofday
210 // parts by: Peter-Paul Koch (http://www.quirksmode.org/js/beat.html)
211 // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
212 // improved by: MeEtc (http://yass.meetcweb.com)
213 // improved by: Brad Touesnard
214 // improved by: Tim Wiel
215 // improved by: Bryan Elliott
216 // improved by: David Randall
217 // improved by: Theriault
218 // improved by: Theriault
219 // improved by: Brett Zamir (http://brett-zamir.me)
220 // improved by: Theriault
221 // improved by: Thomas Beaucourt (http://www.webapp.fr)
222 // improved by: JT
223 // improved by: Theriault
224 // improved by: Rafał Kukawski (http://blog.kukawski.pl)
225 // improved by: Theriault
226 // input by: Brett Zamir (http://brett-zamir.me)
227 // input by: majak
228 // input by: Alex
229 // input by: Martin
230 // input by: Alex Wilson
231 // input by: Haravikk
232 // bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
233 // bugfixed by: majak
234 // bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
235 // bugfixed by: Brett Zamir (http://brett-zamir.me)
236 // bugfixed by: omid (http://phpjs.org/functions/380:380#comment_137122)
237 // bugfixed by: Chris (http://www.devotis.nl/)
238 // note: Uses global: php_js to store the default timezone
239 // note: Although the function potentially allows timezone info (see notes), it currently does not set
240 // note: per a timezone specified by date_default_timezone_set(). Implementers might use
241 // note: this.php_js.currentTimezoneOffset and this.php_js.currentTimezoneDST set by that function
242 // note: in order to adjust the dates in this function (or our other date functions!) accordingly
243 // example 1: date('H:m:s \\m \\i\\s \\m\\o\\n\\t\\h', 1062402400);
244 // returns 1: '09:09:40 m is month'
245 // example 2: date('F j, Y, g:i a', 1062462400);
246 // returns 2: 'September 2, 2003, 2:26 am'
247 // example 3: date('Y W o', 1062462400);
248 // returns 3: '2003 36 2003'
249 // example 4: x = date('Y m d', (new Date()).getTime()/1000);
250 // example 4: (x+'').length == 10 // 2009 01 09
251 // returns 4: true
252 // example 5: date('W', 1104534000);
253 // returns 5: '53'
254 // example 6: date('B t', 1104534000);
255 // returns 6: '999 31'
256 // example 7: date('W U', 1293750000.82); // 2010-12-31
257 // returns 7: '52 1293750000'
258 // example 8: date('W', 1293836400); // 2011-01-01
259 // returns 8: '52'
260 // example 9: date('W Y-m-d', 1293974054); // 2011-01-02
261 // returns 9: '52 2011-01-02'
262
263 let jsdate, f;
264 // Keep this here (works, but for code commented-out below for file size reasons)
265 // var tal= [];
266 const txt_words = [
267 'Sun', 'Mon', 'Tues', 'Wednes', 'Thurs', 'Fri', 'Satur',
268 'January', 'February', 'March', 'April', 'May', 'June',
269 'July', 'August', 'September', 'October', 'November', 'December',
270 ];
271 // trailing backslash -> (dropped)
272 // a backslash followed by any character (including backslash) -> the character
273 // empty string -> empty string
274 const formatChr = /\\?(.?)/gi;
275 const formatChrCb = function (t, s) {
276 return f[t] ? f[t]() : s;
277 };
278 const _pad = function (n, c) {
279 n = String(n);
280 while (n.length < c) {
281 n = '0' + n;
282 }
283 return n;
284 };
285 f = {
286 // Day
287 d() {
288 // Day of month w/leading 0; 01..31
289 return _pad(f.j(), 2);
290 },
291 D() {
292 // Shorthand day name; Mon...Sun
293 return f.l()
294 .slice(0, 3);
295 },
296 j() {
297 // Day of month; 1..31
298 return jsdate.getDate();
299 },
300 l() {
301 // Full day name; Monday...Sunday
302 return txt_words[f.w()] + 'day';
303 },
304 N() {
305 // ISO-8601 day of week; 1[Mon]..7[Sun]
306 return f.w() || 7;
307 },
308 S() {
309 // Ordinal suffix for day of month; st, nd, rd, th
310 const j = f.j();
311 let i = j % 10;
312 if (i <= 3 && parseInt((j % 100) / 10, 10) === 1) {
313 i = 0;
314 }
315 return [ 'st', 'nd', 'rd' ][i - 1] || 'th';
316 },
317 w() {
318 // Day of week; 0[Sun]..6[Sat]
319 return jsdate.getDay();
320 },
321 z() {
322 // Day of year; 0..365
323 const a = new Date(f.Y(), f.n() - 1, f.j());
324 const b = new Date(f.Y(), 0, 1);
325 return Math.round((a - b) / 864e5);
326 },
327
328 // Week
329 W() {
330 // ISO-8601 week number
331 const a = new Date(f.Y(), f.n() - 1, f.j() - f.N() + 3);
332 const b = new Date(a.getFullYear(), 0, 4);
333 return _pad(1 + Math.round((a - b) / 864e5 / 7), 2);
334 },
335
336 // Month
337 F() {
338 // Full month name; January...December
339 return txt_words[6 + f.n()];
340 },
341 m() {
342 // Month w/leading 0; 01...12
343 return _pad(f.n(), 2);
344 },
345 M() {
346 // Shorthand month name; Jan...Dec
347 return f.F()
348 .slice(0, 3);
349 },
350 n() {
351 // Month; 1...12
352 return jsdate.getMonth() + 1;
353 },
354 t() {
355 // Days in month; 28...31
356 return (new Date(f.Y(), f.n(), 0))
357 .getDate();
358 },
359
360 // Year
361 L() {
362 // Is leap year?; 0 or 1
363 const j = f.Y();
364 return j % 4 === 0 & j % 100 !== 0 | j % 400 === 0;
365 },
366 o() {
367 // ISO-8601 year
368 const n = f.n();
369 const W = f.W();
370 const Y = f.Y();
371 // eslint-disable-next-line
372 return Y + (n === 12 && W < 9 ? 1 : n === 1 && W > 9 ? -1 : 0);
373 },
374 Y() {
375 // Full year; e.g. 1980...2010
376 return jsdate.getFullYear();
377 },
378 y() {
379 // Last two digits of year; 00...99
380 return f.Y()
381 .toString()
382 .slice(-2);
383 },
384
385 // Time
386 a() {
387 // am or pm
388 return jsdate.getHours() > 11 ? 'pm' : 'am';
389 },
390 A() {
391 // AM or PM
392 return f.a()
393 .toUpperCase();
394 },
395 B() {
396 // Swatch Internet time; 000..999
397 const H = jsdate.getUTCHours() * 36e2;
398 // Hours
399 const i = jsdate.getUTCMinutes() * 60;
400 // Minutes
401 const s = jsdate.getUTCSeconds(); // Seconds
402 return _pad(Math.floor((H + i + s + 36e2) / 86.4) % 1e3, 3);
403 },
404 g() {
405 // 12-Hours; 1..12
406 return f.G() % 12 || 12;
407 },
408 G() {
409 // 24-Hours; 0..23
410 return jsdate.getHours();
411 },
412 h() {
413 // 12-Hours w/leading 0; 01..12
414 return _pad(f.g(), 2);
415 },
416 H() {
417 // 24-Hours w/leading 0; 00..23
418 return _pad(f.G(), 2);
419 },
420 i() {
421 // Minutes w/leading 0; 00..59
422 return _pad(jsdate.getMinutes(), 2);
423 },
424 s() {
425 // Seconds w/leading 0; 00..59
426 return _pad(jsdate.getSeconds(), 2);
427 },
428 u() {
429 // Microseconds; 000000-999000
430 return _pad(jsdate.getMilliseconds() * 1000, 6);
431 },
432
433 // Timezone
434 e() {
435 // Timezone identifier; e.g. Atlantic/Azores, ...
436 // The following works, but requires inclusion of the very large
437 // timezone_abbreviations_list() function.
438 /* return that.date_default_timezone_get();
439 */
440 throw new Error('Not supported (see source code of date() for timezone on how to add support)');
441 },
442 I() {
443 // DST observed?; 0 or 1
444 // Compares Jan 1 minus Jan 1 UTC to Jul 1 minus Jul 1 UTC.
445 // If they are not equal, then DST is observed.
446 const a = new Date(f.Y(), 0);
447 // Jan 1
448 const c = Date.UTC(f.Y(), 0);
449 // Jan 1 UTC
450 const b = new Date(f.Y(), 6);
451 // Jul 1
452 const d = Date.UTC(f.Y(), 6); // Jul 1 UTC
453 return ((a - c) !== (b - d)) ? 1 : 0;
454 },
455 O() {
456 // Difference to GMT in hour format; e.g. +0200
457 const tzo = jsdate.getTimezoneOffset();
458 const a = Math.abs(tzo);
459 return (tzo > 0 ? '-' : '+') + _pad(Math.floor(a / 60) * 100 + a % 60, 4);
460 },
461 P() {
462 // Difference to GMT w/colon; e.g. +02:00
463 const O = f.O();
464 return (O.substr(0, 3) + ':' + O.substr(3, 2));
465 },
466 T() {
467 // Timezone abbreviation; e.g. EST, MDT, ...
468 // The following works, but requires inclusion of the very
469 // large timezone_abbreviations_list() function.
470 /* var abbr, i, os, _default;
471 if (!tal.length) {
472 tal = that.timezone_abbreviations_list();
473 }
474 if (that.php_js && that.php_js.default_timezone) {
475 _default = that.php_js.default_timezone;
476 for (abbr in tal) {
477 for (i = 0; i < tal[abbr].length; i++) {
478 if (tal[abbr][i].timezone_id === _default) {
479 return abbr.toUpperCase();
480 }
481 }
482 }
483 }
484 for (abbr in tal) {
485 for (i = 0; i < tal[abbr].length; i++) {
486 os = -jsdate.getTimezoneOffset() * 60;
487 if (tal[abbr][i].offset === os) {
488 return abbr.toUpperCase();
489 }
490 }
491 }
492 */
493 return 'UTC';
494 },
495 Z() {
496 // Timezone offset in seconds (-43200...50400)
497 return -jsdate.getTimezoneOffset() * 60;
498 },
499
500 // Full Date/Time
501 c() {
502 // ISO-8601 date.
503 return 'Y-m-d\\TH:i:sP'.replace(formatChr, formatChrCb);
504 },
505 r() {
506 // RFC 2822
507 return 'D, d M Y H:i:s O'.replace(formatChr, formatChrCb);
508 },
509 U() {
510 // Seconds since UNIX epoch
511 return jsdate / 1000 | 0;
512 },
513 };
514 this.date = function (format, timestamp) {
515 // eslint-disable-next-line
516 jsdate = (timestamp === undefined ? new Date() : // Not provided
517 (timestamp instanceof Date) ? new Date(timestamp) : // JS Date()
518 new Date(timestamp * 1000) // UNIX timestamp (auto-convert to int)
519 );
520 return format.replace(formatChr, formatChrCb);
521 };
522 return this.date(format, timestamp);
523};
524
525/**
526 * 空白回调函数
527 *
528 * @param {Error} err
529 */
530exports.noop = function noop(err) {
531 if (err) {
532 console.error('noop callback: %s', err);
533 }
534};
535
536/**
537 * 是否为字符串
538 *
539 * @param {Mixed} str
540 * @return {Boolean}
541 */
542exports.isString = function isString(str) {
543 return (typeof str === 'string');
544};
545
546/**
547 * 是否为整数
548 *
549 * @param {Mixed} str
550 * @return {Boolean}
551 */
552exports.isInteger = function isInteger(str) {
553 return (Math.round(str) === Number(str));
554};
555
556/**
557 * 是否为数字
558 *
559 * @param {Mixed} str
560 * @return {Boolean}
561 */
562exports.isNumber = function isNumber(str) {
563 return (!isNaN(str));
564};
565
566/**
567 * 复制对象
568 *
569 * @param {Object} obj
570 * @return {Object}
571 */
572exports.cloneObject = function cloneObject(obj) {
573 return JSON.parse(JSON.stringify(obj));
574};
575
576/**
577 * 合并对象
578 *
579 * @param {Object} a
580 * @param {Object} b
581 * @return {Object}
582 */
583exports.merge = function merge() {
584 const ret = {};
585 for (let i = 0; i < arguments.length; i++) {
586 const obj = arguments[i];
587 Object.keys(obj).forEach(function (k) {
588 ret[k] = obj[k];
589 });
590 }
591 return ret;
592};
593
594/**
595 * 返回安全的JSON字符串
596 *
597 * @param {Object} data
598 * @param {String|Number} space 缩进
599 * @return {String}
600 */
601exports.jsonStringify = function jsonStringify(data, space) {
602 const seen = [];
603 return JSON.stringify(data, function (key, val) {
604 if (!val || typeof val !== 'object') {
605 return val;
606 }
607 if (seen.indexOf(val) !== -1) {
608 return '[Circular]';
609 }
610 seen.push(val);
611 return val;
612 }, space);
613};
614
615/**
616 * 将arguments对象转换成数组
617 *
618 * @param {Object} args
619 * @return {Array}
620 */
621exports.argumentsToArray = function argumentsToArray(args) {
622 return Array.prototype.slice.call(args);
623};
624
625/**
626 * 取数组的最后一个元素
627 *
628 * @param {Array} arr
629 * @return {Object}
630 */
631exports.getArrayLastItem = function getArrayLastItem(arr) {
632 return arr[arr.length - 1];
633};
634
635/**
636 * 异步函数节流
637 *
638 * @param {Function} fn 函数最后一个参数必须为回调函数,且回调函数第一个参数为 err
639 * @param {Number} maxCcoun
640 * @return {Function}
641 */
642exports.throttleAsync = function throttleAsync(fn, maxCount) {
643 if (!(maxCount > 1)) maxCount = 1;
644 let counter = 0;
645 return function () {
646 const args = utils.argumentsToArray(arguments);
647 const callback = utils.getArrayLastItem(args);
648 if (counter >= maxCount) return callback(new Error('throttleAsync() out of limit'));
649 args.pop();
650 args.push(function () {
651 counter -= 1;
652 callback.apply(null, arguments);
653 });
654 counter += 1;
655 fn.apply(null, args);
656 };
657};
658
659/**
660 * 继承EventEmitter
661 *
662 * @param {Function} fn
663 * @param {Object}
664 */
665exports.inheritsEventEmitter = function inheritsEventEmitter(fn) {
666 return util.inherits(fn, events.EventEmitter);
667};
668
669/**
670 * 继承
671 *
672 * @param {Function} fn
673 * @param {Function} superConstructor
674 * @return {Object}
675 */
676exports.inherits = function inherits(fn, superConstructor) {
677 return util.inherits(fn, superConstructor);
678};
679
680/**
681 * 扩展utils
682 *
683 * @param {Object} obj
684 * @return {Object}
685 */
686exports.extend = function extend(obj) {
687 return utils.merge(exports, obj);
688};
689exports.extends = exports.extend;
690
691exports.array = {};
692
693/**
694 * 取数组最后一个元素
695 *
696 * @param {Array} arr
697 * @return {Object}
698 */
699exports.array.last = function last(arr) {
700 return arr[arr.length - 1];
701};
702
703/**
704 * 取数组第一个元素
705 *
706 * @param {Array} arr
707 * @return {Object}
708 */
709exports.array.head = function head(arr) {
710 return arr[0];
711};
712
713/**
714 * 取数组第一个元素
715 *
716 * @param {Array} arr
717 * @return {Object}
718 */
719exports.array.first = function first(arr) {
720 return arr[0];
721};
722
723/**
724 * 取数组除第一个之外的元素
725 *
726 * @param {Array} arr
727 * @return {Object}
728 */
729exports.array.rest = function rest(arr) {
730 return arr.slice(1);
731};
732
733/**
734 * 复制一个数组
735 *
736 * @param {Array} arr
737 * @return {Object}
738 */
739exports.array.copy = function copy(arr) {
740 return arr.slice();
741};
742
743/**
744 * 组合一组数组
745 *
746 * @param {Array} a
747 * @param {Array} b
748 * @return {Object}
749 */
750exports.array.concat = function concat() {
751 const ret = [];
752 return ret.concat.apply(ret, arguments);
753};
754
755/**
756 * 生成自定义Error类型
757 *
758 * @param {String} name
759 * @param {Object} info
760 * @return {Function}
761 */
762exports.customError = function customError(name, info) {
763 name = name || 'CustomError';
764 info = info || {};
765 const code = '' +
766'function ' + name + '(message, info2) {\n' +
767' Error.captureStackTrace(this, ' + name + ');\n' +
768' this.name = "' + name + '";\n' +
769' this.message = (message || "");\n' +
770' info2 = info2 || {};\n' +
771' for (var i in info) this[i] = info[i];\n' +
772' for (var i in info2) this[i] = info2[i];\n' +
773'}\n' +
774name + '.prototype = Error.prototype;' + name;
775 return eval(code);
776};
777
778/**
779 * 判断是否为Promise对象
780 *
781 * @param {Object} p
782 * @return {Boolean}
783 */
784exports.isPromise = function isPromise(p) {
785 return (p && typeof p.then === 'function' && typeof p.catch === 'function');
786};
787
788exports.promise = {};
789
790/**
791 * 调用异步函数(传参时不包含末尾的callback),返回一个Promise对象
792 *
793 * @param {Function} fn
794 * @return {Object}
795 */
796exports.promise.call = function call(fn) {
797 const args = utils.argumentsToArray(arguments).slice(1);
798 return new Promise(function (resolve, reject) {
799 args.push(function (err, ret) {
800 if (err) {
801 reject(err);
802 } else {
803 resolve(ret);
804 }
805 });
806 let ret;
807 try {
808 ret = fn.apply(null, args);
809 } catch (err) {
810 return reject(err);
811 }
812 if (utils.isPromise(ret)) {
813 ret.then(resolve).catch(reject);
814 }
815 });
816};
817
818/**
819 * 等待所有Promise执行完毕
820 *
821 * @param {Array} _args
822 * @return {Object}
823 */
824exports.promise.all = function all(_args) {
825 const args = Array.isArray(_args) ? _args : utils.argumentsToArray(arguments);
826 return new Promise(function (resolve, reject) {
827 const results = [];
828 let counter = 0;
829 function check() {
830 counter += 1;
831 if (counter === args.length) {
832 resolve(results);
833 }
834 }
835 args.forEach(function (p, i) {
836 p.then(function (ret) {
837 results[i] = [ null, ret ];
838 check();
839 }).catch(function (err) {
840 results[i] = [ err ];
841 check();
842 });
843 });
844 });
845};
846
847/**
848 * 将IP地址转换为long值
849 *
850 * 例: ipToInt('192.0.34.166') ==> 3221234342
851 * ipToInt('255.255.255.256') ==> false
852 *
853 * @param {String} ip
854 * @return {Number}
855 */
856exports.ipToInt = function ipToInt(ip) {
857 const s = ip.split('.');
858 if (s.length !== 4) return false;
859 for (let i = 0; i < 4; i++) {
860 const v = s[i] = parseInt(s[i], 10);
861 if (v < 0 || v > 255) return false;
862 }
863 return s[0] * 16777216 + s[1] * 65536 + s[2] * 256 + s[3];
864};
865
866/**
867 * 将字符串转换为 Buffer
868 *
869 * @param {String} data
870 * @return {Buffer}
871 */
872exports.toBuffer = function toBuffer(data) {
873 if (Buffer.isBuffer(data)) return data;
874 if (typeof data === 'string') return new Buffer(data);
875 throw new Error('invalid data type, must be string or buffer');
876};
877
878/**
879 * 使用指定方法加密数据
880 *
881 * @param {String} algorithm
882 * @param {String|Buffer} key
883 * @param {Buffer} data
884 * @return {Buffer}
885 */
886exports.encrypt = function encrypt(algorithm, key, data) {
887 key = Buffer.isBuffer(key) ? key : keyHash(key);
888 data = utils.toBuffer(data);
889 const cipher = crypto.createCipheriv(algorithm, key, new Buffer(0));
890 const encrypted = [ cipher.update(data), cipher.final() ];
891 return Buffer.concat(encrypted);
892};
893
894/**
895 * 使用指定方法加密数据流
896 *
897 * @param {String} algorithm
898 * @param {String|Buffer} key
899 * @param {Stream} inStream
900 * @return {Stream}
901 */
902exports.encryptStream = function encryptStream(algorithm, key, inStream) {
903 key = Buffer.isBuffer(key) ? key : keyHash(key);
904 const cipher = crypto.createCipheriv(algorithm, key, new Buffer(0));
905 return inStream.pipe(cipher);
906};
907
908/**
909 * 使用指定方法解密数据
910 *
911 * @param {String} algorithm
912 * @param {String|Buffer} key
913 * @param {Buffer} data
914 * @return {Buffer}
915 */
916exports.decrypt = function decrypt(algorithm, key, data) {
917 key = Buffer.isBuffer(key) ? key : keyHash(key);
918 data = utils.toBuffer(data);
919 const cipher = crypto.createDecipheriv(algorithm, key, new Buffer(0));
920 const encrypted = [ cipher.update(data), cipher.final() ];
921 return Buffer.concat(encrypted);
922};
923
924/**
925 * 使用指定方法解密数据流
926 *
927 * @param {String} algorithm
928 * @param {String|Buffer} key
929 * @param {Stream} inStream
930 * @return {Stream}
931 */
932exports.decryptStream = function decryptStream(algorithm, key, inStream) {
933 key = Buffer.isBuffer(key) ? key : keyHash(key);
934 const cipher = crypto.createDecipheriv(algorithm, key, new Buffer(0));
935 return inStream.pipe(cipher);
936};
937
938function keyHash(data) {
939 data = utils.toBuffer(data);
940 return crypto.createHash('sha256').update(data).digest();
941}
942
943/**
944 * 创建 hash 的转换流
945 *
946 * @param {String} method 方法,如 md5, sha1, sha256
947 * @return {Stream}
948 */
949exports.hashTransform = function hashTransform(method, callback) {
950 const cipher = crypto.createHash(method);
951 const transform = new stream.Transform({
952 transform(chunk, encoding, callback) {
953 cipher.update(chunk, encoding);
954 this.push(chunk);
955 callback();
956 },
957 });
958 transform.once('finish', () => callback(null, cipher.digest()));
959 return transform;
960};
961
962/**
963 * 创建一个带 promise 的回调函数
964 *
965 * @return {Function}
966 */
967exports.createPromiseCallback = function createPromiseCallback() {
968 const callback = (err, ret) => {
969 if (err) {
970 callback.reject(err);
971 } else {
972 callback.resolve(ret);
973 }
974 };
975 callback.promise = new Promise((resolve, reject) => {
976 callback.resolve = resolve;
977 callback.reject = reject;
978 });
979 return callback;
980};