@zhin.js/adapter-napcat 1.0.0 → 1.1.0
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 +674 -0
- package/README.md +60 -95
- package/adapters/napcat.js +47 -0
- package/adapters/napcat.ts +64 -0
- package/agent/PERMITS.md +19 -0
- package/{skills/napcat/SKILL.md → agent/skills/napcat.md} +6 -6
- package/agent/tools/ai_tts.ts +19 -0
- package/agent/tools/del_group_notice.ts +20 -0
- package/agent/tools/delete_essence_msg.ts +19 -0
- package/agent/tools/delete_friend.ts +18 -0
- package/agent/tools/download_file.ts +17 -0
- package/agent/tools/forward_single_msg.ts +28 -0
- package/agent/tools/get_ai_characters.ts +17 -0
- package/agent/tools/get_essence_list.ts +17 -0
- package/agent/tools/get_friend_msg_history.ts +18 -0
- package/agent/tools/get_group_file_url.ts +19 -0
- package/agent/tools/get_group_info_ex.ts +17 -0
- package/agent/tools/get_group_msg_history.ts +19 -0
- package/agent/tools/get_group_notice.ts +17 -0
- package/agent/tools/get_group_root_files.ts +17 -0
- package/agent/tools/get_group_shut_list.ts +17 -0
- package/agent/tools/get_mini_app_ark.ts +20 -0
- package/agent/tools/get_user_status.ts +16 -0
- package/agent/tools/group_sign.ts +18 -0
- package/agent/tools/mark_msg_as_read.ts +17 -0
- package/agent/tools/ocr_image.ts +16 -0
- package/agent/tools/send_forward_msg.ts +27 -0
- package/agent/tools/send_group_notice.ts +21 -0
- package/agent/tools/send_like.ts +18 -0
- package/agent/tools/send_poke.ts +18 -0
- package/agent/tools/set_avatar.ts +17 -0
- package/agent/tools/set_emoji_reaction.ts +18 -0
- package/agent/tools/set_essence_msg.ts +19 -0
- package/agent/tools/set_group_portrait.ts +20 -0
- package/agent/tools/set_online_status.ts +18 -0
- package/agent/tools/set_profile.ts +21 -0
- package/agent/tools/set_signature.ts +17 -0
- package/agent/tools/set_title.ts +21 -0
- package/agent/tools/translate.ts +16 -0
- package/agent/tools/upload_group_file.ts +21 -0
- package/commands/endpoint/add/[id].js +3 -0
- package/commands/endpoint/add/[id].ts +3 -0
- package/commands/endpoint/list.js +3 -0
- package/commands/endpoint/list.ts +3 -0
- package/commands/endpoint/remove/[id].js +3 -0
- package/commands/endpoint/remove/[id].ts +3 -0
- package/lib/client.d.ts +52 -0
- package/lib/client.js +62 -0
- package/lib/endpoint-management.d.ts +15 -0
- package/lib/endpoint-management.js +47 -0
- package/lib/http-endpoint.d.ts +27 -0
- package/lib/http-endpoint.js +177 -0
- package/lib/index.d.ts +11 -22
- package/lib/index.js +10 -58
- package/lib/napcat-endpoint-commands.d.ts +1 -0
- package/lib/napcat-endpoint-commands.js +28 -0
- package/lib/napcat-inbound.d.ts +12 -5
- package/lib/napcat-inbound.js +28 -13
- package/lib/napcat-runtime-state.d.ts +1 -0
- package/lib/napcat-runtime-state.js +6 -0
- package/lib/onebot-get-msg.d.ts +16 -3
- package/lib/onebot-get-msg.js +53 -1
- package/lib/protocol.d.ts +165 -0
- package/lib/protocol.js +305 -0
- package/lib/side-event-dispatch.d.ts +7 -0
- package/lib/side-event-dispatch.js +36 -0
- package/lib/webhook.d.ts +2 -0
- package/lib/webhook.js +14 -0
- package/lib/ws-endpoint.d.ts +27 -0
- package/lib/ws-endpoint.js +241 -0
- package/lib/ws-transport.d.ts +13 -0
- package/lib/ws-transport.js +75 -0
- package/lib/ws-types.d.ts +17 -0
- package/lib/ws-types.js +1 -0
- package/lib/wss-auth.d.ts +2 -0
- package/lib/wss-auth.js +16 -0
- package/lib/wss-endpoint.d.ts +26 -0
- package/lib/wss-endpoint.js +187 -0
- package/package.json +62 -30
- package/plugin.js +18 -0
- package/schema.json +110 -0
- package/src/client.ts +79 -0
- package/src/endpoint-management.ts +72 -0
- package/src/http-endpoint.ts +234 -0
- package/src/index.ts +63 -85
- package/src/napcat-endpoint-commands.ts +26 -0
- package/src/napcat-inbound.ts +34 -10
- package/src/napcat-runtime-state.ts +7 -0
- package/src/onebot-get-msg.ts +69 -5
- package/src/protocol.ts +468 -0
- package/src/side-event-dispatch.ts +48 -0
- package/src/webhook.ts +16 -0
- package/src/ws-endpoint.ts +301 -0
- package/src/ws-transport.ts +105 -0
- package/src/ws-types.ts +20 -0
- package/src/wss-auth.ts +17 -0
- package/src/wss-endpoint.ts +242 -0
- package/client/NapCatManagement.tsx +0 -113
- package/client/index.tsx +0 -11
- package/client/tsconfig.json +0 -7
- package/client/utils/api.ts +0 -30
- package/dist/index.js +0 -27
- package/lib/adapter.d.ts +0 -27
- package/lib/adapter.d.ts.map +0 -1
- package/lib/adapter.js +0 -93
- package/lib/adapter.js.map +0 -1
- package/lib/agent-prompt.d.ts +0 -3
- package/lib/agent-prompt.d.ts.map +0 -1
- package/lib/agent-prompt.js +0 -105
- package/lib/agent-prompt.js.map +0 -1
- package/lib/bot-base.d.ts +0 -143
- package/lib/bot-base.d.ts.map +0 -1
- package/lib/bot-base.js +0 -334
- package/lib/bot-base.js.map +0 -1
- package/lib/bot-http.d.ts +0 -18
- package/lib/bot-http.d.ts.map +0 -1
- package/lib/bot-http.js +0 -119
- package/lib/bot-http.js.map +0 -1
- package/lib/bot-ws-client.d.ts +0 -21
- package/lib/bot-ws-client.d.ts.map +0 -1
- package/lib/bot-ws-client.js +0 -165
- package/lib/bot-ws-client.js.map +0 -1
- package/lib/bot-ws-server.d.ts +0 -21
- package/lib/bot-ws-server.d.ts.map +0 -1
- package/lib/bot-ws-server.js +0 -150
- package/lib/bot-ws-server.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/napcat-inbound.d.ts.map +0 -1
- package/lib/napcat-inbound.js.map +0 -1
- package/lib/onebot-get-msg.d.ts.map +0 -1
- package/lib/onebot-get-msg.js.map +0 -1
- package/lib/routes.d.ts +0 -4
- package/lib/routes.d.ts.map +0 -1
- package/lib/routes.js +0 -61
- package/lib/routes.js.map +0 -1
- package/lib/tools.d.ts +0 -8
- package/lib/tools.d.ts.map +0 -1
- package/lib/tools.js +0 -605
- package/lib/tools.js.map +0 -1
- package/lib/types.d.ts +0 -293
- package/lib/types.d.ts.map +0 -1
- package/lib/types.js +0 -6
- package/lib/types.js.map +0 -1
- package/lib/typing-indicator.d.ts +0 -45
- package/lib/typing-indicator.d.ts.map +0 -1
- package/lib/typing-indicator.js +0 -132
- package/lib/typing-indicator.js.map +0 -1
- package/plugin.yml +0 -3
- package/src/adapter.ts +0 -99
- package/src/agent-prompt.ts +0 -114
- package/src/bot-base.ts +0 -376
- package/src/bot-http.ts +0 -109
- package/src/bot-ws-client.ts +0 -164
- package/src/bot-ws-server.ts +0 -150
- package/src/routes.ts +0 -61
- package/src/tools.ts +0 -632
- package/src/types.ts +0 -279
- package/src/typing-indicator.ts +0 -184
package/src/bot-ws-client.ts
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* NapCat 正向 WebSocket 连接
|
|
3
|
-
*/
|
|
4
|
-
import WebSocket from 'ws';
|
|
5
|
-
import { formatCompact } from 'zhin.js';
|
|
6
|
-
import { NapCatBotBase } from './bot-base.js';
|
|
7
|
-
import type { NapCatWsClientConfig, ApiResponse } from './types.js';
|
|
8
|
-
import type { NapCatAdapter } from './adapter.js';
|
|
9
|
-
import { enableTypingIndicator } from './typing-indicator.js';
|
|
10
|
-
|
|
11
|
-
export class NapCatWsClient extends NapCatBotBase {
|
|
12
|
-
private ws?: WebSocket;
|
|
13
|
-
private reconnectTimer?: NodeJS.Timeout;
|
|
14
|
-
private heartbeatTimer?: NodeJS.Timeout;
|
|
15
|
-
private requestId = 0;
|
|
16
|
-
private pendingRequests = new Map<string, {
|
|
17
|
-
resolve: (value: any) => void;
|
|
18
|
-
reject: (error: Error) => void;
|
|
19
|
-
timeout: NodeJS.Timeout;
|
|
20
|
-
}>();
|
|
21
|
-
|
|
22
|
-
declare $config: NapCatWsClientConfig;
|
|
23
|
-
|
|
24
|
-
constructor(adapter: NapCatAdapter, config: NapCatWsClientConfig) {
|
|
25
|
-
super(adapter, config);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async $connect(): Promise<void> {
|
|
29
|
-
return new Promise((resolve, reject) => {
|
|
30
|
-
const headers: Record<string, string> = {};
|
|
31
|
-
let url = this.$config.url;
|
|
32
|
-
if (this.$config.access_token) {
|
|
33
|
-
headers['Authorization'] = `Bearer ${this.$config.access_token}`;
|
|
34
|
-
const u = new URL(url);
|
|
35
|
-
u.searchParams.set('access_token', this.$config.access_token);
|
|
36
|
-
url = u.toString();
|
|
37
|
-
}
|
|
38
|
-
this.ws = new WebSocket(url, { headers });
|
|
39
|
-
|
|
40
|
-
this.ws.on('open', () => {
|
|
41
|
-
this.$connected = true;
|
|
42
|
-
if (!this.$config.access_token) {
|
|
43
|
-
this.logger.warn(formatCompact({ bot: this.$id, ok: false, error: 'missing access_token' }));
|
|
44
|
-
}
|
|
45
|
-
this.logger.info(formatCompact({ bot: this.$id, mode: 'ws' }));
|
|
46
|
-
this.startHeartbeat();
|
|
47
|
-
this.initTypingIndicator();
|
|
48
|
-
resolve();
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
this.ws.on('message', (data) => {
|
|
52
|
-
try {
|
|
53
|
-
this.handleWsMessage(JSON.parse(data.toString()));
|
|
54
|
-
} catch (error) {
|
|
55
|
-
this.emit('error', error);
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
this.ws.on('close', (code, reason) => {
|
|
60
|
-
this.$connected = false;
|
|
61
|
-
const reasonStr = reason?.toString?.() || '';
|
|
62
|
-
const codeHint = code === 1005 ? ' [no status]' : code === 1006 ? ' [abnormal]' : '';
|
|
63
|
-
this.logger.warn(formatCompact( {
|
|
64
|
-
op: 'disconnect',
|
|
65
|
-
bot: this.$id,
|
|
66
|
-
code,
|
|
67
|
-
error: reasonStr || 'closed',
|
|
68
|
-
reconnect_ms: this.$config.reconnect_interval || 5000,
|
|
69
|
-
}));
|
|
70
|
-
reject({ code, reason });
|
|
71
|
-
this.scheduleReconnect();
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
this.ws.on('error', (error) => {
|
|
75
|
-
this.logger.warn(formatCompact( {
|
|
76
|
-
op: 'ws_error',
|
|
77
|
-
bot: this.$id,
|
|
78
|
-
ok: false,
|
|
79
|
-
error: error instanceof Error ? error.message : String(error),
|
|
80
|
-
}));
|
|
81
|
-
reject(error);
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
async $disconnect(): Promise<void> {
|
|
87
|
-
if (this.reconnectTimer) { clearTimeout(this.reconnectTimer); this.reconnectTimer = undefined; }
|
|
88
|
-
if (this.heartbeatTimer) { clearInterval(this.heartbeatTimer); this.heartbeatTimer = undefined; }
|
|
89
|
-
for (const [, req] of this.pendingRequests) { clearTimeout(req.timeout); req.reject(new Error('Connection closed')); }
|
|
90
|
-
this.pendingRequests.clear();
|
|
91
|
-
if (this.ws) { this.ws.close(); this.ws = undefined; }
|
|
92
|
-
this.inboundDeduper.clear();
|
|
93
|
-
this.$connected = false;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
async callApi<T = any>(action: string, params: Record<string, any> = {}): Promise<T> {
|
|
97
|
-
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) throw new Error('WebSocket is not connected');
|
|
98
|
-
const echo = `req_${++this.requestId}`;
|
|
99
|
-
return new Promise((resolve, reject) => {
|
|
100
|
-
const timeout = setTimeout(() => { this.pendingRequests.delete(echo); reject(new Error(`API call timeout: ${action}`)); }, 30000);
|
|
101
|
-
this.pendingRequests.set(echo, { resolve, reject, timeout });
|
|
102
|
-
this.ws!.send(JSON.stringify({ action, params, echo }));
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
private handleWsMessage(message: any): void {
|
|
107
|
-
if (message.echo && this.pendingRequests.has(message.echo)) {
|
|
108
|
-
const req = this.pendingRequests.get(message.echo)!;
|
|
109
|
-
this.pendingRequests.delete(message.echo);
|
|
110
|
-
clearTimeout(req.timeout);
|
|
111
|
-
const resp = message as ApiResponse;
|
|
112
|
-
if (resp.status === 'ok') return req.resolve(resp.data);
|
|
113
|
-
return req.reject(new Error(`API error [${resp.retcode}]: ${resp.message || resp.wording || 'unknown'}`));
|
|
114
|
-
}
|
|
115
|
-
this.dispatchEvent(message);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
private startHeartbeat(): void {
|
|
119
|
-
const interval = this.$config.heartbeat_interval || 30000;
|
|
120
|
-
this.heartbeatTimer = setInterval(() => {
|
|
121
|
-
if (this.ws && this.ws.readyState === WebSocket.OPEN) this.ws.ping();
|
|
122
|
-
}, interval);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
private scheduleReconnect(): void {
|
|
126
|
-
if (this.reconnectTimer) return;
|
|
127
|
-
const interval = this.$config.reconnect_interval || 5000;
|
|
128
|
-
this.reconnectTimer = setTimeout(async () => {
|
|
129
|
-
this.reconnectTimer = undefined;
|
|
130
|
-
try { await this.$connect(); } catch { this.scheduleReconnect(); }
|
|
131
|
-
}, interval);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
protected handleMeta(event: any): void {
|
|
135
|
-
if (event.meta_event_type === 'lifecycle' && event.sub_type === 'connect') {
|
|
136
|
-
this.logger.info(formatCompact({ bot: this.$id, lifecycle: 'connect', self_id: event.self_id }));
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
private initTypingIndicator(): void {
|
|
141
|
-
const tiConfig = this.$config.typingIndicator;
|
|
142
|
-
if (tiConfig && tiConfig.enabled !== false) {
|
|
143
|
-
enableTypingIndicator(this, {
|
|
144
|
-
enabled: tiConfig.enabled ?? true,
|
|
145
|
-
defaultEmoji: tiConfig.defaultEmoji || '128516',
|
|
146
|
-
autoRemove: true,
|
|
147
|
-
removeDelay: 5000,
|
|
148
|
-
privateConfig: tiConfig.privateConfig ? {
|
|
149
|
-
type: tiConfig.privateConfig.type || 'message',
|
|
150
|
-
message: tiConfig.privateConfig.message || '正在思考中...',
|
|
151
|
-
autoRemove: true,
|
|
152
|
-
removeDelay: 3000,
|
|
153
|
-
} : undefined,
|
|
154
|
-
groupConfig: tiConfig.groupConfig ? {
|
|
155
|
-
type: tiConfig.groupConfig.type || 'reaction',
|
|
156
|
-
emoji: tiConfig.groupConfig.emoji || '128516',
|
|
157
|
-
autoRemove: true,
|
|
158
|
-
removeDelay: 5000,
|
|
159
|
-
} : undefined,
|
|
160
|
-
});
|
|
161
|
-
this.logger.info(formatCompact({ bot: this.$id, typingIndicator: 'enabled' }));
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
package/src/bot-ws-server.ts
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* NapCat 反向 WebSocket 连接
|
|
3
|
-
*/
|
|
4
|
-
import WebSocket, { WebSocketServer } from 'ws';
|
|
5
|
-
import { formatCompact } from 'zhin.js';
|
|
6
|
-
import type { IncomingMessage } from 'http';
|
|
7
|
-
import { NapCatBotBase } from './bot-base.js';
|
|
8
|
-
import type { NapCatWsServerConfig, ApiResponse } from './types.js';
|
|
9
|
-
import type { NapCatAdapter } from './adapter.js';
|
|
10
|
-
import type { Router } from '@zhin.js/host-router';
|
|
11
|
-
import { enableTypingIndicator } from './typing-indicator.js';
|
|
12
|
-
|
|
13
|
-
export class NapCatWsServer extends NapCatBotBase {
|
|
14
|
-
#wss?: WebSocketServer;
|
|
15
|
-
#clientMap = new Map<string, WebSocket>();
|
|
16
|
-
private heartbeatTimer?: NodeJS.Timeout;
|
|
17
|
-
private requestId = 0;
|
|
18
|
-
private pendingRequests = new Map<string, {
|
|
19
|
-
resolve: (value: any) => void;
|
|
20
|
-
reject: (error: Error) => void;
|
|
21
|
-
timeout: NodeJS.Timeout;
|
|
22
|
-
}>();
|
|
23
|
-
|
|
24
|
-
declare $config: NapCatWsServerConfig;
|
|
25
|
-
|
|
26
|
-
constructor(adapter: NapCatAdapter, public router: Router, config: NapCatWsServerConfig) {
|
|
27
|
-
super(adapter, config);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async $connect(): Promise<void> {
|
|
31
|
-
if (!this.$config.access_token) {
|
|
32
|
-
this.logger.warn(formatCompact({ bot: this.$id, ok: false, error: 'missing access_token' }));
|
|
33
|
-
}
|
|
34
|
-
this.#wss = this.router.ws(this.$config.path, {
|
|
35
|
-
verifyClient: (info: { origin: string; secure: boolean; req: IncomingMessage }) => {
|
|
36
|
-
const authorization = info.req.headers['authorization'] || '';
|
|
37
|
-
if (this.$config.access_token && authorization !== `Bearer ${this.$config.access_token}`) {
|
|
38
|
-
this.logger.error(`[${this.$id}] auth failed`);
|
|
39
|
-
return false;
|
|
40
|
-
}
|
|
41
|
-
return true;
|
|
42
|
-
},
|
|
43
|
-
});
|
|
44
|
-
this.logger.info(formatCompact( { op: 'listen', bot: this.$id, mode: 'wss', path: this.$config.path }));
|
|
45
|
-
|
|
46
|
-
this.#wss.on('connection', (client, req) => {
|
|
47
|
-
this.startHeartbeat();
|
|
48
|
-
this.logger.info(formatCompact({ bot: this.$id, peer: req.socket.remoteAddress }));
|
|
49
|
-
|
|
50
|
-
client.on('error', (err) => this.logger.warn(formatCompact( {
|
|
51
|
-
op: 'ws_error',
|
|
52
|
-
bot: this.$id,
|
|
53
|
-
ok: false,
|
|
54
|
-
error: err instanceof Error ? err.message : String(err),
|
|
55
|
-
})));
|
|
56
|
-
client.on('close', (code, reason) => {
|
|
57
|
-
const reasonStr = reason?.toString?.() || '';
|
|
58
|
-
this.logger.warn(formatCompact( {
|
|
59
|
-
op: 'disconnect',
|
|
60
|
-
bot: this.$id,
|
|
61
|
-
code,
|
|
62
|
-
error: reasonStr || undefined,
|
|
63
|
-
}));
|
|
64
|
-
for (const [key, val] of this.#clientMap) {
|
|
65
|
-
if (val === client) this.#clientMap.delete(key);
|
|
66
|
-
}
|
|
67
|
-
if (this.#clientMap.size === 0) this.$connected = false;
|
|
68
|
-
});
|
|
69
|
-
client.on('message', (data) => {
|
|
70
|
-
try { this.handleWsMessage(client, JSON.parse(data.toString())); } catch (e) { this.emit('error', e); }
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async $disconnect(): Promise<void> {
|
|
76
|
-
this.#wss?.close();
|
|
77
|
-
if (this.heartbeatTimer) { clearInterval(this.heartbeatTimer); this.heartbeatTimer = undefined; }
|
|
78
|
-
for (const [, req] of this.pendingRequests) { clearTimeout(req.timeout); req.reject(new Error('Connection closed')); }
|
|
79
|
-
this.pendingRequests.clear();
|
|
80
|
-
this.inboundDeduper.clear();
|
|
81
|
-
this.$connected = false;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
async callApi<T = any>(action: string, params: Record<string, any> = {}): Promise<T> {
|
|
85
|
-
const selfId = this.getFirstSelfId();
|
|
86
|
-
const client = this.#clientMap.get(selfId);
|
|
87
|
-
if (!client || client.readyState !== WebSocket.OPEN) throw new Error('WebSocket is not connected');
|
|
88
|
-
const echo = `req_${++this.requestId}`;
|
|
89
|
-
return new Promise((resolve, reject) => {
|
|
90
|
-
const timeout = setTimeout(() => { this.pendingRequests.delete(echo); reject(new Error(`API call timeout: ${action}`)); }, 30000);
|
|
91
|
-
this.pendingRequests.set(echo, { resolve, reject, timeout });
|
|
92
|
-
client.send(JSON.stringify({ action, params, echo }));
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
private getFirstSelfId(): string {
|
|
97
|
-
const first = this.#clientMap.keys().next().value;
|
|
98
|
-
if (!first) throw new Error('No NapCat client connected to reverse WS');
|
|
99
|
-
return first;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
private handleWsMessage(client: WebSocket, message: any): void {
|
|
103
|
-
if (message.self_id != null) {
|
|
104
|
-
const selfIdStr = String(message.self_id);
|
|
105
|
-
if (!this.#clientMap.has(selfIdStr) || this.#clientMap.get(selfIdStr) !== client) {
|
|
106
|
-
this.#clientMap.set(selfIdStr, client);
|
|
107
|
-
if (!this.$connected) this.$connected = true;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
if (message.echo && this.pendingRequests.has(message.echo)) {
|
|
111
|
-
const req = this.pendingRequests.get(message.echo)!;
|
|
112
|
-
this.pendingRequests.delete(message.echo);
|
|
113
|
-
clearTimeout(req.timeout);
|
|
114
|
-
const resp = message as ApiResponse;
|
|
115
|
-
if (resp.status === 'ok') return req.resolve(resp.data);
|
|
116
|
-
return req.reject(new Error(`API error [${resp.retcode}]: ${resp.message || resp.wording || 'unknown'}`));
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (message.post_type === 'meta_event' && message.sub_type === 'connect') {
|
|
120
|
-
this.#clientMap.set(String(message.self_id), client);
|
|
121
|
-
this.$connected = true;
|
|
122
|
-
this.logger.info(formatCompact({ bot: this.$id, self_id: message.self_id }));
|
|
123
|
-
this.initTypingIndicator();
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
this.dispatchEvent(message);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
private startHeartbeat(): void {
|
|
130
|
-
if (this.heartbeatTimer) return;
|
|
131
|
-
const interval = this.$config.heartbeat_interval || 30000;
|
|
132
|
-
this.heartbeatTimer = setInterval(() => {
|
|
133
|
-
for (const client of this.#wss?.clients || []) {
|
|
134
|
-
if (client.readyState === WebSocket.OPEN) client.ping();
|
|
135
|
-
}
|
|
136
|
-
}, interval);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
private initTypingIndicator(): void {
|
|
140
|
-
const tiConfig = (this.$config as any).typingIndicator;
|
|
141
|
-
if (tiConfig && tiConfig.enabled !== false) {
|
|
142
|
-
enableTypingIndicator(this, {
|
|
143
|
-
enabled: true,
|
|
144
|
-
defaultEmoji: tiConfig.defaultEmoji || '128516',
|
|
145
|
-
autoRemove: true,
|
|
146
|
-
removeDelay: 5000,
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
package/src/routes.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import type { Router } from '@zhin.js/host-router';
|
|
2
|
-
import type { NapCatAdapter } from './adapter.js';
|
|
3
|
-
|
|
4
|
-
export function registerRoutes(router: Router, napcat: NapCatAdapter): void {
|
|
5
|
-
router.get('/api/napcat/bots', async (ctx) => {
|
|
6
|
-
try {
|
|
7
|
-
const bots = Array.from(napcat.bots.values());
|
|
8
|
-
if (bots.length === 0) {
|
|
9
|
-
ctx.body = { success: true, data: [], message: '暂无 NapCat 机器人实例' };
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
12
|
-
const result = await Promise.all(
|
|
13
|
-
bots.map(async (bot) => {
|
|
14
|
-
try {
|
|
15
|
-
const connection = (bot.$config as any).connection ?? 'ws';
|
|
16
|
-
const base: Record<string, unknown> = {
|
|
17
|
-
name: bot.$config.name,
|
|
18
|
-
connected: bot.$connected || false,
|
|
19
|
-
connection,
|
|
20
|
-
status: bot.$connected ? 'online' : 'offline',
|
|
21
|
-
lastActivity: new Date().toISOString(),
|
|
22
|
-
};
|
|
23
|
-
if (bot.$connected) {
|
|
24
|
-
try {
|
|
25
|
-
const friends = await bot.getFriendList();
|
|
26
|
-
const groups = await bot.getGroupList();
|
|
27
|
-
base.friendCount = Array.isArray(friends) ? friends.length : 0;
|
|
28
|
-
base.groupCount = Array.isArray(groups) ? groups.length : 0;
|
|
29
|
-
} catch {
|
|
30
|
-
base.friendCount = 0;
|
|
31
|
-
base.groupCount = 0;
|
|
32
|
-
}
|
|
33
|
-
} else {
|
|
34
|
-
base.friendCount = 0;
|
|
35
|
-
base.groupCount = 0;
|
|
36
|
-
}
|
|
37
|
-
return base;
|
|
38
|
-
} catch {
|
|
39
|
-
return {
|
|
40
|
-
name: bot.$config.name,
|
|
41
|
-
connected: false,
|
|
42
|
-
connection: 'unknown',
|
|
43
|
-
status: 'error',
|
|
44
|
-
friendCount: 0,
|
|
45
|
-
groupCount: 0,
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
}),
|
|
49
|
-
);
|
|
50
|
-
ctx.body = { success: true, data: result, timestamp: new Date().toISOString() };
|
|
51
|
-
} catch (error) {
|
|
52
|
-
ctx.status = 500;
|
|
53
|
-
ctx.body = {
|
|
54
|
-
success: false,
|
|
55
|
-
error: 'NAPCAT_API_ERROR',
|
|
56
|
-
message: '获取机器人数据失败',
|
|
57
|
-
details: process.env.NODE_ENV === 'development' ? (error as Error).message : undefined,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
}
|