@maiyunnet/kebab 2.0.2 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +1 -1
- package/lib/sql.js +1 -3
- package/lib/text.js +5 -1
- package/package.json +1 -1
- package/tsconfig.json +1 -1
- package/index.ts +0 -33
- package/lib/buffer.ts +0 -152
- package/lib/captcha.ts +0 -63
- package/lib/consistent.ts +0 -219
- package/lib/core.ts +0 -880
- package/lib/crypto.ts +0 -384
- package/lib/db.ts +0 -719
- package/lib/dns.ts +0 -405
- package/lib/fs.ts +0 -527
- package/lib/jwt.ts +0 -276
- package/lib/kv.ts +0 -1489
- package/lib/lan.ts +0 -87
- package/lib/net/formdata.ts +0 -166
- package/lib/net/request.ts +0 -150
- package/lib/net/response.ts +0 -59
- package/lib/net.ts +0 -662
- package/lib/s3.ts +0 -235
- package/lib/scan.ts +0 -364
- package/lib/session.ts +0 -230
- package/lib/sql.ts +0 -1151
- package/lib/ssh/sftp.ts +0 -508
- package/lib/ssh/shell.ts +0 -123
- package/lib/ssh.ts +0 -191
- package/lib/text.ts +0 -615
- package/lib/time.ts +0 -254
- package/lib/ws.ts +0 -523
- package/lib/zip.ts +0 -447
- package/lib/zlib.ts +0 -350
- package/main.ts +0 -27
- package/sys/child.ts +0 -678
- package/sys/cmd.ts +0 -225
- package/sys/ctr.ts +0 -904
- package/sys/master.ts +0 -355
- package/sys/mod.ts +0 -1871
- package/sys/route.ts +0 -1113
- package/types/index.d.ts +0 -283
- package/www/example/ctr/main.ts +0 -9
- package/www/example/ctr/middle.ts +0 -26
- package/www/example/ctr/test.ts +0 -3218
- package/www/example/mod/test.ts +0 -47
- package/www/example/mod/testdata.ts +0 -30
- package/www/example/ws/mproxy.ts +0 -16
- package/www/example/ws/rproxy.ts +0 -14
- package/www/example/ws/test.ts +0 -36
package/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MOD_CWD = exports.FTMP_CWD = exports.IND_CWD = exports.WWW_CWD = exports.LOG_CWD = exports.LIB_CWD = exports.VHOST_CWD = exports.CERT_CWD = exports.CONF_CWD = exports.ROOT_CWD = exports.SYS_PATH = exports.LIB_PATH = exports.ROOT_PATH = exports.VER = void 0;
|
|
4
|
-
exports.VER = '2.0.
|
|
4
|
+
exports.VER = '2.0.4';
|
|
5
5
|
const dirname = __dirname.replace(/\\/g, '/');
|
|
6
6
|
exports.ROOT_PATH = dirname + '/';
|
|
7
7
|
exports.LIB_PATH = exports.ROOT_PATH + 'lib/';
|
package/lib/sql.js
CHANGED
package/lib/text.js
CHANGED
|
@@ -57,6 +57,7 @@ exports.stringifyResult = stringifyResult;
|
|
|
57
57
|
exports.parseJson = parseJson;
|
|
58
58
|
exports.stringifyJson = stringifyJson;
|
|
59
59
|
exports.isFalsy = isFalsy;
|
|
60
|
+
exports.logicalOr = logicalOr;
|
|
60
61
|
exports.str2int = str2int;
|
|
61
62
|
exports.int2str = int2str;
|
|
62
63
|
const kebab = __importStar(require("~/index"));
|
|
@@ -429,7 +430,10 @@ function stringifyJson(obj, space) {
|
|
|
429
430
|
}, space).replace(/"-mybigint-([-+0-9]+?)"/g, '$1');
|
|
430
431
|
}
|
|
431
432
|
function isFalsy(val) {
|
|
432
|
-
return (val === null || val === undefined || val === '' || val === false || val === 0)
|
|
433
|
+
return (val === null) || (val === undefined) || (val === '') || (val === false) || (val === 0);
|
|
434
|
+
}
|
|
435
|
+
function logicalOr(v1, v2) {
|
|
436
|
+
return (isFalsy(v1) ? v2 : v1);
|
|
433
437
|
}
|
|
434
438
|
function str2int(str, digits = 3) {
|
|
435
439
|
const num = parseFloat(str);
|
package/package.json
CHANGED
package/tsconfig.json
CHANGED
package/index.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Project: Kebab, User: JianSuoQiYue
|
|
3
|
-
* Date: 2019-3-30 12:46:41
|
|
4
|
-
* Last: 2020-3-8 21:04:24, 2022-07-22 14:20:34, 2023-5-24 01:34:57, 2025-6-13 14:49:27
|
|
5
|
-
* --- 本文件用来定义每个目录实体地址的常量 ---
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/** --- 当前系统版本号 --- */
|
|
9
|
-
export const VER = '2.0.2';
|
|
10
|
-
|
|
11
|
-
// --- 服务端用的路径 ---
|
|
12
|
-
|
|
13
|
-
/** --- /xxx/xxx --- */
|
|
14
|
-
const dirname = __dirname.replace(/\\/g, '/');
|
|
15
|
-
|
|
16
|
-
/** --- 框架根目录,以 / 结尾 --- */
|
|
17
|
-
export const ROOT_PATH = dirname + '/';
|
|
18
|
-
export const LIB_PATH = ROOT_PATH + 'lib/';
|
|
19
|
-
export const SYS_PATH = ROOT_PATH + 'sys/';
|
|
20
|
-
|
|
21
|
-
const cwd = process.cwd().replace(/\\/g, '/');
|
|
22
|
-
|
|
23
|
-
/** --- 执行根目录,以 / 结尾 --- */
|
|
24
|
-
export const ROOT_CWD = cwd + '/';
|
|
25
|
-
export const CONF_CWD = ROOT_CWD + 'conf/';
|
|
26
|
-
export const CERT_CWD = CONF_CWD + 'cert/';
|
|
27
|
-
export const VHOST_CWD = CONF_CWD + 'vhost/';
|
|
28
|
-
export const LIB_CWD = ROOT_CWD + 'lib/';
|
|
29
|
-
export const LOG_CWD = ROOT_CWD + 'log/';
|
|
30
|
-
export const WWW_CWD = ROOT_CWD + 'www/';
|
|
31
|
-
export const IND_CWD = ROOT_CWD + 'ind/';
|
|
32
|
-
export const FTMP_CWD = ROOT_CWD + 'ftmp/';
|
|
33
|
-
export const MOD_CWD = ROOT_CWD + 'mod/';
|
package/lib/buffer.ts
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
/** --- 读对象 --- */
|
|
2
|
-
export class Reader {
|
|
3
|
-
|
|
4
|
-
private readonly _buffer: Buffer;
|
|
5
|
-
|
|
6
|
-
/** --- 当前读取位置 --- */
|
|
7
|
-
private _offset: number = 0;
|
|
8
|
-
|
|
9
|
-
public constructor(buffer: Buffer) {
|
|
10
|
-
this._buffer = buffer;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/** --- 读取一个无符号8位整数, BYTE --- */
|
|
14
|
-
public readUInt8(): number {
|
|
15
|
-
const value = this._buffer.readUInt8(this._offset);
|
|
16
|
-
this._offset += 1;
|
|
17
|
-
return value;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/** --- 读取一个无符号16位整数(大端模式),WORD --- */
|
|
21
|
-
public readUInt16BE(): number {
|
|
22
|
-
const value = this._buffer.readUInt16BE(this._offset);
|
|
23
|
-
this._offset += 2;
|
|
24
|
-
return value;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** --- 读取一个无符号32位整数(大端模式), DWORD --- */
|
|
28
|
-
public readUInt32BE(): number {
|
|
29
|
-
const value = this._buffer.readUInt32BE(this._offset);
|
|
30
|
-
this._offset += 4;
|
|
31
|
-
return value;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/** --- 读取一个 BCD 编码的字符串(每个字节表示两个数字)--- */
|
|
35
|
-
public readBCDString(length?: number): string {
|
|
36
|
-
if (length === undefined) {
|
|
37
|
-
length = this._buffer.length - this._offset;
|
|
38
|
-
}
|
|
39
|
-
let str = '';
|
|
40
|
-
for (let i = 0; i < length; i++) {
|
|
41
|
-
const byte = this._buffer.readUInt8(this._offset + i);
|
|
42
|
-
str += (byte >> 4).toString(16).toUpperCase(); // --- 高四位表示第一个数字 ---
|
|
43
|
-
str += (byte & 0x0f).toString(16).toUpperCase(); // --- 低四位表示第二个数字 ---
|
|
44
|
-
}
|
|
45
|
-
this._offset += length;
|
|
46
|
-
return str;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/** --- 读取普通 string --- */
|
|
50
|
-
public readString(length?: number, encoding: BufferEncoding = 'utf8'): string {
|
|
51
|
-
if (length === undefined) {
|
|
52
|
-
length = this._buffer.length - this._offset;
|
|
53
|
-
}
|
|
54
|
-
const buf: number[] = [];
|
|
55
|
-
for (let i = 0; i < length; i++) {
|
|
56
|
-
const byte = this._buffer.readUInt8(this._offset + i);
|
|
57
|
-
if (byte === 0x00) {
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
buf.push(byte);
|
|
61
|
-
}
|
|
62
|
-
this._offset += length;
|
|
63
|
-
return Buffer.from(buf).toString(encoding);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/** --- 读取 Buffer --- */
|
|
67
|
-
public readBuffer(length?: number): Buffer {
|
|
68
|
-
if (length === undefined) {
|
|
69
|
-
length = this._buffer.length - this._offset;
|
|
70
|
-
}
|
|
71
|
-
return this._buffer.subarray(this._offset, this._offset += length);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/** --- 获取完整的 buffer 长度 --- */
|
|
75
|
-
public length(): number {
|
|
76
|
-
return this._buffer.length;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/** --- 写对象 --- */
|
|
82
|
-
export class Writer {
|
|
83
|
-
|
|
84
|
-
private readonly _buffer: Buffer;
|
|
85
|
-
|
|
86
|
-
/** --- 当前读取位置 --- */
|
|
87
|
-
private _offset: number = 0;
|
|
88
|
-
|
|
89
|
-
public constructor(size: number) {
|
|
90
|
-
this._buffer = Buffer.alloc(size);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/** --- [1 字节] 写入一个无符号 8 位整数 --- */
|
|
94
|
-
public writeUInt8(value: number): void {
|
|
95
|
-
this._buffer.writeUInt8(value, this._offset);
|
|
96
|
-
this._offset += 1;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/** --- [2 字节] 写入一个无符号 16 位整数(大端模式) --- */
|
|
100
|
-
public writeUInt16BE(value: number): void {
|
|
101
|
-
this._buffer.writeUInt16BE(value, this._offset);
|
|
102
|
-
this._offset += 2;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/** --- [4 字节] 写入一个无符号 32 位整数(大端模式) --- */
|
|
106
|
-
public writeUInt32BE(value: number): void {
|
|
107
|
-
this._buffer.writeUint32BE(value, this._offset);
|
|
108
|
-
this._offset += 4;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/** --- [每字节 2 数字] 写入一个 BCD 编码的字符串(仅支持数字) --- */
|
|
112
|
-
public writeBCDString(value: string): void {
|
|
113
|
-
for (let i = 0; i < value.length; i += 2) {
|
|
114
|
-
const high = parseInt(value[i], 10); // --- 取十位 ---
|
|
115
|
-
const low = parseInt(value[i + 1], 10); // --- 取个位 ---
|
|
116
|
-
const byte = (high << 4) | low; // --- 拼接为一个字节 ---
|
|
117
|
-
this.writeUInt8(byte);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/** --- 写入普通字符串,返回写入的长度 --- */
|
|
122
|
-
public writeString(value: string, encoding: BufferEncoding = 'utf8'): number {
|
|
123
|
-
const bytes = Buffer.from(value, encoding);
|
|
124
|
-
for (const byte of bytes) {
|
|
125
|
-
this.writeUInt8(byte);
|
|
126
|
-
}
|
|
127
|
-
this._offset += bytes.length;
|
|
128
|
-
return bytes.length;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/** --- 返回 Buffer 对象 --- */
|
|
132
|
-
public get(): Buffer {
|
|
133
|
-
return this._buffer.subarray(0, this._offset);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* --- Buffer Reader 对象 ---
|
|
140
|
-
* @param buffer 要读取的 buffer
|
|
141
|
-
*/
|
|
142
|
-
export function getReader(buffer: Buffer): Reader {
|
|
143
|
-
return new Reader(buffer);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* --- Buffer Writer 对象 ---
|
|
148
|
-
* @param buffer 要读取的 buffer
|
|
149
|
-
*/
|
|
150
|
-
export function getWriter(size: number): Writer {
|
|
151
|
-
return new Writer(size);
|
|
152
|
-
}
|
package/lib/captcha.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Project: Kebab, User: JianSuoQiYue
|
|
3
|
-
* Date: 2019-6-7 12:14:31
|
|
4
|
-
* Last: 2020-3-11 23:33:19, 2022-09-12 10:38:24, 2022-12-29 01:16:26, 2024-4-1 16:40:42, 2025-6-13 19:45:30
|
|
5
|
-
*/
|
|
6
|
-
import * as svgCaptcha from 'svg-captcha';
|
|
7
|
-
import * as mime from '@litert/mime';
|
|
8
|
-
import * as core from '~/lib/core';
|
|
9
|
-
import * as kebab from '~/index';
|
|
10
|
-
|
|
11
|
-
svgCaptcha.loadFont(kebab.LIB_PATH + 'captcha/zcool-addict-italic.ttf');
|
|
12
|
-
|
|
13
|
-
export class Captcha {
|
|
14
|
-
|
|
15
|
-
private readonly _link: svgCaptcha.CaptchaObj;
|
|
16
|
-
|
|
17
|
-
public constructor(opt: { 'width': number; 'height': number; 'length': number; }) {
|
|
18
|
-
this._link = svgCaptcha.create({
|
|
19
|
-
'width': opt.width,
|
|
20
|
-
'height': opt.height,
|
|
21
|
-
'size': opt.length,
|
|
22
|
-
'noise': 15,
|
|
23
|
-
'background': '#fff',
|
|
24
|
-
'charPreset': core.RANDOM_V
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* --- 获取图片 Buffer ---
|
|
30
|
-
*/
|
|
31
|
-
public getBuffer(): string {
|
|
32
|
-
return this._link.data.replace('<rect width="100%" height="100%" fill="#fff"/>', '');
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* --- 获取 base64 格式图片 ---
|
|
37
|
-
*/
|
|
38
|
-
public getBase64(): string {
|
|
39
|
-
return `data:${mime.getMime('svg')};base64,` + Buffer.from(this._link.data.replace('<rect width="100%" height="100%" fill="#fff"/>', '')).toString('base64');
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* --- 获取当前随机码 ---
|
|
44
|
-
*/
|
|
45
|
-
public getPhrase(): string {
|
|
46
|
-
return this._link.text;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* --- 获取验证码对象 ---
|
|
53
|
-
* @param width 宽度
|
|
54
|
-
* @param height 高度
|
|
55
|
-
* @param length 字符个数
|
|
56
|
-
*/
|
|
57
|
-
export function get(width: number, height: number, length: number = 4): Captcha {
|
|
58
|
-
return new Captcha({
|
|
59
|
-
'width': width,
|
|
60
|
-
'height': height,
|
|
61
|
-
'length': length
|
|
62
|
-
});
|
|
63
|
-
}
|
package/lib/consistent.ts
DELETED
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Project: Kebab, User: JianSuoQiYue
|
|
3
|
-
* Date: 2022-09-12 10:51:16
|
|
4
|
-
* Last: 2022-09-12 10:51:20, 2023-3-17 10:52:04, 2023-11-15 11:45:28
|
|
5
|
-
*/
|
|
6
|
-
import * as crypto from '~/lib/crypto';
|
|
7
|
-
|
|
8
|
-
export class Consistent {
|
|
9
|
-
|
|
10
|
-
/** --- 虚拟节点数量 --- */
|
|
11
|
-
private readonly _vcount: number = 300;
|
|
12
|
-
|
|
13
|
-
/** --- hash 环 --- */
|
|
14
|
-
private readonly _circle: Record<string, string> = {};
|
|
15
|
-
|
|
16
|
-
/** --- circle 的 keys --- */
|
|
17
|
-
private _keys: string[] = [];
|
|
18
|
-
|
|
19
|
-
public constructor(vcount: number) {
|
|
20
|
-
this._vcount = vcount;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* --- 获取当前的虚拟节点数量 ---
|
|
25
|
-
*/
|
|
26
|
-
public getVcount(): number {
|
|
27
|
-
return this._vcount;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* 添加节点
|
|
32
|
-
* @param node node 节点名一个或多个
|
|
33
|
-
*/
|
|
34
|
-
public add(node: string | string[]): void {
|
|
35
|
-
addToCircle(this._circle, node, this._vcount);
|
|
36
|
-
this._keys = [];
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* 移除节点
|
|
41
|
-
* @param node node 节点名
|
|
42
|
-
*/
|
|
43
|
-
public remove(node: string | string[]): void {
|
|
44
|
-
if (typeof node === 'string') {
|
|
45
|
-
node = [node];
|
|
46
|
-
}
|
|
47
|
-
for (const v of node) {
|
|
48
|
-
for (let i = 0; i < this._vcount; i++) {
|
|
49
|
-
delete this._circle[hash(v + i.toString())];
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
this._keys = [];
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* 获得一个最近的顺时针节点
|
|
57
|
-
* @param key 为给定键取 Hash,取得顺时针方向上最近的一个虚拟节点对应的实际节点
|
|
58
|
-
*/
|
|
59
|
-
public find(key: string | number): string | null {
|
|
60
|
-
if (this._keys.length === 0) {
|
|
61
|
-
this._keys = Object.keys(this._circle);
|
|
62
|
-
this._keys.sort((a, b) => {
|
|
63
|
-
return parseFloat(a) - parseFloat(b);
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
return findInCircle(this._circle, key, this._keys);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* --- 原数据迁移到新地址 ---
|
|
71
|
-
* @param keys 原始数据 key 集
|
|
72
|
-
* @param node 新增的节点一个或多个
|
|
73
|
-
*/
|
|
74
|
-
public migration(keys: string | number | Array<string | number>, node: string | string[]): Record<string, {
|
|
75
|
-
'old': string;
|
|
76
|
-
'new': string;
|
|
77
|
-
}> {
|
|
78
|
-
const rtn: Record<string, {
|
|
79
|
-
'old': string;
|
|
80
|
-
'new': string;
|
|
81
|
-
}> = {};
|
|
82
|
-
if (!Array.isArray(keys)) {
|
|
83
|
-
keys = [keys];
|
|
84
|
-
}
|
|
85
|
-
// --- 获取老的 key 对应的 node ---
|
|
86
|
-
const mapOld: Record<string, string> = {};
|
|
87
|
-
for (const key of keys) {
|
|
88
|
-
const oldNode = this.find(key);
|
|
89
|
-
if (!oldNode) {
|
|
90
|
-
continue;
|
|
91
|
-
}
|
|
92
|
-
mapOld[key] = oldNode;
|
|
93
|
-
}
|
|
94
|
-
this.add(node);
|
|
95
|
-
// --- 再逐一检测老的和新的的 node 是否一致 ---
|
|
96
|
-
for (const key of keys) {
|
|
97
|
-
const newNode = this.find(key);
|
|
98
|
-
if (!newNode) {
|
|
99
|
-
continue;
|
|
100
|
-
}
|
|
101
|
-
if (mapOld[key] === newNode) {
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
rtn[key] = {
|
|
105
|
-
'old': mapOld[key],
|
|
106
|
-
'new': newNode
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
return rtn;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export function get(vcount = 300): Consistent {
|
|
115
|
-
return new Consistent(vcount);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
*--- 快速查找一个 key 属于哪个 node ---
|
|
120
|
-
* @param key 要查找的key
|
|
121
|
-
* @param nodes node 列表
|
|
122
|
-
* @param vcount 虚拟节点数量
|
|
123
|
-
*/
|
|
124
|
-
export function fast(key: string | number, nodes: string | string[], vcount = 300): string | null {
|
|
125
|
-
const circle: Record<string, string> = {};
|
|
126
|
-
addToCircle(circle, nodes, vcount);
|
|
127
|
-
return findInCircle(circle, key);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* --- hash 函数 ---
|
|
132
|
-
* @param val 要 hash 的值
|
|
133
|
-
*/
|
|
134
|
-
export function hash(val: string | number): number {
|
|
135
|
-
if (typeof val === 'number') {
|
|
136
|
-
val = val.toString();
|
|
137
|
-
}
|
|
138
|
-
const bKey = crypto.hashHmac('md5', val);
|
|
139
|
-
|
|
140
|
-
const res = ((bKey.charCodeAt(3) & 0xFF) << 24) |
|
|
141
|
-
((bKey.charCodeAt(2) & 0xFF) << 16) |
|
|
142
|
-
((bKey.charCodeAt(1) & 0xFF) << 8) |
|
|
143
|
-
(bKey.charCodeAt(0) & 0xFF);
|
|
144
|
-
return res & 0xffffffff;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* --- 获取区间节点系列 ---
|
|
149
|
-
* @param min 最小值(含)
|
|
150
|
-
* @param max 最大值(含)
|
|
151
|
-
* @param pre 前导
|
|
152
|
-
*/
|
|
153
|
-
export function getRange(min: number, max: number, pre: string = ''): string[] {
|
|
154
|
-
const ls: string[] = [];
|
|
155
|
-
for (let i = min; i <= max; ++i) {
|
|
156
|
-
ls.push(pre + i.toString());
|
|
157
|
-
}
|
|
158
|
-
return ls;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* --- 添加到圆环 ---
|
|
163
|
-
* @param circle 圆环
|
|
164
|
-
* @param node node 节点名一个或多个
|
|
165
|
-
* @param vcount 虚拟节点数量
|
|
166
|
-
*/
|
|
167
|
-
export function addToCircle(
|
|
168
|
-
circle: Record<string, string>,
|
|
169
|
-
node: string | string[],
|
|
170
|
-
vcount: number = 300
|
|
171
|
-
): void {
|
|
172
|
-
if (typeof node === 'string') {
|
|
173
|
-
node = [node];
|
|
174
|
-
}
|
|
175
|
-
for (const v of node) {
|
|
176
|
-
for (let i = 0; i < vcount; i++) {
|
|
177
|
-
circle[hash(v + i.toString())] = v;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* --- 获得一个最近的顺时针节点 ---
|
|
184
|
-
* @param circle 圆环
|
|
185
|
-
* @param key 为给定键取 Hash,取得顺时针方向上最近的一个虚拟节点对应的实际节点
|
|
186
|
-
* @param keys keys,留空则自动从 circle 上取
|
|
187
|
-
*/
|
|
188
|
-
export function findInCircle(
|
|
189
|
-
circle: Record<string, string>,
|
|
190
|
-
key: string | number,
|
|
191
|
-
keys: string[] = []
|
|
192
|
-
): string | null {
|
|
193
|
-
let count = keys.length;
|
|
194
|
-
if (keys.length === 0) {
|
|
195
|
-
keys = Object.keys(circle);
|
|
196
|
-
count = keys.length;
|
|
197
|
-
keys.sort((a, b) => {
|
|
198
|
-
return parseFloat(a) - parseFloat(b);
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
if (count === 0) {
|
|
202
|
-
return null;
|
|
203
|
-
}
|
|
204
|
-
if (count === 1) {
|
|
205
|
-
return circle[keys[0]];
|
|
206
|
-
}
|
|
207
|
-
const hashv = hash(key);
|
|
208
|
-
if (circle[hashv] !== undefined) {
|
|
209
|
-
return circle[hashv];
|
|
210
|
-
}
|
|
211
|
-
for (const v of keys) {
|
|
212
|
-
if (parseFloat(v) < hashv) {
|
|
213
|
-
continue;
|
|
214
|
-
}
|
|
215
|
-
return circle[v];
|
|
216
|
-
}
|
|
217
|
-
// --- 没找到 ---
|
|
218
|
-
return circle[keys[0]];
|
|
219
|
-
}
|