@alemonjs/qq-bot 0.0.4 → 0.0.6
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/README.md +33 -2
- package/lib/api.js +2 -2
- package/lib/client.js +218 -200
- package/lib/from.js +4 -4
- package/lib/index.d.ts +4 -4
- package/lib/index.js +52 -107
- package/lib/send/index.js +222 -0
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -23,18 +23,49 @@ qq-bot:
|
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
```sh
|
|
26
|
-
qq-
|
|
26
|
+
qq-bot:
|
|
27
27
|
master_key:
|
|
28
28
|
- ''
|
|
29
29
|
# 默认 推荐nginx进行代理 http://localhost:17157/webhook
|
|
30
|
+
route: '/webhook'
|
|
30
31
|
port: 17157
|
|
31
32
|
# 当配置ws的时候,会连接另一台hook机器人的消息。不会再启动本地端口。
|
|
32
33
|
# 推荐nginx进行代理 http://localhost:17157/
|
|
33
|
-
ws: 'wss://xxxx/
|
|
34
|
+
ws: 'wss://xxxx/websocket'
|
|
34
35
|
# 频道沙盒
|
|
35
36
|
sandbox: false
|
|
36
37
|
```
|
|
37
38
|
|
|
39
|
+
```conf
|
|
40
|
+
server {
|
|
41
|
+
listen 443 ssl http2;
|
|
42
|
+
server_name bundle.com;
|
|
43
|
+
ssl_certificate /usr/local/nginx/bundle.crt;
|
|
44
|
+
ssl_certificate_key /usr/local/nginx/bundle.key;
|
|
45
|
+
|
|
46
|
+
location /webhook {
|
|
47
|
+
# 指向 webhook 服务的端口
|
|
48
|
+
proxy_pass http://localhost:17157;
|
|
49
|
+
proxy_set_header Host $host;
|
|
50
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
51
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
52
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
location /websocket {
|
|
56
|
+
# 指向 WebSocket 服务的端口
|
|
57
|
+
proxy_pass http://localhost:17157;
|
|
58
|
+
proxy_http_version 1.1;
|
|
59
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
60
|
+
proxy_set_header Connection "upgrade";
|
|
61
|
+
proxy_set_header Host $host;
|
|
62
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
63
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
64
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
38
69
|
## Community
|
|
39
70
|
|
|
40
71
|
QQ Group 806943302
|
package/lib/api.js
CHANGED
|
@@ -83,7 +83,6 @@ class QQBotAPI {
|
|
|
83
83
|
* 0 文本 1 图文 2 md 3 ark 4 embed
|
|
84
84
|
*/
|
|
85
85
|
async usersOpenMessages(openid, data, msg_id) {
|
|
86
|
-
console.log('msg_id', msg_id);
|
|
87
86
|
return this.groupService({
|
|
88
87
|
url: `/v2/users/${openid}/messages`,
|
|
89
88
|
method: 'post',
|
|
@@ -104,7 +103,8 @@ class QQBotAPI {
|
|
|
104
103
|
// 如果映射表大小超过 100,则删除最早添加的 MessageId
|
|
105
104
|
if (this.#map.size > 100) {
|
|
106
105
|
const firstKey = this.#map.keys().next().value;
|
|
107
|
-
|
|
106
|
+
if (firstKey)
|
|
107
|
+
this.#map.delete(firstKey);
|
|
108
108
|
}
|
|
109
109
|
return seq;
|
|
110
110
|
}
|
package/lib/client.js
CHANGED
|
@@ -1,210 +1,228 @@
|
|
|
1
|
-
import { QQBotAPI } from './api.js'
|
|
2
|
-
import bodyParser from 'koa-bodyparser'
|
|
3
|
-
import Router from 'koa-router'
|
|
4
|
-
import { WebhookAPI } from './webhook.js'
|
|
5
|
-
import Koa from 'koa'
|
|
6
|
-
import { config } from './config.js'
|
|
7
|
-
import { v4 } from 'uuid'
|
|
8
|
-
import { WebSocketServer, WebSocket } from 'ws'
|
|
1
|
+
import { QQBotAPI } from './api.js';
|
|
2
|
+
import bodyParser from 'koa-bodyparser';
|
|
3
|
+
import Router from 'koa-router';
|
|
4
|
+
import { WebhookAPI } from './webhook.js';
|
|
5
|
+
import Koa from 'koa';
|
|
6
|
+
import { config } from './config.js';
|
|
7
|
+
import { v4 } from 'uuid';
|
|
8
|
+
import { WebSocketServer, WebSocket } from 'ws';
|
|
9
9
|
|
|
10
10
|
class QQBotClient extends QQBotAPI {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
*/
|
|
33
|
-
on(key, val) {
|
|
34
|
-
if (!this.#events[key]) {
|
|
35
|
-
this.#events[key] = []
|
|
11
|
+
#events = {};
|
|
12
|
+
#app = null;
|
|
13
|
+
#count = 0;
|
|
14
|
+
#client = [];
|
|
15
|
+
#ws = null;
|
|
16
|
+
/**
|
|
17
|
+
* 设置配置
|
|
18
|
+
* @param opstion
|
|
19
|
+
*/
|
|
20
|
+
constructor(opstion) {
|
|
21
|
+
super();
|
|
22
|
+
if (opstion.secret)
|
|
23
|
+
config.set('secret', opstion.secret);
|
|
24
|
+
if (opstion.app_id)
|
|
25
|
+
config.set('app_id', opstion.app_id);
|
|
26
|
+
if (opstion.token)
|
|
27
|
+
config.set('token', opstion.token);
|
|
28
|
+
if (opstion.port)
|
|
29
|
+
config.set('port', opstion.port);
|
|
30
|
+
if (opstion.ws)
|
|
31
|
+
config.set('ws', opstion.ws);
|
|
36
32
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
async #setTimeoutBotConfig() {
|
|
46
|
-
const callBack = async () => {
|
|
47
|
-
const app_id = config.get('app_id')
|
|
48
|
-
if (!app_id) return
|
|
49
|
-
const secret = config.get('secret')
|
|
50
|
-
if (!secret) return
|
|
51
|
-
// 发送请求
|
|
52
|
-
const data = await this.getAuthentication(app_id, secret).then(res => res.data)
|
|
53
|
-
config.set('access_token', data.access_token)
|
|
54
|
-
console.info('refresh', data.expires_in, 's')
|
|
55
|
-
setTimeout(callBack, data.expires_in * 1000)
|
|
56
|
-
}
|
|
57
|
-
await callBack()
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
*
|
|
61
|
-
* @param cfg
|
|
62
|
-
* @param conversation
|
|
63
|
-
*/
|
|
64
|
-
connect() {
|
|
65
|
-
try {
|
|
66
|
-
const ws = config.get('ws')
|
|
67
|
-
if (!ws) {
|
|
68
|
-
this.#setTimeoutBotConfig()
|
|
69
|
-
this.#app = new Koa()
|
|
70
|
-
this.#app.use(bodyParser())
|
|
71
|
-
const router = new Router()
|
|
72
|
-
const port = config.get('port')
|
|
73
|
-
const secret = config.get('secret')
|
|
74
|
-
const cfg = {
|
|
75
|
-
secret: secret ?? '',
|
|
76
|
-
port: port ? Number(port) : 17157
|
|
33
|
+
/**
|
|
34
|
+
* 注册事件处理程序
|
|
35
|
+
* @param key 事件名称
|
|
36
|
+
* @param val 事件处理函数
|
|
37
|
+
*/
|
|
38
|
+
on(key, val) {
|
|
39
|
+
if (!this.#events[key]) {
|
|
40
|
+
this.#events[key] = [];
|
|
77
41
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
42
|
+
this.#events[key].push(val);
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 定时鉴权
|
|
47
|
+
* @param cfg
|
|
48
|
+
* @returns
|
|
49
|
+
*/
|
|
50
|
+
async #setTimeoutBotConfig() {
|
|
51
|
+
const callBack = async () => {
|
|
52
|
+
const app_id = config.get('app_id');
|
|
53
|
+
if (!app_id)
|
|
54
|
+
return;
|
|
55
|
+
const secret = config.get('secret');
|
|
56
|
+
if (!secret)
|
|
57
|
+
return;
|
|
58
|
+
// 发送请求
|
|
59
|
+
const data = await this.getAuthentication(app_id, secret).then(res => res.data);
|
|
60
|
+
config.set('access_token', data.access_token);
|
|
61
|
+
console.info('refresh', data.expires_in, 's');
|
|
62
|
+
setTimeout(callBack, data.expires_in * 1000);
|
|
63
|
+
};
|
|
64
|
+
await callBack();
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
*
|
|
68
|
+
* @param cfg
|
|
69
|
+
* @param conversation
|
|
70
|
+
*/
|
|
71
|
+
connect() {
|
|
72
|
+
try {
|
|
73
|
+
const ws = config.get('ws');
|
|
74
|
+
if (!ws) {
|
|
75
|
+
this.#setTimeoutBotConfig();
|
|
76
|
+
this.#app = new Koa();
|
|
77
|
+
this.#app.use(bodyParser());
|
|
78
|
+
const router = new Router();
|
|
79
|
+
const port = config.get('port');
|
|
80
|
+
const secret = config.get('secret');
|
|
81
|
+
const route = config.get('route') ?? '/webhook';
|
|
82
|
+
const cfg = {
|
|
83
|
+
secret: secret ?? '',
|
|
84
|
+
port: port ? Number(port) : 17157
|
|
85
|
+
};
|
|
86
|
+
const ntqqWebhook = new WebhookAPI({
|
|
87
|
+
secret: cfg.secret
|
|
88
|
+
});
|
|
89
|
+
this.#app.use(async (ctx, next) => {
|
|
90
|
+
let rawData = '';
|
|
91
|
+
ctx.req.on('data', chunk => (rawData += chunk));
|
|
92
|
+
ctx.req.on('end', () => (ctx.request.rawBody = rawData));
|
|
93
|
+
await next();
|
|
94
|
+
});
|
|
95
|
+
// 启动服务
|
|
96
|
+
router.post(route, async (ctx) => {
|
|
97
|
+
const sign = ctx.req.headers['x-signature-ed25519'];
|
|
98
|
+
const timestamp = ctx.req.headers['x-signature-timestamp'];
|
|
99
|
+
const rawBody = ctx.request.rawBody;
|
|
100
|
+
const isValid = ntqqWebhook.validSign(timestamp, rawBody, String(sign));
|
|
101
|
+
if (!isValid) {
|
|
102
|
+
ctx.status = 400;
|
|
103
|
+
ctx.body = { msg: 'invalid signature' };
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const body = ctx.request.body;
|
|
107
|
+
if (body.op == 13) {
|
|
108
|
+
ctx.status = 200;
|
|
109
|
+
ctx.body = {
|
|
110
|
+
// 返回明文 token
|
|
111
|
+
plain_token: body.d.plain_token,
|
|
112
|
+
// 生成签名
|
|
113
|
+
signature: ntqqWebhook.getSign(body.d.event_ts, body.d.plain_token)
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
else if (body.op == 0) {
|
|
117
|
+
ctx.status = 204;
|
|
118
|
+
// 根据事件类型,处理事件
|
|
119
|
+
for (const event of this.#events[body.t] || []) {
|
|
120
|
+
event(body.d);
|
|
121
|
+
}
|
|
122
|
+
const access_token = config.get('access_token');
|
|
123
|
+
// 也可以分法到客户端。 发送失败需要处理 或清理调
|
|
124
|
+
for (const client of this.#client) {
|
|
125
|
+
try {
|
|
126
|
+
if (access_token)
|
|
127
|
+
body['access_token'] = access_token;
|
|
128
|
+
client.ws.send(JSON.stringify(body));
|
|
129
|
+
}
|
|
130
|
+
catch (e) {
|
|
131
|
+
this.#error(e);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
this.#app.use(router.routes());
|
|
137
|
+
this.#app.use(router.allowedMethods());
|
|
138
|
+
// 启动服务
|
|
139
|
+
const server = this.#app.listen(cfg.port, () => {
|
|
140
|
+
console.log('Server running at http://localhost:' + cfg.port + route);
|
|
141
|
+
});
|
|
142
|
+
// 创建 WebSocketServer 并监听同一个端口
|
|
143
|
+
const wss = new WebSocketServer({ server: server });
|
|
144
|
+
console.log('Server running at wss://localhost:' + cfg.port + '/');
|
|
145
|
+
// 处理客户端连接
|
|
146
|
+
wss.on('connection', ws => {
|
|
147
|
+
const clientId = v4();
|
|
148
|
+
ws['clientId'] = clientId;
|
|
149
|
+
console.log(clientId, 'connection');
|
|
150
|
+
this.#client.push({ id: clientId, ws });
|
|
151
|
+
// 处理消息事件
|
|
152
|
+
ws.on('message', (message) => {
|
|
153
|
+
// 拿到消息
|
|
154
|
+
try {
|
|
155
|
+
const body = JSON.parse(message.toString());
|
|
156
|
+
for (const event of this.#events[body.t] || []) {
|
|
157
|
+
event(body.d);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
catch (e) {
|
|
161
|
+
this.#error(e);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
// 处理关闭事件
|
|
165
|
+
ws.on('close', () => {
|
|
166
|
+
console.log(`${clientId} disconnected`);
|
|
167
|
+
this.#client = this.#client.filter(client => client.id !== clientId);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
149
170
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
171
|
+
else {
|
|
172
|
+
const reconnect = () => {
|
|
173
|
+
// 使用了ws服务器
|
|
174
|
+
this.#ws = new WebSocket(ws);
|
|
175
|
+
this.#ws.on('open', () => {
|
|
176
|
+
this.#count = 0;
|
|
177
|
+
console.log('ws connected');
|
|
178
|
+
});
|
|
179
|
+
this.#ws.on('message', data => {
|
|
180
|
+
try {
|
|
181
|
+
// 拿到消息
|
|
182
|
+
const body = JSON.parse(data.toString());
|
|
183
|
+
const access_token = body['access_token'];
|
|
184
|
+
if (access_token)
|
|
185
|
+
config.set('access_token', access_token);
|
|
186
|
+
for (const event of this.#events[body.t] || []) {
|
|
187
|
+
event(body.d);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
catch (e) {
|
|
191
|
+
this.#error(e);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
this.#ws.on('close', () => {
|
|
195
|
+
console.log('ws closed');
|
|
196
|
+
// 重连5次,超过5次不再重连
|
|
197
|
+
if (this.#count > 5)
|
|
198
|
+
return;
|
|
199
|
+
// 1.3s 后重连
|
|
200
|
+
setTimeout(() => {
|
|
201
|
+
reconnect();
|
|
202
|
+
}, 1300);
|
|
203
|
+
});
|
|
204
|
+
this.#ws.on('error', e => {
|
|
205
|
+
this.#error(e);
|
|
206
|
+
});
|
|
207
|
+
};
|
|
208
|
+
reconnect();
|
|
174
209
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
this.#ws.on('close', () => {
|
|
180
|
-
console.log('ws closed')
|
|
181
|
-
// 重连5次,超过5次不再重连
|
|
182
|
-
if (this.#count > 5) return
|
|
183
|
-
// 23s 后重连
|
|
184
|
-
setTimeout(() => {
|
|
185
|
-
reconnect()
|
|
186
|
-
}, 23000)
|
|
187
|
-
})
|
|
188
|
-
this.#ws.on('error', e => {
|
|
189
|
-
this.#error(e)
|
|
190
|
-
})
|
|
191
|
-
}
|
|
192
|
-
reconnect()
|
|
193
|
-
} catch (e) {
|
|
194
|
-
this.#error(e)
|
|
210
|
+
}
|
|
211
|
+
catch (e) {
|
|
212
|
+
this.#error(e);
|
|
213
|
+
}
|
|
195
214
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
215
|
+
/**
|
|
216
|
+
*
|
|
217
|
+
* @param error
|
|
218
|
+
*/
|
|
219
|
+
#error(error) {
|
|
220
|
+
if (this.#events['ERROR']) {
|
|
221
|
+
for (const event of this.#events['ERROR'] || []) {
|
|
222
|
+
event(error);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
206
225
|
}
|
|
207
|
-
}
|
|
208
226
|
}
|
|
209
227
|
|
|
210
|
-
export { QQBotClient }
|
|
228
|
+
export { QQBotClient };
|
package/lib/from.js
CHANGED
|
@@ -21,18 +21,18 @@ async function createPicFrom(image, name = 'image.jpg') {
|
|
|
21
21
|
// 是 buffer
|
|
22
22
|
}
|
|
23
23
|
else if (Buffer.isBuffer(image)) {
|
|
24
|
-
const
|
|
24
|
+
const file = await fileTypeFromBuffer(image);
|
|
25
25
|
if (!name)
|
|
26
|
-
name = 'file.' + ext;
|
|
26
|
+
name = 'file.' + file?.ext;
|
|
27
27
|
picData = new Readable();
|
|
28
28
|
picData.push(image);
|
|
29
29
|
picData.push(null);
|
|
30
30
|
// 是 文件流
|
|
31
31
|
}
|
|
32
32
|
else if (isReadable(image)) {
|
|
33
|
-
const
|
|
33
|
+
const file = await fileTypeFromStream(image);
|
|
34
34
|
if (!name)
|
|
35
|
-
name = 'file.' + ext;
|
|
35
|
+
name = 'file.' + file?.ext;
|
|
36
36
|
picData = image;
|
|
37
37
|
}
|
|
38
38
|
else {
|
package/lib/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import * as alemonjs from 'alemonjs'
|
|
1
|
+
import * as alemonjs from 'alemonjs'
|
|
2
2
|
|
|
3
|
-
declare const platform =
|
|
4
|
-
declare const _default: () => alemonjs.ClientAPI
|
|
3
|
+
declare const platform = 'qq-bot'
|
|
4
|
+
declare const _default: () => alemonjs.ClientAPI
|
|
5
5
|
|
|
6
|
-
export { _default as default, platform }
|
|
6
|
+
export { _default as default, platform }
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { defineBot, getConfigValue, useUserHashKey, OnProcessor } from 'alemonjs';
|
|
2
2
|
import { QQBotClient } from './client.js';
|
|
3
|
+
import { GROUP_AT_MESSAGE_CREATE, C2C_MESSAGE_CREATE, DIRECT_MESSAGE_CREATE, AT_MESSAGE_CREATE, MESSAGE_CREATE } from './send/index.js';
|
|
3
4
|
|
|
4
5
|
const client = new Proxy({}, {
|
|
5
6
|
get: (_, prop) => {
|
|
@@ -11,17 +12,26 @@ const client = new Proxy({}, {
|
|
|
11
12
|
});
|
|
12
13
|
const platform = 'qq-bot';
|
|
13
14
|
var index = defineBot(() => {
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
let value = getConfigValue();
|
|
16
|
+
if (!value)
|
|
17
|
+
value = {};
|
|
18
|
+
const config = value[platform];
|
|
16
19
|
const client = new QQBotClient({
|
|
17
20
|
secret: config?.secret,
|
|
18
21
|
app_id: config?.app_id,
|
|
22
|
+
route: config?.route,
|
|
19
23
|
token: config?.token,
|
|
20
24
|
port: config?.port,
|
|
21
25
|
ws: config?.ws
|
|
22
26
|
});
|
|
23
27
|
// 连接
|
|
24
28
|
client.connect();
|
|
29
|
+
/**
|
|
30
|
+
* group
|
|
31
|
+
*
|
|
32
|
+
* GROUP_AT_MESSAGE_CREATE
|
|
33
|
+
* C2C_MESSAGE_CREATE
|
|
34
|
+
*/
|
|
25
35
|
// 监听消息
|
|
26
36
|
client.on('GROUP_AT_MESSAGE_CREATE', async (event) => {
|
|
27
37
|
const master_key = config?.master_key ?? [];
|
|
@@ -47,6 +57,7 @@ var index = defineBot(() => {
|
|
|
47
57
|
});
|
|
48
58
|
// 定义消
|
|
49
59
|
const e = {
|
|
60
|
+
name: 'message.create',
|
|
50
61
|
// 事件类型
|
|
51
62
|
Platform: platform,
|
|
52
63
|
// guild
|
|
@@ -63,7 +74,7 @@ var index = defineBot(() => {
|
|
|
63
74
|
MessageText: event.content?.trim(),
|
|
64
75
|
OpenId: event.author.member_openid,
|
|
65
76
|
CreateAt: Date.now(),
|
|
66
|
-
tag: '
|
|
77
|
+
tag: 'GROUP_AT_MESSAGE_CREATE',
|
|
67
78
|
value: null
|
|
68
79
|
};
|
|
69
80
|
// 当访问的时候获取
|
|
@@ -99,6 +110,7 @@ var index = defineBot(() => {
|
|
|
99
110
|
});
|
|
100
111
|
// 定义消
|
|
101
112
|
const e = {
|
|
113
|
+
name: 'private.message.create',
|
|
102
114
|
// 事件类型
|
|
103
115
|
Platform: platform,
|
|
104
116
|
// 用户Id
|
|
@@ -111,9 +123,9 @@ var index = defineBot(() => {
|
|
|
111
123
|
MessageId: event.id,
|
|
112
124
|
MessageText: event.content?.trim(),
|
|
113
125
|
CreateAt: Date.now(),
|
|
114
|
-
OpenId:
|
|
126
|
+
OpenId: event.author.user_openid,
|
|
115
127
|
//
|
|
116
|
-
tag: '
|
|
128
|
+
tag: 'C2C_MESSAGE_CREATE',
|
|
117
129
|
value: null
|
|
118
130
|
};
|
|
119
131
|
// 当访问的时候获取
|
|
@@ -125,6 +137,9 @@ var index = defineBot(() => {
|
|
|
125
137
|
// 处理消息
|
|
126
138
|
OnProcessor(e, 'private.message.create');
|
|
127
139
|
});
|
|
140
|
+
/**
|
|
141
|
+
* guild
|
|
142
|
+
*/
|
|
128
143
|
client.on('DIRECT_MESSAGE_CREATE', async (event) => {
|
|
129
144
|
// 屏蔽其他机器人的消息
|
|
130
145
|
if (event?.author?.bot)
|
|
@@ -152,11 +167,12 @@ var index = defineBot(() => {
|
|
|
152
167
|
});
|
|
153
168
|
// 定义消
|
|
154
169
|
const e = {
|
|
170
|
+
name: 'private.message.create',
|
|
155
171
|
// 事件类型
|
|
156
172
|
Platform: platform,
|
|
157
173
|
//
|
|
158
|
-
GuildId: event.guild_id,
|
|
159
|
-
ChannelId: event.channel_id,
|
|
174
|
+
// GuildId: event.guild_id,
|
|
175
|
+
// ChannelId: event.channel_id,
|
|
160
176
|
// 用户Id
|
|
161
177
|
UserId: event?.author?.id ?? '',
|
|
162
178
|
UserKey,
|
|
@@ -170,7 +186,7 @@ var index = defineBot(() => {
|
|
|
170
186
|
OpenId: event.guild_id,
|
|
171
187
|
CreateAt: Date.now(),
|
|
172
188
|
//
|
|
173
|
-
tag: '
|
|
189
|
+
tag: 'DIRECT_MESSAGE_CREATE',
|
|
174
190
|
//
|
|
175
191
|
value: null
|
|
176
192
|
};
|
|
@@ -211,6 +227,7 @@ var index = defineBot(() => {
|
|
|
211
227
|
});
|
|
212
228
|
// 定义消
|
|
213
229
|
const e = {
|
|
230
|
+
name: 'message.create',
|
|
214
231
|
// 事件类型
|
|
215
232
|
Platform: platform,
|
|
216
233
|
GuildId: event.guild_id,
|
|
@@ -228,7 +245,7 @@ var index = defineBot(() => {
|
|
|
228
245
|
OpenId: event.guild_id,
|
|
229
246
|
CreateAt: Date.now(),
|
|
230
247
|
//
|
|
231
|
-
tag: '
|
|
248
|
+
tag: 'AT_MESSAGE_CREATE',
|
|
232
249
|
//
|
|
233
250
|
value: null
|
|
234
251
|
};
|
|
@@ -295,6 +312,7 @@ var index = defineBot(() => {
|
|
|
295
312
|
});
|
|
296
313
|
// 定义消
|
|
297
314
|
const e = {
|
|
315
|
+
name: 'message.create',
|
|
298
316
|
// 事件类型
|
|
299
317
|
Platform: platform,
|
|
300
318
|
//
|
|
@@ -312,7 +330,7 @@ var index = defineBot(() => {
|
|
|
312
330
|
OpenId: event.guild_id,
|
|
313
331
|
CreateAt: Date.now(),
|
|
314
332
|
//
|
|
315
|
-
tag: '
|
|
333
|
+
tag: 'MESSAGE_CREATE',
|
|
316
334
|
value: null
|
|
317
335
|
};
|
|
318
336
|
// 当访问的时候获取
|
|
@@ -330,118 +348,45 @@ var index = defineBot(() => {
|
|
|
330
348
|
return {
|
|
331
349
|
api: {
|
|
332
350
|
use: {
|
|
333
|
-
send: (event, val) => {
|
|
351
|
+
send: async (event, val) => {
|
|
334
352
|
if (val.length < 0)
|
|
335
|
-
|
|
353
|
+
;
|
|
336
354
|
// 打 tag
|
|
337
355
|
const tag = event.tag;
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
.map(item => {
|
|
342
|
-
if (item.type == 'Link') {
|
|
343
|
-
return `[${item.options?.title ?? item.value}](${item.value})`;
|
|
344
|
-
}
|
|
345
|
-
else if (item.type == 'Mention') {
|
|
346
|
-
if (item.value == 'everyone' ||
|
|
347
|
-
item.value == 'all' ||
|
|
348
|
-
item.value == '' ||
|
|
349
|
-
typeof item.value != 'string') {
|
|
350
|
-
return ``;
|
|
351
|
-
}
|
|
352
|
-
if (item.options?.belong == 'user') {
|
|
353
|
-
return `<@${item.value}>`;
|
|
354
|
-
}
|
|
355
|
-
return '';
|
|
356
|
-
// return `<qqbot-at-everyone />`
|
|
357
|
-
}
|
|
358
|
-
else if (item.type == 'Text') {
|
|
359
|
-
return item.value;
|
|
360
|
-
}
|
|
361
|
-
})
|
|
362
|
-
.join('');
|
|
363
|
-
if (content) {
|
|
364
|
-
return Promise.all([content].map(item => client.groupOpenMessages(event.GuildId, {
|
|
365
|
-
content: item,
|
|
366
|
-
msg_id: event.MessageId,
|
|
367
|
-
msg_type: 0,
|
|
368
|
-
msg_seq: client.getMessageSeq(event.MessageId)
|
|
369
|
-
})));
|
|
356
|
+
try {
|
|
357
|
+
if (tag == 'GROUP_AT_MESSAGE_CREATE') {
|
|
358
|
+
return await GROUP_AT_MESSAGE_CREATE(client, event, val);
|
|
370
359
|
}
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
return Promise.all(images.map(async (msg) => {
|
|
374
|
-
const file_info = await client
|
|
375
|
-
.postRichMediaByGroup(event.GuildId, {
|
|
376
|
-
file_type: 1,
|
|
377
|
-
file_data: msg.toString('base64')
|
|
378
|
-
})
|
|
379
|
-
.then(res => res?.file_info);
|
|
380
|
-
if (!file_info)
|
|
381
|
-
return Promise.resolve(null);
|
|
382
|
-
return client.groupOpenMessages(event.GuildId, {
|
|
383
|
-
content: '',
|
|
384
|
-
media: {
|
|
385
|
-
file_info
|
|
386
|
-
},
|
|
387
|
-
msg_id: event.MessageId,
|
|
388
|
-
msg_type: 7,
|
|
389
|
-
msg_seq: client.getMessageSeq(event.MessageId)
|
|
390
|
-
});
|
|
391
|
-
}));
|
|
360
|
+
if (tag == 'C2C_MESSAGE_CREATE') {
|
|
361
|
+
return await C2C_MESSAGE_CREATE(client, event, val);
|
|
392
362
|
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
if (item.type == 'Link') {
|
|
399
|
-
return `[${item.options?.title ?? item.value}](${item.value})`;
|
|
400
|
-
}
|
|
401
|
-
else if (item.type == 'Mention') {
|
|
402
|
-
if (item.value == 'everyone' ||
|
|
403
|
-
item.value == 'all' ||
|
|
404
|
-
item.value == '' ||
|
|
405
|
-
typeof item.value != 'string') {
|
|
406
|
-
return `@everyone`;
|
|
407
|
-
}
|
|
408
|
-
if (item.options?.belong == 'user') {
|
|
409
|
-
return `<@!${item.value}>`;
|
|
410
|
-
}
|
|
411
|
-
else if (item.options?.belong == 'channel') {
|
|
412
|
-
return `<#${item.value}>`;
|
|
413
|
-
}
|
|
414
|
-
return '';
|
|
415
|
-
}
|
|
416
|
-
else if (item.type == 'Text') {
|
|
417
|
-
return item.value;
|
|
418
|
-
}
|
|
419
|
-
})
|
|
420
|
-
.join('');
|
|
421
|
-
if (content) {
|
|
422
|
-
return Promise.all([content].map(item => client.channelsMessagesPost(event.ChannelId, {
|
|
423
|
-
content: item,
|
|
424
|
-
msg_id: event.MessageId
|
|
425
|
-
})));
|
|
363
|
+
if (tag == 'DIRECT_MESSAGE_CREATE') {
|
|
364
|
+
return await DIRECT_MESSAGE_CREATE(client, event, val);
|
|
365
|
+
}
|
|
366
|
+
if (tag == 'AT_MESSAGE_CREATE') {
|
|
367
|
+
return await AT_MESSAGE_CREATE(client, event, val);
|
|
426
368
|
}
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
return Promise.all(images.map(item => client.postImage(event.ChannelId, {
|
|
430
|
-
msg_id: event.MessageId,
|
|
431
|
-
image: item
|
|
432
|
-
})));
|
|
369
|
+
if (tag == 'MESSAGE_CREATE') {
|
|
370
|
+
return await AT_MESSAGE_CREATE(client, event, val);
|
|
433
371
|
}
|
|
372
|
+
if (tag == 'MESSAGE_CREATE') {
|
|
373
|
+
return await MESSAGE_CREATE(client, event, val);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
catch (error) {
|
|
377
|
+
return [error];
|
|
434
378
|
}
|
|
435
|
-
return
|
|
379
|
+
return [];
|
|
436
380
|
},
|
|
437
381
|
mention: async (e) => {
|
|
438
382
|
const event = e.value;
|
|
439
383
|
const tag = e.tag;
|
|
440
384
|
// const event = e.value
|
|
441
385
|
const Metions = [];
|
|
442
|
-
|
|
386
|
+
// group
|
|
387
|
+
if (tag == 'GROUP_AT_MESSAGE_CREATE' || 'C2C_MESSAGE_CREATE')
|
|
443
388
|
return Metions;
|
|
444
|
-
|
|
389
|
+
// guild
|
|
445
390
|
if (event.mentions) {
|
|
446
391
|
const mentions = e.value['mentions'];
|
|
447
392
|
// 艾特消息处理
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
const GROUP_AT_MESSAGE_CREATE = (client, event, val) => {
|
|
2
|
+
const content = val
|
|
3
|
+
.filter(item => item.type == 'Link' || item.type == 'Mention' || item.type == 'Text')
|
|
4
|
+
.map(item => {
|
|
5
|
+
if (item.type == 'Link') {
|
|
6
|
+
return `[${item.options?.title ?? item.value}](${item.value})`;
|
|
7
|
+
}
|
|
8
|
+
else if (item.type == 'Mention') {
|
|
9
|
+
if (item.value == 'everyone' ||
|
|
10
|
+
item.value == 'all' ||
|
|
11
|
+
item.value == '' ||
|
|
12
|
+
typeof item.value != 'string') {
|
|
13
|
+
return ``;
|
|
14
|
+
}
|
|
15
|
+
if (item.options?.belong == 'user') {
|
|
16
|
+
return `<@${item.value}>`;
|
|
17
|
+
}
|
|
18
|
+
return '';
|
|
19
|
+
}
|
|
20
|
+
else if (item.type == 'Text') {
|
|
21
|
+
return item.value;
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
.join('');
|
|
25
|
+
if (content) {
|
|
26
|
+
return Promise.all([content].map(item => client.groupOpenMessages(event.GuildId, {
|
|
27
|
+
content: item,
|
|
28
|
+
msg_id: event.MessageId,
|
|
29
|
+
msg_type: 0,
|
|
30
|
+
msg_seq: client.getMessageSeq(event.MessageId)
|
|
31
|
+
})));
|
|
32
|
+
}
|
|
33
|
+
const images = val.filter(item => item.type == 'Image').map(item => item.value);
|
|
34
|
+
if (images) {
|
|
35
|
+
return Promise.all(images.map(async (msg) => {
|
|
36
|
+
const file_info = await client
|
|
37
|
+
.postRichMediaByGroup(event.GuildId, {
|
|
38
|
+
file_type: 1,
|
|
39
|
+
file_data: msg.toString('base64')
|
|
40
|
+
})
|
|
41
|
+
.then(res => res?.file_info);
|
|
42
|
+
if (!file_info)
|
|
43
|
+
return Promise.resolve(null);
|
|
44
|
+
return client.groupOpenMessages(event.GuildId, {
|
|
45
|
+
content: '',
|
|
46
|
+
media: {
|
|
47
|
+
file_info
|
|
48
|
+
},
|
|
49
|
+
msg_id: event.MessageId,
|
|
50
|
+
msg_type: 7,
|
|
51
|
+
msg_seq: client.getMessageSeq(event.MessageId)
|
|
52
|
+
});
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
return [];
|
|
56
|
+
};
|
|
57
|
+
const C2C_MESSAGE_CREATE = (client, event, val) => {
|
|
58
|
+
const content = val
|
|
59
|
+
.filter(item => item.type == 'Link' || item.type == 'Mention' || item.type == 'Text')
|
|
60
|
+
.map(item => {
|
|
61
|
+
if (item.type == 'Text') {
|
|
62
|
+
return item.value;
|
|
63
|
+
}
|
|
64
|
+
return '';
|
|
65
|
+
})
|
|
66
|
+
.join('');
|
|
67
|
+
if (content) {
|
|
68
|
+
return Promise.all([content].map(item => client.usersOpenMessages(event.OpenId, {
|
|
69
|
+
content: item,
|
|
70
|
+
msg_id: event.MessageId,
|
|
71
|
+
msg_type: 0,
|
|
72
|
+
msg_seq: client.getMessageSeq(event.MessageId)
|
|
73
|
+
})));
|
|
74
|
+
}
|
|
75
|
+
const images = val.filter(item => item.type == 'Image').map(item => item.value);
|
|
76
|
+
if (images) {
|
|
77
|
+
return Promise.all(images.map(async (msg) => {
|
|
78
|
+
const file_info = await client
|
|
79
|
+
.postRichMediaByUsers(event.OpenId, {
|
|
80
|
+
file_type: 1,
|
|
81
|
+
file_data: msg.toString('base64')
|
|
82
|
+
})
|
|
83
|
+
.then(res => res?.file_info);
|
|
84
|
+
if (!file_info)
|
|
85
|
+
return Promise.resolve(null);
|
|
86
|
+
return client.usersOpenMessages(event.OpenId, {
|
|
87
|
+
content: '',
|
|
88
|
+
media: {
|
|
89
|
+
file_info
|
|
90
|
+
},
|
|
91
|
+
msg_id: event.MessageId,
|
|
92
|
+
msg_type: 7,
|
|
93
|
+
msg_seq: client.getMessageSeq(event.MessageId)
|
|
94
|
+
});
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
return [];
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* 频道私聊
|
|
101
|
+
* @param client
|
|
102
|
+
* @param event
|
|
103
|
+
* @param val
|
|
104
|
+
* @returns
|
|
105
|
+
*/
|
|
106
|
+
const DIRECT_MESSAGE_CREATE = (client, event, val) => {
|
|
107
|
+
const content = val
|
|
108
|
+
.filter(item => item.type == 'Link' || item.type == 'Mention' || item.type == 'Text')
|
|
109
|
+
.map(item => {
|
|
110
|
+
if (item.type == 'Text') {
|
|
111
|
+
return item.value;
|
|
112
|
+
}
|
|
113
|
+
return '';
|
|
114
|
+
})
|
|
115
|
+
.join('');
|
|
116
|
+
if (content) {
|
|
117
|
+
return Promise.all([content].map(item => client.dmsMessage(event.OpenId, {
|
|
118
|
+
content: item,
|
|
119
|
+
msg_id: event.MessageId
|
|
120
|
+
})));
|
|
121
|
+
}
|
|
122
|
+
const images = val.filter(item => item.type == 'Image').map(item => item.value);
|
|
123
|
+
if (images) {
|
|
124
|
+
return Promise.all(images.map(item => client.postDirectImage(event.OpenId, {
|
|
125
|
+
msg_id: event.MessageId,
|
|
126
|
+
image: item
|
|
127
|
+
})));
|
|
128
|
+
}
|
|
129
|
+
return [];
|
|
130
|
+
};
|
|
131
|
+
const AT_MESSAGE_CREATE = (client, event, val) => {
|
|
132
|
+
const content = val
|
|
133
|
+
.filter(item => item.type == 'Link' || item.type == 'Mention' || item.type == 'Text')
|
|
134
|
+
.map(item => {
|
|
135
|
+
if (item.type == 'Link') {
|
|
136
|
+
return `[${item.options?.title ?? item.value}](${item.value})`;
|
|
137
|
+
}
|
|
138
|
+
else if (item.type == 'Mention') {
|
|
139
|
+
if (item.value == 'everyone' ||
|
|
140
|
+
item.value == 'all' ||
|
|
141
|
+
item.value == '' ||
|
|
142
|
+
typeof item.value != 'string') {
|
|
143
|
+
return `@everyone`;
|
|
144
|
+
}
|
|
145
|
+
if (item.options?.belong == 'user') {
|
|
146
|
+
return `<@!${item.value}>`;
|
|
147
|
+
}
|
|
148
|
+
else if (item.options?.belong == 'channel') {
|
|
149
|
+
return `<#${item.value}>`;
|
|
150
|
+
}
|
|
151
|
+
return '';
|
|
152
|
+
}
|
|
153
|
+
else if (item.type == 'Text') {
|
|
154
|
+
return item.value;
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
.join('');
|
|
158
|
+
if (content) {
|
|
159
|
+
return Promise.all([content].map(item => client.channelsMessagesPost(event.ChannelId, {
|
|
160
|
+
content: item,
|
|
161
|
+
msg_id: event.MessageId
|
|
162
|
+
})));
|
|
163
|
+
}
|
|
164
|
+
const images = val.filter(item => item.type == 'Image').map(item => item.value);
|
|
165
|
+
if (images) {
|
|
166
|
+
return Promise.all(images.map(item => client.postImage(event.ChannelId, {
|
|
167
|
+
msg_id: event.MessageId,
|
|
168
|
+
image: item
|
|
169
|
+
})));
|
|
170
|
+
}
|
|
171
|
+
return [];
|
|
172
|
+
};
|
|
173
|
+
/**
|
|
174
|
+
*
|
|
175
|
+
* @param event
|
|
176
|
+
* @param val
|
|
177
|
+
* @returns
|
|
178
|
+
*/
|
|
179
|
+
const MESSAGE_CREATE = (client, event, val) => {
|
|
180
|
+
const content = val
|
|
181
|
+
.filter(item => item.type == 'Link' || item.type == 'Mention' || item.type == 'Text')
|
|
182
|
+
.map(item => {
|
|
183
|
+
if (item.type == 'Link') {
|
|
184
|
+
return `[${item.options?.title ?? item.value}](${item.value})`;
|
|
185
|
+
}
|
|
186
|
+
else if (item.type == 'Mention') {
|
|
187
|
+
if (item.value == 'everyone' ||
|
|
188
|
+
item.value == 'all' ||
|
|
189
|
+
item.value == '' ||
|
|
190
|
+
typeof item.value != 'string') {
|
|
191
|
+
return `@everyone`;
|
|
192
|
+
}
|
|
193
|
+
if (item.options?.belong == 'user') {
|
|
194
|
+
return `<@!${item.value}>`;
|
|
195
|
+
}
|
|
196
|
+
else if (item.options?.belong == 'channel') {
|
|
197
|
+
return `<#${item.value}>`;
|
|
198
|
+
}
|
|
199
|
+
return '';
|
|
200
|
+
}
|
|
201
|
+
else if (item.type == 'Text') {
|
|
202
|
+
return item.value;
|
|
203
|
+
}
|
|
204
|
+
})
|
|
205
|
+
.join('');
|
|
206
|
+
if (content) {
|
|
207
|
+
return Promise.all([content].map(item => client.channelsMessagesPost(event.ChannelId, {
|
|
208
|
+
content: item,
|
|
209
|
+
msg_id: event.MessageId
|
|
210
|
+
})));
|
|
211
|
+
}
|
|
212
|
+
const images = val.filter(item => item.type == 'Image').map(item => item.value);
|
|
213
|
+
if (images) {
|
|
214
|
+
return Promise.all(images.map(item => client.postImage(event.ChannelId, {
|
|
215
|
+
msg_id: event.MessageId,
|
|
216
|
+
image: item
|
|
217
|
+
})));
|
|
218
|
+
}
|
|
219
|
+
return [];
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
export { AT_MESSAGE_CREATE, C2C_MESSAGE_CREATE, DIRECT_MESSAGE_CREATE, GROUP_AT_MESSAGE_CREATE, MESSAGE_CREATE };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alemonjs/qq-bot",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "qq-bot",
|
|
5
5
|
"author": "lemonade",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,7 +26,6 @@
|
|
|
26
26
|
"@noble/curves": "^1.7.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"alemonjs": "^2.0.0-rc.77",
|
|
30
29
|
"@rollup/plugin-typescript": "^11.1.6",
|
|
31
30
|
"lvyjs": "^0.2.13",
|
|
32
31
|
"rollup": "^4.18.1",
|