@alemonjs/qq-bot 2.1.0-alpha.14 → 2.1.0-alpha.16
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/lib/index.js +4 -14
- package/lib/index.webhook.js +3 -2
- package/lib/index.websoket.js +47 -23
- package/lib/register.js +43 -1
- package/lib/sdk/api.js +3 -3
- package/lib/sdk/client.websoket.js +3 -3
- package/lib/sends.js +8 -1
- package/package.json +1 -1
- package/lib/index.group.js +0 -20
- package/lib/index.guild.js +0 -37
- package/lib/register.d.ts +0 -3
- package/lib/sdk/client.websoket.group.js +0 -221
- package/lib/sdk/client.websoket.guild.js +0 -205
- package/lib/sdk/counter.js +0 -19
- package/lib/sdk/from.js +0 -44
- /package/lib/sdk/{client.js → client.webhook.js} +0 -0
package/lib/index.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { getConfigValue } from 'alemonjs';
|
|
2
|
-
import { start } from './index.
|
|
3
|
-
import { start as start$1 } from './index.
|
|
4
|
-
import { start as start$2 } from './index.webhook.js';
|
|
5
|
-
import { start as start$3 } from './index.websoket.js';
|
|
2
|
+
import { start } from './index.webhook.js';
|
|
3
|
+
import { start as start$1 } from './index.websoket.js';
|
|
6
4
|
import { platform } from './config.js';
|
|
7
5
|
export { useClient, useMode, useValue } from './hook.js';
|
|
8
6
|
export { QQBotAPI as API } from './sdk/api.js';
|
|
@@ -13,20 +11,12 @@ var index = () => {
|
|
|
13
11
|
if (!value)
|
|
14
12
|
value = {};
|
|
15
13
|
const config = value[platform];
|
|
16
|
-
if (config?.
|
|
14
|
+
if (config?.route || config?.port || config?.ws) {
|
|
17
15
|
start();
|
|
18
16
|
return;
|
|
19
17
|
}
|
|
20
|
-
else if (config?.mode == 'group') {
|
|
21
|
-
start$1();
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
else if (config?.route || config?.port || config?.ws) {
|
|
25
|
-
start$2();
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
18
|
else {
|
|
29
|
-
start$
|
|
19
|
+
start$1();
|
|
30
20
|
}
|
|
31
21
|
};
|
|
32
22
|
|
package/lib/index.webhook.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { QQBotClient } from './sdk/client.js';
|
|
1
|
+
import { QQBotClient } from './sdk/client.webhook.js';
|
|
2
2
|
import { register } from './register.js';
|
|
3
3
|
import { getQQBotConfig } from './config.js';
|
|
4
4
|
|
|
5
5
|
const start = () => {
|
|
6
6
|
const config = getQQBotConfig();
|
|
7
|
+
const { master_id, master_key, ...cfgConfig } = config;
|
|
7
8
|
const client = new QQBotClient({
|
|
8
|
-
...
|
|
9
|
+
...cfgConfig
|
|
9
10
|
});
|
|
10
11
|
// 连接
|
|
11
12
|
client.connect();
|
package/lib/index.websoket.js
CHANGED
|
@@ -1,30 +1,54 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import {QQBotClients} from './sdk/client.websoket.js';
|
|
2
|
+
import {register} from './register.js';
|
|
3
|
+
import {getQQBotConfig} from './config.js';
|
|
4
4
|
|
|
5
5
|
const start = () => {
|
|
6
6
|
const config = getQQBotConfig();
|
|
7
|
+
const notPrivateIntents = [
|
|
8
|
+
'GUILDS', // base
|
|
9
|
+
'GUILD_MEMBERS', // base
|
|
10
|
+
'GUILD_MESSAGE_REACTIONS',
|
|
11
|
+
'DIRECT_MESSAGE',
|
|
12
|
+
'PUBLIC_GUILD_MESSAGES'
|
|
13
|
+
];
|
|
14
|
+
const isPrivateIntents = [
|
|
15
|
+
'GUILDS', // base
|
|
16
|
+
'GUILD_MEMBERS', // base
|
|
17
|
+
'GUILD_MESSAGES',
|
|
18
|
+
'GUILD_MESSAGE_REACTIONS',
|
|
19
|
+
'DIRECT_MESSAGE',
|
|
20
|
+
'FORUMS_EVENT'
|
|
21
|
+
];
|
|
22
|
+
const isGroupIntents = [
|
|
23
|
+
'GROUP_AND_C2C_EVENT'
|
|
24
|
+
];
|
|
25
|
+
const pubIntents = [
|
|
26
|
+
'INTERACTION',
|
|
27
|
+
];
|
|
28
|
+
const intents = [];
|
|
29
|
+
if (config?.mode == 'guild') {
|
|
30
|
+
if (config?.is_private) {
|
|
31
|
+
intents.push(...isPrivateIntents, ...pubIntents);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
intents.push(...notPrivateIntents, ...pubIntents);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else if (config?.mode == 'group') {
|
|
38
|
+
intents.push(...isGroupIntents, ...pubIntents);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
if (config?.is_private) {
|
|
42
|
+
intents.push(...isPrivateIntents, ...pubIntents);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
intents.push(...notPrivateIntents, ...isGroupIntents, ...pubIntents);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const curI = config?.intents || intents;
|
|
7
49
|
const client = new QQBotClients({
|
|
8
50
|
...config,
|
|
9
|
-
intents:
|
|
10
|
-
? [
|
|
11
|
-
'GUILDS', // base
|
|
12
|
-
'GUILD_MEMBERS', // base
|
|
13
|
-
'GUILD_MESSAGES',
|
|
14
|
-
'GUILD_MESSAGE_REACTIONS',
|
|
15
|
-
'DIRECT_MESSAGE',
|
|
16
|
-
'INTERACTION',
|
|
17
|
-
'FORUMS_EVENT'
|
|
18
|
-
]
|
|
19
|
-
: [
|
|
20
|
-
'GUILDS', // base
|
|
21
|
-
'GUILD_MEMBERS', // base
|
|
22
|
-
'GUILD_MESSAGE_REACTIONS',
|
|
23
|
-
'DIRECT_MESSAGE',
|
|
24
|
-
'INTERACTION',
|
|
25
|
-
'PUBLIC_GUILD_MESSAGES',
|
|
26
|
-
'GROUP_AND_C2C_EVENT'
|
|
27
|
-
],
|
|
51
|
+
intents: curI,
|
|
28
52
|
is_private: config?.is_private ?? false,
|
|
29
53
|
sandbox: config?.sandbox ?? false,
|
|
30
54
|
shard: config?.shard ?? [0, 1],
|
|
@@ -35,4 +59,4 @@ const start = () => {
|
|
|
35
59
|
register(client);
|
|
36
60
|
};
|
|
37
61
|
|
|
38
|
-
export {
|
|
62
|
+
export {start};
|
package/lib/register.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { cbpPlatform, ResultCode, createResult } from 'alemonjs';
|
|
2
2
|
import { GROUP_AT_MESSAGE_CREATE, C2C_MESSAGE_CREATE, DIRECT_MESSAGE_CREATE, AT_MESSAGE_CREATE, MESSAGE_CREATE } from './sends.js';
|
|
3
|
-
import { getQQBotConfig,
|
|
3
|
+
import { getQQBotConfig, platform, getMaster } from './config.js';
|
|
4
4
|
|
|
5
5
|
const register = (client) => {
|
|
6
6
|
const config = getQQBotConfig();
|
|
@@ -20,6 +20,48 @@ const register = (client) => {
|
|
|
20
20
|
const createUserAvatarURL = (author_id) => {
|
|
21
21
|
return `https://q.qlogo.cn/qqapp/${config.app_id}/${author_id}/640`;
|
|
22
22
|
};
|
|
23
|
+
client.on('GROUP_ADD_ROBOT', async (event) => {
|
|
24
|
+
// 机器人加入群组
|
|
25
|
+
const e = {
|
|
26
|
+
name: 'guild.join',
|
|
27
|
+
Platform: platform,
|
|
28
|
+
GuildId: event.group_openid,
|
|
29
|
+
ChannelId: event.group_openid,
|
|
30
|
+
SpaceId: `GROUP:${event.group_openid}`,
|
|
31
|
+
UserId: event.op_member_openid,
|
|
32
|
+
UserKey: event.op_member_openid,
|
|
33
|
+
UserAvatar: createUserAvatarURL(event.op_member_openid),
|
|
34
|
+
IsMaster: false,
|
|
35
|
+
IsBot: false,
|
|
36
|
+
OpenId: `C2C:${event.op_member_openid}`,
|
|
37
|
+
MessageId: '',
|
|
38
|
+
CreateAt: Date.now(),
|
|
39
|
+
tag: 'GROUP_DEL_ROBOT',
|
|
40
|
+
value: event
|
|
41
|
+
};
|
|
42
|
+
cbp.send(e);
|
|
43
|
+
});
|
|
44
|
+
client.on('GROUP_DEL_ROBOT', async (event) => {
|
|
45
|
+
// 机器人离开群组
|
|
46
|
+
const e = {
|
|
47
|
+
name: 'guild.exit',
|
|
48
|
+
Platform: platform,
|
|
49
|
+
GuildId: event.group_openid,
|
|
50
|
+
ChannelId: event.group_openid,
|
|
51
|
+
SpaceId: `GROUP:${event.group_openid}`,
|
|
52
|
+
UserId: event.op_member_openid,
|
|
53
|
+
UserKey: event.op_member_openid,
|
|
54
|
+
UserAvatar: createUserAvatarURL(event.op_member_openid),
|
|
55
|
+
IsMaster: false,
|
|
56
|
+
IsBot: false,
|
|
57
|
+
OpenId: `C2C:${event.op_member_openid}`,
|
|
58
|
+
MessageId: '',
|
|
59
|
+
CreateAt: Date.now(),
|
|
60
|
+
tag: 'GROUP_DEL_ROBOT',
|
|
61
|
+
value: event
|
|
62
|
+
};
|
|
63
|
+
cbp.send(e);
|
|
64
|
+
});
|
|
23
65
|
// 监听消息
|
|
24
66
|
client.on('GROUP_AT_MESSAGE_CREATE', async (event) => {
|
|
25
67
|
const UserId = event.author.id;
|
package/lib/sdk/api.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
import { config } from './config.js';
|
|
3
3
|
import FormData from 'form-data';
|
|
4
|
-
import { createPicFrom } from '
|
|
4
|
+
import { createPicFrom } from 'alemonjs/utils';
|
|
5
5
|
|
|
6
6
|
const BOTS_API_RUL = 'https://bots.qq.com';
|
|
7
7
|
const API_URL_SANDBOX = 'https://sandbox.api.sgroup.qq.com';
|
|
@@ -250,7 +250,7 @@ class QQBotAPI {
|
|
|
250
250
|
}
|
|
251
251
|
}
|
|
252
252
|
if (image) {
|
|
253
|
-
const from = await createPicFrom(image);
|
|
253
|
+
const from = await createPicFrom({ image });
|
|
254
254
|
if (from) {
|
|
255
255
|
const { picData, name } = from;
|
|
256
256
|
formdata.append('file_image', picData, name);
|
|
@@ -280,7 +280,7 @@ class QQBotAPI {
|
|
|
280
280
|
}
|
|
281
281
|
}
|
|
282
282
|
if (image) {
|
|
283
|
-
const from = await createPicFrom(image);
|
|
283
|
+
const from = await createPicFrom({ image });
|
|
284
284
|
if (from) {
|
|
285
285
|
const { picData, name } = from;
|
|
286
286
|
formdata.append('file_image', picData, name);
|
|
@@ -2,7 +2,7 @@ import WebSocket from 'ws';
|
|
|
2
2
|
import { QQBotAPI } from './api.js';
|
|
3
3
|
import { config } from './config.js';
|
|
4
4
|
import { getIntentsMask } from './intents.js';
|
|
5
|
-
import { Counter } from '
|
|
5
|
+
import { Counter } from 'alemonjs/utils';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* 连接
|
|
@@ -99,7 +99,7 @@ class QQBotClients extends QQBotAPI {
|
|
|
99
99
|
return;
|
|
100
100
|
// 重新连接的逻辑
|
|
101
101
|
const reconnect = async () => {
|
|
102
|
-
if (this.#counter.
|
|
102
|
+
if (this.#counter.value >= 5) {
|
|
103
103
|
console.info('The maximum number of reconnections has been reached, cancel reconnection');
|
|
104
104
|
return;
|
|
105
105
|
}
|
|
@@ -108,7 +108,7 @@ class QQBotClients extends QQBotAPI {
|
|
|
108
108
|
// 重新starrt
|
|
109
109
|
start();
|
|
110
110
|
// 记录
|
|
111
|
-
this.#counter.
|
|
111
|
+
this.#counter.next();
|
|
112
112
|
}, 5000);
|
|
113
113
|
};
|
|
114
114
|
const start = () => {
|
package/lib/sends.js
CHANGED
|
@@ -216,7 +216,14 @@ const createMarkdownText = (data) => {
|
|
|
216
216
|
});
|
|
217
217
|
return `${listStr}\n`;
|
|
218
218
|
}
|
|
219
|
-
|
|
219
|
+
else if (mdItem.type === 'MD.code') {
|
|
220
|
+
const language = mdItem?.options?.language || '';
|
|
221
|
+
return `\`\`\`${language}\n${mdItem.value}\n\`\`\`\n`;
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
const value = mdItem['value'] || '';
|
|
225
|
+
return String(value);
|
|
226
|
+
}
|
|
220
227
|
})
|
|
221
228
|
.join('');
|
|
222
229
|
return content;
|
package/package.json
CHANGED
package/lib/index.group.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { QQBotGroupClient } from './sdk/client.websoket.group.js';
|
|
2
|
-
import { register } from './register.js';
|
|
3
|
-
import { getQQBotConfig } from './config.js';
|
|
4
|
-
|
|
5
|
-
const start = () => {
|
|
6
|
-
const config = getQQBotConfig();
|
|
7
|
-
// intents 需要默认值
|
|
8
|
-
const client = new QQBotGroupClient({
|
|
9
|
-
...config,
|
|
10
|
-
intents: config?.intents ?? ['GROUP_AND_C2C_EVENT'],
|
|
11
|
-
is_private: config?.is_private ?? false,
|
|
12
|
-
sandbox: config?.sandbox ?? false,
|
|
13
|
-
shard: config?.shard ?? [0, 1]
|
|
14
|
-
});
|
|
15
|
-
// 连接
|
|
16
|
-
client.connect(config?.gatewayURL);
|
|
17
|
-
register(client);
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export { start };
|
package/lib/index.guild.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { getQQBotConfig } from './config.js';
|
|
2
|
-
import { register } from './register.js';
|
|
3
|
-
import { QQBotGuildClient } from './sdk/client.websoket.guild.js';
|
|
4
|
-
|
|
5
|
-
const start = () => {
|
|
6
|
-
const config = getQQBotConfig();
|
|
7
|
-
// intents 需要默认值
|
|
8
|
-
const client = new QQBotGuildClient({
|
|
9
|
-
...config,
|
|
10
|
-
intents: config?.intents ?? config?.is_private
|
|
11
|
-
? [
|
|
12
|
-
'GUILDS', // base
|
|
13
|
-
'GUILD_MEMBERS', // base
|
|
14
|
-
'GUILD_MESSAGES',
|
|
15
|
-
'GUILD_MESSAGE_REACTIONS',
|
|
16
|
-
'DIRECT_MESSAGE',
|
|
17
|
-
'INTERACTION',
|
|
18
|
-
'FORUMS_EVENT'
|
|
19
|
-
]
|
|
20
|
-
: [
|
|
21
|
-
'GUILDS', // base
|
|
22
|
-
'GUILD_MEMBERS', // base
|
|
23
|
-
'GUILD_MESSAGE_REACTIONS',
|
|
24
|
-
'DIRECT_MESSAGE',
|
|
25
|
-
'INTERACTION',
|
|
26
|
-
'PUBLIC_GUILD_MESSAGES'
|
|
27
|
-
],
|
|
28
|
-
is_private: config?.is_private ?? false,
|
|
29
|
-
sandbox: config?.sandbox ?? false,
|
|
30
|
-
shard: config?.shard ?? [0, 1]
|
|
31
|
-
});
|
|
32
|
-
// 连接
|
|
33
|
-
client.connect(config?.gatewayURL);
|
|
34
|
-
register(client);
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export { start };
|
package/lib/register.d.ts
DELETED
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
import WebSocket from 'ws';
|
|
2
|
-
import { QQBotAPI } from './api.js';
|
|
3
|
-
import { config } from './config.js';
|
|
4
|
-
import { getIntentsMask } from './intents.js';
|
|
5
|
-
import { Counter } from './counter.js';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* 连接
|
|
9
|
-
*/
|
|
10
|
-
class QQBotGroupClient extends QQBotAPI {
|
|
11
|
-
//
|
|
12
|
-
#counter = new Counter(1); // 初始值为1
|
|
13
|
-
// 标记是否已连接
|
|
14
|
-
#isConnected = false;
|
|
15
|
-
// 存储最新的消息序号
|
|
16
|
-
#heartbeat_interval = 30000;
|
|
17
|
-
// 鉴权
|
|
18
|
-
#IntervalId = null;
|
|
19
|
-
// url
|
|
20
|
-
#gatewayUrl = null;
|
|
21
|
-
/**
|
|
22
|
-
* 设置配置
|
|
23
|
-
* @param opstion
|
|
24
|
-
*/
|
|
25
|
-
constructor(opstion) {
|
|
26
|
-
super();
|
|
27
|
-
for (const key in opstion) {
|
|
28
|
-
config.set(key, opstion[key]);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* 定时鉴权
|
|
33
|
-
* @param cfg
|
|
34
|
-
* @returns
|
|
35
|
-
*/
|
|
36
|
-
async #setTimeoutBotConfig() {
|
|
37
|
-
const accessToken = async () => {
|
|
38
|
-
const app_id = config.get('app_id');
|
|
39
|
-
const secret = config.get('secret');
|
|
40
|
-
if (!app_id || !secret)
|
|
41
|
-
return;
|
|
42
|
-
// 发送请求
|
|
43
|
-
const data = await this.getAuthentication(app_id, secret).then(res => res.data);
|
|
44
|
-
config.set('access_token', data.access_token);
|
|
45
|
-
console.info('refresh', data.expires_in, 's');
|
|
46
|
-
setTimeout(accessToken, data.expires_in * 1000);
|
|
47
|
-
};
|
|
48
|
-
await accessToken();
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* 鉴权数据
|
|
53
|
-
* @returns
|
|
54
|
-
*/
|
|
55
|
-
#aut() {
|
|
56
|
-
const token = config.get('access_token');
|
|
57
|
-
const intents = config.get('intents');
|
|
58
|
-
const shard = config.get('shard');
|
|
59
|
-
return {
|
|
60
|
-
op: 2, // op = 2
|
|
61
|
-
d: {
|
|
62
|
-
token: `QQBot ${token}`,
|
|
63
|
-
intents: getIntentsMask(intents),
|
|
64
|
-
shard: shard,
|
|
65
|
-
properties: {
|
|
66
|
-
$os: process.platform,
|
|
67
|
-
$browser: 'alemonjs',
|
|
68
|
-
$device: 'alemonjs'
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
#ws = null;
|
|
74
|
-
#events = {};
|
|
75
|
-
/**
|
|
76
|
-
* 注册事件处理程序
|
|
77
|
-
* @param key 事件名称
|
|
78
|
-
* @param val 事件处理函数
|
|
79
|
-
*/
|
|
80
|
-
on(key, val) {
|
|
81
|
-
if (!this.#events[key])
|
|
82
|
-
this.#events[key] = [];
|
|
83
|
-
this.#events[key].push(val);
|
|
84
|
-
return this;
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
*
|
|
88
|
-
* @param cfg
|
|
89
|
-
* @param conversation
|
|
90
|
-
*/
|
|
91
|
-
async connect(gatewayURL) {
|
|
92
|
-
// 定时模式
|
|
93
|
-
await this.#setTimeoutBotConfig();
|
|
94
|
-
// 请求url
|
|
95
|
-
if (!this.#gatewayUrl) {
|
|
96
|
-
this.#gatewayUrl = gatewayURL ?? (await this.gateway().then(res => res?.url));
|
|
97
|
-
}
|
|
98
|
-
if (!this.#gatewayUrl)
|
|
99
|
-
return;
|
|
100
|
-
// 重新连接的逻辑
|
|
101
|
-
const reconnect = async () => {
|
|
102
|
-
if (this.#counter.get() >= 5) {
|
|
103
|
-
console.info('The maximum number of reconnections has been reached, cancel reconnection');
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
setTimeout(() => {
|
|
107
|
-
console.info('[ws] reconnecting...');
|
|
108
|
-
// 重新starrt
|
|
109
|
-
start();
|
|
110
|
-
// 记录
|
|
111
|
-
this.#counter.getNextId();
|
|
112
|
-
}, 5000);
|
|
113
|
-
};
|
|
114
|
-
const start = () => {
|
|
115
|
-
if (this.#gatewayUrl) {
|
|
116
|
-
const map = {
|
|
117
|
-
0: async ({ t, d }) => {
|
|
118
|
-
if (this.#events[t]) {
|
|
119
|
-
try {
|
|
120
|
-
for (const event of this.#events[t]) {
|
|
121
|
-
// 是否是函数
|
|
122
|
-
if (typeof event != 'function')
|
|
123
|
-
continue;
|
|
124
|
-
event(d);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
catch (err) {
|
|
128
|
-
if (this.#events['ERROR']) {
|
|
129
|
-
for (const event of this.#events['ERROR']) {
|
|
130
|
-
// 是否是函数
|
|
131
|
-
if (typeof event != 'function')
|
|
132
|
-
continue;
|
|
133
|
-
event(err);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
// Ready Event,鉴权成功
|
|
139
|
-
if (t === 'READY') {
|
|
140
|
-
this.#IntervalId = setInterval(() => {
|
|
141
|
-
if (this.#isConnected) {
|
|
142
|
-
this.#ws &&
|
|
143
|
-
this.#ws.send(JSON.stringify({
|
|
144
|
-
op: 1, // op = 1
|
|
145
|
-
d: null // 如果是第一次连接,传null
|
|
146
|
-
}));
|
|
147
|
-
}
|
|
148
|
-
}, this.#heartbeat_interval);
|
|
149
|
-
}
|
|
150
|
-
// Resumed Event,恢复连接成功
|
|
151
|
-
if (t === 'RESUMED') {
|
|
152
|
-
console.info('[ws] restore connection');
|
|
153
|
-
// 重制次数
|
|
154
|
-
this.#counter.reStart();
|
|
155
|
-
}
|
|
156
|
-
return;
|
|
157
|
-
},
|
|
158
|
-
6: ({ d }) => {
|
|
159
|
-
console.info('[ws] connection attempt', d);
|
|
160
|
-
return;
|
|
161
|
-
},
|
|
162
|
-
7: async ({ d }) => {
|
|
163
|
-
// 执行重新连接
|
|
164
|
-
console.info('[ws] reconnect', d);
|
|
165
|
-
// 取消鉴权发送
|
|
166
|
-
if (this.#IntervalId)
|
|
167
|
-
clearInterval(this.#IntervalId);
|
|
168
|
-
return;
|
|
169
|
-
},
|
|
170
|
-
9: ({ d }) => {
|
|
171
|
-
console.info('[ws] parameter error', d);
|
|
172
|
-
return;
|
|
173
|
-
},
|
|
174
|
-
10: ({ d }) => {
|
|
175
|
-
// 重制次数
|
|
176
|
-
this.#isConnected = true;
|
|
177
|
-
// 记录新循环
|
|
178
|
-
this.#heartbeat_interval = d.heartbeat_interval;
|
|
179
|
-
// 发送鉴权
|
|
180
|
-
this.#ws && this.#ws.send(JSON.stringify(this.#aut()));
|
|
181
|
-
return;
|
|
182
|
-
},
|
|
183
|
-
11: () => {
|
|
184
|
-
// OpCode 11 Heartbeat ACK 消息,心跳发送成功
|
|
185
|
-
console.info('[ws] heartbeat transmission');
|
|
186
|
-
// 重制次数
|
|
187
|
-
this.#counter.reStart();
|
|
188
|
-
return;
|
|
189
|
-
},
|
|
190
|
-
12: ({ d }) => {
|
|
191
|
-
console.info('[ws] platform data', d);
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
};
|
|
195
|
-
// 连接
|
|
196
|
-
this.#ws = new WebSocket(this.#gatewayUrl);
|
|
197
|
-
this.#ws.on('open', () => {
|
|
198
|
-
console.info('[ws] open');
|
|
199
|
-
});
|
|
200
|
-
// 监听消息
|
|
201
|
-
this.#ws.on('message', async (msg) => {
|
|
202
|
-
const message = JSON.parse(msg.toString('utf8'));
|
|
203
|
-
if (process.env.NTQQ_WS == 'dev')
|
|
204
|
-
console.info('message', message);
|
|
205
|
-
// 根据 opcode 进行处理
|
|
206
|
-
if (map[message.op]) {
|
|
207
|
-
map[message.op](message);
|
|
208
|
-
}
|
|
209
|
-
});
|
|
210
|
-
// 关闭
|
|
211
|
-
this.#ws.on('close', async (err) => {
|
|
212
|
-
await reconnect();
|
|
213
|
-
console.info('[ws] close', err);
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
};
|
|
217
|
-
start();
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
export { QQBotGroupClient };
|
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
import WebSocket from 'ws';
|
|
2
|
-
import { config } from './config.js';
|
|
3
|
-
import { getIntentsMask } from './intents.js';
|
|
4
|
-
import { QQBotAPI } from './api.js';
|
|
5
|
-
import { Counter } from './counter.js';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* 连接
|
|
9
|
-
*/
|
|
10
|
-
class QQBotGuildClient extends QQBotAPI {
|
|
11
|
-
//
|
|
12
|
-
#counter = new Counter(1); // 初始值为1
|
|
13
|
-
// 标记是否已连接
|
|
14
|
-
#isConnected = false;
|
|
15
|
-
// 存储最新的消息序号
|
|
16
|
-
#heartbeat_interval = 30000;
|
|
17
|
-
// 鉴权
|
|
18
|
-
#IntervalId = null;
|
|
19
|
-
// url
|
|
20
|
-
#gatewayUrl = null;
|
|
21
|
-
#ws;
|
|
22
|
-
/**
|
|
23
|
-
*
|
|
24
|
-
* @param opstion
|
|
25
|
-
*/
|
|
26
|
-
constructor(opstion) {
|
|
27
|
-
super();
|
|
28
|
-
for (const key in opstion) {
|
|
29
|
-
config.set(key, opstion[key]);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* 鉴权数据
|
|
34
|
-
* @returns
|
|
35
|
-
*/
|
|
36
|
-
#aut() {
|
|
37
|
-
const app_id = config.get('app_id');
|
|
38
|
-
const token = config.get('token');
|
|
39
|
-
const intents = config.get('intents');
|
|
40
|
-
const shard = config.get('shard');
|
|
41
|
-
return {
|
|
42
|
-
op: 2, // op = 2
|
|
43
|
-
d: {
|
|
44
|
-
token: `Bot ${app_id}.${token}`,
|
|
45
|
-
intents: getIntentsMask(intents),
|
|
46
|
-
shard,
|
|
47
|
-
properties: {
|
|
48
|
-
$os: process.platform,
|
|
49
|
-
$browser: 'alemonjs',
|
|
50
|
-
$device: 'alemonjs'
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
#events = {};
|
|
56
|
-
/**
|
|
57
|
-
* 注册事件处理程序
|
|
58
|
-
* @param key 事件名称
|
|
59
|
-
* @param val 事件处理函数
|
|
60
|
-
*/
|
|
61
|
-
on(key, val) {
|
|
62
|
-
if (!this.#events[key])
|
|
63
|
-
this.#events[key] = [];
|
|
64
|
-
this.#events[key].push(val);
|
|
65
|
-
return this;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
*
|
|
69
|
-
* @param cfg
|
|
70
|
-
*/
|
|
71
|
-
async connect(gatewayURL) {
|
|
72
|
-
//
|
|
73
|
-
this.#gatewayUrl =
|
|
74
|
-
gatewayURL ??
|
|
75
|
-
(await this.gateway()
|
|
76
|
-
.then(res => res.url)
|
|
77
|
-
.catch(err => {
|
|
78
|
-
if (this.#events['ERROR']) {
|
|
79
|
-
for (const item of this.#events['ERROR']) {
|
|
80
|
-
item(err);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}));
|
|
84
|
-
// 请求url
|
|
85
|
-
if (!this.#gatewayUrl)
|
|
86
|
-
return this;
|
|
87
|
-
// 重新连接的逻辑
|
|
88
|
-
const reconnect = async () => {
|
|
89
|
-
if (this.#counter.get() >= 5) {
|
|
90
|
-
console.info('The maximum number of reconnections has been reached, cancel reconnection');
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
setTimeout(() => {
|
|
94
|
-
console.info('[ws] reconnecting...');
|
|
95
|
-
// 重新starrt
|
|
96
|
-
start();
|
|
97
|
-
// 记录
|
|
98
|
-
this.#counter.getNextId();
|
|
99
|
-
}, 5000);
|
|
100
|
-
};
|
|
101
|
-
const start = () => {
|
|
102
|
-
if (this.#gatewayUrl) {
|
|
103
|
-
const map = {
|
|
104
|
-
0: async ({ t, d }) => {
|
|
105
|
-
// 执行
|
|
106
|
-
if (this.#events[t]) {
|
|
107
|
-
try {
|
|
108
|
-
for (const event of this.#events[t]) {
|
|
109
|
-
// 是否是函数
|
|
110
|
-
if (typeof event != 'function')
|
|
111
|
-
continue;
|
|
112
|
-
event(d);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
catch (err) {
|
|
116
|
-
if (this.#events['ERROR']) {
|
|
117
|
-
for (const item of this.#events['ERROR']) {
|
|
118
|
-
item(err);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
// Ready Event,鉴权成功
|
|
124
|
-
if (t === 'READY') {
|
|
125
|
-
this.#IntervalId = setInterval(() => {
|
|
126
|
-
if (this.#isConnected) {
|
|
127
|
-
this.#ws.send(JSON.stringify({
|
|
128
|
-
op: 1, // op = 1
|
|
129
|
-
d: null // 如果是第一次连接,传null
|
|
130
|
-
}));
|
|
131
|
-
}
|
|
132
|
-
}, this.#heartbeat_interval);
|
|
133
|
-
}
|
|
134
|
-
// Resumed Event,恢复连接成功
|
|
135
|
-
if (t === 'RESUMED') {
|
|
136
|
-
console.info('[ws] restore connection');
|
|
137
|
-
// 重制次数
|
|
138
|
-
this.#counter.reStart();
|
|
139
|
-
}
|
|
140
|
-
return;
|
|
141
|
-
},
|
|
142
|
-
6: ({ d }) => {
|
|
143
|
-
console.info('[ws] connection attempt', d);
|
|
144
|
-
return;
|
|
145
|
-
},
|
|
146
|
-
7: async ({ d }) => {
|
|
147
|
-
// 执行重新连接
|
|
148
|
-
console.info('[ws] reconnect', d);
|
|
149
|
-
// 取消鉴权发送
|
|
150
|
-
if (this.#IntervalId)
|
|
151
|
-
clearInterval(this.#IntervalId);
|
|
152
|
-
return;
|
|
153
|
-
},
|
|
154
|
-
9: ({ d }) => {
|
|
155
|
-
console.info('[ws] parameter error', d);
|
|
156
|
-
return;
|
|
157
|
-
},
|
|
158
|
-
10: ({ d }) => {
|
|
159
|
-
// 重制次数
|
|
160
|
-
this.#isConnected = true;
|
|
161
|
-
// 记录新循环
|
|
162
|
-
this.#heartbeat_interval = d.heartbeat_interval;
|
|
163
|
-
// 发送鉴权
|
|
164
|
-
this.#ws.send(JSON.stringify(this.#aut()));
|
|
165
|
-
return;
|
|
166
|
-
},
|
|
167
|
-
11: () => {
|
|
168
|
-
// OpCode 11 Heartbeat ACK 消息,心跳发送成功
|
|
169
|
-
console.info('[ws] heartbeat transmission');
|
|
170
|
-
// 重制次数
|
|
171
|
-
this.#counter.reStart();
|
|
172
|
-
return;
|
|
173
|
-
},
|
|
174
|
-
12: ({ d }) => {
|
|
175
|
-
console.info('[ws] platform data', d);
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
};
|
|
179
|
-
// 连接
|
|
180
|
-
this.#ws = new WebSocket(this.#gatewayUrl);
|
|
181
|
-
this.#ws.on('open', () => {
|
|
182
|
-
console.info('[ws] open');
|
|
183
|
-
});
|
|
184
|
-
// 监听消息
|
|
185
|
-
this.#ws.on('message', async (msg) => {
|
|
186
|
-
const message = JSON.parse(msg.toString('utf8'));
|
|
187
|
-
if (process.env.QQ_WS == 'dev')
|
|
188
|
-
console.info('message', message);
|
|
189
|
-
if (map[message.op]) {
|
|
190
|
-
map[message.op](message);
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
// 关闭
|
|
194
|
-
this.#ws.on('close', async (err) => {
|
|
195
|
-
await reconnect();
|
|
196
|
-
console.info('[ws] close', err);
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
};
|
|
200
|
-
start();
|
|
201
|
-
return this;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
export { QQBotGuildClient };
|
package/lib/sdk/counter.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
class Counter {
|
|
2
|
-
#counter = 1;
|
|
3
|
-
#val = 0;
|
|
4
|
-
constructor(initialValue) {
|
|
5
|
-
this.#counter = initialValue;
|
|
6
|
-
this.#val = initialValue;
|
|
7
|
-
}
|
|
8
|
-
getNextId() {
|
|
9
|
-
return ++this.#counter;
|
|
10
|
-
}
|
|
11
|
-
get() {
|
|
12
|
-
return this.#counter;
|
|
13
|
-
}
|
|
14
|
-
reStart() {
|
|
15
|
-
this.#counter = this.#val;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export { Counter };
|
package/lib/sdk/from.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { existsSync, createReadStream } from 'fs';
|
|
2
|
-
import { Readable, isReadable } from 'stream';
|
|
3
|
-
import { basename } from 'path';
|
|
4
|
-
import { fileTypeFromBuffer, fileTypeFromStream } from 'file-type';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 创建form
|
|
8
|
-
* @param image
|
|
9
|
-
* @param name
|
|
10
|
-
* @returns
|
|
11
|
-
*/
|
|
12
|
-
async function createPicFrom(image, name = 'image.jpg') {
|
|
13
|
-
let picData;
|
|
14
|
-
// 是 string
|
|
15
|
-
if (typeof image === 'string') {
|
|
16
|
-
if (!existsSync(image))
|
|
17
|
-
return false;
|
|
18
|
-
if (!name)
|
|
19
|
-
name = basename(image);
|
|
20
|
-
picData = createReadStream(image);
|
|
21
|
-
// 是 buffer
|
|
22
|
-
}
|
|
23
|
-
else if (Buffer.isBuffer(image)) {
|
|
24
|
-
const file = await fileTypeFromBuffer(image);
|
|
25
|
-
if (!name)
|
|
26
|
-
name = 'file.' + file?.ext;
|
|
27
|
-
picData = new Readable();
|
|
28
|
-
picData.push(image);
|
|
29
|
-
picData.push(null);
|
|
30
|
-
// 是 文件流
|
|
31
|
-
}
|
|
32
|
-
else if (isReadable(image)) {
|
|
33
|
-
const file = await fileTypeFromStream(image);
|
|
34
|
-
if (!name)
|
|
35
|
-
name = 'file.' + file?.ext;
|
|
36
|
-
picData = image;
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
return false;
|
|
40
|
-
}
|
|
41
|
-
return { picData, image, name };
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export { createPicFrom };
|
|
File without changes
|