node-karin 0.9.0 → 0.10.1

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.
Files changed (131) hide show
  1. package/config/defSet/group.yaml +40 -2
  2. package/lib/adapter/onebot/11/index.d.ts +2 -0
  3. package/lib/adapter/onebot/11/index.js +3 -1
  4. package/lib/cli/init.js +1 -1
  5. package/lib/cli/karin.js +1 -1
  6. package/lib/core/index.d.ts +9 -9
  7. package/lib/core/index.js +9 -9
  8. package/lib/core/init/dir.js +7 -0
  9. package/lib/core/init/init.js +46 -0
  10. package/lib/core/{karin.d.ts → karin/karin.d.ts} +1 -1
  11. package/lib/core/karin/karin.js +194 -0
  12. package/lib/core/{listener.d.ts → listener/listener.d.ts} +1 -1
  13. package/lib/core/listener/listener.js +213 -0
  14. package/lib/core/{plugin.app.d.ts → plugin/app.d.ts} +1 -1
  15. package/lib/core/plugin/app.js +19 -0
  16. package/lib/core/{plugin.d.ts → plugin/base.d.ts} +1 -1
  17. package/lib/core/plugin/base.js +140 -0
  18. package/lib/core/{plugin.loader.d.ts → plugin/loader.d.ts} +3 -3
  19. package/lib/core/plugin/loader.js +579 -0
  20. package/lib/core/process/process.js +100 -0
  21. package/lib/core/server/server.js +283 -0
  22. package/lib/db/index.d.ts +2 -2
  23. package/lib/db/index.js +2 -2
  24. package/lib/db/level/level.js +36 -0
  25. package/lib/db/redis/redis.js +135 -0
  26. package/lib/db/redis/redis_level.js +287 -0
  27. package/lib/event/{event.handler.d.ts → handler/base.d.ts} +2 -2
  28. package/lib/event/handler/base.js +173 -0
  29. package/lib/event/{message.handler.d.ts → handler/message.d.ts} +3 -3
  30. package/lib/event/handler/message.js +270 -0
  31. package/lib/event/{notice.handler.d.ts → handler/notice.d.ts} +3 -3
  32. package/lib/event/handler/notice.js +212 -0
  33. package/lib/event/{request.handler.d.ts → handler/request.d.ts} +3 -3
  34. package/lib/event/handler/request.js +118 -0
  35. package/lib/event/{review.handler.d.ts → handler/review.d.ts} +3 -3
  36. package/lib/event/handler/review.js +391 -0
  37. package/lib/event/index.d.ts +5 -5
  38. package/lib/event/index.js +5 -5
  39. package/lib/render/base.d.ts +1 -1
  40. package/lib/render/client.d.ts +1 -1
  41. package/lib/render/client.js +5 -7
  42. package/lib/render/client_even.d.ts +30 -0
  43. package/lib/render/client_even.js +153 -0
  44. package/lib/render/http.d.ts +1 -1
  45. package/lib/render/http.js +1 -1
  46. package/lib/render/server.js +1 -1
  47. package/lib/types/adapter/api.d.ts +5 -1
  48. package/lib/types/adapter/{adapter.d.ts → base.d.ts} +2 -2
  49. package/lib/types/config/config.js +1 -0
  50. package/lib/types/element/element.js +1 -0
  51. package/lib/types/event/message.d.ts +1 -1
  52. package/lib/types/event/reply.d.ts +1 -1
  53. package/lib/types/index.d.ts +6 -6
  54. package/lib/types/index.js +6 -6
  55. package/lib/types/logger/logger.js +1 -0
  56. package/lib/types/{plugin.d.ts → plugin/plugin.d.ts} +3 -3
  57. package/lib/types/plugin/plugin.js +1 -0
  58. package/lib/types/render/render.js +1 -0
  59. package/lib/utils/{common.d.ts → common/common.d.ts} +14 -13
  60. package/lib/utils/common/common.js +591 -0
  61. package/lib/utils/{config.d.ts → config/config.d.ts} +37 -19
  62. package/lib/utils/config/config.js +328 -0
  63. package/lib/utils/config/updateVersion.js +145 -0
  64. package/lib/utils/config/yamlEditor.js +292 -0
  65. package/lib/utils/{handler.d.ts → core/handler.d.ts} +1 -1
  66. package/lib/utils/core/handler.js +115 -0
  67. package/lib/utils/core/init.js +213 -0
  68. package/lib/utils/core/logger.js +105 -0
  69. package/lib/utils/{segment.d.ts → core/segment.d.ts} +1 -1
  70. package/lib/utils/core/segment.js +441 -0
  71. package/lib/utils/index.d.ts +11 -11
  72. package/lib/utils/index.js +11 -11
  73. package/lib/utils/{button.d.ts → tools/button.d.ts} +1 -1
  74. package/lib/utils/tools/button.js +38 -0
  75. package/lib/utils/tools/exec.js +37 -0
  76. package/lib/utils/tools/ffmpeg.js +25 -0
  77. package/lib/utils/tools/update.js +139 -0
  78. package/package.json +1 -1
  79. package/lib/core/dir.js +0 -7
  80. package/lib/core/init.js +0 -42
  81. package/lib/core/karin.js +0 -194
  82. package/lib/core/listener.js +0 -217
  83. package/lib/core/plugin.app.js +0 -19
  84. package/lib/core/plugin.js +0 -145
  85. package/lib/core/plugin.loader.js +0 -561
  86. package/lib/core/process.js +0 -98
  87. package/lib/core/server.js +0 -269
  88. package/lib/db/level.js +0 -37
  89. package/lib/db/redis.js +0 -134
  90. package/lib/db/redis_level.js +0 -293
  91. package/lib/event/event.handler.js +0 -167
  92. package/lib/event/message.handler.js +0 -254
  93. package/lib/event/notice.handler.js +0 -204
  94. package/lib/event/request.handler.js +0 -110
  95. package/lib/event/review.handler.js +0 -386
  96. package/lib/types/config.js +0 -1
  97. package/lib/types/element.js +0 -1
  98. package/lib/types/logger.js +0 -1
  99. package/lib/types/plugin.js +0 -1
  100. package/lib/types/render.js +0 -1
  101. package/lib/utils/button.js +0 -34
  102. package/lib/utils/common.js +0 -596
  103. package/lib/utils/config.js +0 -318
  104. package/lib/utils/exec.js +0 -36
  105. package/lib/utils/ffmpeg.js +0 -25
  106. package/lib/utils/handler.js +0 -109
  107. package/lib/utils/init.js +0 -208
  108. package/lib/utils/logger.js +0 -104
  109. package/lib/utils/segment.js +0 -470
  110. package/lib/utils/update.js +0 -135
  111. package/lib/utils/updateVersion.js +0 -145
  112. package/lib/utils/yamlEditor.js +0 -279
  113. /package/lib/core/{dir.d.ts → init/dir.d.ts} +0 -0
  114. /package/lib/core/{init.d.ts → init/init.d.ts} +0 -0
  115. /package/lib/core/{process.d.ts → process/process.d.ts} +0 -0
  116. /package/lib/core/{server.d.ts → server/server.d.ts} +0 -0
  117. /package/lib/db/{level.d.ts → level/level.d.ts} +0 -0
  118. /package/lib/db/{redis.d.ts → redis/redis.d.ts} +0 -0
  119. /package/lib/db/{redis_level.d.ts → redis/redis_level.d.ts} +0 -0
  120. /package/lib/types/adapter/{adapter.js → base.js} +0 -0
  121. /package/lib/types/{config.d.ts → config/config.d.ts} +0 -0
  122. /package/lib/types/{element.d.ts → element/element.d.ts} +0 -0
  123. /package/lib/types/{logger.d.ts → logger/logger.d.ts} +0 -0
  124. /package/lib/types/{render.d.ts → render/render.d.ts} +0 -0
  125. /package/lib/utils/{updateVersion.d.ts → config/updateVersion.d.ts} +0 -0
  126. /package/lib/utils/{yamlEditor.d.ts → config/yamlEditor.d.ts} +0 -0
  127. /package/lib/utils/{init.d.ts → core/init.d.ts} +0 -0
  128. /package/lib/utils/{logger.d.ts → core/logger.d.ts} +0 -0
  129. /package/lib/utils/{exec.d.ts → tools/exec.d.ts} +0 -0
  130. /package/lib/utils/{ffmpeg.d.ts → tools/ffmpeg.d.ts} +0 -0
  131. /package/lib/utils/{update.d.ts → tools/update.d.ts} +0 -0
@@ -0,0 +1,283 @@
1
+ import fs from 'fs';
2
+ import Process from '../process/process.js';
3
+ import { WebSocketServer } from 'ws';
4
+ import { createServer } from 'http';
5
+ import { listener } from '../listener/listener.js';
6
+ import express from 'express';
7
+ import { exec, config, logger, common } from '../../utils/index.js';
8
+ import { AdapterOneBot11 } from '../../adapter/onebot/11/index.js';
9
+ import { render, HttpRenderer, Wormhole, RenderClient } from '../../render/index.js';
10
+ export const server = new (class Server {
11
+ reg;
12
+ list;
13
+ app;
14
+ server;
15
+ WebSocketServer;
16
+ RegExp;
17
+ constructor() {
18
+ this.reg = /(?:)/;
19
+ this.list = [];
20
+ this.app = express();
21
+ this.server = createServer(this.app);
22
+ this.WebSocketServer = new WebSocketServer({ server: this.server });
23
+ this.RegExp = new RegExp(`(${process.cwd()}|${process.cwd().replace(/\\/g, '/')})`, 'g');
24
+ }
25
+ /**
26
+ * 监听WebSocket连接并初始化http服务器
27
+ */
28
+ async init() {
29
+ try {
30
+ /** 防止多进程端口冲突 启动失败 */
31
+ await Process.check();
32
+ this.WebSocketServer.on('connection', (socket, request) => {
33
+ const path = request.url;
34
+ const headers = request.headers;
35
+ logger.debug('[反向WS]', path, JSON.stringify(headers, null, 2));
36
+ try {
37
+ const Adapter = listener.getAdapter(path);
38
+ if (!Adapter) {
39
+ logger.error(`[反向WS] 适配器不存在:${path}`);
40
+ return socket.close();
41
+ }
42
+ const KarinAdapter = new Adapter();
43
+ if (typeof KarinAdapter?.server === 'function') {
44
+ KarinAdapter.server(socket, request);
45
+ }
46
+ }
47
+ catch (error) {
48
+ logger.error(`[反向WS] 注册适配器发生错误:${path}`, error.stack || error.message || error);
49
+ socket.close();
50
+ }
51
+ });
52
+ /** GET接口 - 获取当前启动信息 */
53
+ this.app.get('/api/ping', (req, res) => {
54
+ /** 只允许本机ip访问 */
55
+ if (req.hostname === 'localhost' || req.hostname === '127.0.0.1') {
56
+ const data = {
57
+ pm2_id: process.env.pm_id || '',
58
+ uptime: process.uptime(),
59
+ karin_app_mode: process.env.karin_app_mode,
60
+ karin_app_lang: process.env.karin_app_lang,
61
+ karin_app_runner: process.env.karin_app_runner,
62
+ karin_app_start_count: process.env.karin_app_start_count,
63
+ };
64
+ res.json(data);
65
+ }
66
+ else {
67
+ res.status(403).json({ error: '禁止访问', message: '无效的请求' });
68
+ }
69
+ });
70
+ /** GET接口 - 退出当前进程 */
71
+ this.app.get('/api/exit', async (req) => {
72
+ /** 只允许本机ip访问 */
73
+ if (req.hostname === 'localhost' || req.hostname === '127.0.0.1') {
74
+ logger.mark('[服务器][HTTP] 收到退出请求,即将退出');
75
+ /** 关闭服务器 */
76
+ listener.emit('exit.grpc');
77
+ this.server.close();
78
+ /** 如果是pm2 获取当前pm2ID 使用 */
79
+ if (process.env.pm_id)
80
+ await exec(`pm2 delete ${process.env.pm_id}`);
81
+ /** 正常启动的进程 */
82
+ process.exit();
83
+ }
84
+ });
85
+ /** 控制台适配器 */
86
+ this.app.get('/api/input', (req, res) => {
87
+ const name = req.query.name;
88
+ const token = req.query.token;
89
+ if (!name || !token) {
90
+ logger.error('[HTTP][input] 缺少参数', req.query);
91
+ return res.status(403).json({ error: '禁止访问', message: '缺少参数' });
92
+ }
93
+ // 禁止键入向上级目录
94
+ if (name.includes('/')) {
95
+ logger.error('[HTTP][input] 无效的文件名', name);
96
+ return res.status(403).json({ error: '禁止访问', message: '无效的文件名' });
97
+ }
98
+ const CfgToken = config.Config.AdapterInput.token;
99
+ if (CfgToken === 'AdapterInput' || CfgToken !== token) {
100
+ logger.error('[HTTP][input] 无效的令牌', token);
101
+ return res.status(403).json({ error: '禁止访问', message: '无效的令牌' });
102
+ }
103
+ const file = process.cwd() + `/temp/input/${name}`;
104
+ if (!fs.existsSync(file)) {
105
+ logger.error('[HTTP][input] 文件不存在', file);
106
+ return res.status(404).json({ error: '文件不存在', message: '找不到指定文件' });
107
+ }
108
+ logger.info(`${logger.yellow('[HTTP][input]')} ${logger.green(token)} file:${file}`);
109
+ res.sendFile(file);
110
+ });
111
+ /** 监听端口 */
112
+ const { host, port } = config.Server.http;
113
+ this.server.listen(port, host, () => {
114
+ logger.mark('[服务器][启动成功][HTTP]: ' + logger.green(`http://${host}:${port}`));
115
+ });
116
+ listener.once('restart.http', () => {
117
+ logger.mark('[服务器][重启][HTTP] 正在重启HTTP服务器...');
118
+ this.#restartServer();
119
+ });
120
+ const renderCfg = config.Server.websocket.render;
121
+ if (Array.isArray(renderCfg) && renderCfg.length) {
122
+ for (const url of renderCfg) {
123
+ new RenderClient(url).start();
124
+ }
125
+ }
126
+ const Onebot11 = config.Server.websocket.OneBot11Host;
127
+ if (Array.isArray(Onebot11) && Onebot11.length) {
128
+ for (const connect of Onebot11) {
129
+ new AdapterOneBot11().client(connect);
130
+ }
131
+ }
132
+ const { enable, WormholeClient } = config.Server.HttpRender;
133
+ if (enable) {
134
+ this.static();
135
+ if (WormholeClient) {
136
+ Wormhole();
137
+ return this;
138
+ }
139
+ const { host, post, token } = config.Server.HttpRender;
140
+ /** 注册渲染器 */
141
+ const rd = new HttpRenderer(host, post, token);
142
+ render.app({ id: 'puppeteer', type: 'image', render: rd.render.bind(rd) });
143
+ }
144
+ return this;
145
+ }
146
+ catch (error) {
147
+ logger.error('初始化HTTP服务器失败: ', error);
148
+ return false;
149
+ }
150
+ }
151
+ /**
152
+ * HTTP渲染器
153
+ */
154
+ static() {
155
+ this.staticPath();
156
+ /** GET接口 - 渲染 */
157
+ this.app.get('/api/renderHtml', (req, res) => {
158
+ try {
159
+ let { html } = req.query;
160
+ if (!html)
161
+ return res.status(404).send(JSON.stringify({ code: 404, msg: 'Not Found' }));
162
+ html = decodeURIComponent(html)
163
+ .replace(/\\/g, '/')
164
+ .replace(/^\.\//, '');
165
+ /** 判断是否为html文件且路径存在 */
166
+ if (!html.endsWith('.html') || !fs.existsSync(html)) {
167
+ const not_found = config.Server.HttpRender.not_found;
168
+ if (not_found.startsWith('http')) {
169
+ return res.redirect(not_found);
170
+ }
171
+ else {
172
+ return res.status(404).send(JSON.stringify({ code: 404, msg: not_found || '?' }));
173
+ }
174
+ }
175
+ let content = fs.readFileSync(html, 'utf-8');
176
+ /** 处理所有绝对路径、相对路径 */
177
+ content = content.replace(this.RegExp, '');
178
+ res.send(content);
179
+ }
180
+ catch (e) {
181
+ logger.error('[服务器][GET接口 - 渲染]', e);
182
+ res.status(500).send(JSON.stringify({ code: 500, msg: 'Internal Server Error' }));
183
+ }
184
+ });
185
+ /** 拦截静态资源 防止恶意访问 */
186
+ this.app.use((req, res, next) => {
187
+ logger.debug(`[静态资源][${req.headers.host}] ${req.url}`);
188
+ /** 解码 */
189
+ req.url = decodeURIComponent(req.url);
190
+ req.url = req.url
191
+ .replace(/\\/g, '/')
192
+ .replace(/^\.\//, '')
193
+ .replace(/^(\.\.\/)+/, '');
194
+ /** 拦截非资源文件 */
195
+ this.reg.lastIndex = 0;
196
+ if (!this.reg.test(req.url)) {
197
+ logger.mark(`[${req.ip}][拦截非资源文件]`, req.url);
198
+ res.status(404).send(JSON.stringify({ code: 404, msg: 'Not Found' }));
199
+ return;
200
+ }
201
+ next();
202
+ });
203
+ /** 设置静态文件目录 */
204
+ this.app.use(express.static(process.cwd()));
205
+ }
206
+ /**
207
+ * 构建静态资源路径
208
+ */
209
+ async staticPath() {
210
+ this.list = [];
211
+ /** 读取./resources文件夹 */
212
+ const resDir = './resources';
213
+ const resdirs = fs.readdirSync(resDir);
214
+ for (const dir of resdirs) {
215
+ const file = `${resDir}/${dir}`;
216
+ if (common.isDir(file))
217
+ this.list.push(file.replace('.', ''));
218
+ }
219
+ /** 读取./temp/html下所有文件夹 */
220
+ const htmlDir = './temp/html';
221
+ const dirs = fs.readdirSync(htmlDir);
222
+ for (const dir of dirs) {
223
+ const file = `${htmlDir}/${dir}`;
224
+ if (common.isDir(file))
225
+ this.list.push(file.replace('.', ''));
226
+ }
227
+ /** 读取./plugins/xxx/resources下所有文件夹 */
228
+ const pluginsDir = './plugins';
229
+ const plugins = fs.readdirSync(pluginsDir);
230
+ for (const dir of plugins) {
231
+ /** 忽略不是karin-plugin-开头 */
232
+ if (!dir.startsWith('karin-plugin-'))
233
+ continue;
234
+ const file = `${pluginsDir}/${dir}`;
235
+ const resFile = `${file}/resources`;
236
+ /** 包含resources文件夹 */
237
+ if (common.isDir(file) && common.isDir(resFile))
238
+ this.list.push(resFile.replace('.', ''));
239
+ const componentsFile = `${file}/lib/components`;
240
+ /** 包含lib/components文件夹 兼容mys */
241
+ if (common.isDir(file) && common.isDir(componentsFile))
242
+ this.list.push(componentsFile.replace('.', ''));
243
+ /** 读取package.json 查找是否存在自定义资源文件入口 */
244
+ const pkgFile = `${file}/package.json`;
245
+ if (!common.exists(pkgFile))
246
+ continue;
247
+ const pkg = common.readJson(pkgFile);
248
+ if (!pkg?.karin?.static || !Array.isArray(pkg.karin.static))
249
+ continue;
250
+ /** 标准格式为 lib/test/xxxx */
251
+ for (let staticFile of pkg.karin.static) {
252
+ /** 不允许向上级目录 ../开头等 */
253
+ if (staticFile.startsWith('../'))
254
+ continue;
255
+ /** ./开头去掉./ */
256
+ if (staticFile.startsWith('./'))
257
+ staticFile = staticFile.slice(2);
258
+ this.list.push(`${file}/${staticFile}`);
259
+ }
260
+ }
261
+ this.reg = new RegExp(`(${this.list.join('|')})`, 'g');
262
+ }
263
+ /** 重启当前HTTP服务器 */
264
+ async #restartServer() {
265
+ try {
266
+ /** 断开所有 WebSocket 连接 */
267
+ for (const ws of this.WebSocketServer.clients)
268
+ ws.terminate();
269
+ /** 关闭当前HTTP服务器 */
270
+ this.server.close();
271
+ /** 延迟1秒 */
272
+ await common.sleep(1000);
273
+ /** 创建一个新的服务器实例 */
274
+ this.server = createServer(this.app);
275
+ this.WebSocketServer = new WebSocketServer({ server: this.server });
276
+ this.init();
277
+ this.static();
278
+ }
279
+ catch (err) {
280
+ logger.error('[服务器][重启失败]', err);
281
+ }
282
+ }
283
+ })();
package/lib/db/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export * from './level.js';
2
- export * from './redis.js';
1
+ export * from './level/level.js';
2
+ export * from './redis/redis.js';
package/lib/db/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export * from './level.js'
2
- export * from './redis.js'
1
+ export * from './level/level.js'
2
+ export * from './redis/redis.js'
@@ -0,0 +1,36 @@
1
+ import { Level } from 'level';
2
+ const path = process.cwd() + '/data/db/Level';
3
+ /**
4
+ * @type {Level}
5
+ */
6
+ export default 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
+ * 对get方法进行重写 找不到数据时返回null
17
+ */
18
+ async get(key) {
19
+ try {
20
+ const res = await super.get(key);
21
+ return res;
22
+ }
23
+ catch {
24
+ return '';
25
+ }
26
+ }
27
+ /**
28
+ * 增加set方法
29
+ * @param {string} key 键
30
+ * @param {object|string} value 值
31
+ */
32
+ async set(key, value) {
33
+ return await super.put(key, value);
34
+ }
35
+ }
36
+ export const level = new LevelDB();
@@ -0,0 +1,135 @@
1
+ import { exec } from 'child_process';
2
+ import RedisLevel from './redis_level.js';
3
+ import { logger, config } from '../../utils/index.js';
4
+ import { createClient, createCluster } from 'redis';
5
+ class Redis {
6
+ id;
7
+ RunCmd;
8
+ constructor() {
9
+ this.id = 'redis';
10
+ this.RunCmd = '';
11
+ }
12
+ /**
13
+ * redis实例化
14
+ */
15
+ async start() {
16
+ const { host, port, username, password, db: database, cluster } = config.redis;
17
+ /** 集群模式 */
18
+ if (cluster && cluster.enable) {
19
+ const rootNodes = cluster.rootNodes.map((node) => ({ url: node }));
20
+ logger.debug('正在连接 Redis 集群...');
21
+ const { status, data } = await this.connectCluster(rootNodes);
22
+ if (status === 'ok') {
23
+ logger.info('Redis 集群连接成功');
24
+ return data;
25
+ }
26
+ logger.error(`Redis 集群建立连接失败:${logger.red(data)}`);
27
+ return false;
28
+ }
29
+ logger.debug(`正在连接 ${logger.green(`Redis://${host}:${port}/${database}`)}`);
30
+ const options = { socket: { host, port }, username, password, database };
31
+ /** 第一次连接 */
32
+ const { status, data } = await this.connect(options);
33
+ if (status === 'ok') {
34
+ logger.info('Redis 连接成功');
35
+ return data;
36
+ }
37
+ /** 第一次连接失败尝试拉起 windows直接降级 */
38
+ if (process.platform === 'win32') {
39
+ // logger.info(`Redis 建立连接失败:${data}`)
40
+ return await this.LevelDB();
41
+ }
42
+ this.RunCmd = 'redis-server --save 900 1 --save 300 10 --daemonize yes' + (await this.aarch64());
43
+ logger.info('正在尝试启动 Redis...');
44
+ try {
45
+ await this.execSync(this.RunCmd);
46
+ /** 启动成功再次重试 */
47
+ const { status, data } = await this.connect(options);
48
+ if (status === 'ok') {
49
+ logger.info('Redis 连接成功');
50
+ return data;
51
+ }
52
+ logger.debug(`Redis 二次建立连接失败:${logger.red(data)}`);
53
+ return false;
54
+ }
55
+ catch (error) {
56
+ logger.debug(`Redis 启动失败:${logger.red(data)}`);
57
+ return await this.LevelDB();
58
+ }
59
+ }
60
+ /**
61
+ * 降级为 LevelDB
62
+ */
63
+ async LevelDB() {
64
+ try {
65
+ logger.debug('使用LevelDB代替Redis实现基础Api');
66
+ const redis = new RedisLevel();
67
+ return redis;
68
+ }
69
+ catch (error) {
70
+ logger.error('降级为 LevelDB 失败');
71
+ logger.error(error);
72
+ return false;
73
+ }
74
+ }
75
+ /**
76
+ * 连接 Redis 单例
77
+ */
78
+ async connect(options) {
79
+ const client = createClient(options);
80
+ try {
81
+ await client.connect();
82
+ return { status: 'ok', data: client };
83
+ }
84
+ catch (error) {
85
+ return { status: 'error', data: error };
86
+ }
87
+ }
88
+ /**
89
+ * 连接 Redis 集群
90
+ */
91
+ async connectCluster(rootNodes) {
92
+ const client = createCluster({ rootNodes });
93
+ try {
94
+ await client.connect();
95
+ return { status: 'ok', data: client };
96
+ }
97
+ catch (error) {
98
+ return { status: 'error', data: error };
99
+ }
100
+ }
101
+ /**
102
+ * 判断是否为 ARM64 并返回参数
103
+ */
104
+ async aarch64() {
105
+ try {
106
+ /** 判断arch */
107
+ const arch = await this.execSync('uname -m');
108
+ if (arch && arch.includes('aarch64')) {
109
+ /** 提取 Redis 版本 */
110
+ const version = await this.execSync('redis-server -v');
111
+ if (version) {
112
+ /** 提取版本号 */
113
+ const RedisVersion = version.match(/v=(\d)./);
114
+ /** 如果>=6版本则忽略警告 */
115
+ if (RedisVersion && Number(RedisVersion[1]) >= 6)
116
+ return ' --ignore-warnings ARM64-COW-BUG';
117
+ }
118
+ }
119
+ return '';
120
+ }
121
+ catch {
122
+ return '';
123
+ }
124
+ }
125
+ execSync(cmd) {
126
+ return new Promise((resolve, reject) => {
127
+ exec(cmd, (error, stdout) => {
128
+ if (error)
129
+ return reject(error);
130
+ resolve(stdout);
131
+ });
132
+ });
133
+ }
134
+ }
135
+ export const redis = await new Redis().start();