@karinjs/adapter-qqbot 2.2.1 → 3.0.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.
- package/dist/apps/cleanup.d.ts +6 -2
- package/dist/apps/cleanup.js +5 -10
- package/dist/apps/login.d.ts +2 -16
- package/dist/apps/login.js +138 -85
- package/dist/config-D1_LqrcJ.js +196 -0
- package/dist/index.d.ts +409 -234
- package/dist/index.js +347 -365
- package/dist/logger-sza6kuy3.js +27 -0
- package/dist/message-CVJVFAGR.js +1844 -0
- package/dist/utils-lb9ZdWay.js +32 -0
- package/dist/web.config.d.ts +3 -5
- package/dist/web.config.js +44 -84
- package/package.json +8 -5
- package/dist/common-by1GpV0b.js +0 -49
- package/dist/config-B_Gc9JKZ.js +0 -253
- package/dist/message-Dt4QkDYn.js +0 -1739
- package/dist/onboard-BXQ1cG8h.js +0 -252
- package/dist/utils-DIq0lGMt.js +0 -4
package/dist/apps/cleanup.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
//#region src/apps/cleanup.d.ts
|
|
2
|
-
/**
|
|
3
|
-
|
|
2
|
+
/**
|
|
3
|
+
* 每 10 分钟清理一次过期的 getMsg/getHistoryMsg 本地缓存与 file_info 上传缓存。
|
|
4
|
+
*
|
|
5
|
+
* file_info 上传缓存不依赖 messageCache 开关,因此任务始终注册。
|
|
6
|
+
*/
|
|
7
|
+
declare const clearMessageCache: import("node-karin").Task;
|
|
4
8
|
//#endregion
|
|
5
9
|
export { clearMessageCache };
|
package/dist/apps/cleanup.js
CHANGED
|
@@ -1,22 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as getMessageStore } from "../message-Dt4QkDYn.js";
|
|
1
|
+
import { t as getMessageStore } from "../message-CVJVFAGR.js";
|
|
3
2
|
import karin from "node-karin";
|
|
4
3
|
|
|
5
4
|
//#region src/apps/cleanup.ts
|
|
6
5
|
/**
|
|
7
|
-
*
|
|
6
|
+
* 每 10 分钟清理一次过期的 getMsg/getHistoryMsg 本地缓存与 file_info 上传缓存。
|
|
8
7
|
*
|
|
9
|
-
*
|
|
8
|
+
* file_info 上传缓存不依赖 messageCache 开关,因此任务始终注册。
|
|
10
9
|
*/
|
|
11
|
-
const
|
|
12
|
-
return config().some((item) => item.messageCache.enable);
|
|
13
|
-
};
|
|
14
|
-
/** 每 10 分钟清理一次过期的 getMsg/getHistoryMsg 本地缓存。 */
|
|
15
|
-
const clearMessageCache = enabledMessageCache() ? karin.task("qqbot 适配器消息缓存清理", "*/10 * * * *", async () => await getMessageStore().cleanupExpired(), {
|
|
10
|
+
const clearMessageCache = karin.task("qqbot 适配器消息缓存清理", "*/10 * * * *", async () => await getMessageStore().cleanupExpired(), {
|
|
16
11
|
name: "qqbot 适配器消息缓存清理任务",
|
|
17
12
|
log: false,
|
|
18
13
|
type: "skip"
|
|
19
|
-
})
|
|
14
|
+
});
|
|
20
15
|
|
|
21
16
|
//#endregion
|
|
22
17
|
export { clearMessageCache };
|
package/dist/apps/login.d.ts
CHANGED
|
@@ -1,18 +1,4 @@
|
|
|
1
1
|
//#region src/apps/login.d.ts
|
|
2
|
-
|
|
3
|
-
* #QQ登录 指令
|
|
4
|
-
*
|
|
5
|
-
* 仅主人可用。匹配 `#QQ登录` 或 `#qqlogin`(大小写均可)。
|
|
6
|
-
* 必须带 `#` 前缀。
|
|
7
|
-
*
|
|
8
|
-
* 流程:
|
|
9
|
-
* 1. 立即回复"开始扫码"
|
|
10
|
-
* 2. 触发扫码授权流程
|
|
11
|
-
* 3. 每次生成新二维码 → 把 PNG 图片回复给触发者
|
|
12
|
-
* 4. 授权成功 → 回复结果,watch 回调自动初始化 bot
|
|
13
|
-
*
|
|
14
|
-
* ⚠ 注意:扫码授权会刷新该 appId 的 secret,旧 secret 立即失效
|
|
15
|
-
*/
|
|
16
|
-
declare const qqLogin: import("node-karin").Command<keyof import("node-karin").MessageEventMap>;
|
|
2
|
+
declare const QQBotLogin: import("node-karin").Command<keyof import("node-karin").MessageEventMap>;
|
|
17
3
|
//#endregion
|
|
18
|
-
export {
|
|
4
|
+
export { QQBotLogin };
|
package/dist/apps/login.js
CHANGED
|
@@ -1,106 +1,159 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as runQrOnboard } from "../onboard-BXQ1cG8h.js";
|
|
1
|
+
import { i as getDefaultConfig, n as config } from "../config-D1_LqrcJ.js";
|
|
3
2
|
import karin, { segment } from "node-karin";
|
|
3
|
+
import qrcode from "qrcode";
|
|
4
|
+
import axios from "node-karin/axios";
|
|
5
|
+
import crypto from "node:crypto";
|
|
4
6
|
|
|
5
|
-
//#region src/
|
|
7
|
+
//#region src/core/qrcode/session.ts
|
|
8
|
+
const BASEURL = "q.qq.com";
|
|
9
|
+
const headers = {
|
|
10
|
+
"Content-Type": "application/json",
|
|
11
|
+
Accept: "application/json"
|
|
12
|
+
};
|
|
13
|
+
/** 生成随机密钥 */
|
|
14
|
+
const RandomKey = () => {
|
|
15
|
+
return crypto.randomBytes(32).toString("base64");
|
|
16
|
+
};
|
|
6
17
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* 流程:
|
|
13
|
-
* 1. 立即回复"开始扫码"
|
|
14
|
-
* 2. 触发扫码授权流程
|
|
15
|
-
* 3. 每次生成新二维码 → 把 PNG 图片回复给触发者
|
|
16
|
-
* 4. 授权成功 → 回复结果,watch 回调自动初始化 bot
|
|
17
|
-
*
|
|
18
|
-
* ⚠ 注意:扫码授权会刷新该 appId 的 secret,旧 secret 立即失效
|
|
18
|
+
* 解密密钥
|
|
19
|
+
* @param encryptedBase64
|
|
20
|
+
* @param keyBase64
|
|
21
|
+
* @returns
|
|
19
22
|
*/
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
const decryptSecret = (encryptedBase64, keyBase64) => {
|
|
24
|
+
const key = Buffer.from(keyBase64, "base64");
|
|
25
|
+
const data = Buffer.from(encryptedBase64, "base64");
|
|
26
|
+
const IV = data.subarray(0, 12);
|
|
27
|
+
const authtag = data.subarray(data.length - 16);
|
|
28
|
+
const ciphertext = data.subarray(12, data.length - 16);
|
|
29
|
+
const decipher = crypto.createDecipheriv("aes-256-gcm", key, IV);
|
|
30
|
+
decipher.setAuthTag(authtag);
|
|
31
|
+
return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
|
|
32
|
+
};
|
|
22
33
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
34
|
+
* 创建绑定任务
|
|
35
|
+
* @param timeout 超时时间
|
|
25
36
|
*/
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
|
|
37
|
+
const createBindTask = async (timeout = 1e4) => {
|
|
38
|
+
const url = `https://${BASEURL}/lite/create_bind_task`;
|
|
39
|
+
const key = RandomKey();
|
|
40
|
+
const { data } = await axios.post(url, { key }, {
|
|
41
|
+
headers,
|
|
42
|
+
timeout
|
|
43
|
+
});
|
|
44
|
+
if (data.retcode !== 0) throw new Error(data.msg ?? "创建绑定任务失败");
|
|
45
|
+
if (!data.data?.task_id) throw new Error("创建绑定任务失败: task_id 缺失");
|
|
46
|
+
return {
|
|
47
|
+
taskId: data.data.task_id,
|
|
48
|
+
aesKey: key
|
|
49
|
+
};
|
|
31
50
|
};
|
|
32
51
|
/**
|
|
33
|
-
*
|
|
34
|
-
* @param
|
|
35
|
-
* @param
|
|
52
|
+
* 查询绑定结果
|
|
53
|
+
* @param taskId 任务id
|
|
54
|
+
* @param timeout 超时时间
|
|
36
55
|
*/
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
|
|
56
|
+
const checkBindResult = async (taskId, timeout = 1e4) => {
|
|
57
|
+
const url = `https://${BASEURL}/lite/poll_bind_result`;
|
|
58
|
+
const { data } = await axios.post(url, { task_id: taskId }, {
|
|
59
|
+
headers,
|
|
60
|
+
timeout
|
|
61
|
+
});
|
|
62
|
+
if (data.retcode !== 0) throw new Error(data.msg ?? "查询绑定结果失败");
|
|
63
|
+
return {
|
|
64
|
+
status: data.data?.status ?? 0,
|
|
65
|
+
appId: String(data.data?.bot_appid ?? ""),
|
|
66
|
+
encryptedSecret: data.data?.bot_encrypt_secret ?? "",
|
|
67
|
+
userOpenid: data.data?.user_openid ?? void 0
|
|
68
|
+
};
|
|
40
69
|
};
|
|
70
|
+
/** 构建连接URL */
|
|
71
|
+
const buildConnectUrl = (taskId) => `https://${BASEURL}/qqbot/openclaw/connect.html?task_id=${encodeURIComponent(taskId)}&source=karin&_wv=2`;
|
|
72
|
+
|
|
73
|
+
//#endregion
|
|
74
|
+
//#region src/core/qrcode/qr.ts
|
|
75
|
+
const WaitingMS = 2e3;
|
|
41
76
|
/**
|
|
42
|
-
*
|
|
43
|
-
* @param
|
|
44
|
-
* @param
|
|
45
|
-
* @
|
|
77
|
+
* 轮询绑定结果
|
|
78
|
+
* @param taskId 任务ID
|
|
79
|
+
* @param key 解密密钥
|
|
80
|
+
* @returns QQBot 的appid与secret
|
|
46
81
|
*/
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
82
|
+
const PollBindResult = async (taskId, key) => {
|
|
83
|
+
while (true) {
|
|
84
|
+
let data;
|
|
85
|
+
try {
|
|
86
|
+
data = await checkBindResult(taskId);
|
|
87
|
+
} catch {
|
|
88
|
+
await new Promise((resolve) => setTimeout(resolve, WaitingMS));
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (data.status === 2) {
|
|
92
|
+
const secret = decryptSecret(data.encryptedSecret, key);
|
|
93
|
+
return {
|
|
94
|
+
status: data.status,
|
|
95
|
+
appId: data.appId,
|
|
96
|
+
secret
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
if (data.status === 3) return { status: data.status };
|
|
100
|
+
await new Promise((resolve) => setTimeout(resolve, WaitingMS));
|
|
52
101
|
}
|
|
53
|
-
messageIds.length = 0;
|
|
54
102
|
};
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
* @param elements 回复内容。
|
|
65
|
-
*/
|
|
66
|
-
const replyAndTrack = async (elements) => {
|
|
67
|
-
const result = await e.reply(elements);
|
|
68
|
-
trackReply(result, messageIds);
|
|
69
|
-
return result;
|
|
103
|
+
|
|
104
|
+
//#endregion
|
|
105
|
+
//#region src/apps/login.ts
|
|
106
|
+
let busy = false;
|
|
107
|
+
const QQBotLogin = karin.command(/^#qqbot(登录|login)$/i, async (e) => {
|
|
108
|
+
const msgIds = [];
|
|
109
|
+
const reply = async (elements) => {
|
|
110
|
+
const res = await e.reply(elements, { at: true });
|
|
111
|
+
msgIds.push(res.messageId);
|
|
70
112
|
};
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
segment.image(base64),
|
|
82
|
-
segment.text(`或在手机 QQ 打开链接:\n${url}`)
|
|
83
|
-
]);
|
|
84
|
-
} catch (err) {
|
|
85
|
-
log("warn", "[扫码登录] 推送二维码失败:", err);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
113
|
+
if (busy) return await e.reply("已有扫码授权在进行中,请稍候再试", { reply: true });
|
|
114
|
+
busy = true;
|
|
115
|
+
await reply("注意: 确认登录后将刷新 QQBot 的 AppSecret,旧的 AppSecret 将失效");
|
|
116
|
+
const task = await createBindTask();
|
|
117
|
+
const url = buildConnectUrl(task.taskId);
|
|
118
|
+
const msg = [segment.text("请使用 QQ 扫码登录")];
|
|
119
|
+
if (e.bot.adapter.protocol === "console") {
|
|
120
|
+
const qrcode$1 = await qrcode.toString(url, {
|
|
121
|
+
type: "terminal",
|
|
122
|
+
small: true
|
|
88
123
|
});
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
124
|
+
msg.push(segment.text(`\n${qrcode$1}`));
|
|
125
|
+
} else {
|
|
126
|
+
const qrcode$2 = await qrcode.toDataURL(url);
|
|
127
|
+
msg.push(segment.image(qrcode$2));
|
|
128
|
+
}
|
|
129
|
+
msg.push(segment.text(`或使用手机 QQ 打开链接登录: ${url}`));
|
|
130
|
+
await reply(msg);
|
|
131
|
+
const ok = await PollBindResult(task.taskId, task.aesKey);
|
|
132
|
+
msgIds.forEach(async (id) => {
|
|
133
|
+
await e.bot.recallMsg(e.contact, id).catch(() => {});
|
|
134
|
+
});
|
|
135
|
+
if (ok.status === 2) {
|
|
136
|
+
const list = config();
|
|
137
|
+
const idx = list.findIndex((item) => item.appId === ok.appId);
|
|
138
|
+
if (idx >= 0) {
|
|
139
|
+
list[idx].secret = ok.secret;
|
|
140
|
+
e.reply(`Bot存在,已更新[${ok.appId}]配置`, { reply: true });
|
|
141
|
+
} else {
|
|
142
|
+
const defaults = getDefaultConfig()[0];
|
|
143
|
+
list.push({
|
|
144
|
+
...defaults,
|
|
145
|
+
appId: ok.appId,
|
|
146
|
+
secret: ok.secret
|
|
147
|
+
});
|
|
148
|
+
e.reply(`[${ok.appId}] 扫码登录成功`, { reply: true });
|
|
149
|
+
}
|
|
150
|
+
return;
|
|
98
151
|
}
|
|
152
|
+
return await e.reply("二维码过期,请重新触发指令", { reply: true });
|
|
99
153
|
}, {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
authFailMsg: "#QQ登录 仅限主人使用"
|
|
154
|
+
perm: "master",
|
|
155
|
+
name: "QQBot 扫码登录"
|
|
103
156
|
});
|
|
104
157
|
|
|
105
158
|
//#endregion
|
|
106
|
-
export {
|
|
159
|
+
export { QQBotLogin };
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { common, karinPathBase, logger, requireFileSync, watch } from "node-karin";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
|
|
6
|
+
//#region src/root.ts
|
|
7
|
+
/** 当前文件的绝对路径 */
|
|
8
|
+
const filePath = fileURLToPath(import.meta.url);
|
|
9
|
+
/** 插件包绝对路径 */
|
|
10
|
+
const dirPath = path.resolve(filePath, "../..");
|
|
11
|
+
/** 插件包的名称 */
|
|
12
|
+
const basename = path.basename(dirPath);
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/utils/plugin.ts
|
|
16
|
+
/**
|
|
17
|
+
* 读取当前插件的 package.json。
|
|
18
|
+
*
|
|
19
|
+
* @returns package.json 内容。
|
|
20
|
+
*/
|
|
21
|
+
const pkg = () => requireFileSync(`${dirPath}/package.json`);
|
|
22
|
+
/** 当前插件 npm 包名,如 @karinjs/adapter-qqbot。 */
|
|
23
|
+
const pluginName = pkg().name;
|
|
24
|
+
/** 文件系统目录名:把 npm 包名里的 `/` 规范化为 `-`,与 Karin 框架对齐。 */
|
|
25
|
+
const pluginDirName = pluginName.replace(/\//g, "-");
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/utils/config.ts
|
|
29
|
+
let cache;
|
|
30
|
+
const cacheMap = {};
|
|
31
|
+
/** 延迟注入,避免与 core/index.ts 循环依赖 */
|
|
32
|
+
let _createBot;
|
|
33
|
+
let _destroyBot;
|
|
34
|
+
const bindHandlers = (createBot, destroyBot) => {
|
|
35
|
+
_createBot = createBot;
|
|
36
|
+
_destroyBot = destroyBot;
|
|
37
|
+
};
|
|
38
|
+
/** 配置目录:${karinPathBase}/@karinjs-adapter-qqbot/config */
|
|
39
|
+
const dirConfig = `${karinPathBase}/${pluginDirName}/config`;
|
|
40
|
+
const configPath = `${dirConfig}/config.json`;
|
|
41
|
+
const syncCache = (data) => {
|
|
42
|
+
cache = data;
|
|
43
|
+
Object.keys(cacheMap).forEach((key) => delete cacheMap[key]);
|
|
44
|
+
data.forEach((v) => {
|
|
45
|
+
cacheMap[v.appId] = v;
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* 读取配置
|
|
50
|
+
*/
|
|
51
|
+
const config = () => {
|
|
52
|
+
if (!fs.existsSync(configPath)) {
|
|
53
|
+
fs.mkdirSync(dirConfig, { recursive: true });
|
|
54
|
+
fs.writeFileSync(configPath, JSON.stringify([], null, 2));
|
|
55
|
+
}
|
|
56
|
+
if (cache) return cache;
|
|
57
|
+
const user = requireFileSync(configPath);
|
|
58
|
+
const result = formatConfig(user);
|
|
59
|
+
syncCache(result);
|
|
60
|
+
return result;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* 直接从磁盘读取配置,不使用内存缓存。
|
|
64
|
+
*/
|
|
65
|
+
const readConfigFile = () => {
|
|
66
|
+
if (!fs.existsSync(configPath)) return config();
|
|
67
|
+
return formatConfig(requireFileSync(configPath));
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* 获取单 bot 配置
|
|
71
|
+
*/
|
|
72
|
+
const getConfig = (appid) => cacheMap[appid];
|
|
73
|
+
/**
|
|
74
|
+
* 写入配置
|
|
75
|
+
*/
|
|
76
|
+
const writeConfig = (data) => {
|
|
77
|
+
fs.mkdirSync(dirConfig, { recursive: true });
|
|
78
|
+
const normalized = formatConfig(data);
|
|
79
|
+
fs.writeFileSync(configPath, JSON.stringify(normalized, null, 2));
|
|
80
|
+
syncCache(normalized);
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* 用默认值补齐用户配置
|
|
84
|
+
*/
|
|
85
|
+
const formatConfig = (user) => {
|
|
86
|
+
const def = getDefaultConfig()[0];
|
|
87
|
+
return user.map((item) => {
|
|
88
|
+
const { markdown, messageCache, event, ...rest } = item;
|
|
89
|
+
return {
|
|
90
|
+
...def,
|
|
91
|
+
...rest,
|
|
92
|
+
markdown: {
|
|
93
|
+
...def.markdown,
|
|
94
|
+
...markdown
|
|
95
|
+
},
|
|
96
|
+
messageCache: normalizeMessageCache(def.messageCache, messageCache),
|
|
97
|
+
event: {
|
|
98
|
+
...def.event,
|
|
99
|
+
...event
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
const MESSAGE_CACHE_LEVELS = [
|
|
105
|
+
"minimal",
|
|
106
|
+
"standard",
|
|
107
|
+
"full"
|
|
108
|
+
];
|
|
109
|
+
/**
|
|
110
|
+
* 规范化消息缓存配置,非法枚举与越界数值回落默认值。
|
|
111
|
+
*
|
|
112
|
+
* @param def 默认消息缓存配置。
|
|
113
|
+
* @param user 用户消息缓存配置。
|
|
114
|
+
* @returns 补齐并夹取后的消息缓存配置。
|
|
115
|
+
*/
|
|
116
|
+
const normalizeMessageCache = (def, user) => {
|
|
117
|
+
const merged = {
|
|
118
|
+
...def,
|
|
119
|
+
...user
|
|
120
|
+
};
|
|
121
|
+
return {
|
|
122
|
+
enable: !!merged.enable,
|
|
123
|
+
self: !!merged.self,
|
|
124
|
+
level: MESSAGE_CACHE_LEVELS.includes(merged.level) ? merged.level : def.level,
|
|
125
|
+
ttlHours: clampNumber(merged.ttlHours, 1, 720, def.ttlHours),
|
|
126
|
+
maxRows: clampNumber(merged.maxRows, 1e3, 5e6, def.maxRows)
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* 将数值夹取到闭区间;非法值返回 fallback。
|
|
131
|
+
*
|
|
132
|
+
* @param value 用户输入值。
|
|
133
|
+
* @param min 最小值。
|
|
134
|
+
* @param max 最大值。
|
|
135
|
+
* @param fallback 非法时使用的默认值。
|
|
136
|
+
* @returns 合法数值。
|
|
137
|
+
*/
|
|
138
|
+
const clampNumber = (value, min, max, fallback) => {
|
|
139
|
+
const num = Number(value);
|
|
140
|
+
if (!Number.isFinite(num)) return fallback;
|
|
141
|
+
return Math.min(Math.max(Math.trunc(num), min), max);
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* 默认配置
|
|
145
|
+
*/
|
|
146
|
+
const getDefaultConfig = () => [{
|
|
147
|
+
appId: "",
|
|
148
|
+
secret: "",
|
|
149
|
+
qqEnable: true,
|
|
150
|
+
guildEnable: true,
|
|
151
|
+
guildMode: 0,
|
|
152
|
+
regex: [{
|
|
153
|
+
reg: "^/",
|
|
154
|
+
rep: "#"
|
|
155
|
+
}],
|
|
156
|
+
markdown: { enable: true },
|
|
157
|
+
messageCache: {
|
|
158
|
+
enable: false,
|
|
159
|
+
self: false,
|
|
160
|
+
level: "standard",
|
|
161
|
+
ttlHours: 24,
|
|
162
|
+
maxRows: 2e5
|
|
163
|
+
},
|
|
164
|
+
event: { type: 2 }
|
|
165
|
+
}];
|
|
166
|
+
/**
|
|
167
|
+
* 监听配置文件,比较前后差异决定重建 / 销毁 bot
|
|
168
|
+
*/
|
|
169
|
+
setTimeout(() => {
|
|
170
|
+
watch(`${dirConfig}/config.json`, (old, now) => {
|
|
171
|
+
const oldConfig = formatConfig(old);
|
|
172
|
+
const nowConfig = formatConfig(now);
|
|
173
|
+
syncCache(nowConfig);
|
|
174
|
+
const diff = common.diffArray(oldConfig, nowConfig);
|
|
175
|
+
diff.removed.forEach((v) => _destroyBot?.(v.appId));
|
|
176
|
+
if (diff.added.length > 0) {
|
|
177
|
+
const ids = new Set(diff.added.map((v) => v.appId));
|
|
178
|
+
nowConfig.forEach((v) => {
|
|
179
|
+
if (!ids.has(v.appId)) return;
|
|
180
|
+
if (v.event.type === 0) return;
|
|
181
|
+
_createBot?.(v);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
diff.common.forEach((curr) => {
|
|
185
|
+
const prev = oldConfig.find((c) => c.appId === curr.appId);
|
|
186
|
+
if (!prev) return;
|
|
187
|
+
if (JSON.stringify(prev) === JSON.stringify(curr)) return;
|
|
188
|
+
logger.info(`[QQ Official Bot][配置监听] 配置已变更: ${curr.appId},重新初始化`);
|
|
189
|
+
_destroyBot?.(prev.appId);
|
|
190
|
+
if (curr.event.type !== 0) _createBot?.(curr);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
}, 2e3);
|
|
194
|
+
|
|
195
|
+
//#endregion
|
|
196
|
+
export { readConfigFile as a, pluginDirName as c, getDefaultConfig as i, basename as l, config as n, writeConfig as o, getConfig as r, pkg as s, bindHandlers as t };
|