node-karin 0.10.0 → 0.10.2

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 (129) hide show
  1. package/config/defSet/group.yaml +40 -2
  2. package/lib/adapter/onebot/11/index.js +1 -1
  3. package/lib/cli/init.js +1 -1
  4. package/lib/cli/karin.js +1 -1
  5. package/lib/core/index.d.ts +9 -9
  6. package/lib/core/index.js +9 -9
  7. package/lib/core/init/dir.js +7 -0
  8. package/lib/core/init/init.js +46 -0
  9. package/lib/core/{karin.d.ts → karin/karin.d.ts} +1 -1
  10. package/lib/core/karin/karin.js +194 -0
  11. package/lib/core/{listener.d.ts → listener/listener.d.ts} +1 -1
  12. package/lib/core/listener/listener.js +213 -0
  13. package/lib/core/{plugin.app.d.ts → plugin/app.d.ts} +1 -1
  14. package/lib/core/plugin/app.js +19 -0
  15. package/lib/core/{plugin.d.ts → plugin/base.d.ts} +1 -1
  16. package/lib/core/plugin/base.js +140 -0
  17. package/lib/core/{plugin.loader.d.ts → plugin/loader.d.ts} +3 -3
  18. package/lib/core/plugin/loader.js +579 -0
  19. package/lib/core/process/process.js +100 -0
  20. package/lib/core/server/server.js +283 -0
  21. package/lib/db/index.d.ts +2 -2
  22. package/lib/db/index.js +2 -2
  23. package/lib/db/level/level.js +36 -0
  24. package/lib/db/redis/redis.js +135 -0
  25. package/lib/db/redis/redis_level.js +287 -0
  26. package/lib/event/{event.handler.d.ts → handler/base.d.ts} +2 -2
  27. package/lib/event/handler/base.js +173 -0
  28. package/lib/event/{message.handler.d.ts → handler/message.d.ts} +3 -3
  29. package/lib/event/handler/message.js +270 -0
  30. package/lib/event/{notice.handler.d.ts → handler/notice.d.ts} +3 -3
  31. package/lib/event/handler/notice.js +212 -0
  32. package/lib/event/{request.handler.d.ts → handler/request.d.ts} +3 -3
  33. package/lib/event/handler/request.js +118 -0
  34. package/lib/event/{review.handler.d.ts → handler/review.d.ts} +3 -3
  35. package/lib/event/handler/review.js +391 -0
  36. package/lib/event/index.d.ts +5 -5
  37. package/lib/event/index.js +5 -5
  38. package/lib/render/base.d.ts +1 -1
  39. package/lib/render/client.d.ts +1 -1
  40. package/lib/render/client.js +2 -12
  41. package/lib/render/client_even.d.ts +1 -1
  42. package/lib/render/client_even.js +2 -12
  43. package/lib/render/http.d.ts +1 -1
  44. package/lib/render/http.js +1 -1
  45. package/lib/render/server.js +1 -1
  46. package/lib/types/adapter/{adapter.d.ts → base.d.ts} +2 -2
  47. package/lib/types/config/config.js +1 -0
  48. package/lib/types/element/element.js +1 -0
  49. package/lib/types/event/message.d.ts +1 -1
  50. package/lib/types/event/reply.d.ts +1 -1
  51. package/lib/types/index.d.ts +6 -6
  52. package/lib/types/index.js +6 -6
  53. package/lib/types/logger/logger.js +1 -0
  54. package/lib/types/{plugin.d.ts → plugin/plugin.d.ts} +3 -3
  55. package/lib/types/plugin/plugin.js +1 -0
  56. package/lib/types/render/render.js +1 -0
  57. package/lib/utils/{common.d.ts → common/common.d.ts} +1 -1
  58. package/lib/utils/common/common.js +591 -0
  59. package/lib/utils/{config.d.ts → config/config.d.ts} +37 -19
  60. package/lib/utils/config/config.js +328 -0
  61. package/lib/utils/config/updateVersion.js +145 -0
  62. package/lib/utils/config/yamlEditor.js +292 -0
  63. package/lib/utils/{handler.d.ts → core/handler.d.ts} +1 -1
  64. package/lib/utils/core/handler.js +115 -0
  65. package/lib/utils/core/init.js +213 -0
  66. package/lib/utils/core/logger.js +105 -0
  67. package/lib/utils/{segment.d.ts → core/segment.d.ts} +1 -1
  68. package/lib/utils/core/segment.js +441 -0
  69. package/lib/utils/index.d.ts +11 -11
  70. package/lib/utils/index.js +11 -11
  71. package/lib/utils/{button.d.ts → tools/button.d.ts} +1 -1
  72. package/lib/utils/tools/button.js +38 -0
  73. package/lib/utils/tools/exec.js +37 -0
  74. package/lib/utils/tools/ffmpeg.js +25 -0
  75. package/lib/utils/tools/update.js +139 -0
  76. package/package.json +1 -1
  77. package/lib/core/dir.js +0 -7
  78. package/lib/core/init.js +0 -42
  79. package/lib/core/karin.js +0 -194
  80. package/lib/core/listener.js +0 -217
  81. package/lib/core/plugin.app.js +0 -19
  82. package/lib/core/plugin.js +0 -145
  83. package/lib/core/plugin.loader.js +0 -561
  84. package/lib/core/process.js +0 -98
  85. package/lib/core/server.js +0 -269
  86. package/lib/db/level.js +0 -37
  87. package/lib/db/redis.js +0 -134
  88. package/lib/db/redis_level.js +0 -293
  89. package/lib/event/event.handler.js +0 -167
  90. package/lib/event/message.handler.js +0 -254
  91. package/lib/event/notice.handler.js +0 -204
  92. package/lib/event/request.handler.js +0 -110
  93. package/lib/event/review.handler.js +0 -387
  94. package/lib/types/config.js +0 -1
  95. package/lib/types/element.js +0 -1
  96. package/lib/types/logger.js +0 -1
  97. package/lib/types/plugin.js +0 -1
  98. package/lib/types/render.js +0 -1
  99. package/lib/utils/button.js +0 -34
  100. package/lib/utils/common.js +0 -572
  101. package/lib/utils/config.js +0 -318
  102. package/lib/utils/exec.js +0 -36
  103. package/lib/utils/ffmpeg.js +0 -25
  104. package/lib/utils/handler.js +0 -109
  105. package/lib/utils/init.js +0 -208
  106. package/lib/utils/logger.js +0 -104
  107. package/lib/utils/segment.js +0 -470
  108. package/lib/utils/update.js +0 -135
  109. package/lib/utils/updateVersion.js +0 -145
  110. package/lib/utils/yamlEditor.js +0 -279
  111. /package/lib/core/{dir.d.ts → init/dir.d.ts} +0 -0
  112. /package/lib/core/{init.d.ts → init/init.d.ts} +0 -0
  113. /package/lib/core/{process.d.ts → process/process.d.ts} +0 -0
  114. /package/lib/core/{server.d.ts → server/server.d.ts} +0 -0
  115. /package/lib/db/{level.d.ts → level/level.d.ts} +0 -0
  116. /package/lib/db/{redis.d.ts → redis/redis.d.ts} +0 -0
  117. /package/lib/db/{redis_level.d.ts → redis/redis_level.d.ts} +0 -0
  118. /package/lib/types/adapter/{adapter.js → base.js} +0 -0
  119. /package/lib/types/{config.d.ts → config/config.d.ts} +0 -0
  120. /package/lib/types/{element.d.ts → element/element.d.ts} +0 -0
  121. /package/lib/types/{logger.d.ts → logger/logger.d.ts} +0 -0
  122. /package/lib/types/{render.d.ts → render/render.d.ts} +0 -0
  123. /package/lib/utils/{updateVersion.d.ts → config/updateVersion.d.ts} +0 -0
  124. /package/lib/utils/{yamlEditor.d.ts → config/yamlEditor.d.ts} +0 -0
  125. /package/lib/utils/{init.d.ts → core/init.d.ts} +0 -0
  126. /package/lib/utils/{logger.d.ts → core/logger.d.ts} +0 -0
  127. /package/lib/utils/{exec.d.ts → tools/exec.d.ts} +0 -0
  128. /package/lib/utils/{ffmpeg.d.ts → tools/ffmpeg.d.ts} +0 -0
  129. /package/lib/utils/{update.d.ts → tools/update.d.ts} +0 -0
@@ -0,0 +1,591 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import Yaml from 'yaml';
4
+ import axios from 'axios';
5
+ import lodash from 'lodash';
6
+ import { promisify } from 'util';
7
+ import { fileURLToPath } from 'url';
8
+ import { pipeline, Readable } from 'stream';
9
+ import { logger, segment, YamlEditor } from '../../utils/index.js';
10
+ /**
11
+ * 常用方法
12
+ */
13
+ class Common {
14
+ streamPipeline;
15
+ constructor() {
16
+ this.streamPipeline = promisify(pipeline);
17
+ }
18
+ /**
19
+ * 休眠函数
20
+ * @param ms 毫秒
21
+ */
22
+ sleep(ms) {
23
+ return new Promise(resolve => setTimeout(resolve, ms));
24
+ }
25
+ /**
26
+ * 下载保存文件
27
+ * @param fileUrl 下载地址
28
+ * @param savePath 保存路径
29
+ * @param param axios参数
30
+ */
31
+ async downFile(fileUrl, savePath, param = {}) {
32
+ try {
33
+ this.mkdir(path.dirname(savePath));
34
+ logger.info(`[下载文件] ${fileUrl}`);
35
+ const response = await axios.get(fileUrl, { ...param, responseType: 'stream' });
36
+ await this.streamPipeline(response.data, fs.createWriteStream(savePath));
37
+ return true;
38
+ }
39
+ catch (err) {
40
+ logger.error(`下载文件错误:${err}`);
41
+ return false;
42
+ }
43
+ }
44
+ /**
45
+ * 对axios进行简单封装,超时、错误后返回null,不会抛出异常
46
+ * @param url 请求地址
47
+ * @param type 请求类型
48
+ * @param param axios参数
49
+ */
50
+ async axios(url, type = 'get', param = {}) {
51
+ try {
52
+ if (type === 'post')
53
+ return await axios.post(url, param.data, param);
54
+ return await axios.get(url, param);
55
+ }
56
+ catch (error) {
57
+ logger.debug(error);
58
+ return null;
59
+ }
60
+ }
61
+ /**
62
+ * 递归创建目录
63
+ * @param dirname - 要创建的文件夹路径
64
+ */
65
+ mkdir(dirname) {
66
+ if (fs.existsSync(dirname))
67
+ return true;
68
+ /** 递归自调用 */
69
+ if (this.mkdir(path.dirname(dirname)))
70
+ fs.mkdirSync(dirname);
71
+ return true;
72
+ }
73
+ /**
74
+ * 标准化文件路径
75
+ * @param file - 相对路径
76
+ * @param isDir - 返回绝对路径
77
+ * @param isFile - 添加file://前缀
78
+ * @returns 标准化后的路径
79
+ */
80
+ absPath(file, isDir = true, isFile = false) {
81
+ file = file.replace(/\\/g, '/');
82
+ if (file.startsWith('file://')) {
83
+ /** linux */
84
+ if (path.sep === '/') {
85
+ file = file.replace('file://', '');
86
+ }
87
+ else {
88
+ /** windows */
89
+ file = file.replace(/^file:[/]{2,3}/g, '');
90
+ }
91
+ }
92
+ file = path.normalize(file);
93
+ /** 判断路径是否为绝对路径 否则转为绝对路径 */
94
+ if (isDir && !path.isAbsolute(file)) {
95
+ file = path.resolve(file);
96
+ }
97
+ if (isFile)
98
+ file = 'file://' + file;
99
+ file = file.replace(/\\/g, '/');
100
+ return file;
101
+ }
102
+ /**
103
+ * 判断是否为文件夹
104
+ * @param path - 路径
105
+ * @returns 返回true为文件夹
106
+ */
107
+ isDir(path) {
108
+ try {
109
+ return fs.statSync(path).isDirectory();
110
+ }
111
+ catch {
112
+ return false;
113
+ }
114
+ }
115
+ /**
116
+ * 判断是否为插件包
117
+ * @param path - 路径
118
+ * @returns 返回true为插件包
119
+ */
120
+ isPlugin(path) {
121
+ return this.exists(`${path}/package.json`);
122
+ }
123
+ /**
124
+ * 判断路径是否存在
125
+ * @param path - 路径
126
+ * @returns 返回true为存在
127
+ */
128
+ exists(path) {
129
+ try {
130
+ return fs.existsSync(path);
131
+ }
132
+ catch {
133
+ return false;
134
+ }
135
+ }
136
+ /**
137
+ * - 解析json文件
138
+ */
139
+ readJson(file) {
140
+ try {
141
+ return JSON.parse(fs.readFileSync(file, 'utf8'));
142
+ }
143
+ catch (error) {
144
+ logger.error('[common] 读取json文件错误:' + error);
145
+ return null;
146
+ }
147
+ }
148
+ /**
149
+ * - 写入json文件
150
+ */
151
+ writeJson(file, data) {
152
+ try {
153
+ fs.writeFileSync(file, JSON.stringify(data, null, 2));
154
+ return true;
155
+ }
156
+ catch (error) {
157
+ logger.error('[common] 写入json文件错误:' + error);
158
+ return false;
159
+ }
160
+ }
161
+ /**
162
+ * - 解析yaml文件
163
+ */
164
+ readYaml(file) {
165
+ try {
166
+ return Yaml.parse(fs.readFileSync(file, 'utf8'));
167
+ }
168
+ catch (error) {
169
+ logger.error('[common] 读取yaml文件错误:' + error);
170
+ return null;
171
+ }
172
+ }
173
+ /**
174
+ * - 写入yaml文件
175
+ */
176
+ writeYaml(file, data) {
177
+ try {
178
+ fs.writeFileSync(file, Yaml.stringify(data));
179
+ return true;
180
+ }
181
+ catch (error) {
182
+ logger.error('[common] 写入yaml文件错误:' + error);
183
+ return false;
184
+ }
185
+ }
186
+ /**
187
+ * 根据文件后缀名从指定路径下读取符合要求的文件
188
+ * @param path - 路径
189
+ * @param ext - 后缀名、或后缀名列表
190
+ * @example common.readDir('./plugins', '.js')
191
+ * @example common.readDir('./plugins', ['.js', '.ts'])
192
+ */
193
+ readDir(_path, ext) {
194
+ if (!this.isDir(_path))
195
+ return null;
196
+ const files = fs.readdirSync(_path, { withFileTypes: true });
197
+ const list = [];
198
+ if (!Array.isArray(ext))
199
+ ext = [ext];
200
+ // 排除文件夹 和不符合后缀名的文件
201
+ files.forEach(v => {
202
+ if (v.isDirectory())
203
+ return;
204
+ if (ext.includes(path.extname(v.name)))
205
+ list.push(v.name);
206
+ });
207
+ return list;
208
+ }
209
+ /**
210
+ * 根据传入的 import.meta.url 计算相对于项目根目录的路径,返回需要的 '../' 层级。
211
+ * @param url - import.meta.url
212
+ * @returns 相对路径的层级数量,用 '../' 表示
213
+ * @example
214
+ * // 在 plugins/karin-plugin-example/index.ts 中使用
215
+ * common.urlToPath(import.meta.url) // 返回 '../../'
216
+ */
217
+ urlToPath(url) {
218
+ /** 当前文件的绝对路径 */
219
+ const filePath = fileURLToPath(url);
220
+ /** 当前文件所在目录的绝对路径 */
221
+ const dirPath = path.dirname(filePath);
222
+ /** 项目根目录 */
223
+ const rootPath = process.cwd();
224
+ /** 当前文件到项目根目录的相对路径 */
225
+ const relativePath = path.relative(dirPath, rootPath);
226
+ /** 相对路径的层级数量 */
227
+ const upLevelsCount = relativePath.split(path.sep).length;
228
+ /** 返回构建的路径 */
229
+ const upPath = lodash.repeat('../', upLevelsCount);
230
+ return upPath;
231
+ }
232
+ /**
233
+ * 传入相对路径 分割为两部分 1为文件夹路径 2为文件名 文件夹路径无前缀开头
234
+ * @param _path - 路径
235
+ */
236
+ splitPath(_path) {
237
+ const list = _path.replace(/\\/g, '/').split('/');
238
+ if (list[0] === '.')
239
+ list.shift();
240
+ const pop = list.pop() || '';
241
+ const dir = path.join(...list);
242
+ return { dir, pop };
243
+ }
244
+ /**
245
+ * 将文件转换为不带前缀的base64字符串
246
+ * @param file - 文件路径或Buffer对象、可读流对象、http地址、base64://字符串
247
+ * @param options - 选项 http为true时返回http地址
248
+ * @returns 返回base64字符串
249
+ */
250
+ async base64(file, options = { http: false }) {
251
+ /** 非字符串 */
252
+ if (typeof file !== 'string') {
253
+ if (Buffer.isBuffer(file))
254
+ return file.toString('base64');
255
+ if (file instanceof Readable)
256
+ return (await this.stream(file)).toString('base64');
257
+ return file;
258
+ }
259
+ /** base64:// */
260
+ if (file.startsWith('base64://'))
261
+ return file.replace('base64://', '');
262
+ /** http */
263
+ if (file.startsWith('http')) {
264
+ if (options.http)
265
+ return file;
266
+ const response = await axios.get(file, { responseType: 'arraybuffer' });
267
+ return Buffer.from(response.data, 'binary').toString('base64');
268
+ }
269
+ /** file:// */
270
+ const files = file.replace(/^file:\/\//, '');
271
+ if (fs.existsSync(files))
272
+ return fs.readFileSync(file).toString('base64');
273
+ /** 无前缀base64:// */
274
+ return Buffer.from(file, 'base64').toString('base64');
275
+ }
276
+ /**
277
+ * 将文件转换为Buffer对象 仅支持标准格式
278
+ * @param file - 文件路径或Buffer对象、可读流对象、http地址、base64://字符串
279
+ * @param options - 选项 http为true时返回http地址
280
+ * @returns - 返回Buffer对象
281
+ */
282
+ async buffer(file, options) {
283
+ /** 非字符串 */
284
+ if (typeof file !== 'string') {
285
+ if (Buffer.isBuffer(file))
286
+ return file;
287
+ if (file instanceof Readable)
288
+ return await this.stream(file);
289
+ return file;
290
+ }
291
+ /** base64 */
292
+ if (file.startsWith('base64://')) {
293
+ return Buffer.from(file.replace('base64://', ''), 'base64');
294
+ }
295
+ /** http */
296
+ if (file.startsWith('http')) {
297
+ if (options?.http)
298
+ return file;
299
+ const response = await axios.get(file, { responseType: 'arraybuffer' });
300
+ return Buffer.from(response.data);
301
+ }
302
+ /** file:// */
303
+ const files = file.replace(/^file:\/\//, '');
304
+ if (fs.existsSync(files))
305
+ return fs.readFileSync(files);
306
+ /** 无前缀base64:// */
307
+ return Buffer.from(file, 'base64');
308
+ }
309
+ /**
310
+ * 将数据流对象转换为Buffer对象
311
+ * @param {stream.Readable} stream - 要转换的数据流对象
312
+ * @returns {Promise<Buffer>} - 返回Buffer
313
+ */
314
+ stream(stream) {
315
+ return new Promise((resolve, reject) => {
316
+ const chunks = [];
317
+ stream.on('data', chunk => chunks.push(chunk));
318
+ stream.on('end', () => resolve(Buffer.concat(chunks)));
319
+ stream.on('error', error => reject(error));
320
+ });
321
+ }
322
+ /**
323
+ * 标准化发送的消息内容
324
+ * @param elements - 消息内容
325
+ */
326
+ makeMessage(elements) {
327
+ /** 将msg格式化为数组 */
328
+ if (!Array.isArray(elements))
329
+ elements = [elements];
330
+ const message = [];
331
+ elements.forEach(v => {
332
+ if (typeof v === 'string') {
333
+ message.push(segment.text(v));
334
+ }
335
+ else {
336
+ message.push(v);
337
+ }
338
+ });
339
+ return message;
340
+ }
341
+ /**
342
+ * 制作简单转发,返回segment.node[]。仅简单包装node,也可以自己组装
343
+ * @param elements
344
+ * @param fakeUin 转发用户的QQ号 必填
345
+ * @param fakeNick 转发用户显示的昵称 必填
346
+ */
347
+ makeForward(elements, fakeUin, fakeNick) {
348
+ if (!Array.isArray(elements))
349
+ elements = [elements];
350
+ return elements.map(element => {
351
+ const NodeElement = this.makeMessage(element);
352
+ return segment.node(fakeUin, fakeNick, NodeElement);
353
+ });
354
+ }
355
+ /**
356
+ * 获取git插件列表
357
+ * @param isPack - 是否屏蔽不带package.json的插件,默认为false
358
+ */
359
+ getPlugins(isPack = false) {
360
+ const dir = this.absPath('./plugins', false);
361
+ let list = fs.readdirSync(dir, { withFileTypes: true });
362
+ /** 忽略非文件夹、非 karin-plugin-开头的文件夹 */
363
+ list = list.filter(v => v.isDirectory() && v.name.startsWith('karin-plugin-'));
364
+ if (isPack)
365
+ list = list.filter(v => fs.existsSync(`${dir}/${v.name}/package.json`));
366
+ const arr = [];
367
+ list.map(v => arr.push(v.name));
368
+ return arr;
369
+ }
370
+ /**
371
+ * 获取npm插件列表
372
+ * @param showDetails - 是否返回详细信息,默认为false
373
+ * 默认只返回插件npm包名,为true时返回详细的{dir, name}[]
374
+ */
375
+ async getNpmPlugins(showDetails) {
376
+ /** 屏蔽的依赖包列表 */
377
+ const pkgdependencies = [
378
+ '@grpc/grpc-js',
379
+ '@grpc/proto-loader',
380
+ 'art-template',
381
+ 'axios',
382
+ 'chalk',
383
+ 'chokidar',
384
+ 'express',
385
+ 'kritor-proto',
386
+ 'level',
387
+ 'lodash',
388
+ 'log4js',
389
+ 'moment',
390
+ 'node-karin',
391
+ 'node-schedule',
392
+ 'redis',
393
+ 'ws',
394
+ 'yaml',
395
+ ];
396
+ const pkg = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
397
+ const dependencies = Object.keys(pkg.dependencies).filter((name) => !pkgdependencies.includes(name));
398
+ if (!showDetails) {
399
+ const list = [];
400
+ // 检查pkg是否存在karin字段
401
+ const readPackageJson = async (name) => {
402
+ try {
403
+ const pkgPath = path.join(process.cwd(), 'node_modules', name, 'package.json');
404
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
405
+ if (pkg?.karin)
406
+ list.push(name);
407
+ }
408
+ catch { }
409
+ };
410
+ await Promise.all(dependencies.map(readPackageJson));
411
+ return list;
412
+ }
413
+ else {
414
+ const list = [];
415
+ const readPackageJson = async (files) => {
416
+ try {
417
+ const pkgPath = path.join(process.cwd(), 'node_modules', files, 'package.json');
418
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
419
+ if (pkg?.karin) {
420
+ if (pkg?.main) {
421
+ const dir = `${files}/${path.dirname(pkg.main).replace(/\.\//, '')}`;
422
+ list.push({ dir, name: path.basename(pkg.main), isMain: true });
423
+ }
424
+ if (pkg?.karin?.apps?.length) {
425
+ pkg.karin.apps.forEach((app) => {
426
+ fs.readdirSync(`./node_modules/${files}/${app}`).forEach((filename) => {
427
+ /** 忽略非js */
428
+ if (!filename.endsWith('.js'))
429
+ return;
430
+ const dir = `${files}/${app}`;
431
+ list.push({ dir, name: filename, isMain: false });
432
+ });
433
+ });
434
+ }
435
+ }
436
+ }
437
+ catch { }
438
+ };
439
+ await Promise.all(dependencies.map(readPackageJson));
440
+ return list;
441
+ }
442
+ }
443
+ /**
444
+ * 获取运行时间
445
+ */
446
+ uptime() {
447
+ const time = process.uptime();
448
+ const day = Math.floor(time / 86400);
449
+ const hour = Math.floor((time % 86400) / 3600);
450
+ const min = Math.floor((time % 3600) / 60);
451
+ const sec = Math.floor(time % 60);
452
+ const parts = [day ? `${day}天` : '', hour ? `${hour}小时` : '', min ? `${min}分钟` : '', !day && sec ? `${sec}秒` : ''];
453
+ return parts.filter(Boolean).join('');
454
+ }
455
+ /**
456
+ * 构建消息体日志
457
+ * @param - 消息体
458
+ */
459
+ makeMessageLog(message) {
460
+ const logs = [];
461
+ for (const val of message) {
462
+ switch (val.type) {
463
+ case 'text':
464
+ logs.push(val.text);
465
+ break;
466
+ case 'face':
467
+ logs.push(`[face:${val.id}]`);
468
+ break;
469
+ case 'video':
470
+ case 'image':
471
+ case 'voice':
472
+ case 'record':
473
+ case 'file': {
474
+ let file;
475
+ if (Buffer.isBuffer(val.file)) {
476
+ file = 'Buffer://...';
477
+ }
478
+ else if (/^http|^file/.test(val.file)) {
479
+ file = val.file;
480
+ }
481
+ else {
482
+ file = 'base64://...';
483
+ }
484
+ logs.push(`[${val.type}:${file}]`);
485
+ break;
486
+ }
487
+ case 'at':
488
+ logs.push(`[at:${val.uid}]`);
489
+ break;
490
+ case 'rps':
491
+ logs.push(`[rps:${val.id}]`);
492
+ break;
493
+ case 'dice':
494
+ logs.push(`[dice:${val.id}]`);
495
+ break;
496
+ case 'poke':
497
+ logs.push(`[poke:${val.id}]`);
498
+ break;
499
+ case 'share':
500
+ logs.push(`[share:${JSON.stringify(val)}]`);
501
+ break;
502
+ case 'contact':
503
+ logs.push(`[contact:${JSON.stringify(val)}]`);
504
+ break;
505
+ case 'location':
506
+ logs.push(`[location:${JSON.stringify(val)}]`);
507
+ break;
508
+ case 'music':
509
+ logs.push(`[music:${JSON.stringify(val)}]`);
510
+ break;
511
+ case 'reply':
512
+ logs.push(`[reply:${val.message_id}]`);
513
+ break;
514
+ case 'forward':
515
+ logs.push(`[forward:${val.res_id}]`);
516
+ break;
517
+ case 'xml':
518
+ logs.push(`[xml:${val.data}]`);
519
+ break;
520
+ case 'json':
521
+ logs.push(`[json:${val.data}]`);
522
+ break;
523
+ case 'markdown': {
524
+ logs.push(`[markdown:${val.content}]`);
525
+ break;
526
+ }
527
+ case 'markdown_tpl': {
528
+ const params = val.params;
529
+ if (!params)
530
+ break;
531
+ const content = { id: val.custom_template_id };
532
+ for (const v of params)
533
+ content[v.key] = v.values[0];
534
+ logs.push(`[markdown_tpl:${JSON.stringify(content)}]`);
535
+ break;
536
+ }
537
+ case 'rows': {
538
+ const rows = [];
539
+ for (const v of val.rows)
540
+ rows.push(JSON.stringify(v.data));
541
+ logs.push(`[rows:${JSON.stringify(rows)}]`);
542
+ break;
543
+ }
544
+ case 'button':
545
+ logs.push(`[button:${JSON.stringify(val.data)}]`);
546
+ break;
547
+ case 'long_msg':
548
+ logs.push(`[long_msg:${val.id}]`);
549
+ break;
550
+ default:
551
+ logs.push(`[未知:${JSON.stringify(val)}]`);
552
+ }
553
+ }
554
+ return logs.join('');
555
+ }
556
+ /**
557
+ * 更新yaml文件
558
+ * @param filePath - 文件路径
559
+ * @param settings - 设置项
560
+ */
561
+ updateYaml(filePath, settings) {
562
+ let yaml = new YamlEditor(filePath);
563
+ /** 先添加内容 */
564
+ settings.forEach(({ key, val }) => {
565
+ try {
566
+ if (!yaml.has(key))
567
+ yaml.set(key, val);
568
+ }
569
+ catch (error) {
570
+ logger.error(`[common] 更新yaml文件时出错:${error.stack || error.message || error}`);
571
+ }
572
+ });
573
+ /** 先保存 */
574
+ yaml.save();
575
+ /** 重新解析 再次写入注释 直接写入注释会报错 写入的不是node节点模式 */
576
+ yaml = new YamlEditor(filePath);
577
+ settings.forEach(({ key, comment }) => {
578
+ try {
579
+ yaml.comment(key, comment, true);
580
+ }
581
+ catch (error) {
582
+ logger.error(`[common] 更新yaml文件时出错:${error.stack || error.message || error}`);
583
+ }
584
+ });
585
+ yaml.save();
586
+ }
587
+ }
588
+ /**
589
+ * 常用方法
590
+ */
591
+ export const common = new Common();
@@ -1,5 +1,5 @@
1
1
  import { Logger } from 'log4js';
2
- import { Redis, App, Config, Server, Package, GroupCfg } from '../types/index.js';
2
+ import { Redis, App, Config, Server, Package, GroupCfg, KarinEventTypes } from '../../types/index.js';
3
3
  /**
4
4
  * 配置文件
5
5
  */
@@ -24,7 +24,9 @@ export declare const config: {
24
24
  watcher: Map<string, any>;
25
25
  review: boolean;
26
26
  logger: Logger;
27
- /** 初始化配置 */
27
+ /**
28
+ * 初始化配置
29
+ */
28
30
  initCfg(): Promise<void>;
29
31
  getPlugins(): Promise<string[]>;
30
32
  /**
@@ -53,7 +55,9 @@ export declare const config: {
53
55
  * 管理员列表
54
56
  */
55
57
  readonly admin: string[];
56
- /** App管理 */
58
+ /**
59
+ * App管理
60
+ */
57
61
  readonly App: App;
58
62
  /**
59
63
  * 基本配置
@@ -70,22 +74,27 @@ export declare const config: {
70
74
  readonly package: Package;
71
75
  /**
72
76
  * 获取群配置
77
+ * @param group_id - 群号
78
+ * @param e - 事件
73
79
  */
74
- group(group_id?: string): GroupCfg;
80
+ group(group_id: string, e: KarinEventTypes): GroupCfg;
75
81
  /**
76
82
  * 获取配置yaml
83
+ * @param type 类型
84
+ * @param name 文件名称
85
+ * @param isWatch 是否监听文件
77
86
  */
78
87
  getYaml(type: "defSet" | "config", name: string, isWatch?: boolean): any;
79
88
  /**
80
89
  * 监听配置文件
81
- * @param {'defSet'|'config'} type 类型
82
- * @param {string} name 文件名称 不带后缀
83
- * @param {string} file 文件路径
90
+ * @param type 类型
91
+ * @param name 文件名称 不带后缀
92
+ * @param file 文件路径
84
93
  */
85
94
  watch(type: "defSet" | "config", name: string, file: string): Promise<true | undefined>;
86
- change_App(): Promise<void>;
87
- change_config(): Promise<void>;
88
- change_group(): Promise<void>;
95
+ changeApp(): Promise<void>;
96
+ changeCfg(): Promise<void>;
97
+ changeGroup(): Promise<void>;
89
98
  "__#2@#review"(): Promise<void>;
90
99
  };
91
100
  export declare const Cfg: {
@@ -109,7 +118,9 @@ export declare const Cfg: {
109
118
  watcher: Map<string, any>;
110
119
  review: boolean;
111
120
  logger: Logger;
112
- /** 初始化配置 */
121
+ /**
122
+ * 初始化配置
123
+ */
113
124
  initCfg(): Promise<void>;
114
125
  getPlugins(): Promise<string[]>;
115
126
  /**
@@ -138,7 +149,9 @@ export declare const Cfg: {
138
149
  * 管理员列表
139
150
  */
140
151
  readonly admin: string[];
141
- /** App管理 */
152
+ /**
153
+ * App管理
154
+ */
142
155
  readonly App: App;
143
156
  /**
144
157
  * 基本配置
@@ -155,21 +168,26 @@ export declare const Cfg: {
155
168
  readonly package: Package;
156
169
  /**
157
170
  * 获取群配置
171
+ * @param group_id - 群号
172
+ * @param e - 事件
158
173
  */
159
- group(group_id?: string): GroupCfg;
174
+ group(group_id: string, e: KarinEventTypes): GroupCfg;
160
175
  /**
161
176
  * 获取配置yaml
177
+ * @param type 类型
178
+ * @param name 文件名称
179
+ * @param isWatch 是否监听文件
162
180
  */
163
181
  getYaml(type: "defSet" | "config", name: string, isWatch?: boolean): any;
164
182
  /**
165
183
  * 监听配置文件
166
- * @param {'defSet'|'config'} type 类型
167
- * @param {string} name 文件名称 不带后缀
168
- * @param {string} file 文件路径
184
+ * @param type 类型
185
+ * @param name 文件名称 不带后缀
186
+ * @param file 文件路径
169
187
  */
170
188
  watch(type: "defSet" | "config", name: string, file: string): Promise<true | undefined>;
171
- change_App(): Promise<void>;
172
- change_config(): Promise<void>;
173
- change_group(): Promise<void>;
189
+ changeApp(): Promise<void>;
190
+ changeCfg(): Promise<void>;
191
+ changeGroup(): Promise<void>;
174
192
  "__#2@#review"(): Promise<void>;
175
193
  };