@alemonjs/onebot 2.1.0-alpha.0 → 2.1.0-alpha.10

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 CHANGED
@@ -9,4 +9,10 @@ onebot:
9
9
  reverse_enable: false # 启用后正向连接配置失效,地址:ws://127.0.0.1:17158
10
10
  reverse_port: 17158 # 返向连接服务端口,启用反向连接后生效
11
11
  master_key: null
12
+ # 使用 user_key
13
+ master_key:
14
+ - 'xxx'
15
+ # 使用 user_id
16
+ master_id:
17
+ - 'yyy'
12
18
  ```
package/lib/config.js CHANGED
@@ -1,9 +1,20 @@
1
- import { getConfigValue } from 'alemonjs';
1
+ import { getConfigValue, useUserHashKey } from 'alemonjs';
2
2
 
3
3
  const platform = 'onebot';
4
4
  const getOneBotConfig = () => {
5
5
  const value = getConfigValue() || {};
6
6
  return value[platform] || {};
7
7
  };
8
+ const getMaster = (UserId) => {
9
+ const config = getOneBotConfig();
10
+ const master_key = config.master_key || [];
11
+ const master_id = config.master_id || [];
12
+ const UserKey = useUserHashKey({
13
+ Platform: platform,
14
+ UserId: UserId
15
+ });
16
+ const is = master_key.includes(UserKey) || master_id.includes(UserId);
17
+ return [is, UserKey];
18
+ };
8
19
 
9
- export { getOneBotConfig, platform };
20
+ export { getMaster, getOneBotConfig, platform };
package/lib/db.js ADDED
@@ -0,0 +1,4 @@
1
+ const BotMe = {
2
+ id: ''};
3
+
4
+ export { BotMe };
package/lib/hook.d.ts ADDED
@@ -0,0 +1,38 @@
1
+ import { EventKeys, Events } from 'alemonjs';
2
+ import { OneBotAPI } from './sdk/api.js';
3
+ import { MESSAGES_TYPE, DIRECT_MESSAGE_TYPE } from './sdk/types.js';
4
+
5
+ type MAP = {
6
+ 'message.create': MESSAGES_TYPE;
7
+ 'private.message.create': DIRECT_MESSAGE_TYPE;
8
+ 'interaction.create': undefined;
9
+ 'private.interaction.create': undefined;
10
+ 'message.update': undefined;
11
+ 'message.delete': undefined;
12
+ 'message.reaction.add': undefined;
13
+ 'message.reaction.remove': undefined;
14
+ 'channal.create': undefined;
15
+ 'channal.delete': undefined;
16
+ 'guild.join': undefined;
17
+ 'guild.exit': undefined;
18
+ 'member.add': undefined;
19
+ 'member.remove': undefined;
20
+ 'private.message.update': undefined;
21
+ 'private.message.delete': undefined;
22
+ 'private.friend.add': undefined;
23
+ 'private.guild.add': undefined;
24
+ };
25
+ /**
26
+ *
27
+ * @param event
28
+ * @returns
29
+ */
30
+ declare const useValue: <T extends EventKeys>(event: Events[T]) => readonly [MAP[T]];
31
+ /**
32
+ *
33
+ * @param event
34
+ * @returns
35
+ */
36
+ declare const useClient: <T extends EventKeys>(event: Events[T]) => readonly [OneBotAPI, MAP[T]];
37
+
38
+ export { useClient, useValue };
package/lib/hook.js ADDED
@@ -0,0 +1,24 @@
1
+ import { createEventValue, useClient as useClient$1 } from 'alemonjs';
2
+ import { OneBotAPI } from './sdk/api.js';
3
+
4
+ /**
5
+ *
6
+ * @param event
7
+ * @returns
8
+ */
9
+ const useValue = (event) => {
10
+ const value = createEventValue(event);
11
+ return [value];
12
+ };
13
+ /**
14
+ *
15
+ * @param event
16
+ * @returns
17
+ */
18
+ const useClient = (event) => {
19
+ const [client] = useClient$1(event, OneBotAPI);
20
+ const value = createEventValue(event);
21
+ return [client, value];
22
+ };
23
+
24
+ export { useClient, useValue };
package/lib/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { platform } from './config.js';
2
2
  export { OneBotAPI as API } from './sdk/api.js';
3
+ export { useClient, useValue } from './hook.js';
3
4
 
4
- declare const _default: () => void;
5
+ declare const main: () => void;
5
6
 
6
- export { _default as default };
7
+ export { main as default };
package/lib/index.js CHANGED
@@ -1,13 +1,13 @@
1
- import { cbpPlatform, useUserHashKey, createResult, ResultCode } from 'alemonjs';
1
+ import { cbpPlatform, createResult, ResultCode } from 'alemonjs';
2
2
  import { getBufferByURL } from 'alemonjs/utils';
3
- import { OneBotClient } from './sdk/wss.js';
4
3
  import { readFileSync } from 'fs';
5
- import { getOneBotConfig, platform } from './config.js';
4
+ import { getOneBotConfig, getMaster, platform } from './config.js';
5
+ import { OneBotClient } from './sdk/wss.js';
6
+ import { BotMe } from './db.js';
6
7
  export { OneBotAPI as API } from './sdk/api.js';
8
+ export { useClient, useValue } from './hook.js';
7
9
 
8
- const MyBot = {
9
- id: ''};
10
- var index = () => {
10
+ const main = () => {
11
11
  const config = getOneBotConfig();
12
12
  const client = new OneBotClient({
13
13
  // url
@@ -19,8 +19,8 @@ var index = () => {
19
19
  // 反向连接端口
20
20
  reverse_port: config?.reverse_port ?? 17158
21
21
  });
22
- client.connect();
23
- const url = `ws://127.0.0.1:${process.env?.port || config?.port || 17117}`;
22
+ void client.connect();
23
+ const url = `ws://127.0.0.1:${process.env?.port || 17117}`;
24
24
  const cbp = cbpPlatform(url);
25
25
  const createUserAvatar = (id) => {
26
26
  return `https://q1.qlogo.cn/g?b=qq&s=0&nk=${id}`;
@@ -28,7 +28,7 @@ var index = () => {
28
28
  const getMessageText = (message) => {
29
29
  let msg = '';
30
30
  for (const item of message) {
31
- if (item.type == 'text') {
31
+ if (item.type === 'text') {
32
32
  msg += item.data.text;
33
33
  }
34
34
  }
@@ -36,18 +36,14 @@ var index = () => {
36
36
  };
37
37
  client.on('META', event => {
38
38
  if (event?.self_id) {
39
- MyBot.id = String(event.self_id);
39
+ BotMe.id = String(event.self_id);
40
40
  }
41
41
  });
42
42
  client.on('MESSAGES', event => {
43
- const uis = config?.master_id ?? [];
44
43
  const msg = getMessageText(event.message);
45
44
  const UserId = String(event.user_id);
46
45
  const UserAvatar = createUserAvatar(UserId);
47
- const UserKey = useUserHashKey({
48
- Platform: platform,
49
- UserId
50
- });
46
+ const [isMaster, UserKey] = getMaster(UserId);
51
47
  const groupId = String(event.group_id);
52
48
  // 定义消
53
49
  const e = {
@@ -55,7 +51,7 @@ var index = () => {
55
51
  Platform: platform,
56
52
  GuildId: groupId,
57
53
  ChannelId: groupId,
58
- IsMaster: uis.includes(UserId),
54
+ IsMaster: isMaster,
59
55
  SpaceId: groupId,
60
56
  IsBot: false,
61
57
  UserId: UserId,
@@ -72,19 +68,15 @@ var index = () => {
72
68
  cbp.send(e);
73
69
  });
74
70
  client.on('DIRECT_MESSAGE', event => {
75
- const uis = config?.master_id ?? [];
76
71
  const msg = getMessageText(event.message);
77
72
  const UserId = String(event.user_id);
78
73
  const UserAvatar = createUserAvatar(UserId);
79
- const UserKey = useUserHashKey({
80
- Platform: platform,
81
- UserId
82
- });
74
+ const [isMaster, UserKey] = getMaster(UserId);
83
75
  // 定义消
84
76
  const e = {
85
77
  name: 'private.message.create',
86
78
  Platform: platform,
87
- IsMaster: uis.includes(String(event.user_id)),
79
+ IsMaster: isMaster,
88
80
  IsBot: false,
89
81
  UserId: UserId,
90
82
  UserName: event.sender.nickname,
@@ -99,228 +91,300 @@ var index = () => {
99
91
  };
100
92
  cbp.send(e);
101
93
  });
102
- // 错误处理
103
- client.on('ERROR', event => {
104
- logger.error(event);
105
- });
106
- const sendGroup = async (event, val) => {
107
- if (val.length < 0)
108
- return [];
109
- const content = val
110
- .filter(item => item.type == 'Mention' || item.type == 'Text')
111
- .map(item => item.value)
112
- .join('');
113
- try {
114
- if (content) {
115
- const res = await client.sendGroupMessage({
116
- group_id: event.ChannelId,
117
- message: [
118
- {
119
- type: 'text',
120
- data: {
121
- text: content
122
- }
94
+ /**
95
+ * @param val
96
+ * @returns
97
+ */
98
+ const DataToMessage = async (val = []) => {
99
+ // 空元素
100
+ const empty = {
101
+ type: 'text',
102
+ data: {
103
+ text: ''
104
+ }
105
+ };
106
+ const message = await Promise.all(val.map(async (item) => {
107
+ if (item.type === 'Text') {
108
+ return {
109
+ type: 'text',
110
+ data: {
111
+ text: item.value
112
+ }
113
+ };
114
+ }
115
+ else if (item.type === 'Mention') {
116
+ const options = item.options || {};
117
+ if (options.belong === 'everyone') {
118
+ return {
119
+ type: 'at',
120
+ data: {
121
+ qq: 'all',
122
+ nickname: ''
123
123
  }
124
- ]
125
- });
126
- return [createResult(ResultCode.Ok, 'client.groupOpenMessages', res)];
124
+ };
125
+ }
126
+ else if (options.belong === 'user') {
127
+ return {
128
+ type: 'at',
129
+ data: {
130
+ qq: item.value
131
+ }
132
+ };
133
+ }
134
+ return empty;
127
135
  }
128
- const images = val.filter(item => item.type == 'Image' || item.type == 'ImageFile' || item.type == 'ImageURL');
129
- if (images) {
130
- return Promise.all(images.map(async (item) => {
131
- let data = null;
132
- if (item.type === 'ImageFile') {
133
- const db = readFileSync(item.value);
134
- data = db;
136
+ else if (item.type === 'Image') {
137
+ return {
138
+ type: 'image',
139
+ data: {
140
+ file: `base64://${item.value}`
135
141
  }
136
- else if (item.type === 'ImageURL') {
137
- const db = await getBufferByURL(item.value);
138
- data = db;
142
+ };
143
+ }
144
+ else if (item.type === 'ImageFile') {
145
+ const db = readFileSync(item.value);
146
+ return {
147
+ type: 'image',
148
+ data: {
149
+ file: `base64://${db.toString('base64')}`
139
150
  }
140
- else {
141
- // data = item.value
142
- data = Buffer.from(item.value, 'base64');
151
+ };
152
+ }
153
+ else if (item.type === 'ImageURL') {
154
+ const db = await getBufferByURL(item.value);
155
+ return {
156
+ type: 'image',
157
+ data: {
158
+ file: `base64://${db.toString('base64')}`
143
159
  }
144
- client.sendGroupMessage({
145
- group_id: event.ChannelId,
146
- message: [
147
- {
148
- type: 'image',
149
- data: {
150
- file: `base64://${data.toString('base64')}`
151
- }
152
- }
153
- ]
154
- });
155
- return createResult(ResultCode.Ok, 'client.groupOpenMessages', {
156
- id: null
157
- });
158
- }));
160
+ };
159
161
  }
162
+ return empty;
163
+ }));
164
+ return message;
165
+ };
166
+ /**
167
+ *
168
+ * @param ChannelId
169
+ * @param val
170
+ * @returns
171
+ */
172
+ const sendGroup = async (ChannelId, val) => {
173
+ if (val.length < 0) {
174
+ return [];
175
+ }
176
+ try {
177
+ const message = await DataToMessage(val);
178
+ const res = await client.sendGroupMessage({
179
+ group_id: ChannelId,
180
+ message: message
181
+ });
182
+ return [createResult(ResultCode.Ok, 'client.groupOpenMessages', res)];
160
183
  }
161
184
  catch (error) {
162
185
  return [createResult(ResultCode.Fail, 'client.groupOpenMessages', error)];
163
186
  }
164
- return [];
165
187
  };
166
188
  /**
167
189
  *
168
- * @param event
190
+ * @param UserId
169
191
  * @param val
170
192
  * @returns
171
193
  */
172
- const sendPrivate = async (event, val) => {
173
- if (val.length < 0)
174
- return Promise.all([]);
175
- const content = val
176
- .filter(item => item.type == 'Link' || item.type == 'Mention' || item.type == 'Text')
177
- .map(item => item.value)
178
- .join('');
194
+ const sendPrivate = async (UserId, val) => {
195
+ if (val.length < 0) {
196
+ return [];
197
+ }
179
198
  try {
180
- if (content) {
181
- const res = await client.sendPrivateMessage({
182
- user_id: event.UserId,
183
- message: [
184
- {
185
- type: 'text',
186
- data: {
187
- text: content
188
- }
189
- }
190
- ]
191
- });
192
- return [createResult(ResultCode.Ok, 'client.sendPrivateMessage', res)];
193
- }
194
- const images = val.filter(item => item.type == 'Image' || item.type == 'ImageFile' || item.type == 'ImageURL');
195
- if (images) {
196
- return Promise.all(images.map(async (item) => {
197
- let data = null;
198
- if (item.type === 'ImageFile') {
199
- const db = readFileSync(item.value);
200
- data = db;
201
- }
202
- else if (item.type === 'ImageURL') {
203
- const db = await getBufferByURL(item.value);
204
- data = db;
205
- }
206
- else {
207
- // data = item.value
208
- data = Buffer.from(item.value, 'base64');
209
- }
210
- client.sendPrivateMessage({
211
- user_id: event.UserId,
212
- message: [
213
- {
214
- type: 'image',
215
- data: {
216
- file: `base64://${data.toString('base64')}`
217
- }
218
- }
219
- ]
220
- });
221
- return createResult(ResultCode.Ok, 'client.sendPrivateMessage', {
222
- id: null
223
- });
224
- }));
225
- }
199
+ const message = await DataToMessage(val);
200
+ const res = await client.sendPrivateMessage({
201
+ user_id: UserId,
202
+ message: message
203
+ });
204
+ return [createResult(ResultCode.Ok, 'client.groupOpenMessages', res)];
226
205
  }
227
206
  catch (error) {
228
- return [createResult(ResultCode.Fail, 'client.sendPrivateMessage', error)];
207
+ return [createResult(ResultCode.Fail, 'client.groupOpenMessages', error)];
229
208
  }
230
- return [];
231
209
  };
232
210
  const api = {
233
211
  active: {
234
212
  send: {
235
- channel: (event, val) => {
236
- return sendGroup(event, val);
213
+ channel: (SpaceId, val) => {
214
+ return sendGroup(Number(SpaceId), val);
237
215
  },
238
- user: (event, val) => {
239
- return sendPrivate(event, val);
216
+ user: (OpenId, val) => {
217
+ return sendPrivate(Number(OpenId), val);
240
218
  }
241
219
  }
242
220
  },
243
221
  use: {
244
222
  send: (event, val) => {
245
- if (val.length < 0)
223
+ if (val.length < 0) {
246
224
  return Promise.all([]);
247
- if (event['name'] == 'private.message.create') {
248
- return sendPrivate(event, val);
249
225
  }
250
- else if (event['name'] == 'message.create') {
251
- return sendGroup(event, val);
226
+ if (event['name'] === 'private.message.create') {
227
+ const UserId = Number(event.UserId);
228
+ return sendPrivate(UserId, val);
229
+ }
230
+ else if (event['name'] === 'message.create') {
231
+ const GroupId = Number(event.ChannelId);
232
+ return sendGroup(GroupId, val);
252
233
  }
253
234
  return Promise.all([]);
254
235
  },
255
- mention: async (event) => {
256
- const uis = config?.master_id ?? [];
236
+ mention: event => {
257
237
  const e = event.value;
258
- if (event['name'] == 'message.create' || event['name'] == 'private.message.create') {
259
- const Metions = [];
238
+ const names = ['message.create', 'private.message.create'];
239
+ if (names.includes(event.name)) {
240
+ const Mentions = [];
260
241
  for (const item of e.message) {
261
- if (item.type == 'at') {
242
+ if (item.type === 'at') {
262
243
  let isBot = false;
263
- const uid = String(item.data.qq);
264
- if (uid == 'all') {
244
+ const UserId = String(item.data.qq);
245
+ if (UserId === 'all') {
265
246
  continue;
266
247
  }
267
- if (uid == MyBot.id) {
248
+ if (UserId === BotMe.id) {
268
249
  isBot = true;
269
250
  }
270
- const avatar = createUserAvatar(uid);
271
- Metions.push({
272
- UserId: uid,
273
- UserKey: useUserHashKey({
274
- Platform: platform,
275
- UserId: uid
276
- }),
251
+ const [isMaster, UserKey] = getMaster(UserId);
252
+ const avatar = createUserAvatar(UserId);
253
+ Mentions.push({
254
+ UserId: UserId,
255
+ IsMaster: isMaster,
256
+ UserKey: UserKey,
277
257
  UserName: item.data?.nickname,
278
258
  UserAvatar: avatar,
279
- IsMaster: uis.includes(uid),
280
259
  IsBot: isBot
281
260
  });
282
261
  }
283
262
  }
284
- return Metions;
263
+ return new Promise(resolve => resolve(Mentions));
285
264
  }
286
- return [];
265
+ return new Promise(resolve => resolve([]));
266
+ },
267
+ delete(messageId) {
268
+ return client.deleteMsg({ message_id: Number(messageId) });
269
+ },
270
+ file: {
271
+ channel: client.uploadGroupFile.bind(client),
272
+ user: client.uploadPrivateFile.bind(client)
273
+ },
274
+ forward: {
275
+ channel: client.sendGroupForward.bind(client),
276
+ user: client.sendPrivateForward.bind(client)
287
277
  }
288
278
  }
289
279
  };
290
- cbp.onactions(async (data, consume) => {
291
- if (data.action === 'message.send') {
292
- const event = data.payload.event;
293
- const paramFormat = data.payload.params.format;
294
- const res = await api.use.send(event, paramFormat);
295
- consume(res);
296
- }
297
- else if (data.action === 'message.send.channel') {
298
- const channel_id = data.payload.ChannelId;
299
- const val = data.payload.params.format;
300
- const res = await api.active.send.channel(channel_id, val);
301
- consume(res);
302
- }
303
- else if (data.action === 'message.send.user') {
304
- const user_id = data.payload.UserId;
305
- const val = data.payload.params.format;
306
- const res = await api.active.send.user(user_id, val);
307
- consume(res);
308
- }
309
- else if (data.action === 'mention.get') {
310
- const event = data.payload.event;
311
- const res = await api.use.mention(event);
312
- consume([createResult(ResultCode.Ok, '请求完成', res)]);
280
+ const onactions = async (data, consume) => {
281
+ switch (data.action) {
282
+ case 'message.send': {
283
+ const event = data.payload.event;
284
+ const paramFormat = data.payload.params.format;
285
+ const res = await api.use.send(event, paramFormat);
286
+ return consume(res);
287
+ }
288
+ case 'message.send.channel': {
289
+ const channel_id = data.payload.ChannelId;
290
+ const val = data.payload.params.format;
291
+ const res = await api.active.send.channel(channel_id, val);
292
+ return consume(res);
293
+ }
294
+ case 'message.send.user': {
295
+ const user_id = data.payload.UserId;
296
+ const val = data.payload.params.format;
297
+ const res = await api.active.send.user(user_id, val);
298
+ return consume(res);
299
+ }
300
+ case 'mention.get': {
301
+ const event = data.payload.event;
302
+ const res = await api.use.mention(event);
303
+ return consume([createResult(ResultCode.Ok, '请求完成', res)]);
304
+ }
305
+ case 'message.delete': {
306
+ const res = await api.use
307
+ .delete(data.payload.MessageId)
308
+ .then(res => createResult(ResultCode.Ok, data.action, res))
309
+ .catch(err => createResult(ResultCode.Fail, data.action, err));
310
+ return consume([res]);
311
+ }
312
+ case 'file.send.channel': {
313
+ const res = await api.use.file
314
+ .channel(data.payload.ChannelId, data.payload.params)
315
+ .then(res => createResult(ResultCode.Ok, data.action, res))
316
+ .catch(err => createResult(ResultCode.Fail, data.action, err));
317
+ return consume([res]);
318
+ }
319
+ case 'file.send.user': {
320
+ const res = await api.use.file
321
+ .user(data.payload.UserId, data.payload.params)
322
+ .then(res => createResult(ResultCode.Ok, data.action, res))
323
+ .catch(err => createResult(ResultCode.Fail, data.action, err));
324
+ return consume([res]);
325
+ }
326
+ case 'message.forward.channel': {
327
+ const res = await api.use.forward
328
+ .channel(data.payload.ChannelId, data.payload.params.map(i => ({
329
+ ...i,
330
+ content: DataToMessage(i.content)
331
+ })))
332
+ .then(res => createResult(ResultCode.Ok, data.action, res))
333
+ .catch(err => createResult(ResultCode.Fail, data.action, err));
334
+ return consume([res]);
335
+ }
336
+ case 'message.forward.user': {
337
+ const res = await api.use.forward
338
+ .user(data.payload.UserId, data.payload.params.map(i => ({
339
+ ...i,
340
+ content: DataToMessage(i.content)
341
+ })))
342
+ .then(res => createResult(ResultCode.Ok, data.action, res))
343
+ .catch(err => createResult(ResultCode.Fail, data.action, err));
344
+ return consume([res]);
345
+ }
313
346
  }
314
- });
315
- // 处理 api 调用
316
- cbp.onapis(async (data, consume) => {
347
+ };
348
+ cbp.onactions((data, consume) => void onactions(data, consume));
349
+ const onapis = async (data, consume) => {
317
350
  const key = data.payload?.key;
318
351
  if (client[key]) {
319
352
  const params = data.payload.params;
320
353
  const res = await client[key](...params);
321
354
  consume([createResult(ResultCode.Ok, '请求完成', res)]);
322
355
  }
356
+ };
357
+ // 处理 api 调用
358
+ cbp.onapis((data, consume) => void onapis(data, consume));
359
+ };
360
+ const mainProcess = () => {
361
+ ['SIGINT', 'SIGTERM', 'SIGQUIT', 'disconnect'].forEach(sig => {
362
+ process?.on?.(sig, () => {
363
+ logger?.info?.(`[alemonjs][${sig}] 收到信号,正在关闭...`);
364
+ setImmediate(() => process.exit(0));
365
+ });
366
+ });
367
+ process?.on?.('exit', code => {
368
+ logger?.info?.(`[alemonjs][exit] 进程退出,code=${code}`);
369
+ });
370
+ // 监听主进程消息
371
+ process.on('message', msg => {
372
+ try {
373
+ const data = typeof msg === 'string' ? JSON.parse(msg) : msg;
374
+ if (data?.type === 'start') {
375
+ main();
376
+ }
377
+ else if (data?.type === 'stop') {
378
+ process.exit(0);
379
+ }
380
+ }
381
+ catch { }
323
382
  });
383
+ // 主动发送 ready 消息
384
+ if (process.send) {
385
+ process.send(JSON.stringify({ type: 'ready' }));
386
+ }
324
387
  };
388
+ mainProcess();
325
389
 
326
- export { index as default, platform };
390
+ export { main as default, platform };
package/lib/sdk/api.d.ts CHANGED
@@ -68,6 +68,43 @@ declare class OneBotAPI {
68
68
  approve: boolean;
69
69
  reason?: string;
70
70
  }): Promise<any>;
71
+ /** 撤回消息 */
72
+ deleteMsg(options: {
73
+ message_id: number;
74
+ }): Promise<any>;
75
+ /** 上传私聊文件 */
76
+ uploadPrivateFile(options: {
77
+ user_id: number;
78
+ file: string;
79
+ name?: string;
80
+ }): Promise<any>;
81
+ /** 上传群文件 */
82
+ uploadGroupFile(options: {
83
+ group_id: number;
84
+ file: string;
85
+ name?: string;
86
+ folder?: string;
87
+ }): Promise<any>;
88
+ /** 发送私聊转发 */
89
+ sendPrivateForward(options: {
90
+ user_id: number;
91
+ messages: {
92
+ time?: number;
93
+ content: any[];
94
+ user_id?: string;
95
+ nickname?: string;
96
+ }[];
97
+ }): Promise<any>;
98
+ /** 发送群转发 */
99
+ sendGroupForward(options: {
100
+ group_id: number;
101
+ messages: {
102
+ time?: number;
103
+ content: any[];
104
+ user_id?: string;
105
+ nickname?: string;
106
+ }[];
107
+ }): Promise<any>;
71
108
  }
72
109
 
73
110
  export { OneBotAPI };
package/lib/sdk/api.js CHANGED
@@ -59,8 +59,9 @@ class OneBotAPI {
59
59
  * @returns
60
60
  */
61
61
  sendPrivateMessage(options) {
62
- if (!this.ws)
62
+ if (!this.ws) {
63
63
  return;
64
+ }
64
65
  return send(this.ws, {
65
66
  action: 'send_private_msg',
66
67
  params: options
@@ -72,8 +73,9 @@ class OneBotAPI {
72
73
  * @returns
73
74
  */
74
75
  sendGroupMessage(options) {
75
- if (!this.ws)
76
+ if (!this.ws) {
76
77
  return;
78
+ }
77
79
  return send(this.ws, {
78
80
  action: 'send_group_msg',
79
81
  params: options
@@ -85,8 +87,9 @@ class OneBotAPI {
85
87
  * @returns
86
88
  */
87
89
  sendMessage(options) {
88
- if (!this.ws)
90
+ if (!this.ws) {
89
91
  return;
92
+ }
90
93
  return send(this.ws, {
91
94
  action: 'send_msg',
92
95
  params: options
@@ -96,8 +99,9 @@ class OneBotAPI {
96
99
  * 好友列表
97
100
  */
98
101
  getFriendList() {
99
- if (!this.ws)
102
+ if (!this.ws) {
100
103
  return;
104
+ }
101
105
  return send(this.ws, {
102
106
  action: 'get_friend_list',
103
107
  params: {}
@@ -107,8 +111,9 @@ class OneBotAPI {
107
111
  * 群列表
108
112
  */
109
113
  getGroupList() {
110
- if (!this.ws)
114
+ if (!this.ws) {
111
115
  return;
116
+ }
112
117
  return send(this.ws, {
113
118
  action: 'get_group_list',
114
119
  params: {}
@@ -120,8 +125,9 @@ class OneBotAPI {
120
125
  * @returns
121
126
  */
122
127
  getGroupMemberList(options) {
123
- if (!this.ws)
128
+ if (!this.ws) {
124
129
  return;
130
+ }
125
131
  return send(this.ws, {
126
132
  action: 'get_group_member_list',
127
133
  params: options
@@ -133,8 +139,9 @@ class OneBotAPI {
133
139
  * @returns
134
140
  */
135
141
  setFriendAddRequest(options) {
136
- if (!this.ws)
142
+ if (!this.ws) {
137
143
  return;
144
+ }
138
145
  return send(this.ws, {
139
146
  action: 'set_friend_add_request',
140
147
  params: options
@@ -146,13 +153,74 @@ class OneBotAPI {
146
153
  * @returns
147
154
  */
148
155
  setGroupAddRequest(options) {
149
- if (!this.ws)
156
+ if (!this.ws) {
150
157
  return;
158
+ }
151
159
  return send(this.ws, {
152
160
  action: 'set_group_add_request',
153
161
  params: options
154
162
  });
155
163
  }
164
+ /** 撤回消息 */
165
+ deleteMsg(options) {
166
+ if (!this.ws) {
167
+ return;
168
+ }
169
+ return send(this.ws, {
170
+ action: 'delete_msg',
171
+ params: options
172
+ });
173
+ }
174
+ /** 上传私聊文件 */
175
+ uploadPrivateFile(options) {
176
+ if (!this.ws) {
177
+ return;
178
+ }
179
+ return send(this.ws, {
180
+ action: 'upload_private_file',
181
+ params: options
182
+ });
183
+ }
184
+ /** 上传群文件 */
185
+ uploadGroupFile(options) {
186
+ if (!this.ws) {
187
+ return;
188
+ }
189
+ return send(this.ws, {
190
+ action: 'upload_group_file',
191
+ params: options
192
+ });
193
+ }
194
+ /** 发送私聊转发 */
195
+ sendPrivateForward(options) {
196
+ if (!this.ws) {
197
+ return;
198
+ }
199
+ return send(this.ws, {
200
+ action: 'send_private_forward_msg',
201
+ params: {
202
+ user_id: 80000000,
203
+ nickname: '匿名消息',
204
+ ...options,
205
+ messages: options.messages.map(data => ({ data, type: 'node' }))
206
+ }
207
+ });
208
+ }
209
+ /** 发送群转发 */
210
+ sendGroupForward(options) {
211
+ if (!this.ws) {
212
+ return;
213
+ }
214
+ return send(this.ws, {
215
+ action: 'send_group_forward_msg',
216
+ params: {
217
+ user_id: 80000000,
218
+ nickname: '匿名消息',
219
+ ...options,
220
+ messages: options.messages.map(data => ({ data, type: 'node' }))
221
+ }
222
+ });
223
+ }
156
224
  }
157
225
 
158
226
  export { OneBotAPI, consume };
@@ -0,0 +1,72 @@
1
+ interface Sender {
2
+ user_id: number;
3
+ nickname: string;
4
+ card: string;
5
+ role: 'admin' | 'member';
6
+ }
7
+ type Message = {
8
+ type: 'image';
9
+ data: {
10
+ file: string;
11
+ sub_type: number;
12
+ file_id: string;
13
+ url: string;
14
+ file_size: string;
15
+ file_unique: string;
16
+ };
17
+ } | {
18
+ type: 'text';
19
+ data: {
20
+ text: string;
21
+ };
22
+ } | {
23
+ type: 'json';
24
+ data: string;
25
+ } | {
26
+ type: 'forward';
27
+ data: {
28
+ id: number;
29
+ content: any[];
30
+ };
31
+ };
32
+ interface MESSAGES_TYPE {
33
+ self_id: number;
34
+ user_id: number;
35
+ time: number;
36
+ message_id: number;
37
+ message_seq: number;
38
+ real_id: number;
39
+ message_type: 'group';
40
+ sender: Sender;
41
+ raw_message: string;
42
+ font: number;
43
+ sub_type: 'normal';
44
+ message: Message[];
45
+ message_format: 'array';
46
+ post_type: 'message';
47
+ group_id: number;
48
+ }
49
+ interface DIRECT_MESSAGE_TYPE {
50
+ self_id: number;
51
+ user_id: number;
52
+ time: number;
53
+ message_id: number;
54
+ message_seq: number;
55
+ real_id: number;
56
+ message_type: 'private';
57
+ sender: {
58
+ user_id: 1715713638;
59
+ nickname: string;
60
+ card: '';
61
+ };
62
+ raw_message: string;
63
+ font: 14;
64
+ sub_type: 'group' | 'friend';
65
+ message: Message[];
66
+ message_format: 'array';
67
+ post_type: 'message';
68
+ group_id: number;
69
+ temp_source: number;
70
+ }
71
+
72
+ export type { DIRECT_MESSAGE_TYPE, MESSAGES_TYPE };
package/lib/sdk/wss.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import WebSocket, { WebSocketServer } from 'ws';
2
2
  import { OneBotAPI, consume } from './api.js';
3
+ import dayjs from 'dayjs';
3
4
 
4
5
  /**
5
6
  * 连接
@@ -24,6 +25,15 @@ class OneBotClient extends OneBotAPI {
24
25
  }
25
26
  }
26
27
  #events = {};
28
+ // 重连次数
29
+ #count = 0;
30
+ #getReConnectTime() {
31
+ const time = this.#count > 3 ? 1000 * 6 : 1000 * 1;
32
+ const curTime = this.#count > 6 ? 1000 * this.#count * 2 : time;
33
+ logger.info(`[OneBot] 等待 ${dayjs(curTime).format('mm:ss')} 后重新连接`);
34
+ this.#count++;
35
+ return curTime;
36
+ }
27
37
  /**
28
38
  * 注册事件处理程序
29
39
  * @param key 事件名称
@@ -38,63 +48,65 @@ class OneBotClient extends OneBotAPI {
38
48
  * @param cfg
39
49
  * @param conversation
40
50
  */
41
- async connect() {
51
+ connect() {
42
52
  const { url, access_token: token, reverse_enable, reverse_port } = this.#options;
43
- const c = token == '' || !token
53
+ const notToken = !token || token === '';
54
+ const c = notToken
44
55
  ? {}
45
56
  : {
46
57
  headers: {
47
58
  ['Authorization']: `Bearer ${token}`
48
59
  }
49
60
  };
50
- const onMessage = async (data) => {
61
+ const onMessage = data => {
51
62
  try {
52
63
  const event = JSON.parse(data.toString());
53
64
  if (!event) {
54
- if (this.#events['ERROR'])
55
- this.#events['ERROR'](event);
56
- return;
65
+ logger.error('[OneBot] WebSocket message is empty');
57
66
  }
58
- else if (event?.post_type == 'meta_event') {
59
- if (this.#events['META'])
67
+ else if (event?.post_type === 'meta_event') {
68
+ if (this.#events['META']) {
60
69
  this.#events['META'](event);
61
- return;
70
+ }
62
71
  }
63
- else if (event?.post_type == 'message') {
64
- if (event?.message_type == 'group') {
65
- if (this.#events['MESSAGES'])
72
+ else if (event?.post_type === 'message') {
73
+ if (event?.message_type === 'group') {
74
+ if (this.#events['MESSAGES']) {
66
75
  this.#events['MESSAGES'](event);
76
+ }
67
77
  }
68
- else if (event?.message_type == 'private') {
69
- if (this.#events['DIRECT_MESSAGE'])
78
+ else if (event?.message_type === 'private') {
79
+ if (this.#events['DIRECT_MESSAGE']) {
70
80
  this.#events['DIRECT_MESSAGE'](event);
81
+ }
71
82
  }
72
- return;
73
83
  }
74
- else if (event?.post_type == 'notice') {
75
- if (event?.notice_type == 'group_increase') {
84
+ else if (event?.post_type === 'notice') {
85
+ if (event?.notice_type === 'group_increase') {
76
86
  // 群成员增加
77
- if (this.#events['NOTICE_GROUP_MEMBER_INCREASE'])
87
+ if (this.#events['NOTICE_GROUP_MEMBER_INCREASE']) {
78
88
  this.#events['NOTICE_GROUP_MEMBER_INCREASE'](event);
89
+ }
79
90
  }
80
- else if (event?.notice_type == 'group_decrease') {
91
+ else if (event?.notice_type === 'group_decrease') {
81
92
  // 群成员减少
82
- if (this.#events['NOTICE_GROUP_MEMBER_REDUCE'])
93
+ if (this.#events['NOTICE_GROUP_MEMBER_REDUCE']) {
83
94
  this.#events['NOTICE_GROUP_MEMBER_REDUCE'](event);
95
+ }
84
96
  }
85
- return;
86
97
  }
87
- else if (event?.post_type == 'request') {
98
+ else if (event?.post_type === 'request') {
88
99
  // 收到加群 或 加好友的请求。
89
- if (event?.request_type == 'friend') {
90
- if (this.#events['REQUEST_ADD_FRIEND'])
100
+ if (event?.request_type === 'friend') {
101
+ if (this.#events['REQUEST_ADD_FRIEND']) {
91
102
  this.#events['REQUEST_ADD_FRIEND'](event);
103
+ }
92
104
  }
93
- else if (event?.request_type == 'group') {
94
- if (this.#events['REQUEST_ADD_GROUP'])
105
+ else if (event?.request_type === 'group') {
106
+ if (this.#events['REQUEST_ADD_GROUP']) {
95
107
  this.#events['REQUEST_ADD_GROUP'](event);
108
+ }
96
109
  }
97
- return;
98
110
  }
99
111
  else if (event?.echo) {
100
112
  // 消费
@@ -102,16 +114,18 @@ class OneBotClient extends OneBotAPI {
102
114
  }
103
115
  }
104
116
  catch (err) {
105
- if (this.#events['ERROR'])
106
- this.#events['ERROR'](err);
117
+ logger.error('[OneBot] WebSocket error: ', err);
107
118
  }
108
119
  };
109
120
  const onClose = (code, reason) => {
110
- if (this.#events['ERROR'])
111
- this.#events['ERROR']({
112
- de: code,
113
- reason: reason.toString('utf8')
114
- });
121
+ logger.error(`[OneBot] WebSocket closed: ${code} - ${reason.toString('utf8')}`);
122
+ if (reverse_enable) {
123
+ return;
124
+ }
125
+ const curTime = this.#getReConnectTime();
126
+ setTimeout(() => {
127
+ this.connect();
128
+ }, curTime);
115
129
  };
116
130
  if (!this.ws) {
117
131
  if (reverse_enable) {
@@ -123,14 +137,15 @@ class OneBotClient extends OneBotAPI {
123
137
  this.ws.on('message', onMessage);
124
138
  // close
125
139
  this.ws.on('close', onClose);
126
- console.info('connected: ws://127.0.0.1:' + reverse_port);
140
+ logger.info(`[OneBot] connected: ws://127.0.0.1:${reverse_port}`);
127
141
  });
128
142
  }
129
143
  else {
130
144
  // forward_open
131
145
  this.ws = new WebSocket(url, c);
132
146
  this.ws.on('open', () => {
133
- console.debug(`open:${url}`);
147
+ logger.info(`[OneBot] connected: ${url}`);
148
+ this.#count = 0;
134
149
  });
135
150
  // message
136
151
  this.ws.on('message', onMessage);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alemonjs/onebot",
3
- "version": "2.1.0-alpha.0",
3
+ "version": "2.1.0-alpha.10",
4
4
  "description": "onebot v11",
5
5
  "author": "lemonade",
6
6
  "license": "MIT",
@@ -21,8 +21,12 @@
21
21
  "alemonjs"
22
22
  ],
23
23
  "dependencies": {
24
+ "dayjs": "^1.11.13",
24
25
  "ws": "^8.18.1"
25
26
  },
27
+ "peerDependencies": {
28
+ "alemonjs": "^2.1.0-alpha.15"
29
+ },
26
30
  "alemonjs": {
27
31
  "desktop": {
28
32
  "platform": [