@zhin.js/adapter-onebot11 1.0.0 → 1.0.2
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/CHANGELOG.md +18 -0
- package/LICENSE +21 -0
- package/README.md +82 -1
- package/lib/index.d.ts +87 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +393 -0
- package/lib/index.js.map +1 -0
- package/package.json +23 -9
- package/src/index.ts +283 -77
- package/tsconfig.json +3 -4
- package/dist/index.d.ts +0 -36
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -211
- package/dist/index.js.map +0 -1
- package/tsconfig.tsbuildinfo +0 -1
package/package.json
CHANGED
|
@@ -1,25 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-onebot11",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "zhin adapter for onebot11",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./
|
|
7
|
-
"types": "./
|
|
6
|
+
"main": "./lib/index.js",
|
|
7
|
+
"types": "./lib/index.d.ts",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
|
-
"types": "./
|
|
11
|
-
"import": "./
|
|
10
|
+
"types": "./lib/index.d.ts",
|
|
11
|
+
"import": "./lib/index.js"
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"ws": "^8.18.3"
|
|
16
|
+
},
|
|
14
17
|
"devDependencies": {
|
|
15
|
-
"
|
|
16
|
-
"@
|
|
18
|
+
"@types/node": "^24.3.0",
|
|
19
|
+
"@types/ws": "^8.18.1",
|
|
20
|
+
"typescript": "^5.3.0"
|
|
17
21
|
},
|
|
18
22
|
"peerDependencies": {
|
|
19
|
-
"zhin.js": "1.0.
|
|
23
|
+
"zhin.js": "1.0.2",
|
|
24
|
+
"@zhin.js/types": "1.0.1",
|
|
25
|
+
"@zhin.js/http": "1.0.1"
|
|
26
|
+
},
|
|
27
|
+
"peerDependenciesMeta": {
|
|
28
|
+
"@zhin.js/types": {
|
|
29
|
+
"optional": true
|
|
30
|
+
},
|
|
31
|
+
"@zhin.js/http": {
|
|
32
|
+
"optional": true
|
|
33
|
+
}
|
|
20
34
|
},
|
|
21
35
|
"scripts": {
|
|
22
36
|
"build": "tsc",
|
|
23
|
-
"clean": "rm -rf
|
|
37
|
+
"clean": "rm -rf lib"
|
|
24
38
|
}
|
|
25
39
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,26 +1,57 @@
|
|
|
1
|
-
import WebSocket from 'ws';
|
|
1
|
+
import WebSocket, {WebSocketServer} from 'ws';
|
|
2
2
|
import {EventEmitter} from "events";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
import {
|
|
4
|
+
Bot,
|
|
5
|
+
Plugin,
|
|
6
|
+
Adapter,
|
|
7
|
+
BotConfig,
|
|
8
|
+
Message,
|
|
9
|
+
registerAdapter,
|
|
10
|
+
User,
|
|
11
|
+
Group,
|
|
12
|
+
MessageSegment,
|
|
13
|
+
SendOptions,
|
|
14
|
+
MessageType, segment, useContext, SendContent
|
|
15
|
+
} from 'zhin.js';
|
|
16
|
+
import type {Router} from '@zhin.js/http'
|
|
17
|
+
import {IncomingMessage} from "http";
|
|
18
|
+
import {clearInterval} from "node:timers";
|
|
19
|
+
|
|
20
|
+
declare module 'zhin.js'{
|
|
21
|
+
interface RegisteredAdapters{
|
|
22
|
+
'onebot11':Adapter<OneBot11WsClient>
|
|
23
|
+
'onebot11.wss':Adapter<OneBot11WsServer>
|
|
8
24
|
}
|
|
9
25
|
}
|
|
10
26
|
// ============================================================================
|
|
11
27
|
// OneBot11 配置和类型
|
|
12
28
|
// ============================================================================
|
|
13
29
|
|
|
14
|
-
export interface
|
|
30
|
+
export interface OneBot11Config extends BotConfig {
|
|
15
31
|
context: 'onebot11';
|
|
16
|
-
|
|
32
|
+
type:string
|
|
17
33
|
access_token?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface OneBot11WsClientConfig extends OneBot11Config{
|
|
36
|
+
type:'ws'
|
|
37
|
+
url: string;
|
|
18
38
|
reconnect_interval?: number;
|
|
19
39
|
heartbeat_interval?: number;
|
|
20
40
|
}
|
|
41
|
+
export interface OneBot11WsServerConfig extends OneBot11Config{
|
|
42
|
+
type:'ws_reverse'
|
|
43
|
+
path:string
|
|
44
|
+
heartbeat_interval?: number;
|
|
45
|
+
}
|
|
46
|
+
export interface OneBot11HTTPConfig extends OneBot11Config{
|
|
47
|
+
type:'http_sse'
|
|
48
|
+
port:number
|
|
49
|
+
path:string
|
|
50
|
+
}
|
|
21
51
|
|
|
22
52
|
interface OneBot11Message {
|
|
23
53
|
post_type: string;
|
|
54
|
+
self_id:string
|
|
24
55
|
message_type?: string;
|
|
25
56
|
sub_type?: string;
|
|
26
57
|
message_id: number;
|
|
@@ -45,8 +76,8 @@ interface ApiResponse<T = any> {
|
|
|
45
76
|
// OneBot11 适配器实现
|
|
46
77
|
// ============================================================================
|
|
47
78
|
|
|
48
|
-
export class OneBot11WsClient extends EventEmitter implements Bot<
|
|
49
|
-
connected?:boolean
|
|
79
|
+
export class OneBot11WsClient extends EventEmitter implements Bot<OneBot11Message,OneBot11WsClientConfig> {
|
|
80
|
+
$connected?:boolean
|
|
50
81
|
private ws?: WebSocket;
|
|
51
82
|
private reconnectTimer?: NodeJS.Timeout;
|
|
52
83
|
private heartbeatTimer?: NodeJS.Timeout;
|
|
@@ -57,23 +88,25 @@ export class OneBot11WsClient extends EventEmitter implements Bot<OneBotV11Confi
|
|
|
57
88
|
timeout: NodeJS.Timeout;
|
|
58
89
|
}>();
|
|
59
90
|
|
|
60
|
-
constructor(public plugin:Plugin,public config:
|
|
91
|
+
constructor(public plugin:Plugin,public $config: OneBot11WsClientConfig) {
|
|
61
92
|
super();
|
|
93
|
+
this.$connected=false
|
|
62
94
|
}
|
|
63
95
|
|
|
64
96
|
|
|
65
|
-
async connect(): Promise<void> {
|
|
97
|
+
async $connect(): Promise<void> {
|
|
66
98
|
return new Promise((resolve, reject) => {
|
|
67
|
-
let wsUrl = this
|
|
99
|
+
let wsUrl = this.$config.url;
|
|
68
100
|
const headers: Record<string, string> = {};
|
|
69
101
|
|
|
70
|
-
if (this
|
|
71
|
-
headers['Authorization'] = `Bearer ${this
|
|
102
|
+
if (this.$config.access_token) {
|
|
103
|
+
headers['Authorization'] = `Bearer ${this.$config.access_token}`;
|
|
72
104
|
}
|
|
73
105
|
this.ws = new WebSocket(wsUrl,{headers});
|
|
74
106
|
|
|
75
107
|
this.ws.on('open', () => {
|
|
76
|
-
this
|
|
108
|
+
this.$connected=true;
|
|
109
|
+
if(!this.$config.access_token) this.plugin.logger.warn(`missing 'access_token', your OneBot protocol is not safely`)
|
|
77
110
|
this.startHeartbeat();
|
|
78
111
|
resolve();
|
|
79
112
|
});
|
|
@@ -88,7 +121,7 @@ export class OneBot11WsClient extends EventEmitter implements Bot<OneBotV11Confi
|
|
|
88
121
|
});
|
|
89
122
|
|
|
90
123
|
this.ws.on('close', (code,reason) => {
|
|
91
|
-
this
|
|
124
|
+
this.$connected=false
|
|
92
125
|
reject({code,reason})
|
|
93
126
|
this.scheduleReconnect();
|
|
94
127
|
});
|
|
@@ -99,7 +132,7 @@ export class OneBot11WsClient extends EventEmitter implements Bot<OneBotV11Confi
|
|
|
99
132
|
});
|
|
100
133
|
}
|
|
101
134
|
|
|
102
|
-
async disconnect(): Promise<void> {
|
|
135
|
+
async $disconnect(): Promise<void> {
|
|
103
136
|
if (this.reconnectTimer) {
|
|
104
137
|
clearTimeout(this.reconnectTimer);
|
|
105
138
|
this.reconnectTimer = undefined;
|
|
@@ -122,53 +155,56 @@ export class OneBot11WsClient extends EventEmitter implements Bot<OneBotV11Confi
|
|
|
122
155
|
this.ws = undefined;
|
|
123
156
|
}
|
|
124
157
|
}
|
|
158
|
+
$formatMessage(onebotMsg: OneBot11Message){
|
|
159
|
+
const message=Message.from(onebotMsg,{
|
|
160
|
+
$id: onebotMsg.message_id.toString(),
|
|
161
|
+
$adapter:'onebot11',
|
|
162
|
+
$bot:`${this.$config.name}`,
|
|
163
|
+
$sender:{
|
|
164
|
+
id:onebotMsg.user_id.toString(),
|
|
165
|
+
name:onebotMsg.user_id.toString()
|
|
166
|
+
},
|
|
167
|
+
$channel:{
|
|
168
|
+
id: (onebotMsg.group_id || onebotMsg.user_id).toString(),
|
|
169
|
+
type:onebotMsg.group_id?'group':'private'
|
|
170
|
+
},
|
|
171
|
+
$content: onebotMsg.message,
|
|
172
|
+
$raw: onebotMsg.raw_message,
|
|
173
|
+
$timestamp: onebotMsg.time,
|
|
174
|
+
$reply:async (content: MessageSegment[], quote?: boolean|string):Promise<void>=> {
|
|
175
|
+
if(quote) content.unshift({type:'reply',data:{message_id:message.$id}})
|
|
176
|
+
this.plugin.dispatch('message.send',{
|
|
177
|
+
...message.$channel,
|
|
178
|
+
context:'onebot11',
|
|
179
|
+
bot:`${this.$config.name}`,
|
|
180
|
+
content
|
|
181
|
+
})
|
|
182
|
+
}
|
|
183
|
+
})
|
|
184
|
+
return message
|
|
185
|
+
}
|
|
125
186
|
|
|
126
|
-
async sendMessage(options: SendOptions): Promise<void> {
|
|
187
|
+
async $sendMessage(options: SendOptions): Promise<void> {
|
|
127
188
|
options=await this.plugin.app.handleBeforeSend(options)
|
|
128
|
-
this.plugin.logger.info(`send ${options.type}(${options.id}):`,options.content)
|
|
129
189
|
const messageData: any = {
|
|
130
190
|
message: options.content
|
|
131
191
|
};
|
|
132
|
-
|
|
133
192
|
if (options.type==='group') {
|
|
134
193
|
await this.callApi('send_group_msg', {
|
|
135
194
|
group_id: parseInt(options.id),
|
|
136
195
|
...messageData
|
|
137
196
|
});
|
|
197
|
+
this.plugin.logger.info(`send ${options.type}(${options.id}):${segment.raw(options.content)}`)
|
|
138
198
|
} else if (options.type==='private') {
|
|
139
199
|
await this.callApi('send_private_msg', {
|
|
140
200
|
user_id: parseInt(options.id),
|
|
141
201
|
...messageData
|
|
142
202
|
});
|
|
203
|
+
this.plugin.logger.info(`send ${options.type}(${options.id}):${segment.raw(options.content)}`)
|
|
143
204
|
} else {
|
|
144
205
|
throw new Error('Either group_id or user_id must be provided');
|
|
145
206
|
}
|
|
146
207
|
}
|
|
147
|
-
|
|
148
|
-
async getUser(userId: string): Promise<User> {
|
|
149
|
-
const response = await this.callApi('get_stranger_info', {
|
|
150
|
-
user_id: parseInt(userId)
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
return {
|
|
154
|
-
user_id: userId,
|
|
155
|
-
nickname: response.nickname,
|
|
156
|
-
card: response.card
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
async getGroup(groupId: string): Promise<Group> {
|
|
161
|
-
const response = await this.callApi('get_group_info', {
|
|
162
|
-
group_id: parseInt(groupId)
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
return {
|
|
166
|
-
group_id: groupId,
|
|
167
|
-
group_name: response.group_name,
|
|
168
|
-
member_count: response.member_count
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
|
|
172
208
|
private async callApi(action: string, params: any = {}): Promise<any> {
|
|
173
209
|
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
174
210
|
throw new Error('WebSocket is not connected');
|
|
@@ -215,38 +251,14 @@ export class OneBot11WsClient extends EventEmitter implements Bot<OneBotV11Confi
|
|
|
215
251
|
}
|
|
216
252
|
|
|
217
253
|
private handleOneBot11Message(onebotMsg: OneBot11Message): void {
|
|
218
|
-
const message
|
|
219
|
-
id: onebotMsg.message_id.toString(),
|
|
220
|
-
adapter:'onebot11',
|
|
221
|
-
bot:`${this.config.name}`,
|
|
222
|
-
sender:{
|
|
223
|
-
id:onebotMsg.user_id.toString(),
|
|
224
|
-
name:onebotMsg.user_id.toString()
|
|
225
|
-
},
|
|
226
|
-
channel:{
|
|
227
|
-
id:(onebotMsg.group_id||onebotMsg.user_id).toString(),
|
|
228
|
-
type:onebotMsg.group_id?'group':'private'
|
|
229
|
-
},
|
|
230
|
-
content: onebotMsg.message,
|
|
231
|
-
raw: onebotMsg.raw_message,
|
|
232
|
-
timestamp: onebotMsg.time,
|
|
233
|
-
reply:async (content: MessageSegment[], quote?: boolean|string):Promise<void>=> {
|
|
234
|
-
if(quote) content.unshift({type:'reply',data:{message_id:message.id}})
|
|
235
|
-
this.plugin.dispatch('message.send',{
|
|
236
|
-
...message.channel,
|
|
237
|
-
context:'onebot11',
|
|
238
|
-
bot:`${this.config.name}`,
|
|
239
|
-
content
|
|
240
|
-
})
|
|
241
|
-
}
|
|
242
|
-
};
|
|
254
|
+
const message = this.$formatMessage(onebotMsg);
|
|
243
255
|
this.plugin.dispatch('message.receive',message)
|
|
244
|
-
this.plugin.logger.info(`recv ${message
|
|
245
|
-
this.plugin.dispatch(`message.${message
|
|
256
|
+
this.plugin.logger.info(`recv ${message.$channel.type}(${message.$channel.id}):${segment.raw(message.$content)}`)
|
|
257
|
+
this.plugin.dispatch(`message.${message.$channel.type}.receive`,message)
|
|
246
258
|
}
|
|
247
259
|
|
|
248
260
|
private startHeartbeat(): void {
|
|
249
|
-
const interval = this
|
|
261
|
+
const interval = this.$config.heartbeat_interval || 30000;
|
|
250
262
|
this.heartbeatTimer = setInterval(() => {
|
|
251
263
|
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
252
264
|
this.ws.ping();
|
|
@@ -259,11 +271,11 @@ export class OneBot11WsClient extends EventEmitter implements Bot<OneBotV11Confi
|
|
|
259
271
|
return;
|
|
260
272
|
}
|
|
261
273
|
|
|
262
|
-
const interval = this
|
|
274
|
+
const interval = this.$config.reconnect_interval || 5000;
|
|
263
275
|
this.reconnectTimer = setTimeout(async () => {
|
|
264
276
|
this.reconnectTimer = undefined;
|
|
265
277
|
try {
|
|
266
|
-
await this
|
|
278
|
+
await this.$connect();
|
|
267
279
|
} catch (error) {
|
|
268
280
|
this.emit('error',new Error(`Reconnection failed: ${error}`));
|
|
269
281
|
this.scheduleReconnect();
|
|
@@ -271,4 +283,198 @@ export class OneBot11WsClient extends EventEmitter implements Bot<OneBotV11Confi
|
|
|
271
283
|
}, interval);
|
|
272
284
|
}
|
|
273
285
|
}
|
|
274
|
-
|
|
286
|
+
export class OneBot11WsServer extends EventEmitter implements Bot<OneBot11Message,OneBot11WsServerConfig> {
|
|
287
|
+
$connected?:boolean
|
|
288
|
+
#wss?:WebSocketServer
|
|
289
|
+
#clientMap:Map<string,WebSocket>=new Map<string,WebSocket>()
|
|
290
|
+
private heartbeatTimer?: NodeJS.Timeout;
|
|
291
|
+
private requestId = 0;
|
|
292
|
+
private pendingRequests = new Map<string, {
|
|
293
|
+
resolve: (value: any) => void;
|
|
294
|
+
reject: (error: Error) => void;
|
|
295
|
+
timeout: NodeJS.Timeout;
|
|
296
|
+
}>();
|
|
297
|
+
|
|
298
|
+
constructor(public plugin:Plugin,public router:Router,public $config: OneBot11WsServerConfig) {
|
|
299
|
+
super();
|
|
300
|
+
this.$connected=false
|
|
301
|
+
}
|
|
302
|
+
async $connect(): Promise<void> {
|
|
303
|
+
if(!this.$config.access_token) this.plugin.logger.warn(`missing 'access_token', your OneBot protocol is not safely`)
|
|
304
|
+
this.#wss=this.router.ws(this.$config.path,{verifyClient:(info:{ origin: string; secure: boolean; req: IncomingMessage })=>{
|
|
305
|
+
const {
|
|
306
|
+
req: { headers },
|
|
307
|
+
} = info;
|
|
308
|
+
const authorization = headers['authorization'] || '';
|
|
309
|
+
if (this.$config.access_token && authorization !== `Bearer ${this.$config.access_token}`) {
|
|
310
|
+
this.plugin.logger.error('鉴权失败');
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
return true;
|
|
314
|
+
}})
|
|
315
|
+
this.$connected=true;
|
|
316
|
+
this.plugin.logger.info(`ws server start at path:${this.$config.path}`)
|
|
317
|
+
this.#wss.on('connection', (client,req) => {
|
|
318
|
+
this.startHeartbeat();
|
|
319
|
+
this.plugin.logger.info(`已连接到协议端:${req.socket.remoteAddress}`);
|
|
320
|
+
client.on('error', err => {
|
|
321
|
+
this.plugin.logger.error('连接出错:', err);
|
|
322
|
+
});
|
|
323
|
+
client.on('close', code => {
|
|
324
|
+
this.plugin.logger.error(`与连接端(${req.socket.remoteAddress})断开,错误码:${code}`);
|
|
325
|
+
for(const [key,value] of this.#clientMap){
|
|
326
|
+
if(client===value) this.#clientMap.delete(key)
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
client.on('message',(data) => {
|
|
330
|
+
try {
|
|
331
|
+
const message = JSON.parse(data.toString());
|
|
332
|
+
this.handleWebSocketMessage(client,message);
|
|
333
|
+
} catch (error) {
|
|
334
|
+
this.emit('error',error)
|
|
335
|
+
}
|
|
336
|
+
})
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
async $disconnect(): Promise<void> {
|
|
341
|
+
this.#wss?.close();
|
|
342
|
+
if(this.heartbeatTimer){
|
|
343
|
+
clearInterval(this.heartbeatTimer)
|
|
344
|
+
delete this.heartbeatTimer;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
$formatMessage(onebotMsg: OneBot11Message){
|
|
348
|
+
const message=Message.from(onebotMsg,{
|
|
349
|
+
$id: onebotMsg.message_id.toString(),
|
|
350
|
+
$adapter:'onebot11',
|
|
351
|
+
$bot:`${this.$config.name}`,
|
|
352
|
+
$sender:{
|
|
353
|
+
id:onebotMsg.user_id.toString(),
|
|
354
|
+
name:onebotMsg.user_id.toString()
|
|
355
|
+
},
|
|
356
|
+
$channel:{
|
|
357
|
+
id:[onebotMsg.self_id,(onebotMsg.group_id||onebotMsg.user_id)].join(':'),
|
|
358
|
+
type:onebotMsg.group_id?'group':'private'
|
|
359
|
+
},
|
|
360
|
+
$content: onebotMsg.message,
|
|
361
|
+
$raw: onebotMsg.raw_message,
|
|
362
|
+
$timestamp: onebotMsg.time,
|
|
363
|
+
$reply:async (content: SendContent, quote?: boolean|string):Promise<void>=> {
|
|
364
|
+
if(!Array.isArray(content)) content=[content];
|
|
365
|
+
if(quote) content.unshift({type:'reply',data:{message_id:message.$id}})
|
|
366
|
+
this.plugin.dispatch('message.send',{
|
|
367
|
+
...message.$channel,
|
|
368
|
+
context:'onebot11',
|
|
369
|
+
bot:`${this.$config.name}`,
|
|
370
|
+
content
|
|
371
|
+
})
|
|
372
|
+
}
|
|
373
|
+
})
|
|
374
|
+
return message
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
async $sendMessage(options: SendOptions): Promise<void> {
|
|
378
|
+
options=await this.plugin.app.handleBeforeSend(options)
|
|
379
|
+
const messageData: any = {
|
|
380
|
+
message: options.content
|
|
381
|
+
};
|
|
382
|
+
if (options.type==='group') {
|
|
383
|
+
const [self_id,id]=options.id.split(':')
|
|
384
|
+
await this.callApi(self_id,'send_group_msg', {
|
|
385
|
+
group_id: parseInt(id),
|
|
386
|
+
...messageData
|
|
387
|
+
});
|
|
388
|
+
this.plugin.logger.info(`send ${options.type}(${id}):${segment.raw(options.content)}`)
|
|
389
|
+
} else if (options.type==='private') {
|
|
390
|
+
const [self_id,id]=options.id.split(':')
|
|
391
|
+
await this.callApi(self_id,'send_private_msg', {
|
|
392
|
+
user_id: parseInt(id),
|
|
393
|
+
...messageData
|
|
394
|
+
});
|
|
395
|
+
this.plugin.logger.info(`send ${options.type}(${id}):${segment.raw(options.content)}`)
|
|
396
|
+
} else {
|
|
397
|
+
throw new Error('Either group_id or user_id must be provided');
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
private async callApi(self_id:string,action: string, params: any = {}): Promise<any> {
|
|
401
|
+
const client=this.#clientMap.get(self_id)
|
|
402
|
+
if (!client || client.readyState !== WebSocket.OPEN) {
|
|
403
|
+
throw new Error('WebSocket is not connected');
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const echo = `req_${++this.requestId}`;
|
|
407
|
+
const message = {
|
|
408
|
+
action,
|
|
409
|
+
params,
|
|
410
|
+
echo
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
return new Promise((resolve, reject) => {
|
|
414
|
+
const timeout = setTimeout(() => {
|
|
415
|
+
this.pendingRequests.delete(echo);
|
|
416
|
+
reject(new Error(`API call timeout: ${action}`));
|
|
417
|
+
}, 30000); // 30秒超时
|
|
418
|
+
|
|
419
|
+
this.pendingRequests.set(echo, { resolve, reject, timeout });
|
|
420
|
+
client.send(JSON.stringify(message));
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
private handleWebSocketMessage(client:WebSocket,message: any): void {
|
|
425
|
+
// 处理API响应
|
|
426
|
+
if (message.echo && this.pendingRequests.has(message.echo)) {
|
|
427
|
+
const request = this.pendingRequests.get(message.echo)!;
|
|
428
|
+
this.pendingRequests.delete(message.echo);
|
|
429
|
+
clearTimeout(request.timeout);
|
|
430
|
+
|
|
431
|
+
const response = message as ApiResponse;
|
|
432
|
+
if (response.status === 'ok') {
|
|
433
|
+
return request.resolve(response.data);
|
|
434
|
+
}
|
|
435
|
+
return request.reject(new Error(`API error: ${response.retcode}`));
|
|
436
|
+
}
|
|
437
|
+
switch (message.post_type){
|
|
438
|
+
case 'message':
|
|
439
|
+
return this.handleMessage(message);
|
|
440
|
+
case 'meta_event':
|
|
441
|
+
return this.handleMetaEvent(client,message)
|
|
442
|
+
}
|
|
443
|
+
// 处理事件消息
|
|
444
|
+
if (message.post_type === 'message') {
|
|
445
|
+
} else if (message.post_type === 'meta_event' && message.meta_event_type === 'heartbeat') {
|
|
446
|
+
// 心跳消息,暂时忽略
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
private handleMetaEvent(client:WebSocket,message:any){
|
|
450
|
+
switch (message.sub_type){
|
|
451
|
+
case 'heartbeat':
|
|
452
|
+
break;
|
|
453
|
+
case 'connect':
|
|
454
|
+
this.#clientMap.set(message.self_id,client);
|
|
455
|
+
this.plugin.logger.info(`client ${message.self_id} of ${this.$config.name} by ${this.$config.context} connected`)
|
|
456
|
+
break;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
private handleMessage(onebotMsg: OneBot11Message): void {
|
|
460
|
+
const message = this.$formatMessage(onebotMsg);
|
|
461
|
+
this.plugin.dispatch('message.receive',message)
|
|
462
|
+
this.plugin.logger.info(`recv ${message.$channel.type}(${onebotMsg.group_id||onebotMsg.user_id}):${segment.raw(message.$content)}`)
|
|
463
|
+
this.plugin.dispatch(`message.${message.$channel.type}.receive`,message)
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
private startHeartbeat(): void {
|
|
467
|
+
const interval = this.$config.heartbeat_interval || 30000;
|
|
468
|
+
this.heartbeatTimer = setInterval(() => {
|
|
469
|
+
for(const client of this.#wss?.clients||[]){
|
|
470
|
+
if (client && client.readyState === WebSocket.OPEN) {
|
|
471
|
+
client.ping();
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}, interval);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
registerAdapter(new Adapter('onebot11',OneBot11WsClient))
|
|
478
|
+
useContext('router',(router)=>{
|
|
479
|
+
registerAdapter(new Adapter('onebot11.wss',(p,c:OneBot11WsServerConfig)=>new OneBot11WsServer(p,router,c)));
|
|
480
|
+
})
|
package/tsconfig.json
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"compilerOptions": {
|
|
3
3
|
"target": "ES2022",
|
|
4
4
|
"module": "ESNext",
|
|
5
|
-
"moduleResolution": "
|
|
6
|
-
"outDir": "./
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"outDir": "./lib",
|
|
7
7
|
"rootDir": "./src",
|
|
8
8
|
"strict": true,
|
|
9
9
|
"esModuleInterop": true,
|
|
@@ -17,9 +17,8 @@
|
|
|
17
17
|
"declaration": true,
|
|
18
18
|
"declarationMap": true,
|
|
19
19
|
"sourceMap": true,
|
|
20
|
-
"composite": true,
|
|
21
20
|
"verbatimModuleSyntax": false
|
|
22
21
|
},
|
|
23
22
|
"include": ["src/**/*"],
|
|
24
|
-
"exclude": ["
|
|
23
|
+
"exclude": ["lib", "node_modules"]
|
|
25
24
|
}
|
package/dist/index.d.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from "events";
|
|
2
|
-
import { Bot, Plugin, Adapter, BotConfig, User, Group, SendOptions } from 'zhin.js';
|
|
3
|
-
declare module '@zhin.js/types' {
|
|
4
|
-
interface GlobalContext {
|
|
5
|
-
onebot11: Adapter<OneBot11WsClient>;
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
export interface OneBotV11Config extends BotConfig {
|
|
9
|
-
context: 'onebot11';
|
|
10
|
-
url: string;
|
|
11
|
-
access_token?: string;
|
|
12
|
-
reconnect_interval?: number;
|
|
13
|
-
heartbeat_interval?: number;
|
|
14
|
-
}
|
|
15
|
-
export declare class OneBot11WsClient extends EventEmitter implements Bot<OneBotV11Config> {
|
|
16
|
-
plugin: Plugin;
|
|
17
|
-
config: OneBotV11Config;
|
|
18
|
-
connected?: boolean;
|
|
19
|
-
private ws?;
|
|
20
|
-
private reconnectTimer?;
|
|
21
|
-
private heartbeatTimer?;
|
|
22
|
-
private requestId;
|
|
23
|
-
private pendingRequests;
|
|
24
|
-
constructor(plugin: Plugin, config: OneBotV11Config);
|
|
25
|
-
connect(): Promise<void>;
|
|
26
|
-
disconnect(): Promise<void>;
|
|
27
|
-
sendMessage(options: SendOptions): Promise<void>;
|
|
28
|
-
getUser(userId: string): Promise<User>;
|
|
29
|
-
getGroup(groupId: string): Promise<Group>;
|
|
30
|
-
private callApi;
|
|
31
|
-
private handleWebSocketMessage;
|
|
32
|
-
private handleOneBot11Message;
|
|
33
|
-
private startHeartbeat;
|
|
34
|
-
private scheduleReconnect;
|
|
35
|
-
}
|
|
36
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,YAAY,EAAC,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,GAAG,EAAC,MAAM,EAAC,OAAO,EAAC,SAAS,EAA0B,IAAI,EAAE,KAAK,EAAkB,WAAW,EAAE,MAAM,SAAS,CAAC;AAEzH,OAAO,QAAQ,gBAAgB,CAAA;IAC7B,UAAU,aAAa;QACrB,QAAQ,EAAC,OAAO,CAAC,gBAAgB,CAAC,CAAA;KACnC;CACF;AAKD,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAChD,OAAO,EAAE,UAAU,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AA4BD,qBAAa,gBAAiB,SAAQ,YAAa,YAAW,GAAG,CAAC,eAAe,CAAC;IAY7D,MAAM,EAAC,MAAM;IAAQ,MAAM,EAAE,eAAe;IAX/D,SAAS,CAAC,EAAC,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,CAAC,CAAY;IACvB,OAAO,CAAC,cAAc,CAAC,CAAiB;IACxC,OAAO,CAAC,cAAc,CAAC,CAAiB;IACxC,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,eAAe,CAIlB;gBAEc,MAAM,EAAC,MAAM,EAAQ,MAAM,EAAE,eAAe;IAKzD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAqCxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAwB3B,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBhD,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYtC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;YAYjC,OAAO;IAuBrB,OAAO,CAAC,sBAAsB;IAsB9B,OAAO,CAAC,qBAAqB;IA+B7B,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,iBAAiB;CAgB1B"}
|