@alemonjs/qq-bot 2.1.0-alpha.17 → 2.1.0-alpha.18

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.
@@ -43,16 +43,18 @@ class QQBotClient extends QQBotAPI {
43
43
  async #setTimeoutBotConfig() {
44
44
  const callBack = async () => {
45
45
  const app_id = config.get('app_id');
46
- if (!app_id)
46
+ if (!app_id) {
47
47
  return;
48
+ }
48
49
  const secret = config.get('secret');
49
- if (!secret)
50
+ if (!secret) {
50
51
  return;
52
+ }
51
53
  // 发送请求
52
54
  const data = await this.getAuthentication(app_id, secret).then(res => res.data);
53
55
  config.set('access_token', data.access_token);
54
56
  console.info('refresh', data.expires_in, 's');
55
- setTimeout(callBack, data.expires_in * 1000);
57
+ setTimeout(() => void callBack(), data.expires_in * 1000);
56
58
  };
57
59
  await callBack();
58
60
  }
@@ -65,7 +67,7 @@ class QQBotClient extends QQBotAPI {
65
67
  try {
66
68
  const ws = config.get('ws');
67
69
  if (!ws) {
68
- this.#setTimeoutBotConfig();
70
+ void this.#setTimeoutBotConfig();
69
71
  this.#app = new Koa();
70
72
  this.#app.use(bodyParser());
71
73
  const router = new Router();
@@ -86,7 +88,7 @@ class QQBotClient extends QQBotAPI {
86
88
  await next();
87
89
  });
88
90
  // 启动服务
89
- router.post(route, async (ctx) => {
91
+ router.post(route, ctx => {
90
92
  const sign = ctx.req.headers['x-signature-ed25519'];
91
93
  const timestamp = ctx.req.headers['x-signature-timestamp'];
92
94
  const rawBody = ctx.request.rawBody;
@@ -97,7 +99,7 @@ class QQBotClient extends QQBotAPI {
97
99
  return;
98
100
  }
99
101
  const body = ctx.request.body;
100
- if (body.op == 13) {
102
+ if (+body.op === 13) {
101
103
  ctx.status = 200;
102
104
  ctx.body = {
103
105
  // 返回明文 token
@@ -106,18 +108,19 @@ class QQBotClient extends QQBotAPI {
106
108
  signature: ntqqWebhook.getSign(body.d.event_ts, body.d.plain_token)
107
109
  };
108
110
  }
109
- else if (body.op == 0) {
111
+ else if (+body.op === 0) {
110
112
  ctx.status = 204;
111
113
  // 根据事件类型,处理事件
112
114
  for (const event of this.#events[body.t] || []) {
113
115
  event(body.d);
114
116
  }
115
- const access_token = config.get('access_token');
117
+ const accessToken = config.get('access_token');
116
118
  // 也可以分法到客户端。 发送失败需要处理 或清理调
117
119
  for (const client of this.#client) {
118
120
  try {
119
- if (access_token)
120
- body['access_token'] = access_token;
121
+ if (accessToken) {
122
+ body['access_token'] = accessToken;
123
+ }
121
124
  client.ws.send(JSON.stringify(body));
122
125
  }
123
126
  catch (e) {
@@ -173,9 +176,10 @@ class QQBotClient extends QQBotAPI {
173
176
  try {
174
177
  // 拿到消息
175
178
  const body = JSON.parse(data.toString());
176
- const access_token = body['access_token'];
177
- if (access_token)
178
- config.set('access_token', access_token);
179
+ const accessToken = body['access_token'];
180
+ if (accessToken) {
181
+ config.set('access_token', accessToken);
182
+ }
179
183
  for (const event of this.#events[body.t] || []) {
180
184
  event(body.d);
181
185
  }
@@ -187,8 +191,9 @@ class QQBotClient extends QQBotAPI {
187
191
  this.#ws.on('close', () => {
188
192
  console.log('ws closed');
189
193
  // 重连5次,超过5次不再重连
190
- if (this.#count > 5)
194
+ if (this.#count > 5) {
191
195
  return;
196
+ }
192
197
  // 1.3s 后重连
193
198
  setTimeout(() => {
194
199
  reConnect();
@@ -37,16 +37,16 @@ class QQBotClients extends QQBotAPI {
37
37
  const accessToken = async () => {
38
38
  const app_id = config.get('app_id');
39
39
  const secret = config.get('secret');
40
- if (!app_id || !secret)
40
+ if (!app_id || !secret) {
41
41
  return;
42
+ }
42
43
  // 发送请求
43
44
  const data = await this.getAuthentication(app_id, secret).then(res => res.data);
44
45
  config.set('access_token', data.access_token);
45
46
  console.info('refresh', data.expires_in, 's');
46
- setTimeout(accessToken, data.expires_in * 1000);
47
+ setTimeout(() => void accessToken(), data.expires_in * 1000);
47
48
  };
48
49
  await accessToken();
49
- return;
50
50
  }
51
51
  /**
52
52
  * 鉴权数据
@@ -78,8 +78,9 @@ class QQBotClients extends QQBotAPI {
78
78
  * @param val 事件处理函数
79
79
  */
80
80
  on(key, val) {
81
- if (!this.#events[key])
81
+ if (!this.#events[key]) {
82
82
  this.#events[key] = [];
83
+ }
83
84
  this.#events[key].push(val);
84
85
  return this;
85
86
  }
@@ -95,16 +96,17 @@ class QQBotClients extends QQBotAPI {
95
96
  if (!this.#gatewayUrl) {
96
97
  this.#gatewayUrl = gatewayURL ?? (await this.gateway().then(res => res?.url));
97
98
  }
98
- if (!this.#gatewayUrl)
99
+ if (!this.#gatewayUrl) {
99
100
  return;
101
+ }
100
102
  // 重新连接的逻辑
101
- const reconnect = async () => {
103
+ const reconnect = () => {
102
104
  if (this.#counter.value >= 5) {
103
105
  console.info('The maximum number of reconnections has been reached, cancel reconnection');
104
106
  return;
105
107
  }
106
108
  setTimeout(() => {
107
- console.info('[ws] reconnecting...');
109
+ console.info('[ws-qqbot] reconnecting...');
108
110
  // 重新starrt
109
111
  start();
110
112
  // 记录
@@ -114,13 +116,14 @@ class QQBotClients extends QQBotAPI {
114
116
  const start = () => {
115
117
  if (this.#gatewayUrl) {
116
118
  const map = {
117
- 0: async ({ t, d }) => {
119
+ 0: ({ t, d }) => {
118
120
  if (this.#events[t]) {
119
121
  try {
120
122
  for (const event of this.#events[t]) {
121
123
  // 是否是函数
122
- if (typeof event != 'function')
124
+ if (typeof event !== 'function') {
123
125
  continue;
126
+ }
124
127
  event(d);
125
128
  }
126
129
  }
@@ -128,8 +131,9 @@ class QQBotClients extends QQBotAPI {
128
131
  if (this.#events['ERROR']) {
129
132
  for (const event of this.#events['ERROR']) {
130
133
  // 是否是函数
131
- if (typeof event != 'function')
134
+ if (typeof event !== 'function') {
132
135
  continue;
136
+ }
133
137
  event(err);
134
138
  }
135
139
  }
@@ -138,38 +142,34 @@ class QQBotClients extends QQBotAPI {
138
142
  // Ready Event,鉴权成功
139
143
  if (t === 'READY') {
140
144
  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
- }));
145
+ if (this.#isConnected && this.#ws) {
146
+ this.#ws.send(JSON.stringify({
147
+ op: 1, // op = 1
148
+ d: null // 如果是第一次连接,传null
149
+ }));
147
150
  }
148
151
  }, this.#heartbeat_interval);
149
152
  }
150
153
  // Resumed Event,恢复连接成功
151
154
  if (t === 'RESUMED') {
152
- console.info('[ws] restore connection');
155
+ console.info('[ws-qqbot] restore connection');
153
156
  // 重制次数
154
157
  this.#counter.reStart();
155
158
  }
156
- return;
157
159
  },
158
160
  6: ({ d }) => {
159
- console.info('[ws] connection attempt', d);
160
- return;
161
+ console.info('[ws-qqbot] connection attempt', d);
161
162
  },
162
- 7: async ({ d }) => {
163
+ 7: ({ d }) => {
163
164
  // 执行重新连接
164
- console.info('[ws] reconnect', d);
165
+ console.info('[ws-qqbot] reconnect', d);
165
166
  // 取消鉴权发送
166
- if (this.#IntervalId)
167
+ if (this.#IntervalId) {
167
168
  clearInterval(this.#IntervalId);
168
- return;
169
+ }
169
170
  },
170
171
  9: ({ d }) => {
171
- console.info('[ws] parameter error', d);
172
- return;
172
+ console.info('[ws-qqbot] parameter error', d);
173
173
  },
174
174
  10: ({ d }) => {
175
175
  // 重制次数
@@ -177,40 +177,40 @@ class QQBotClients extends QQBotAPI {
177
177
  // 记录新循环
178
178
  this.#heartbeat_interval = d.heartbeat_interval;
179
179
  // 发送鉴权
180
- this.#ws && this.#ws.send(JSON.stringify(this.#aut()));
181
- return;
180
+ if (this.#ws) {
181
+ this.#ws.send(JSON.stringify(this.#aut()));
182
+ }
182
183
  },
183
184
  11: () => {
184
185
  // OpCode 11 Heartbeat ACK 消息,心跳发送成功
185
- console.info('[ws] heartbeat transmission');
186
+ console.info('[ws-qqbot] heartbeat transmission');
186
187
  // 重制次数
187
188
  this.#counter.reStart();
188
- return;
189
189
  },
190
190
  12: ({ d }) => {
191
- console.info('[ws] platform data', d);
192
- return;
191
+ console.debug('[ws-qqbot] platform data', d);
193
192
  }
194
193
  };
195
194
  // 连接
196
195
  this.#ws = new WebSocket(this.#gatewayUrl);
197
196
  this.#ws.on('open', () => {
198
- console.info('[ws] open');
197
+ console.info('[ws-qqbot] open');
199
198
  });
200
199
  // 监听消息
201
- this.#ws.on('message', async (msg) => {
200
+ this.#ws.on('message', msg => {
202
201
  const message = JSON.parse(msg.toString('utf8'));
203
- if (process.env.NTQQ_WS == 'dev')
202
+ if (process.env.NTQQ_WS === 'dev') {
204
203
  console.info('message', message);
204
+ }
205
205
  // 根据 opcode 进行处理
206
206
  if (map[message.op]) {
207
207
  map[message.op](message);
208
208
  }
209
209
  });
210
210
  // 关闭
211
- this.#ws.on('close', async (err) => {
212
- await reconnect();
213
- console.info('[ws] close', err);
211
+ this.#ws.on('close', err => {
212
+ void reconnect();
213
+ console.info('[ws-qqbot] close', err);
214
214
  });
215
215
  }
216
216
  };
@@ -0,0 +1,109 @@
1
+ const filterHeaders = (headers = {}) => {
2
+ if (!headers) {
3
+ return headers;
4
+ }
5
+ const filtered = {};
6
+ const sensitiveKeys = [/^authorization$/i, /^cookie$/i, /^set-cookie$/i, /token/i, /key/i, /jwt/i, /^session[-_]id$/i, /^uid$/i, /^user[-_]id$/i];
7
+ for (const key in headers) {
8
+ if (/^_/.test(key)) {
9
+ continue; // 跳过 _ 开头
10
+ }
11
+ // 去掉 Symbol 类型的 key
12
+ if (typeof key === 'symbol') {
13
+ continue;
14
+ }
15
+ // 去掉函数
16
+ if (typeof headers[key] === 'function') {
17
+ continue;
18
+ }
19
+ // 如果是敏感字段全部替换为 ******
20
+ if (sensitiveKeys.some(re => re.test(key))) {
21
+ filtered[key] = '******';
22
+ }
23
+ else {
24
+ filtered[key] = headers[key];
25
+ }
26
+ }
27
+ return filtered;
28
+ };
29
+ const filterConfig = (config = {}) => {
30
+ if (!config) {
31
+ return config;
32
+ }
33
+ const filtered = {};
34
+ for (const key in config) {
35
+ if (/^_/.test(key)) {
36
+ continue; // 跳过 _ 开头
37
+ }
38
+ // 去掉 Symbol 类型的 key
39
+ if (typeof key === 'symbol') {
40
+ continue;
41
+ }
42
+ // 去掉函数
43
+ if (typeof config[key] === 'function') {
44
+ continue;
45
+ }
46
+ filtered[key] = config[key];
47
+ }
48
+ return filtered;
49
+ };
50
+ const filterRequest = (request = {}) => {
51
+ if (!request) {
52
+ return request;
53
+ }
54
+ const filtered = {};
55
+ for (const key in request) {
56
+ if (/^_/.test(key)) {
57
+ continue; // 跳过 _ 开头
58
+ }
59
+ // 去掉 Symbol 类型的 key
60
+ if (typeof key === 'symbol') {
61
+ continue;
62
+ }
63
+ // 去掉函数
64
+ if (typeof request[key] === 'function') {
65
+ continue;
66
+ }
67
+ filtered[key] = request[key];
68
+ }
69
+ return filtered;
70
+ };
71
+ // 处理axios错误
72
+ const loggerError = (err) => {
73
+ // 错误时的请求头
74
+ logger.error('[axios] error', {
75
+ config: {
76
+ headers: filterHeaders(err?.config?.headers),
77
+ params: err?.config?.params,
78
+ data: err?.config?.data
79
+ },
80
+ response: {
81
+ status: err?.response?.status,
82
+ statusText: err?.response?.statusText,
83
+ headers: filterHeaders(err?.response?.headers),
84
+ config: filterConfig(err?.response?.config),
85
+ request: filterRequest(err?.response?.request),
86
+ data: err?.response?.data
87
+ },
88
+ message: err?.message
89
+ });
90
+ };
91
+ /**
92
+ * 基础请求
93
+ * @param service
94
+ * @param options
95
+ * @returns
96
+ */
97
+ const createAxiosInstance = (service, options) => {
98
+ return new Promise((resolve, reject) => {
99
+ service(options)
100
+ .then(res => resolve(res?.data ?? {}))
101
+ .catch(err => {
102
+ loggerError(err);
103
+ // 丢出错误中携带的响应数据
104
+ reject(err?.response?.data);
105
+ });
106
+ });
107
+ };
108
+
109
+ export { createAxiosInstance };
@@ -37,10 +37,12 @@ class WebhookAPI {
37
37
  */
38
38
  getKey() {
39
39
  let seed = this.config.secret;
40
- if (!seed)
40
+ if (!seed) {
41
41
  throw new Error("secret not set, can't calc ed25519 key");
42
- while (seed.length < 32)
43
- seed = seed.repeat(2); // Ed25519 的种子大小是 32 字节
42
+ }
43
+ while (seed.length < 32) {
44
+ seed = seed.repeat(2);
45
+ } // Ed25519 的种子大小是 32 字节
44
46
  seed = seed.slice(0, 32); // 修剪到 32 字节
45
47
  const privateKey = Buffer.from(seed);
46
48
  return {