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.
- package/config/defSet/group.yaml +40 -2
- package/lib/adapter/onebot/11/index.js +1 -1
- package/lib/cli/init.js +1 -1
- package/lib/cli/karin.js +1 -1
- package/lib/core/index.d.ts +9 -9
- package/lib/core/index.js +9 -9
- package/lib/core/init/dir.js +7 -0
- package/lib/core/init/init.js +46 -0
- package/lib/core/{karin.d.ts → karin/karin.d.ts} +1 -1
- package/lib/core/karin/karin.js +194 -0
- package/lib/core/{listener.d.ts → listener/listener.d.ts} +1 -1
- package/lib/core/listener/listener.js +213 -0
- package/lib/core/{plugin.app.d.ts → plugin/app.d.ts} +1 -1
- package/lib/core/plugin/app.js +19 -0
- package/lib/core/{plugin.d.ts → plugin/base.d.ts} +1 -1
- package/lib/core/plugin/base.js +140 -0
- package/lib/core/{plugin.loader.d.ts → plugin/loader.d.ts} +3 -3
- package/lib/core/plugin/loader.js +579 -0
- package/lib/core/process/process.js +100 -0
- package/lib/core/server/server.js +283 -0
- package/lib/db/index.d.ts +2 -2
- package/lib/db/index.js +2 -2
- package/lib/db/level/level.js +36 -0
- package/lib/db/redis/redis.js +135 -0
- package/lib/db/redis/redis_level.js +287 -0
- package/lib/event/{event.handler.d.ts → handler/base.d.ts} +2 -2
- package/lib/event/handler/base.js +173 -0
- package/lib/event/{message.handler.d.ts → handler/message.d.ts} +3 -3
- package/lib/event/handler/message.js +270 -0
- package/lib/event/{notice.handler.d.ts → handler/notice.d.ts} +3 -3
- package/lib/event/handler/notice.js +212 -0
- package/lib/event/{request.handler.d.ts → handler/request.d.ts} +3 -3
- package/lib/event/handler/request.js +118 -0
- package/lib/event/{review.handler.d.ts → handler/review.d.ts} +3 -3
- package/lib/event/handler/review.js +391 -0
- package/lib/event/index.d.ts +5 -5
- package/lib/event/index.js +5 -5
- package/lib/render/base.d.ts +1 -1
- package/lib/render/client.d.ts +1 -1
- package/lib/render/client.js +2 -12
- package/lib/render/client_even.d.ts +1 -1
- package/lib/render/client_even.js +2 -12
- package/lib/render/http.d.ts +1 -1
- package/lib/render/http.js +1 -1
- package/lib/render/server.js +1 -1
- package/lib/types/adapter/{adapter.d.ts → base.d.ts} +2 -2
- package/lib/types/config/config.js +1 -0
- package/lib/types/element/element.js +1 -0
- package/lib/types/event/message.d.ts +1 -1
- package/lib/types/event/reply.d.ts +1 -1
- package/lib/types/index.d.ts +6 -6
- package/lib/types/index.js +6 -6
- package/lib/types/logger/logger.js +1 -0
- package/lib/types/{plugin.d.ts → plugin/plugin.d.ts} +3 -3
- package/lib/types/plugin/plugin.js +1 -0
- package/lib/types/render/render.js +1 -0
- package/lib/utils/{common.d.ts → common/common.d.ts} +1 -1
- package/lib/utils/common/common.js +591 -0
- package/lib/utils/{config.d.ts → config/config.d.ts} +37 -19
- package/lib/utils/config/config.js +328 -0
- package/lib/utils/config/updateVersion.js +145 -0
- package/lib/utils/config/yamlEditor.js +292 -0
- package/lib/utils/{handler.d.ts → core/handler.d.ts} +1 -1
- package/lib/utils/core/handler.js +115 -0
- package/lib/utils/core/init.js +213 -0
- package/lib/utils/core/logger.js +105 -0
- package/lib/utils/{segment.d.ts → core/segment.d.ts} +1 -1
- package/lib/utils/core/segment.js +441 -0
- package/lib/utils/index.d.ts +11 -11
- package/lib/utils/index.js +11 -11
- package/lib/utils/{button.d.ts → tools/button.d.ts} +1 -1
- package/lib/utils/tools/button.js +38 -0
- package/lib/utils/tools/exec.js +37 -0
- package/lib/utils/tools/ffmpeg.js +25 -0
- package/lib/utils/tools/update.js +139 -0
- package/package.json +1 -1
- package/lib/core/dir.js +0 -7
- package/lib/core/init.js +0 -42
- package/lib/core/karin.js +0 -194
- package/lib/core/listener.js +0 -217
- package/lib/core/plugin.app.js +0 -19
- package/lib/core/plugin.js +0 -145
- package/lib/core/plugin.loader.js +0 -561
- package/lib/core/process.js +0 -98
- package/lib/core/server.js +0 -269
- package/lib/db/level.js +0 -37
- package/lib/db/redis.js +0 -134
- package/lib/db/redis_level.js +0 -293
- package/lib/event/event.handler.js +0 -167
- package/lib/event/message.handler.js +0 -254
- package/lib/event/notice.handler.js +0 -204
- package/lib/event/request.handler.js +0 -110
- package/lib/event/review.handler.js +0 -387
- package/lib/types/config.js +0 -1
- package/lib/types/element.js +0 -1
- package/lib/types/logger.js +0 -1
- package/lib/types/plugin.js +0 -1
- package/lib/types/render.js +0 -1
- package/lib/utils/button.js +0 -34
- package/lib/utils/common.js +0 -572
- package/lib/utils/config.js +0 -318
- package/lib/utils/exec.js +0 -36
- package/lib/utils/ffmpeg.js +0 -25
- package/lib/utils/handler.js +0 -109
- package/lib/utils/init.js +0 -208
- package/lib/utils/logger.js +0 -104
- package/lib/utils/segment.js +0 -470
- package/lib/utils/update.js +0 -135
- package/lib/utils/updateVersion.js +0 -145
- package/lib/utils/yamlEditor.js +0 -279
- /package/lib/core/{dir.d.ts → init/dir.d.ts} +0 -0
- /package/lib/core/{init.d.ts → init/init.d.ts} +0 -0
- /package/lib/core/{process.d.ts → process/process.d.ts} +0 -0
- /package/lib/core/{server.d.ts → server/server.d.ts} +0 -0
- /package/lib/db/{level.d.ts → level/level.d.ts} +0 -0
- /package/lib/db/{redis.d.ts → redis/redis.d.ts} +0 -0
- /package/lib/db/{redis_level.d.ts → redis/redis_level.d.ts} +0 -0
- /package/lib/types/adapter/{adapter.js → base.js} +0 -0
- /package/lib/types/{config.d.ts → config/config.d.ts} +0 -0
- /package/lib/types/{element.d.ts → element/element.d.ts} +0 -0
- /package/lib/types/{logger.d.ts → logger/logger.d.ts} +0 -0
- /package/lib/types/{render.d.ts → render/render.d.ts} +0 -0
- /package/lib/utils/{updateVersion.d.ts → config/updateVersion.d.ts} +0 -0
- /package/lib/utils/{yamlEditor.d.ts → config/yamlEditor.d.ts} +0 -0
- /package/lib/utils/{init.d.ts → core/init.d.ts} +0 -0
- /package/lib/utils/{logger.d.ts → core/logger.d.ts} +0 -0
- /package/lib/utils/{exec.d.ts → tools/exec.d.ts} +0 -0
- /package/lib/utils/{ffmpeg.d.ts → tools/ffmpeg.d.ts} +0 -0
- /package/lib/utils/{update.d.ts → tools/update.d.ts} +0 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import exec from './exec.js';
|
|
2
|
+
import logger from '../core/logger.js';
|
|
3
|
+
import { config } from '../config/config.js';
|
|
4
|
+
/**
|
|
5
|
+
* 执行 ffmpeg 命令
|
|
6
|
+
*/
|
|
7
|
+
export async function ffmpeg() {
|
|
8
|
+
let ffmpeg = 'ffmpeg';
|
|
9
|
+
const { status } = await exec('ffmpeg -version', false);
|
|
10
|
+
if (status !== 'ok') {
|
|
11
|
+
logger.debug('ffmpeg 未安装,开始尝试读取配置文件是否存在ffmpeg路径');
|
|
12
|
+
const ffmpegPath = config.Config.ffmpeg_path;
|
|
13
|
+
if (!ffmpegPath) {
|
|
14
|
+
logger.warn('ffmpeg 未安装,请安装 ffmpeg 或手动配置 ffmpeg 路径后重启');
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
ffmpeg = `"${ffmpegPath}"`;
|
|
18
|
+
}
|
|
19
|
+
// 返回函数
|
|
20
|
+
return async (cmd, log = true, options = { cwd: process.cwd(), encoding: 'utf-8' }) => {
|
|
21
|
+
cmd = cmd.replace(/^ffmpeg/, '').trim();
|
|
22
|
+
cmd = `${ffmpeg} ${cmd}`;
|
|
23
|
+
return await exec(cmd, log, options);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import exec from './exec.js';
|
|
3
|
+
export const update = new (class Update {
|
|
4
|
+
dir;
|
|
5
|
+
constructor() {
|
|
6
|
+
this.dir = './plugins';
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 更新框架或插件
|
|
10
|
+
* @param path - 插件相对路径
|
|
11
|
+
* @param cmd - 更新命令 默认git pull
|
|
12
|
+
* @param time - 超时时间 默认120s
|
|
13
|
+
*/
|
|
14
|
+
async update(path, cmd = 'git pull', time = 120) {
|
|
15
|
+
/** 检查一下路径是否存在 */
|
|
16
|
+
if (!fs.existsSync(path))
|
|
17
|
+
return { status: 'failed', data: '路径不存在' };
|
|
18
|
+
/** 检查是否有.git文件夹 */
|
|
19
|
+
if (!fs.existsSync(`${path}/.git`))
|
|
20
|
+
return { status: 'failed', data: '该路径不是一个git仓库' };
|
|
21
|
+
/** 设置超时时间 */
|
|
22
|
+
const timer = setTimeout(() => {
|
|
23
|
+
return { status: 'failed', data: '执行超时' };
|
|
24
|
+
}, time * 1000);
|
|
25
|
+
const options = { env: process.env, cwd: path, encoding: 'utf-8' };
|
|
26
|
+
/** 记录当前短哈希 */
|
|
27
|
+
const hash = await this.getHash(path);
|
|
28
|
+
/** 执行更新 */
|
|
29
|
+
const { status, error } = await exec(cmd, true, options);
|
|
30
|
+
/** 执行成功 */
|
|
31
|
+
if (status === 'ok') {
|
|
32
|
+
clearTimeout(timer);
|
|
33
|
+
/** 再次获取短哈希 查看是否有更新 */
|
|
34
|
+
const newHash = await this.getHash(path);
|
|
35
|
+
if (hash === newHash) {
|
|
36
|
+
const time = await this.getTime(path);
|
|
37
|
+
return {
|
|
38
|
+
status: 'ok',
|
|
39
|
+
data: ['\n当前版本已是最新版本', `Hash: ${hash}`, `最后更新:${await this.getCommit({ path, count: 1 })}`, `最后提交时间:${time}`].join('\n'),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const Commit = await this.getCommit({ path, hash });
|
|
43
|
+
return {
|
|
44
|
+
status: 'ok',
|
|
45
|
+
data: ['\n更新成功', `当前Hash: ${newHash}`, `更新日志:\n${Commit}`].join('\n'),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const msg = ['\n更新失败', `当前Hash: ${hash}`, `错误信息:${error?.message?.toString() || error?.stack?.toString() || error?.toString()}`, '请解决错误后重试或执行【#强制更新】'];
|
|
49
|
+
return { status: 'failed', data: msg.join('\n') };
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 获取指定仓库最后一次提交时间日期
|
|
53
|
+
* @param path - 插件相对路径
|
|
54
|
+
*/
|
|
55
|
+
async getTime(path) {
|
|
56
|
+
const cmd = 'git log -1 --format=%cd --date=format:"%Y-%m-%d %H:%M:%S"';
|
|
57
|
+
const data = await exec(cmd, false, { cwd: path, encoding: 'utf-8' });
|
|
58
|
+
if (data.status === 'failed')
|
|
59
|
+
return '获取时间失败,请重试或更新Git~';
|
|
60
|
+
return data.stdout.trim();
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 获取指定仓库最后一次提交哈希值
|
|
64
|
+
* @param {string} path - 插件相对路径
|
|
65
|
+
* @param {boolean} [short] - 是否获取短哈希 默认true
|
|
66
|
+
* @returns {Promise<string>}
|
|
67
|
+
*/
|
|
68
|
+
async getHash(path, short = true) {
|
|
69
|
+
const cmd = short ? 'git rev-parse --short HEAD' : 'git rev-parse HEAD';
|
|
70
|
+
const data = await exec(cmd, false, { cwd: path, encoding: 'utf-8' });
|
|
71
|
+
if (data.status === 'failed') {
|
|
72
|
+
const text = data.error;
|
|
73
|
+
throw new Error(text);
|
|
74
|
+
}
|
|
75
|
+
return data.stdout.trim();
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* 获取指定仓库的提交记录
|
|
79
|
+
* @param {{
|
|
80
|
+
* path: string,
|
|
81
|
+
* count?: number,
|
|
82
|
+
* hash?: string
|
|
83
|
+
* }} options - 参数
|
|
84
|
+
* @param {string} options.path - 插件相对路径
|
|
85
|
+
* @param {number} [options.count] - 获取日志条数 默认1条
|
|
86
|
+
* @param {string} [options.hash] - 指定HEAD
|
|
87
|
+
* @returns {Promise<string>}
|
|
88
|
+
*/
|
|
89
|
+
async getCommit(options) {
|
|
90
|
+
const { path, count = 1, hash, branch } = options;
|
|
91
|
+
let cmd = `git log -${count} --format="[%ad]%s %n" --date="format:%m-%d %H:%M"`;
|
|
92
|
+
/** 键入HEAD */
|
|
93
|
+
if (hash)
|
|
94
|
+
cmd = `git log ${hash}..HEAD --format="[%ad] %s %n" --date="format:%m-%d %H:%M"`;
|
|
95
|
+
/** 指定分支 */
|
|
96
|
+
if (branch)
|
|
97
|
+
cmd = `git log -${count} ${branch} --format="[%ad] %s %n" --date="format:%m-%d %H:%M"`;
|
|
98
|
+
const data = await exec(cmd, false, { cwd: path, encoding: 'utf-8' });
|
|
99
|
+
if (data.status === 'failed') {
|
|
100
|
+
const text = data.error;
|
|
101
|
+
throw new Error(text);
|
|
102
|
+
}
|
|
103
|
+
return data.stdout.trim();
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* 检查插件是否有更新
|
|
107
|
+
* @param {string} path - 插件相对路径
|
|
108
|
+
* @param {number} [time] - 超时时间 默认120s
|
|
109
|
+
* @returns {Promise<{status: 'ok'|'failed', data: string|boolean}>}
|
|
110
|
+
*/
|
|
111
|
+
async checkUpdate(path, time = 120) {
|
|
112
|
+
/** 检查一下路径是否存在 */
|
|
113
|
+
if (!fs.existsSync(path))
|
|
114
|
+
return { status: 'failed', data: '路径不存在' };
|
|
115
|
+
/** 检查是否有.git文件夹 */
|
|
116
|
+
if (!fs.existsSync(`${path}/.git`))
|
|
117
|
+
return { status: 'failed', data: '该路径不是一个git仓库' };
|
|
118
|
+
/** 设置超时时间 */
|
|
119
|
+
const timer = setTimeout(() => {
|
|
120
|
+
return { status: 'failed', data: '执行超时' };
|
|
121
|
+
}, time * 1000);
|
|
122
|
+
const options = { env: process.env, cwd: path, encoding: 'utf-8' };
|
|
123
|
+
/** git fetch origin */
|
|
124
|
+
const { status, error } = await exec('git fetch origin', false, options);
|
|
125
|
+
if (status === 'failed')
|
|
126
|
+
return { status: 'failed', data: error?.message };
|
|
127
|
+
/** git status -uno */
|
|
128
|
+
const { stdout } = await exec('git status -uno', false, options);
|
|
129
|
+
clearTimeout(timer);
|
|
130
|
+
/** 检查是否有更新 没更新直接返回 */
|
|
131
|
+
if (stdout.includes('Your branch is up to date with'))
|
|
132
|
+
return { status: 'ok', data: false };
|
|
133
|
+
/** 获取落后几次更新 */
|
|
134
|
+
const count = stdout.match(/Your branch is behind '.*' by (\d+) commits/)?.[1] || 1;
|
|
135
|
+
const data = await this.getCommit({ path, count, branch: 'origin' });
|
|
136
|
+
return { status: 'ok', data, count };
|
|
137
|
+
}
|
|
138
|
+
})();
|
|
139
|
+
export const Update = update;
|
package/package.json
CHANGED
package/lib/core/dir.js
DELETED
package/lib/core/init.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { logger } from '../utils/index.js'
|
|
2
|
-
/**
|
|
3
|
-
* 启动日志
|
|
4
|
-
*/
|
|
5
|
-
logger.mark('Karin 启动中...')
|
|
6
|
-
logger.mark('https://github.com/KarinJS/Karin')
|
|
7
|
-
/**
|
|
8
|
-
* 设置标题
|
|
9
|
-
*/
|
|
10
|
-
process.title = 'Karin'
|
|
11
|
-
/**
|
|
12
|
-
* 设置时区
|
|
13
|
-
*/
|
|
14
|
-
process.env.TZ = 'Asia/Shanghai'
|
|
15
|
-
const init = () => {
|
|
16
|
-
if (!process.env.karin_app_lang) { process.env.karin_app_lang = 'js' }
|
|
17
|
-
if (!process.env.karin_app_mode) { process.env.karin_app_mode = 'prod' }
|
|
18
|
-
if (!process.env.karin_app_runner) { process.env.karin_app_runner = 'node' }
|
|
19
|
-
if (!process.env.karin_app_start_count) { process.env.karin_app_start_count = '0' }
|
|
20
|
-
/** 正常启动 */
|
|
21
|
-
if (process.env.karin_app_runner === 'node' && process.env.karin_app_lang === 'js' && process.env.karin_app_mode === 'prod') {
|
|
22
|
-
logger.debug('当前为 JavaScript 生产模式')
|
|
23
|
-
return
|
|
24
|
-
}
|
|
25
|
-
/** pm2 */
|
|
26
|
-
if (process.env.karin_app_runner === 'pm2') {
|
|
27
|
-
logger.info('当前为 PM2 模式')
|
|
28
|
-
return
|
|
29
|
-
}
|
|
30
|
-
/** js开发模式 */
|
|
31
|
-
if (process.env.karin_app_lang === 'js' && process.env.karin_app_mode === 'dev') {
|
|
32
|
-
logger.info('当前为 JavaScript 开发模式')
|
|
33
|
-
return
|
|
34
|
-
}
|
|
35
|
-
/** ts开发模式 */
|
|
36
|
-
if (process.env.karin_app_lang === 'ts' && process.env.karin_app_mode === 'dev') {
|
|
37
|
-
logger.info('当前为 TypeScript 开发模式')
|
|
38
|
-
return
|
|
39
|
-
}
|
|
40
|
-
logger.error('未知的启动模式')
|
|
41
|
-
}
|
|
42
|
-
init()
|
package/lib/core/karin.js
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
import { server } from './server.js'
|
|
2
|
-
import { stateArr } from './plugin.js'
|
|
3
|
-
import PluginApp from './plugin.app.js'
|
|
4
|
-
import { common } from '../utils/index.js'
|
|
5
|
-
import { listener } from './listener.js'
|
|
6
|
-
import onebot11 from '../adapter/onebot/11/index.js'
|
|
7
|
-
import { render, RenderServer } from '../render/index.js'
|
|
8
|
-
export class Karin {
|
|
9
|
-
start
|
|
10
|
-
constructor () {
|
|
11
|
-
this.start = false
|
|
12
|
-
this.run()
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* - 快速构建命令
|
|
17
|
-
* @param reg - 正则表达式
|
|
18
|
-
* @param second - 函数或者字符串或者KarinElement、KarinElement数组
|
|
19
|
-
* @param options - 选项
|
|
20
|
-
* @returns - 返回插件对象
|
|
21
|
-
*/
|
|
22
|
-
command (reg, second, options = {}) {
|
|
23
|
-
reg = typeof reg === 'string' ? new RegExp(reg) : reg
|
|
24
|
-
const fnc = typeof second === 'function'
|
|
25
|
-
? second
|
|
26
|
-
: async (e) => {
|
|
27
|
-
const element = typeof second === 'number' ? String(second) : second
|
|
28
|
-
if ('delay' in options && options.delay) { await common.sleep(options.delay) }
|
|
29
|
-
await e.reply(element, {
|
|
30
|
-
at: ('at' in options && options.at) || false,
|
|
31
|
-
reply: ('reply' in options && options.reply) || false,
|
|
32
|
-
recallMsg: ('recallMsg' in options && Number(options.recallMsg)) || 0,
|
|
33
|
-
})
|
|
34
|
-
return !('stop' in options && !options.stop)
|
|
35
|
-
}
|
|
36
|
-
const data = {
|
|
37
|
-
name: options.name || 'function',
|
|
38
|
-
priority: options.priority,
|
|
39
|
-
rule: [
|
|
40
|
-
{
|
|
41
|
-
reg,
|
|
42
|
-
fnc,
|
|
43
|
-
permission: options.permission || 'all',
|
|
44
|
-
log: options.log ?? true,
|
|
45
|
-
},
|
|
46
|
-
],
|
|
47
|
-
}
|
|
48
|
-
return PluginApp(data)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* - 构建定时任务
|
|
53
|
-
* @param name - 任务名称
|
|
54
|
-
* @param cron - cron表达式
|
|
55
|
-
* @param fnc - 执行函数
|
|
56
|
-
* @param options - 选项
|
|
57
|
-
*/
|
|
58
|
-
task (name, cron, fnc, options) {
|
|
59
|
-
if (!name) { throw new Error('[task]: 缺少参数[name]') }
|
|
60
|
-
if (!cron) { throw new Error('[task]: 缺少参数[cron]') }
|
|
61
|
-
if (!fnc) { throw new Error('[task]: 缺少参数[fnc]') }
|
|
62
|
-
const data = {
|
|
63
|
-
name: options?.name || 'task',
|
|
64
|
-
priority: options?.priority,
|
|
65
|
-
task: [
|
|
66
|
-
{
|
|
67
|
-
name,
|
|
68
|
-
cron,
|
|
69
|
-
fnc,
|
|
70
|
-
log: options?.log ?? true,
|
|
71
|
-
},
|
|
72
|
-
],
|
|
73
|
-
}
|
|
74
|
-
return PluginApp(data)
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* - 构建handler
|
|
79
|
-
* @param key - 事件key
|
|
80
|
-
* @param fnc - 函数实现
|
|
81
|
-
* @param options - 选项
|
|
82
|
-
*/
|
|
83
|
-
handler (key, fnc, options) {
|
|
84
|
-
if (!key) { throw new Error('[handler]: 缺少参数[key]') }
|
|
85
|
-
if (!fnc) { throw new Error('[handler]: 缺少参数[fnc]') }
|
|
86
|
-
const priority = options?.priority || 10000
|
|
87
|
-
const data = {
|
|
88
|
-
name: options?.name || 'handler',
|
|
89
|
-
priority,
|
|
90
|
-
handler: [
|
|
91
|
-
{
|
|
92
|
-
key,
|
|
93
|
-
fnc,
|
|
94
|
-
priority,
|
|
95
|
-
},
|
|
96
|
-
],
|
|
97
|
-
}
|
|
98
|
-
return PluginApp(data)
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* 构建contact
|
|
103
|
-
* @param peer - 群号或者id
|
|
104
|
-
* @param isGroup - 是否是群聊
|
|
105
|
-
* @param sub_peer - 子id
|
|
106
|
-
*/
|
|
107
|
-
contact (peer, isGroup = true, sub_peer) {
|
|
108
|
-
if (isGroup) {
|
|
109
|
-
return {
|
|
110
|
-
scene: 'group' /* Scene.Group */,
|
|
111
|
-
peer,
|
|
112
|
-
sub_peer: sub_peer || '',
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return {
|
|
116
|
-
scene: 'friend' /* Scene.Private */,
|
|
117
|
-
peer,
|
|
118
|
-
sub_peer: sub_peer || '',
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* - 渲染
|
|
124
|
-
* @param data - 渲染参数
|
|
125
|
-
* @param multiPage - 分片高度
|
|
126
|
-
* @returns - 返回图片base64或数组
|
|
127
|
-
*/
|
|
128
|
-
render (data, multiPage) {
|
|
129
|
-
if (typeof data === 'string') {
|
|
130
|
-
/** 分片 */
|
|
131
|
-
if (typeof multiPage === 'number' || multiPage === true) {
|
|
132
|
-
return render.renderMultiHtml(data, multiPage)
|
|
133
|
-
}
|
|
134
|
-
/** 快速渲染 */
|
|
135
|
-
return render.renderHtml(data)
|
|
136
|
-
}
|
|
137
|
-
/** 正常渲染 */
|
|
138
|
-
return render.render(data)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* 上下文
|
|
143
|
-
* @param e - 消息事件
|
|
144
|
-
* @param options - 上下文选项
|
|
145
|
-
*/
|
|
146
|
-
async ctx (e, options) {
|
|
147
|
-
const time = options?.time || 120
|
|
148
|
-
const userId = options?.userId || e.user_id
|
|
149
|
-
const key = e.group_id ? `${e.group_id}.${userId}` : userId
|
|
150
|
-
stateArr[key] = { type: 'ctx' }
|
|
151
|
-
// 返回promise 设置超时时间
|
|
152
|
-
return new Promise((resolve, reject) => {
|
|
153
|
-
setTimeout(() => {
|
|
154
|
-
if (stateArr[key]) {
|
|
155
|
-
delete stateArr[key]
|
|
156
|
-
if (options?.reply) { e.reply(options.replyMsg || '操作超时已取消') }
|
|
157
|
-
reject(new Error('操作超时已取消'))
|
|
158
|
-
return true
|
|
159
|
-
}
|
|
160
|
-
}, time * 1000)
|
|
161
|
-
listener.once(`ctx:${key}`, (e) => resolve(e))
|
|
162
|
-
})
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* accept
|
|
167
|
-
* @param event - 监听事件
|
|
168
|
-
* @param fnc - 实现函数
|
|
169
|
-
*/
|
|
170
|
-
accept (event, fnc, options) {
|
|
171
|
-
const data = {
|
|
172
|
-
name: options?.name || 'accept',
|
|
173
|
-
priority: options?.priority,
|
|
174
|
-
event,
|
|
175
|
-
accept: fnc,
|
|
176
|
-
log: options?.log,
|
|
177
|
-
}
|
|
178
|
-
return PluginApp(data)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* - 启动
|
|
183
|
-
*/
|
|
184
|
-
run () {
|
|
185
|
-
if (this.start) { return }
|
|
186
|
-
this.start = true
|
|
187
|
-
server.init()
|
|
188
|
-
listener.emit('load.plugin')
|
|
189
|
-
listener.emit('adapter', RenderServer)
|
|
190
|
-
listener.emit('adapter', onebot11)
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
export const karin = new Karin()
|
|
194
|
-
export default karin
|
package/lib/core/listener.js
DELETED
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from 'events'
|
|
2
|
-
import { pluginLoader } from './plugin.loader.js'
|
|
3
|
-
import { common, logger, config, segment } from '../utils/index.js'
|
|
4
|
-
import NoticeHandler from '../event/notice.handler.js'
|
|
5
|
-
import RequestHandler from '../event/request.handler.js'
|
|
6
|
-
import { MessageHandler } from '../event/message.handler.js'
|
|
7
|
-
import { level } from '../db/index.js'
|
|
8
|
-
/**
|
|
9
|
-
* 监听器管理
|
|
10
|
-
*/
|
|
11
|
-
class Listeners extends EventEmitter {
|
|
12
|
-
/**
|
|
13
|
-
* Bot索引
|
|
14
|
-
* @type - Bot索引
|
|
15
|
-
*/
|
|
16
|
-
index
|
|
17
|
-
/**
|
|
18
|
-
* 框架名称
|
|
19
|
-
*/
|
|
20
|
-
name
|
|
21
|
-
list
|
|
22
|
-
adapter
|
|
23
|
-
constructor () {
|
|
24
|
-
super()
|
|
25
|
-
this.index = 0
|
|
26
|
-
this.name = 'Karin'
|
|
27
|
-
this.list = []
|
|
28
|
-
this.adapter = []
|
|
29
|
-
this.on('error', data => logger.error(data))
|
|
30
|
-
this.on('load.plugin', () => pluginLoader.load())
|
|
31
|
-
this.on('adapter', data => {
|
|
32
|
-
let path = data.path || '无'
|
|
33
|
-
if (path && data.type !== 'grpc') { path = `ws://127.0.0.1:${config.Server.http.port}${data.path}` }
|
|
34
|
-
path = logger.green(path)
|
|
35
|
-
logger.info(`[适配器][注册][${data.type}]: ` + path)
|
|
36
|
-
this.addAdapter(data)
|
|
37
|
-
})
|
|
38
|
-
this.on('message', data => new MessageHandler(data))
|
|
39
|
-
this.on('notice', data => new NoticeHandler(data))
|
|
40
|
-
this.on('request', data => new RequestHandler(data))
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* 注册Bot 返回索引id
|
|
45
|
-
*/
|
|
46
|
-
addBot (data) {
|
|
47
|
-
this.index++
|
|
48
|
-
const index = this.index
|
|
49
|
-
if (!data.bot) {
|
|
50
|
-
logger.error('[Bot管理][注册] 注册失败: Bot实例不能为空', JSON.stringify(data))
|
|
51
|
-
return false
|
|
52
|
-
}
|
|
53
|
-
this.list.push({ index, type: data.type, bot: data.bot })
|
|
54
|
-
logger.info(`[机器人][注册][${data.type}] ` + logger.green(`[account:${data.bot.account.uid || data.bot.account.uin}(${data.bot.account.name})]`))
|
|
55
|
-
this.#online(data.bot.account.uid || data.bot.account.uin)
|
|
56
|
-
logger.debug('注册', this.list)
|
|
57
|
-
return index
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* 发送上线通知
|
|
62
|
-
*/
|
|
63
|
-
async #online (uid) {
|
|
64
|
-
/** 重启 */
|
|
65
|
-
const key = `karin:restart:${uid}`
|
|
66
|
-
const options = await level.get(key)
|
|
67
|
-
if (!options) { return }
|
|
68
|
-
const { id, contact, time, message_id } = options
|
|
69
|
-
/** 重启花费时间 保留2位小数 */
|
|
70
|
-
const restartTime = ((Date.now() - time) / 1000).toFixed(2)
|
|
71
|
-
/** 超过2分钟不发 */
|
|
72
|
-
if (Number(restartTime) > 120) {
|
|
73
|
-
await level.del(key)
|
|
74
|
-
return false
|
|
75
|
-
}
|
|
76
|
-
const element = [
|
|
77
|
-
segment.reply(message_id),
|
|
78
|
-
segment.text(`Karin 重启成功:${restartTime}秒`),
|
|
79
|
-
]
|
|
80
|
-
await this.sendMsg(id, contact, element)
|
|
81
|
-
await level.del(key)
|
|
82
|
-
return true
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* 卸载Bot
|
|
87
|
-
* @param index - Bot的索引id
|
|
88
|
-
*/
|
|
89
|
-
delBot (index) {
|
|
90
|
-
this.list = this.list.filter(item => item.index !== index)
|
|
91
|
-
logger.debug('[机器人][卸载] ', this.list)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* 通过Bot uid 获取Bot
|
|
96
|
-
* @param uid - Bot的uid 未传入则返回第一个Bot
|
|
97
|
-
*/
|
|
98
|
-
getBot (uid = '') {
|
|
99
|
-
uid = String(uid)
|
|
100
|
-
if (this.list.length === 0) {
|
|
101
|
-
logger.error('[Bot管理][UID] 当前Bot列表为空')
|
|
102
|
-
return undefined
|
|
103
|
-
}
|
|
104
|
-
if (!uid) { return this.list[0].bot }
|
|
105
|
-
const index = this.list.findIndex(item => String(item.bot.account.uid) === uid)
|
|
106
|
-
if (index === -1) {
|
|
107
|
-
logger.error('[Bot管理][UID] 无法找到对应的 Bot 实例')
|
|
108
|
-
return undefined
|
|
109
|
-
}
|
|
110
|
-
return this.list[index].bot
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* 根据索引获取Bot
|
|
115
|
-
* @param index - Bot的索引id
|
|
116
|
-
*/
|
|
117
|
-
getBotByIndex (index) {
|
|
118
|
-
index = this.list.findIndex(item => item.index === index)
|
|
119
|
-
if (index === -1) {
|
|
120
|
-
throw new Error('[Bot管理][索引] 无法找到对应的 Bot 实例')
|
|
121
|
-
}
|
|
122
|
-
return this.list[index].bot
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* 获取当前已注册Bot数量
|
|
127
|
-
*/
|
|
128
|
-
getBotCount () {
|
|
129
|
-
return this.list.length
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* 获取所有Bot列表
|
|
134
|
-
* @param isIndex - 是否返回包含的索引列表 默认返回Bot实例列表
|
|
135
|
-
*/
|
|
136
|
-
getBotAll (isIndex = false) {
|
|
137
|
-
if (isIndex) { return this.list }
|
|
138
|
-
return this.list.map(item => item.bot)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* 注册适配器
|
|
143
|
-
* @param data - 适配器信息
|
|
144
|
-
* @param data.type - 适配器类型
|
|
145
|
-
* @param data.adapter - 适配器实例
|
|
146
|
-
* @param data.path - 适配器路径
|
|
147
|
-
*/
|
|
148
|
-
addAdapter (data) {
|
|
149
|
-
const adapter = { type: data.type, adapter: data.adapter, path: '' }
|
|
150
|
-
if (data.path) { adapter.path = data.path }
|
|
151
|
-
this.adapter.push(adapter)
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* 通过path获取适配器 仅适用于反向WS适配器
|
|
156
|
-
* @param path - 适配器路径
|
|
157
|
-
*/
|
|
158
|
-
getAdapter (path = '') {
|
|
159
|
-
const index = this.adapter.findIndex(item => item?.path === path)
|
|
160
|
-
if (index === -1) {
|
|
161
|
-
logger.error('[适配器管理] 无法找到对应的适配器实例')
|
|
162
|
-
return undefined
|
|
163
|
-
}
|
|
164
|
-
return this.adapter[index].adapter
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* 获取适配器列表
|
|
169
|
-
* @param isType - 是否返回包含的类型列表 默认返回适配器实例列表
|
|
170
|
-
*/
|
|
171
|
-
getAdapterAll (isType = false) {
|
|
172
|
-
if (isType) { return this.adapter }
|
|
173
|
-
return this.adapter.map(item => item.adapter)
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* 发送主动消息
|
|
178
|
-
* @param uid - Bot的uid
|
|
179
|
-
* @param contact - 目标信息
|
|
180
|
-
* @param elements - 消息内容
|
|
181
|
-
* @param options - 消息选项
|
|
182
|
-
* @param options.recallMsg - 发送成功后撤回消息时间
|
|
183
|
-
* @param options.retry_count - 重试次数
|
|
184
|
-
*/
|
|
185
|
-
async sendMsg (uid, contact, elements, options = { recallMsg: 0, retry_count: 1 }) {
|
|
186
|
-
const bot = this.getBot(uid)
|
|
187
|
-
if (!bot) { throw new Error('发送消息失败: 未找到对应Bot实例') }
|
|
188
|
-
const { recallMsg, retry_count } = options
|
|
189
|
-
/** 标准化 */
|
|
190
|
-
const NewElements = common.makeMessage(elements)
|
|
191
|
-
/** 结果 */
|
|
192
|
-
let result = {}
|
|
193
|
-
const reply_log = common.makeMessageLog(NewElements)
|
|
194
|
-
const self_id = bot.account.uid || bot.account.uin
|
|
195
|
-
if (contact.scene === 'group') {
|
|
196
|
-
logger.bot('info', self_id, `${logger.green('Send Proactive Group')} ${contact.peer}: ${reply_log}`)
|
|
197
|
-
} else {
|
|
198
|
-
logger.bot('info', self_id, `${logger.green('Send Proactive private')} ${contact.peer}: ${reply_log}`)
|
|
199
|
-
}
|
|
200
|
-
try {
|
|
201
|
-
this.emit('karin:count:send', 1)
|
|
202
|
-
/** 取结果 */
|
|
203
|
-
result = await bot.SendMessage(contact, NewElements, retry_count)
|
|
204
|
-
logger.bot('debug', self_id, `主动消息结果:${JSON.stringify(result, null, 2)}`)
|
|
205
|
-
} catch (error) {
|
|
206
|
-
logger.bot('error', self_id, `主动消息发送失败:${reply_log}`)
|
|
207
|
-
logger.bot('error', self_id, error)
|
|
208
|
-
}
|
|
209
|
-
/** 快速撤回 */
|
|
210
|
-
if (recallMsg && bot.RecallMessage && recallMsg > 0 && result?.message_id) {
|
|
211
|
-
setTimeout(() => bot.RecallMessage(contact, result.message_id), recallMsg * 1000)
|
|
212
|
-
}
|
|
213
|
-
return result
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
export const listener = new Listeners()
|
|
217
|
-
export const Bot = listener
|
package/lib/core/plugin.app.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export default function PluginApp (options) {
|
|
2
|
-
return {
|
|
3
|
-
file: {
|
|
4
|
-
dir: options?.file?.dir || '',
|
|
5
|
-
name: options?.file?.name || '',
|
|
6
|
-
type: options?.file?.type || 'function',
|
|
7
|
-
Fnc: options?.file?.fnc || '',
|
|
8
|
-
},
|
|
9
|
-
name: options.name || '',
|
|
10
|
-
event: options.event || 'message' /* EventType.Message */,
|
|
11
|
-
priority: options.priority || 10000,
|
|
12
|
-
accept: options.accept ?? false,
|
|
13
|
-
log: options.log ?? true,
|
|
14
|
-
rule: options.rule || [],
|
|
15
|
-
task: options.task || [],
|
|
16
|
-
handler: options.handler || [],
|
|
17
|
-
button: options.button || [],
|
|
18
|
-
}
|
|
19
|
-
}
|