node-karin 0.0.3
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/LICENSE +674 -0
- package/README.md +57 -0
- package/config/defSet/App.yaml +37 -0
- package/config/defSet/config.yaml +43 -0
- package/config/defSet/group.yaml +18 -0
- package/config/defSet/pm2.yaml +21 -0
- package/config/defSet/redis.yaml +18 -0
- package/config/defSet/server.yaml +42 -0
- package/config/view/App.yaml +74 -0
- package/config/view/config.yaml +100 -0
- package/config/view/group.yaml +62 -0
- package/config/view/pm2.yaml +41 -0
- package/config/view/redis.yaml +25 -0
- package/config/view/server.yaml +93 -0
- package/lib/adapter/onebot/onebot11.d.ts +430 -0
- package/lib/adapter/onebot/onebot11.js +1302 -0
- package/lib/core/init.d.ts +0 -0
- package/lib/core/init.js +4 -0
- package/lib/core/karin.d.ts +72 -0
- package/lib/core/karin.js +51 -0
- package/lib/core/listener.d.ts +121 -0
- package/lib/core/listener.js +188 -0
- package/lib/core/plugin.app.d.ts +15 -0
- package/lib/core/plugin.app.js +18 -0
- package/lib/core/plugin.d.ts +182 -0
- package/lib/core/plugin.js +138 -0
- package/lib/core/plugin.loader.d.ts +149 -0
- package/lib/core/plugin.loader.js +462 -0
- package/lib/core/server.d.ts +26 -0
- package/lib/core/server.js +213 -0
- package/lib/db/level.d.ts +20 -0
- package/lib/db/level.js +38 -0
- package/lib/db/redis.d.ts +41 -0
- package/lib/db/redis.js +137 -0
- package/lib/db/redis_level.d.ts +113 -0
- package/lib/db/redis_level.js +290 -0
- package/lib/event/event.d.ts +138 -0
- package/lib/event/event.handler.d.ts +29 -0
- package/lib/event/event.handler.js +142 -0
- package/lib/event/event.js +120 -0
- package/lib/event/message.d.ts +102 -0
- package/lib/event/message.handler.d.ts +25 -0
- package/lib/event/message.handler.js +240 -0
- package/lib/event/message.js +70 -0
- package/lib/event/notice.d.ts +49 -0
- package/lib/event/notice.js +15 -0
- package/lib/event/request.d.ts +49 -0
- package/lib/event/request.js +15 -0
- package/lib/event/review.handler.d.ts +54 -0
- package/lib/event/review.handler.js +382 -0
- package/lib/index.d.ts +23 -0
- package/lib/index.js +40 -0
- package/lib/renderer/app.d.ts +53 -0
- package/lib/renderer/app.js +93 -0
- package/lib/renderer/base.d.ts +30 -0
- package/lib/renderer/base.js +71 -0
- package/lib/renderer/client.d.ts +30 -0
- package/lib/renderer/client.js +159 -0
- package/lib/renderer/http.d.ts +19 -0
- package/lib/renderer/http.js +51 -0
- package/lib/renderer/server.d.ts +42 -0
- package/lib/renderer/server.js +112 -0
- package/lib/renderer/wormhole.d.ts +1 -0
- package/lib/renderer/wormhole.js +154 -0
- package/lib/types/adapter.d.ts +575 -0
- package/lib/types/adapter.js +1 -0
- package/lib/types/config.d.ts +327 -0
- package/lib/types/config.js +1 -0
- package/lib/types/element.d.ts +576 -0
- package/lib/types/element.js +1 -0
- package/lib/types/index.d.ts +8 -0
- package/lib/types/index.js +8 -0
- package/lib/types/logger.d.ts +109 -0
- package/lib/types/logger.js +1 -0
- package/lib/types/onebots11.d.ts +1371 -0
- package/lib/types/onebots11.js +1 -0
- package/lib/types/plugin.d.ts +282 -0
- package/lib/types/plugin.js +1 -0
- package/lib/types/render.d.ts +111 -0
- package/lib/types/render.js +1 -0
- package/lib/types/reply.d.ts +40 -0
- package/lib/types/reply.js +1 -0
- package/lib/types/types.d.ts +898 -0
- package/lib/types/types.js +1 -0
- package/lib/utils/YamlEditor.d.ts +62 -0
- package/lib/utils/YamlEditor.js +208 -0
- package/lib/utils/button.d.ts +49 -0
- package/lib/utils/button.js +79 -0
- package/lib/utils/common.d.ts +123 -0
- package/lib/utils/common.js +413 -0
- package/lib/utils/config.d.ts +72 -0
- package/lib/utils/config.js +254 -0
- package/lib/utils/exec.d.ts +22 -0
- package/lib/utils/exec.js +36 -0
- package/lib/utils/ffmpeg.d.ts +12 -0
- package/lib/utils/ffmpeg.js +25 -0
- package/lib/utils/handler.d.ts +76 -0
- package/lib/utils/handler.js +102 -0
- package/lib/utils/logger.d.ts +3 -0
- package/lib/utils/logger.js +104 -0
- package/lib/utils/segment.d.ts +276 -0
- package/lib/utils/segment.js +448 -0
- package/lib/utils/update.d.ts +69 -0
- package/lib/utils/update.js +151 -0
- package/lib/utils/updateVersion.d.ts +33 -0
- package/lib/utils/updateVersion.js +145 -0
- package/package.json +92 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Level } from 'level';
|
|
2
|
+
/**
|
|
3
|
+
* @type {Level}
|
|
4
|
+
*/
|
|
5
|
+
declare class LevelDB extends Level {
|
|
6
|
+
id: string;
|
|
7
|
+
constructor();
|
|
8
|
+
/**
|
|
9
|
+
* 对get方法进行重写 找不到数据时返回null
|
|
10
|
+
*/
|
|
11
|
+
get(key: string): Promise<string>;
|
|
12
|
+
/**
|
|
13
|
+
* 增加set方法
|
|
14
|
+
* @param {string} key 键
|
|
15
|
+
* @param {object|string} value 值
|
|
16
|
+
*/
|
|
17
|
+
set(key: string, value: string): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
declare const level: LevelDB;
|
|
20
|
+
export default level;
|
package/lib/db/level.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Level } from 'level'
|
|
2
|
+
const path = process.cwd() + '/data/db/Level'
|
|
3
|
+
/**
|
|
4
|
+
* @type {Level}
|
|
5
|
+
*/
|
|
6
|
+
class LevelDB extends Level {
|
|
7
|
+
id
|
|
8
|
+
constructor () {
|
|
9
|
+
super(path, { valueEncoding: 'json' })
|
|
10
|
+
/**
|
|
11
|
+
* @type {'Level'} 唯一标识符 用于区分不同的数据库
|
|
12
|
+
*/
|
|
13
|
+
this.id = 'Level'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 对get方法进行重写 找不到数据时返回null
|
|
18
|
+
*/
|
|
19
|
+
async get (key) {
|
|
20
|
+
try {
|
|
21
|
+
const res = await super.get(key)
|
|
22
|
+
return res
|
|
23
|
+
} catch {
|
|
24
|
+
return ''
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 增加set方法
|
|
30
|
+
* @param {string} key 键
|
|
31
|
+
* @param {object|string} value 值
|
|
32
|
+
*/
|
|
33
|
+
async set (key, value) {
|
|
34
|
+
return await super.put(key, value)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const level = new LevelDB()
|
|
38
|
+
export default level
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import RedisLevel from './redis_level.js';
|
|
2
|
+
import redis from 'redis';
|
|
3
|
+
export default class Redis {
|
|
4
|
+
id: 'redis';
|
|
5
|
+
RunCmd: string;
|
|
6
|
+
constructor();
|
|
7
|
+
/**
|
|
8
|
+
* redis实例化
|
|
9
|
+
*/
|
|
10
|
+
start(): Promise<(redis.RedisClientType | string) | RedisLevel | false>;
|
|
11
|
+
/**
|
|
12
|
+
* 降级为 LevelDB
|
|
13
|
+
*/
|
|
14
|
+
LevelDB(): Promise<false | RedisLevel>;
|
|
15
|
+
/**
|
|
16
|
+
* 连接 Redis 单例
|
|
17
|
+
* @param {import("redis").RedisClientOptions} options
|
|
18
|
+
* @return {Promise<{status: 'ok', data: import("redis").RedisClientType} | {status: 'error', data: Error}>}
|
|
19
|
+
*/
|
|
20
|
+
connect(options: redis.RedisClientOptions): Promise<{
|
|
21
|
+
status: 'ok';
|
|
22
|
+
data: redis.RedisClientType;
|
|
23
|
+
} | {
|
|
24
|
+
status: 'error';
|
|
25
|
+
data: string;
|
|
26
|
+
}>;
|
|
27
|
+
/**
|
|
28
|
+
* 连接 Redis 集群
|
|
29
|
+
*/
|
|
30
|
+
connectCluster(rootNodes: {
|
|
31
|
+
url: string;
|
|
32
|
+
}[]): Promise<{
|
|
33
|
+
status: string;
|
|
34
|
+
data: unknown;
|
|
35
|
+
}>;
|
|
36
|
+
/**
|
|
37
|
+
* 判断是否为 ARM64 并返回参数
|
|
38
|
+
*/
|
|
39
|
+
aarch64(): Promise<string>;
|
|
40
|
+
execSync(cmd: string): Promise<string>;
|
|
41
|
+
}
|
package/lib/db/redis.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { exec } from 'child_process'
|
|
2
|
+
import RedisLevel from './redis_level.js'
|
|
3
|
+
import logger from '../utils/logger.js'
|
|
4
|
+
import config from '../utils/config.js'
|
|
5
|
+
import { createClient, createCluster } from 'redis'
|
|
6
|
+
export default class Redis {
|
|
7
|
+
id
|
|
8
|
+
RunCmd
|
|
9
|
+
constructor () {
|
|
10
|
+
this.id = 'redis'
|
|
11
|
+
this.RunCmd = ''
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* redis实例化
|
|
16
|
+
*/
|
|
17
|
+
async start () {
|
|
18
|
+
const { host, port, username, password, db: database, cluster } = config.redis
|
|
19
|
+
/** 集群模式 */
|
|
20
|
+
if (cluster && cluster.enable) {
|
|
21
|
+
const rootNodes = cluster.rootNodes.map((node) => ({ url: node }))
|
|
22
|
+
logger.info('正在连接 Redis 集群...')
|
|
23
|
+
const { status, data } = await this.connectCluster(rootNodes)
|
|
24
|
+
if (status === 'ok') {
|
|
25
|
+
logger.info('Redis 集群连接成功')
|
|
26
|
+
return data
|
|
27
|
+
}
|
|
28
|
+
logger.error(`Redis 集群建立连接失败:${logger.red(data)}`)
|
|
29
|
+
return false
|
|
30
|
+
}
|
|
31
|
+
logger.info(`正在连接 ${logger.green(`Redis://${host}:${port}/${database}`)}`)
|
|
32
|
+
const options = { socket: { host, port }, username, password, database }
|
|
33
|
+
/** 第一次连接 */
|
|
34
|
+
const { status, data } = await this.connect(options)
|
|
35
|
+
if (status === 'ok') {
|
|
36
|
+
logger.info('Redis 连接成功')
|
|
37
|
+
return data
|
|
38
|
+
}
|
|
39
|
+
/** 第一次连接失败尝试拉起 windows直接降级 */
|
|
40
|
+
if (process.platform === 'win32') {
|
|
41
|
+
logger.error(`Redis 建立连接失败:${logger.red(data)}`)
|
|
42
|
+
return await this.LevelDB()
|
|
43
|
+
}
|
|
44
|
+
this.RunCmd = 'redis-server --save 900 1 --save 300 10 --daemonize yes' + (await this.aarch64())
|
|
45
|
+
logger.info('正在尝试启动 Redis...')
|
|
46
|
+
try {
|
|
47
|
+
await this.execSync(this.RunCmd)
|
|
48
|
+
/** 启动成功再次重试 */
|
|
49
|
+
const { status, data } = await this.connect(options)
|
|
50
|
+
if (status === 'ok') {
|
|
51
|
+
logger.info('Redis 连接成功')
|
|
52
|
+
return data
|
|
53
|
+
}
|
|
54
|
+
logger.error(`Redis 二次建立连接失败:${logger.red(data)}`)
|
|
55
|
+
return false
|
|
56
|
+
} catch (error) {
|
|
57
|
+
logger.error(`Redis 启动失败:${logger.red(data)}`)
|
|
58
|
+
return await this.LevelDB()
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 降级为 LevelDB
|
|
64
|
+
*/
|
|
65
|
+
async LevelDB () {
|
|
66
|
+
try {
|
|
67
|
+
logger.mark(logger.red('正在降级为 LevelDB 代替 Redis 只能使用基础功能'))
|
|
68
|
+
const redis = new RedisLevel()
|
|
69
|
+
logger.info('LevelDB 降级成功')
|
|
70
|
+
return redis
|
|
71
|
+
} catch (error) {
|
|
72
|
+
logger.error('降级为 LevelDB 失败')
|
|
73
|
+
logger.error(error)
|
|
74
|
+
return false
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 连接 Redis 单例
|
|
80
|
+
* @param {import("redis").RedisClientOptions} options
|
|
81
|
+
* @return {Promise<{status: 'ok', data: import("redis").RedisClientType} | {status: 'error', data: Error}>}
|
|
82
|
+
*/
|
|
83
|
+
async connect (options) {
|
|
84
|
+
const client = createClient(options)
|
|
85
|
+
try {
|
|
86
|
+
await client.connect()
|
|
87
|
+
return { status: 'ok', data: client }
|
|
88
|
+
} catch (error) {
|
|
89
|
+
return { status: 'error', data: error }
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* 连接 Redis 集群
|
|
95
|
+
*/
|
|
96
|
+
async connectCluster (rootNodes) {
|
|
97
|
+
const client = createCluster({ rootNodes })
|
|
98
|
+
try {
|
|
99
|
+
await client.connect()
|
|
100
|
+
return { status: 'ok', data: client }
|
|
101
|
+
} catch (error) {
|
|
102
|
+
return { status: 'error', data: error }
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* 判断是否为 ARM64 并返回参数
|
|
108
|
+
*/
|
|
109
|
+
async aarch64 () {
|
|
110
|
+
try {
|
|
111
|
+
/** 判断arch */
|
|
112
|
+
const arch = await this.execSync('uname -m')
|
|
113
|
+
if (arch && arch.includes('aarch64')) {
|
|
114
|
+
/** 提取 Redis 版本 */
|
|
115
|
+
const version = await this.execSync('redis-server -v')
|
|
116
|
+
if (version) {
|
|
117
|
+
/** 提取版本号 */
|
|
118
|
+
const RedisVersion = version.match(/v=(\d)./)
|
|
119
|
+
/** 如果>=6版本则忽略警告 */
|
|
120
|
+
if (RedisVersion && Number(RedisVersion[1]) >= 6) { return ' --ignore-warnings ARM64-COW-BUG' }
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return ''
|
|
124
|
+
} catch {
|
|
125
|
+
return ''
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
execSync (cmd) {
|
|
130
|
+
return new Promise((resolve, reject) => {
|
|
131
|
+
exec(cmd, (error, stdout) => {
|
|
132
|
+
if (error) { return reject(error) }
|
|
133
|
+
resolve(stdout)
|
|
134
|
+
})
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
export default class RedisLevel {
|
|
2
|
+
#private;
|
|
3
|
+
id: string;
|
|
4
|
+
constructor();
|
|
5
|
+
/**
|
|
6
|
+
* get 获取数据
|
|
7
|
+
* @param {string} key 键
|
|
8
|
+
* @returns {Promise<string>|Error} 数据
|
|
9
|
+
*/
|
|
10
|
+
get(key: string): Promise<string | null>;
|
|
11
|
+
/**
|
|
12
|
+
* set 设置数据
|
|
13
|
+
* @param {string} key 键
|
|
14
|
+
* @param {string} value 值
|
|
15
|
+
* @param {object} [options] 选项
|
|
16
|
+
* @param [options.EX] 过期时间 单位秒
|
|
17
|
+
* @returns {Promise<void>|Error}
|
|
18
|
+
*/
|
|
19
|
+
set(key: string, value: string, options?: {
|
|
20
|
+
EX: number;
|
|
21
|
+
} | undefined): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* del 删除数据
|
|
24
|
+
* @param {string} key 键
|
|
25
|
+
* @returns {Promise<void>|Error}
|
|
26
|
+
*/
|
|
27
|
+
del(key: string): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* keys 获取所有键
|
|
30
|
+
* @param {string} [prefix] 前缀
|
|
31
|
+
* @returns {Promise<string[]>|Error} 键列表
|
|
32
|
+
*/
|
|
33
|
+
keys(prefix?: string): Promise<string[]>;
|
|
34
|
+
/**
|
|
35
|
+
* incr 递增数据
|
|
36
|
+
* @param {string} key 键
|
|
37
|
+
* @returns {Promise<number>|Error}
|
|
38
|
+
*/
|
|
39
|
+
incr(key: string): Promise<number>;
|
|
40
|
+
/**
|
|
41
|
+
* decr 递减数据
|
|
42
|
+
* @param {string} key 键
|
|
43
|
+
* @returns {Promise<number>|Error}
|
|
44
|
+
*/
|
|
45
|
+
decr(key: string): Promise<number>;
|
|
46
|
+
/**
|
|
47
|
+
* expire 设置过期时间
|
|
48
|
+
* @param {string} key 键
|
|
49
|
+
* @param seconds 过期时间 单位秒
|
|
50
|
+
* @returns {Promise<number>|Error}
|
|
51
|
+
*/
|
|
52
|
+
expire(key: string, seconds: number): Promise<number>;
|
|
53
|
+
/**
|
|
54
|
+
* ttl 获取过期时间
|
|
55
|
+
* @param {string} key 键
|
|
56
|
+
* @returns {Promise<number>|Error}
|
|
57
|
+
*/
|
|
58
|
+
ttl(key: string): Promise<number>;
|
|
59
|
+
/**
|
|
60
|
+
* setEx 设置数据并设置过期时间
|
|
61
|
+
* @param {string} key 键
|
|
62
|
+
* @param seconds 过期时间 单位秒
|
|
63
|
+
* @param {string} value 值
|
|
64
|
+
* @returns {Promise<void>|Error}
|
|
65
|
+
*/
|
|
66
|
+
setEx(key: string, seconds: number, value: string): Promise<void>;
|
|
67
|
+
/**
|
|
68
|
+
* exists 判断键是否存在
|
|
69
|
+
* @param {string} key 键
|
|
70
|
+
* @returns {Promise<number>|Error}
|
|
71
|
+
*/
|
|
72
|
+
exists(key: string): Promise<number>;
|
|
73
|
+
/**
|
|
74
|
+
* zAdd 有序集合添加元素
|
|
75
|
+
* @param {string} key 键
|
|
76
|
+
* @param {object} data 数据
|
|
77
|
+
* @param data.score 分数
|
|
78
|
+
* @param {string} data.value 值
|
|
79
|
+
*/
|
|
80
|
+
zAdd(key: string, { score, value }: {
|
|
81
|
+
score: number;
|
|
82
|
+
value: string;
|
|
83
|
+
}): Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* zRem 有序集合删除元素
|
|
86
|
+
* @param {string} key 键
|
|
87
|
+
* @param {string} value 值
|
|
88
|
+
*/
|
|
89
|
+
zRem(key: string, value: string): Promise<void>;
|
|
90
|
+
/**
|
|
91
|
+
* zIncrBy 有序集合分数递增
|
|
92
|
+
* @param {string} key 键
|
|
93
|
+
* @param increment 递增值
|
|
94
|
+
* @param {string} value 值
|
|
95
|
+
* @returns {Promise<number>|Error}
|
|
96
|
+
*/
|
|
97
|
+
zIncrBy(key: string, increment: number, value: string): Promise<number>;
|
|
98
|
+
/**
|
|
99
|
+
* zRangeByScore 有序集合根据分数范围获取元素
|
|
100
|
+
* @param {string} key 键
|
|
101
|
+
* @param min 最小分数
|
|
102
|
+
* @param max 最大分数
|
|
103
|
+
* @returns {Promise<string[]>|Error}
|
|
104
|
+
*/
|
|
105
|
+
zRangeByScore(key: string, min: number, max: number): Promise<any[]>;
|
|
106
|
+
/**
|
|
107
|
+
* zScore 有序集合获取元素分数
|
|
108
|
+
* @param {string} key 键
|
|
109
|
+
* @param {string} value 值
|
|
110
|
+
* @returns {Promise<number>|Error}
|
|
111
|
+
*/
|
|
112
|
+
zScore(key: string, value: string): Promise<number | null>;
|
|
113
|
+
}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { Level } from 'level'
|
|
2
|
+
export default class RedisLevel {
|
|
3
|
+
#level
|
|
4
|
+
#expireMap
|
|
5
|
+
id
|
|
6
|
+
constructor () {
|
|
7
|
+
const path = process.cwd() + '/data/db/RedisLevel'
|
|
8
|
+
this.#level = new Level(path, { valueEncoding: 'json' })
|
|
9
|
+
/**
|
|
10
|
+
* @type {'RedisLevel'} 唯一标识符 用于区分不同的数据库
|
|
11
|
+
*/
|
|
12
|
+
this.id = 'RedisLevel'
|
|
13
|
+
/**
|
|
14
|
+
* 过期时间映射表
|
|
15
|
+
* @type {Map<string, number>} 键: 值 (过期时间)
|
|
16
|
+
*/
|
|
17
|
+
this.#expireMap = new Map()
|
|
18
|
+
/**
|
|
19
|
+
* 开启过期时间处理
|
|
20
|
+
*/
|
|
21
|
+
this.#expireHandle()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 过期时间处理 每分钟检查一次
|
|
26
|
+
*/
|
|
27
|
+
async #expireHandle () {
|
|
28
|
+
setInterval(async () => {
|
|
29
|
+
const now = Date.now()
|
|
30
|
+
// 获取代理对象的键值对数组
|
|
31
|
+
const entries = Array.from(this.#expireMap.entries())
|
|
32
|
+
for (const [key, expire] of entries) {
|
|
33
|
+
if (expire < now) {
|
|
34
|
+
await this.#level.del(key)
|
|
35
|
+
this.#expireMap.delete(key) // 通过代理的方式删除键值对
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}, 60000)
|
|
39
|
+
/**
|
|
40
|
+
* 对expireMap进行代理 实现持久化 每次触发都保存到数据库
|
|
41
|
+
*/
|
|
42
|
+
const handler = {
|
|
43
|
+
get: function (target, prop, receiver) {
|
|
44
|
+
if (prop === 'get' || prop === 'entries') {
|
|
45
|
+
return function (...args) {
|
|
46
|
+
const reflect = Reflect.get(target, prop).apply(target, args)
|
|
47
|
+
return typeof reflect === 'function' ? reflect.bind(target) : reflect
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const reflect = Reflect.get(target, prop, receiver)
|
|
51
|
+
return typeof reflect === 'function' ? reflect.bind(target) : reflect
|
|
52
|
+
},
|
|
53
|
+
set: function (target, key, value) {
|
|
54
|
+
target.set(key, value)
|
|
55
|
+
// 修改后持久化到数据库
|
|
56
|
+
const reflect = Reflect.set(target, key, value)
|
|
57
|
+
return typeof reflect === 'function' ? reflect.bind(target) : reflect
|
|
58
|
+
},
|
|
59
|
+
deleteProperty: function (target, key) {
|
|
60
|
+
Reflect.deleteProperty(target, key)
|
|
61
|
+
// 删除后持久化到数据库
|
|
62
|
+
const reflect = Reflect.deleteProperty(target, key)
|
|
63
|
+
return typeof reflect === 'function' ? reflect.bind(target) : reflect
|
|
64
|
+
},
|
|
65
|
+
}
|
|
66
|
+
this.#expireMap = new Proxy(this.#expireMap, handler)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* get 获取数据
|
|
71
|
+
* @param {string} key 键
|
|
72
|
+
* @returns {Promise<string>|Error} 数据
|
|
73
|
+
*/
|
|
74
|
+
async get (key) {
|
|
75
|
+
try {
|
|
76
|
+
/** 先查过期时间 */
|
|
77
|
+
const expire = this.#expireMap.get(key)
|
|
78
|
+
if (expire && expire < Date.now()) {
|
|
79
|
+
await this.#level.del(key)
|
|
80
|
+
this.#expireMap.delete(key)
|
|
81
|
+
return null
|
|
82
|
+
}
|
|
83
|
+
return await this.#level.get(key)
|
|
84
|
+
} catch (error) {
|
|
85
|
+
if (error.notFound) { return null }
|
|
86
|
+
throw error
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* set 设置数据
|
|
92
|
+
* @param {string} key 键
|
|
93
|
+
* @param {string} value 值
|
|
94
|
+
* @param {object} [options] 选项
|
|
95
|
+
* @param [options.EX] 过期时间 单位秒
|
|
96
|
+
* @returns {Promise<void>|Error}
|
|
97
|
+
*/
|
|
98
|
+
async set (key, value, options) {
|
|
99
|
+
if (options && options.EX) {
|
|
100
|
+
this.#expireMap.set(key, Date.now() + options.EX * 1000)
|
|
101
|
+
}
|
|
102
|
+
return await this.#level.put(key, value)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* del 删除数据
|
|
107
|
+
* @param {string} key 键
|
|
108
|
+
* @returns {Promise<void>|Error}
|
|
109
|
+
*/
|
|
110
|
+
async del (key) {
|
|
111
|
+
this.#expireMap.delete(key)
|
|
112
|
+
return await this.#level.del(key)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* keys 获取所有键
|
|
117
|
+
* @param {string} [prefix] 前缀
|
|
118
|
+
* @returns {Promise<string[]>|Error} 键列表
|
|
119
|
+
*/
|
|
120
|
+
async keys (prefix = '') {
|
|
121
|
+
const keys = []
|
|
122
|
+
for await (const key of this.#level.keys({ gte: prefix, lt: prefix + '\xFF' })) {
|
|
123
|
+
// Check if the key has expired
|
|
124
|
+
const expire = this.#expireMap.get(key)
|
|
125
|
+
if (expire && expire < Date.now()) {
|
|
126
|
+
await this.#level.del(key)
|
|
127
|
+
this.#expireMap.delete(key)
|
|
128
|
+
} else {
|
|
129
|
+
keys.push(key)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return keys
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* incr 递增数据
|
|
137
|
+
* @param {string} key 键
|
|
138
|
+
* @returns {Promise<number>|Error}
|
|
139
|
+
*/
|
|
140
|
+
async incr (key) {
|
|
141
|
+
let value = Number(await this.get(key))
|
|
142
|
+
if (value === null) {
|
|
143
|
+
value = 0
|
|
144
|
+
} else {
|
|
145
|
+
value = Number(value)
|
|
146
|
+
if (isNaN(value)) { throw new Error('Value is not a number') }
|
|
147
|
+
}
|
|
148
|
+
value += 1
|
|
149
|
+
await this.set(key, value.toString())
|
|
150
|
+
return value
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* decr 递减数据
|
|
155
|
+
* @param {string} key 键
|
|
156
|
+
* @returns {Promise<number>|Error}
|
|
157
|
+
*/
|
|
158
|
+
async decr (key) {
|
|
159
|
+
let value = Number(await this.get(key))
|
|
160
|
+
if (value === null) {
|
|
161
|
+
value = 0
|
|
162
|
+
} else {
|
|
163
|
+
value = Number(value)
|
|
164
|
+
if (isNaN(value)) { throw new Error('Value is not a number') }
|
|
165
|
+
}
|
|
166
|
+
value -= 1
|
|
167
|
+
await this.set(key, value.toString())
|
|
168
|
+
return value
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* expire 设置过期时间
|
|
173
|
+
* @param {string} key 键
|
|
174
|
+
* @param seconds 过期时间 单位秒
|
|
175
|
+
* @returns {Promise<number>|Error}
|
|
176
|
+
*/
|
|
177
|
+
async expire (key, seconds) {
|
|
178
|
+
this.#expireMap.set(key, Date.now() + seconds * 1000)
|
|
179
|
+
return seconds
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* ttl 获取过期时间
|
|
184
|
+
* @param {string} key 键
|
|
185
|
+
* @returns {Promise<number>|Error}
|
|
186
|
+
*/
|
|
187
|
+
async ttl (key) {
|
|
188
|
+
const expire = this.#expireMap.get(key)
|
|
189
|
+
if (expire) {
|
|
190
|
+
return Math.ceil((expire - Date.now()) / 1000)
|
|
191
|
+
}
|
|
192
|
+
return -2
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* setEx 设置数据并设置过期时间
|
|
197
|
+
* @param {string} key 键
|
|
198
|
+
* @param seconds 过期时间 单位秒
|
|
199
|
+
* @param {string} value 值
|
|
200
|
+
* @returns {Promise<void>|Error}
|
|
201
|
+
*/
|
|
202
|
+
async setEx (key, seconds, value) {
|
|
203
|
+
this.#expireMap.set(key, Date.now() + seconds * 1000)
|
|
204
|
+
return await this.#level.put(key, value)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* exists 判断键是否存在
|
|
209
|
+
* @param {string} key 键
|
|
210
|
+
* @returns {Promise<number>|Error}
|
|
211
|
+
*/
|
|
212
|
+
async exists (key) {
|
|
213
|
+
const value = await this.get(key)
|
|
214
|
+
return value === null ? 0 : 1
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* zAdd 有序集合添加元素
|
|
219
|
+
* @param {string} key 键
|
|
220
|
+
* @param {object} data 数据
|
|
221
|
+
* @param data.score 分数
|
|
222
|
+
* @param {string} data.value 值
|
|
223
|
+
*/
|
|
224
|
+
async zAdd (key, { score, value }) {
|
|
225
|
+
const set = await this.get(key)
|
|
226
|
+
const arr = (set ? JSON.parse(set) : [])
|
|
227
|
+
arr.push({ score, value })
|
|
228
|
+
arr.sort((a, b) => a.score - b.score)
|
|
229
|
+
await this.set(key, JSON.stringify(arr))
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* zRem 有序集合删除元素
|
|
234
|
+
* @param {string} key 键
|
|
235
|
+
* @param {string} value 值
|
|
236
|
+
*/
|
|
237
|
+
async zRem (key, value) {
|
|
238
|
+
const set = await this.get(key)
|
|
239
|
+
if (set === null) { return }
|
|
240
|
+
let arr = JSON.parse(set)
|
|
241
|
+
arr = arr.filter((item) => item.value !== value)
|
|
242
|
+
await this.set(key, JSON.stringify(arr))
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* zIncrBy 有序集合分数递增
|
|
247
|
+
* @param {string} key 键
|
|
248
|
+
* @param increment 递增值
|
|
249
|
+
* @param {string} value 值
|
|
250
|
+
* @returns {Promise<number>|Error}
|
|
251
|
+
*/
|
|
252
|
+
async zIncrBy (key, increment, value) {
|
|
253
|
+
const set = await this.get(key)
|
|
254
|
+
if (set === null) { throw new Error('Set does not exist') }
|
|
255
|
+
const arr = JSON.parse(set)
|
|
256
|
+
const item = arr.find((item) => item.value === value)
|
|
257
|
+
if (item) { item.score += increment }
|
|
258
|
+
arr.sort((a, b) => a.score - b.score)
|
|
259
|
+
await this.set(key, JSON.stringify(arr))
|
|
260
|
+
return item.score
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* zRangeByScore 有序集合根据分数范围获取元素
|
|
265
|
+
* @param {string} key 键
|
|
266
|
+
* @param min 最小分数
|
|
267
|
+
* @param max 最大分数
|
|
268
|
+
* @returns {Promise<string[]>|Error}
|
|
269
|
+
*/
|
|
270
|
+
async zRangeByScore (key, min, max) {
|
|
271
|
+
const set = await this.get(key)
|
|
272
|
+
if (set === null) { return [] }
|
|
273
|
+
const arr = JSON.parse(set)
|
|
274
|
+
return arr.filter((item) => item.score >= min && item.score <= max).map((item) => item.value)
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* zScore 有序集合获取元素分数
|
|
279
|
+
* @param {string} key 键
|
|
280
|
+
* @param {string} value 值
|
|
281
|
+
* @returns {Promise<number>|Error}
|
|
282
|
+
*/
|
|
283
|
+
async zScore (key, value) {
|
|
284
|
+
const set = await this.get(key)
|
|
285
|
+
if (set === null) { return null }
|
|
286
|
+
const arr = JSON.parse(set)
|
|
287
|
+
const item = arr.find((item) => item.value === value)
|
|
288
|
+
return item ? item.score : null
|
|
289
|
+
}
|
|
290
|
+
}
|