onebots 0.0.1
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/LICENSE +21 -0
- package/README.md +59 -0
- package/lib/bin.d.ts +2 -0
- package/lib/bin.js +5 -0
- package/lib/config.sample.yaml +31 -0
- package/lib/db.d.ts +19 -0
- package/lib/db.js +91 -0
- package/lib/index.d.ts +5 -0
- package/lib/index.js +21 -0
- package/lib/onebot.d.ts +43 -0
- package/lib/onebot.js +85 -0
- package/lib/server/app.d.ts +52 -0
- package/lib/server/app.js +232 -0
- package/lib/server/router.d.ts +9 -0
- package/lib/server/router.js +32 -0
- package/lib/service/V11/action/common.d.ts +64 -0
- package/lib/service/V11/action/common.js +115 -0
- package/lib/service/V11/action/friend.d.ts +38 -0
- package/lib/service/V11/action/friend.js +44 -0
- package/lib/service/V11/action/group.d.ts +104 -0
- package/lib/service/V11/action/group.js +138 -0
- package/lib/service/V11/action/index.d.ts +9 -0
- package/lib/service/V11/action/index.js +10 -0
- package/lib/service/V11/config.d.ts +10 -0
- package/lib/service/V11/config.js +2 -0
- package/lib/service/V11/index.d.ts +95 -0
- package/lib/service/V11/index.js +481 -0
- package/lib/service/V12/action/common.d.ts +32 -0
- package/lib/service/V12/action/common.js +105 -0
- package/lib/service/V12/action/friend.d.ts +13 -0
- package/lib/service/V12/action/friend.js +15 -0
- package/lib/service/V12/action/group.d.ts +104 -0
- package/lib/service/V12/action/group.js +138 -0
- package/lib/service/V12/action/guild.d.ts +2 -0
- package/lib/service/V12/action/guild.js +6 -0
- package/lib/service/V12/action/index.d.ts +10 -0
- package/lib/service/V12/action/index.js +11 -0
- package/lib/service/V12/config.d.ts +17 -0
- package/lib/service/V12/config.js +2 -0
- package/lib/service/V12/index.d.ts +102 -0
- package/lib/service/V12/index.js +530 -0
- package/lib/types.d.ts +3 -0
- package/lib/types.js +2 -0
- package/lib/utils.d.ts +13 -0
- package/lib/utils.js +139 -0
- package/package.json +58 -0
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.V12 = void 0;
|
|
7
|
+
const path_1 = require("path");
|
|
8
|
+
const onebot_1 = require("../../onebot");
|
|
9
|
+
const action_1 = require("./action");
|
|
10
|
+
const events_1 = require("events");
|
|
11
|
+
const url_1 = require("url");
|
|
12
|
+
const http_1 = __importDefault(require("http"));
|
|
13
|
+
const https_1 = __importDefault(require("https"));
|
|
14
|
+
const ws_1 = require("ws");
|
|
15
|
+
const icqq_cq_enable_1 = require("icqq-cq-enable");
|
|
16
|
+
const utils_1 = require("../../utils");
|
|
17
|
+
const db_1 = require("../../db");
|
|
18
|
+
const app_1 = require("../../server/app");
|
|
19
|
+
class V12 extends events_1.EventEmitter {
|
|
20
|
+
constructor(oneBot, client, config) {
|
|
21
|
+
super();
|
|
22
|
+
this.oneBot = oneBot;
|
|
23
|
+
this.client = client;
|
|
24
|
+
this.config = config;
|
|
25
|
+
this.version = 'V12';
|
|
26
|
+
this.timestamp = Date.now();
|
|
27
|
+
this.wsr = new Set();
|
|
28
|
+
this.db = new db_1.Db((0, path_1.join)(app_1.App.configDir, 'data', this.client.uin + '.json'));
|
|
29
|
+
if (!this.history)
|
|
30
|
+
this.db.set('eventBuffer', []);
|
|
31
|
+
this.action = new action_1.Action();
|
|
32
|
+
this.logger = this.oneBot.app.getLogger(this.client.uin, this.version);
|
|
33
|
+
}
|
|
34
|
+
get history() {
|
|
35
|
+
return this.db.get('eventBuffer');
|
|
36
|
+
}
|
|
37
|
+
start(path) {
|
|
38
|
+
this.path = `/${this.client.uin}`;
|
|
39
|
+
if (path)
|
|
40
|
+
this.path += path;
|
|
41
|
+
if (this.config.use_http) {
|
|
42
|
+
const config = typeof this.config.use_http === 'boolean' ? {} : this.config.use_http || {};
|
|
43
|
+
this.startHttp({
|
|
44
|
+
access_token: this.config.access_token,
|
|
45
|
+
event_enabled: true,
|
|
46
|
+
event_buffer_size: 50,
|
|
47
|
+
...config
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
if (this.config.use_ws) {
|
|
51
|
+
const config = typeof this.config.use_ws === 'boolean' ? {} : this.config.use_ws || {};
|
|
52
|
+
this.startWs({
|
|
53
|
+
access_token: this.config.access_token,
|
|
54
|
+
...config
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
this.config.webhook.forEach(config => {
|
|
58
|
+
if (typeof config === 'string') {
|
|
59
|
+
config = {
|
|
60
|
+
url: config,
|
|
61
|
+
access_token: this.config.access_token,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
config = {
|
|
66
|
+
access_token: this.config.access_token,
|
|
67
|
+
...config
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
this.startWebhook(config);
|
|
71
|
+
});
|
|
72
|
+
this.config.ws_reverse.forEach(config => {
|
|
73
|
+
if (typeof config === 'string') {
|
|
74
|
+
config = {
|
|
75
|
+
url: config,
|
|
76
|
+
access_token: this.config.access_token,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
config = {
|
|
81
|
+
access_token: this.config.access_token,
|
|
82
|
+
...config
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
this.startWsReverse(config);
|
|
86
|
+
});
|
|
87
|
+
if (this.config.heartbeat) {
|
|
88
|
+
this.heartbeat = setInterval(() => {
|
|
89
|
+
this.dispatch({
|
|
90
|
+
self_id: this.client.uin,
|
|
91
|
+
time: Math.floor(Date.now() / 1000),
|
|
92
|
+
type: "meta",
|
|
93
|
+
detail_type: "heartbeat",
|
|
94
|
+
interval: this.config.heartbeat * 1000,
|
|
95
|
+
status: this.action.getStatus.apply(this)
|
|
96
|
+
});
|
|
97
|
+
}, this.config.heartbeat * 1000);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
startHttp(config) {
|
|
101
|
+
this.oneBot.app.router.all(new RegExp(`^${this.path}/(.*)$`), (ctx) => this._httpRequestHandler(ctx, config));
|
|
102
|
+
this.logger.mark(`开启http服务器成功,监听:http://127.0.0.1:${this.oneBot.app.config.port}${this.path}`);
|
|
103
|
+
this.on('dispatch', (payload) => {
|
|
104
|
+
if (!['message', 'notice', 'request', 'system'].includes(payload.type))
|
|
105
|
+
return;
|
|
106
|
+
if (config.event_enabled) {
|
|
107
|
+
this.history.push(payload);
|
|
108
|
+
if (config.event_buffer_size !== 0 && this.history.length > config.event_buffer_size)
|
|
109
|
+
this.history.shift();
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
startWebhook(config) {
|
|
114
|
+
this.on('dispatch', (unserialized) => {
|
|
115
|
+
const serialized = JSON.stringify(unserialized);
|
|
116
|
+
const options = {
|
|
117
|
+
method: "POST",
|
|
118
|
+
timeout: this.config.request_timeout * 1000,
|
|
119
|
+
headers: {
|
|
120
|
+
"Content-Type": "application/json",
|
|
121
|
+
"Content-Length": Buffer.byteLength(serialized),
|
|
122
|
+
"X-Self-ID": String(this.client.uin),
|
|
123
|
+
"User-Agent": "OneBot",
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
const protocol = config.url.startsWith("https") ? https_1.default : http_1.default;
|
|
127
|
+
try {
|
|
128
|
+
protocol.request(config.url, options, (res) => {
|
|
129
|
+
if (res.statusCode !== 200)
|
|
130
|
+
return this.logger.warn(`POST(${config.url})上报事件收到非200响应:` + res.statusCode);
|
|
131
|
+
let data = "";
|
|
132
|
+
res.setEncoding("utf-8");
|
|
133
|
+
res.on("data", (chunk) => data += chunk);
|
|
134
|
+
res.on("end", () => {
|
|
135
|
+
this.logger.debug(`收到HTTP响应 ${res.statusCode} :` + data);
|
|
136
|
+
if (!data)
|
|
137
|
+
return;
|
|
138
|
+
try {
|
|
139
|
+
this._quickOperate(unserialized, JSON.parse(data));
|
|
140
|
+
}
|
|
141
|
+
catch (e) {
|
|
142
|
+
this.logger.error(`快速操作遇到错误:` + e.message);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}).on("error", (err) => {
|
|
146
|
+
this.logger.error(`POST(${config.url})上报事件失败:` + err.message);
|
|
147
|
+
}).end(serialized, () => {
|
|
148
|
+
this.logger.debug(`POST(${config.url})上报事件成功: ` + serialized);
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
catch (e) {
|
|
152
|
+
this.logger.error(`POST(${config.url})上报失败:` + e.message);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
startWs(config) {
|
|
157
|
+
this.wss = this.oneBot.app.router.ws(this.path, this.oneBot.app.httpServer);
|
|
158
|
+
this.logger.mark(`开启ws服务器成功,监听:ws://127.0.0.1:${this.oneBot.app.config.port}${this.path}`);
|
|
159
|
+
this.wss.on("error", (err) => {
|
|
160
|
+
this.logger.error(err.message);
|
|
161
|
+
});
|
|
162
|
+
this.wss.on("connection", (ws, req) => {
|
|
163
|
+
this.logger.info(`ws客户端(${req.headers.origin})已连接`);
|
|
164
|
+
ws.on("error", (err) => {
|
|
165
|
+
this.logger.error(`ws客户端(${req.headers.origin})报错:${err.message}`);
|
|
166
|
+
});
|
|
167
|
+
ws.on("close", (code, reason) => {
|
|
168
|
+
this.logger.warn(`ws客户端(${req.headers.origin})连接关闭,关闭码${code},关闭理由:` + reason);
|
|
169
|
+
});
|
|
170
|
+
if (config.access_token) {
|
|
171
|
+
const url = new url_1.URL(req.url, "http://127.0.0.1");
|
|
172
|
+
const token = url.searchParams.get('access_token');
|
|
173
|
+
if (token)
|
|
174
|
+
req.headers["authorization"] = `Bearer ${token}`;
|
|
175
|
+
if (!req.headers["authorization"] || req.headers["authorization"] !== `Bearer ${config.access_token}`)
|
|
176
|
+
return ws.close(1002, "wrong access token");
|
|
177
|
+
}
|
|
178
|
+
this._webSocketHandler(ws);
|
|
179
|
+
});
|
|
180
|
+
this.on('dispatch', (unserialized) => {
|
|
181
|
+
const serialized = JSON.stringify(unserialized);
|
|
182
|
+
for (const ws of this.wss.clients) {
|
|
183
|
+
ws.send(serialized, (err) => {
|
|
184
|
+
if (err)
|
|
185
|
+
this.logger.error(`正向WS(${ws.url})上报事件失败: ` + err.message);
|
|
186
|
+
else
|
|
187
|
+
this.logger.debug(`正向WS(${ws.url})上报事件成功: ` + serialized);
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
startWsReverse(config) {
|
|
193
|
+
const ws = this._createWsr(config.url, config);
|
|
194
|
+
this.on('dispatch', (unserialized) => {
|
|
195
|
+
if (this.wsr.has(ws)) {
|
|
196
|
+
ws.send(JSON.stringify(unserialized));
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
stop() {
|
|
201
|
+
return this.client.logout();
|
|
202
|
+
}
|
|
203
|
+
dispatch(data = {}) {
|
|
204
|
+
if (!data)
|
|
205
|
+
data = {};
|
|
206
|
+
if (!data.post_type) {
|
|
207
|
+
// @ts-ignore
|
|
208
|
+
data.sub_type = 'online';
|
|
209
|
+
if (data.image) {
|
|
210
|
+
// @ts-ignore
|
|
211
|
+
data.system_type = 'login';
|
|
212
|
+
// @ts-ignore
|
|
213
|
+
data.sub_type = 'qrcode';
|
|
214
|
+
}
|
|
215
|
+
else if (data.url) {
|
|
216
|
+
// @ts-ignore
|
|
217
|
+
data.system_type = 'login';
|
|
218
|
+
// @ts-ignore
|
|
219
|
+
data.sub_type = 'slider';
|
|
220
|
+
if (data.phone) {
|
|
221
|
+
// @ts-ignore
|
|
222
|
+
data.sub_type = 'device';
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
else if (data.message) {
|
|
226
|
+
// @ts-ignore
|
|
227
|
+
data.system_type = 'login';
|
|
228
|
+
// @ts-ignore
|
|
229
|
+
data.sub_type = 'error';
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const payload = {
|
|
233
|
+
id: (0, utils_1.uuid)(),
|
|
234
|
+
impl: 'icqq_onebot',
|
|
235
|
+
platform: 'qq',
|
|
236
|
+
self_id: `${this.client.uin}`,
|
|
237
|
+
type: data.post_type || 'meta',
|
|
238
|
+
detail_type: data.message_type || data.notice_type || data.request_type || data.system_type,
|
|
239
|
+
...data,
|
|
240
|
+
};
|
|
241
|
+
if (payload.type === 'notice') {
|
|
242
|
+
switch (payload.detail_type) {
|
|
243
|
+
case 'friend':
|
|
244
|
+
payload.detail_type += payload.sub_type;
|
|
245
|
+
break;
|
|
246
|
+
case 'group':
|
|
247
|
+
if (['increase', 'decrease'].includes(payload.sub_type))
|
|
248
|
+
payload.detail_type = 'group_member_' + payload.sub_type;
|
|
249
|
+
else if (payload.sub_type === 'recall')
|
|
250
|
+
payload.detail_type = 'group_message_delete';
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
this.emit('dispatch', payload);
|
|
254
|
+
}
|
|
255
|
+
async apply(req) {
|
|
256
|
+
let { action, params, echo } = req;
|
|
257
|
+
action = (0, utils_1.toLine)(action);
|
|
258
|
+
let is_async = action.includes("_async");
|
|
259
|
+
if (is_async)
|
|
260
|
+
action = action.replace("_async", "");
|
|
261
|
+
if (action === 'send_msg') {
|
|
262
|
+
if (["private", "group", "discuss", 'channel'].includes(params.detail_type)) {
|
|
263
|
+
action = "send_" + params.detail_type + "_msg";
|
|
264
|
+
}
|
|
265
|
+
else if (params.user_id)
|
|
266
|
+
action = "send_private_msg";
|
|
267
|
+
else if (params.group_id)
|
|
268
|
+
action = "send_group_msg";
|
|
269
|
+
else if (params.discuss_id)
|
|
270
|
+
action = "send_discuss_msg";
|
|
271
|
+
else if (params.channel_id && params.guild_id)
|
|
272
|
+
action = "send_guild_msg";
|
|
273
|
+
else
|
|
274
|
+
throw new Error('required detail_type or input (user_id/group_id/(guild_id and channel_id))');
|
|
275
|
+
}
|
|
276
|
+
const method = (0, utils_1.toHump)(action);
|
|
277
|
+
if (Reflect.has(this.action, method)) {
|
|
278
|
+
const ARGS = String(Reflect.get(this.action, method)).match(/\(.*\)/)?.[0]
|
|
279
|
+
.replace("(", "")
|
|
280
|
+
.replace(")", "")
|
|
281
|
+
.split(",")
|
|
282
|
+
.filter(Boolean).map(v => v.replace(/=.+/, "").trim());
|
|
283
|
+
const args = [];
|
|
284
|
+
for (let k of ARGS) {
|
|
285
|
+
if (Reflect.has(params, k)) {
|
|
286
|
+
if (onebot_1.BOOLS.includes(k))
|
|
287
|
+
params[k] = (0, utils_1.toBool)(params[k]);
|
|
288
|
+
if (k === 'message') {
|
|
289
|
+
if (typeof params[k] === 'string') {
|
|
290
|
+
params[k] = (0, icqq_cq_enable_1.fromCqcode)(params[k]);
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
params[k] = (0, icqq_cq_enable_1.fromSegment)(params[k]);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
args.push(params[k]);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
let ret, result;
|
|
300
|
+
try {
|
|
301
|
+
ret = this.action[method].apply(this, args);
|
|
302
|
+
}
|
|
303
|
+
catch (e) {
|
|
304
|
+
return JSON.stringify(V12.error(e.message));
|
|
305
|
+
}
|
|
306
|
+
if (ret instanceof Promise) {
|
|
307
|
+
if (is_async) {
|
|
308
|
+
result = V12.success(null, 0);
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
result = V12.success(await ret, 0);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
result = V12.success(await ret, 0);
|
|
316
|
+
}
|
|
317
|
+
if (result.data instanceof Map)
|
|
318
|
+
result.data = [...result.data.values()];
|
|
319
|
+
if (echo) {
|
|
320
|
+
result.echo = echo;
|
|
321
|
+
}
|
|
322
|
+
return JSON.stringify(result);
|
|
323
|
+
}
|
|
324
|
+
else
|
|
325
|
+
throw new onebot_1.NotFoundError();
|
|
326
|
+
}
|
|
327
|
+
async _httpRequestHandler(ctx, config) {
|
|
328
|
+
if (ctx.method === 'OPTIONS') {
|
|
329
|
+
return ctx.writeHead(200, {
|
|
330
|
+
'Access-Control-Allow-Origin': '*',
|
|
331
|
+
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
|
|
332
|
+
'Access-Control-Allow-Headers': 'Content-Type, authorization'
|
|
333
|
+
}).end();
|
|
334
|
+
}
|
|
335
|
+
const url = new url_1.URL(ctx.url, `http://127.0.0.1`);
|
|
336
|
+
if (config.access_token) {
|
|
337
|
+
if (ctx.headers["authorization"]) {
|
|
338
|
+
if (ctx.headers["authorization"] !== `Bearer ${config.access_token}`)
|
|
339
|
+
return ctx.res.writeHead(403).end();
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
const access_token = url.searchParams.get("access_token");
|
|
343
|
+
if (!access_token)
|
|
344
|
+
return ctx.res.writeHead(401).end();
|
|
345
|
+
else if (access_token !== this.config.access_token)
|
|
346
|
+
return ctx.res.writeHead(403).end();
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
ctx.res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
350
|
+
if (this.config.enable_cors)
|
|
351
|
+
ctx.res.setHeader("Access-Control-Allow-Origin", "*");
|
|
352
|
+
const action = url.pathname.replace(`${this.path}`, '').slice(1);
|
|
353
|
+
if (ctx.method === "GET") {
|
|
354
|
+
try {
|
|
355
|
+
const ret = await this.apply({ action, params: ctx.query });
|
|
356
|
+
ctx.res.writeHead(200).end(ret);
|
|
357
|
+
}
|
|
358
|
+
catch (e) {
|
|
359
|
+
ctx.res.writeHead(500).end(e.message);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
else if (ctx.method === "POST") {
|
|
363
|
+
try {
|
|
364
|
+
const params = { ...ctx.query, ...ctx.request.body };
|
|
365
|
+
const ret = await this.apply({ action, params });
|
|
366
|
+
ctx.res.writeHead(200).end(ret);
|
|
367
|
+
}
|
|
368
|
+
catch (e) {
|
|
369
|
+
ctx.res.writeHead(500).end(e.message);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
ctx.res.writeHead(405).end();
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* 快速操作
|
|
378
|
+
*/
|
|
379
|
+
_quickOperate(event, res) {
|
|
380
|
+
if (event.type === "message") {
|
|
381
|
+
if (res.reply) {
|
|
382
|
+
if (event.detail_type === "discuss")
|
|
383
|
+
return;
|
|
384
|
+
const action = event.detail_type === "private" ? "sendPrivateMsg" : "sendGroupMsg";
|
|
385
|
+
const id = event.detail_type === "private" ? event.user_id : event.group_id;
|
|
386
|
+
this.client[action](id, res.reply, res.auto_escape);
|
|
387
|
+
}
|
|
388
|
+
if (event.detail_type === "group") {
|
|
389
|
+
if (res.delete)
|
|
390
|
+
this.client.deleteMsg(event.message_id);
|
|
391
|
+
if (res.kick && !event.anonymous)
|
|
392
|
+
this.client.setGroupKick(event.group_id, event.user_id, res.reject_add_request);
|
|
393
|
+
if (res.ban)
|
|
394
|
+
this.client.setGroupBan(event.group_id, event.user_id, res.ban_duration > 0 ? res.ban_duration : 1800);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
if (event.type === "request" && "approve" in res) {
|
|
398
|
+
const action = event.detail_type === "friend" ? "setFriendAddRequest" : "setGroupAddRequest";
|
|
399
|
+
this.client[action](event.flag, res.approve, res.reason ? res.reason : "", !!res.block);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* 创建反向ws
|
|
404
|
+
*/
|
|
405
|
+
_createWsr(url, config) {
|
|
406
|
+
const timestmap = Date.now();
|
|
407
|
+
const headers = {
|
|
408
|
+
"X-Self-ID": String(this.client.uin),
|
|
409
|
+
"X-Client-Role": "Universal",
|
|
410
|
+
"User-Agent": "OneBot",
|
|
411
|
+
};
|
|
412
|
+
if (config.access_token)
|
|
413
|
+
headers.Authorization = "Bearer " + config.access_token;
|
|
414
|
+
const ws = new ws_1.WebSocket(url, { headers });
|
|
415
|
+
ws.on("error", (err) => {
|
|
416
|
+
this.logger.error(err.message);
|
|
417
|
+
});
|
|
418
|
+
ws.on("open", () => {
|
|
419
|
+
this.logger.info(`反向ws(${url})连接成功。`);
|
|
420
|
+
this.wsr.add(ws);
|
|
421
|
+
this._webSocketHandler(ws);
|
|
422
|
+
});
|
|
423
|
+
ws.on("close", (code) => {
|
|
424
|
+
this.wsr.delete(ws);
|
|
425
|
+
if (timestmap < this.timestamp)
|
|
426
|
+
return;
|
|
427
|
+
this.logger.warn(`反向ws(${url})被关闭,关闭码${code},将在${this.config.reconnect_interval}秒后尝试重连。`);
|
|
428
|
+
setTimeout(() => {
|
|
429
|
+
if (timestmap < this.timestamp)
|
|
430
|
+
return;
|
|
431
|
+
this._createWsr(url, config);
|
|
432
|
+
}, this.config.reconnect_interval * 1000);
|
|
433
|
+
});
|
|
434
|
+
return ws;
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* 处理ws消息
|
|
438
|
+
*/
|
|
439
|
+
_webSocketHandler(ws) {
|
|
440
|
+
ws.on("message", async (msg) => {
|
|
441
|
+
this.logger.debug(" 收到ws消息:" + msg);
|
|
442
|
+
var data;
|
|
443
|
+
try {
|
|
444
|
+
data = JSON.parse(String(msg));
|
|
445
|
+
let ret;
|
|
446
|
+
if (data.action.startsWith(".handle_quick_operation")) {
|
|
447
|
+
const event = data.params.context, res = data.params.operation;
|
|
448
|
+
this._quickOperate(event, res);
|
|
449
|
+
ret = JSON.stringify({
|
|
450
|
+
retcode: 0,
|
|
451
|
+
status: "ok",
|
|
452
|
+
data: null,
|
|
453
|
+
message: null,
|
|
454
|
+
echo: data.echo
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
else {
|
|
458
|
+
ret = await this.apply(data);
|
|
459
|
+
}
|
|
460
|
+
ws.send(ret);
|
|
461
|
+
}
|
|
462
|
+
catch (e) {
|
|
463
|
+
let code, message;
|
|
464
|
+
if (e instanceof onebot_1.NotFoundError) {
|
|
465
|
+
code = 10002;
|
|
466
|
+
message = "不支持的api";
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
code = 10003;
|
|
470
|
+
message = "请求格式错误";
|
|
471
|
+
}
|
|
472
|
+
ws.send(JSON.stringify({
|
|
473
|
+
retcode: code,
|
|
474
|
+
status: "failed",
|
|
475
|
+
data: null,
|
|
476
|
+
error: {
|
|
477
|
+
code, message
|
|
478
|
+
},
|
|
479
|
+
echo: data?.echo
|
|
480
|
+
}));
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
this.dispatch(V12.genMetaEvent(this.client.uin, "connect"));
|
|
484
|
+
this.dispatch(V12.genMetaEvent(this.client.uin, "enable"));
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
exports.V12 = V12;
|
|
488
|
+
(function (V12) {
|
|
489
|
+
V12.defaultConfig = {
|
|
490
|
+
heartbeat: 3,
|
|
491
|
+
access_token: '',
|
|
492
|
+
request_timeout: 15,
|
|
493
|
+
reconnect_interval: 3,
|
|
494
|
+
enable_cors: true,
|
|
495
|
+
use_http: true,
|
|
496
|
+
use_ws: true,
|
|
497
|
+
webhook: [],
|
|
498
|
+
ws_reverse: []
|
|
499
|
+
};
|
|
500
|
+
function success(data, retcode = 0, echo) {
|
|
501
|
+
return {
|
|
502
|
+
retcode,
|
|
503
|
+
status: retcode === 0 ? 'ok' : 'failed',
|
|
504
|
+
data,
|
|
505
|
+
message: '',
|
|
506
|
+
echo
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
V12.success = success;
|
|
510
|
+
function error(message, retcode = 10001, echo) {
|
|
511
|
+
return {
|
|
512
|
+
retcode,
|
|
513
|
+
status: 'failed',
|
|
514
|
+
data: null,
|
|
515
|
+
message,
|
|
516
|
+
echo
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
V12.error = error;
|
|
520
|
+
function genMetaEvent(uin, type) {
|
|
521
|
+
return {
|
|
522
|
+
self_id: uin,
|
|
523
|
+
time: Math.floor(Date.now() / 1000),
|
|
524
|
+
type: "meta",
|
|
525
|
+
detail_type: "lifecycle",
|
|
526
|
+
sub_type: type,
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
V12.genMetaEvent = genMetaEvent;
|
|
530
|
+
})(V12 = exports.V12 || (exports.V12 = {}));
|
package/lib/types.d.ts
ADDED
package/lib/types.js
ADDED
package/lib/utils.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare function deepMerge<T extends any>(base: T, ...from: T[]): T;
|
|
2
|
+
export declare function deepClone<T extends any>(obj: T): T;
|
|
3
|
+
export declare function pick<T, K extends keyof T>(source: T, keys?: Iterable<K>, forced?: boolean): Pick<T, K>;
|
|
4
|
+
export declare function omit<T, K extends keyof T>(source: T, keys?: Iterable<K>): Omit<T, K>;
|
|
5
|
+
export interface Class {
|
|
6
|
+
new (...args: any[]): any;
|
|
7
|
+
}
|
|
8
|
+
export declare function Mixin(base: Class, ...classes: Class[]): Class;
|
|
9
|
+
export declare function toHump(action: string): string;
|
|
10
|
+
export declare function toLine(name: string): string;
|
|
11
|
+
export declare function toBool(v: any): boolean;
|
|
12
|
+
export declare function uuid(): string;
|
|
13
|
+
export declare function getProperties(obj: any): any;
|
package/lib/utils.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.getProperties = exports.uuid = exports.toBool = exports.toLine = exports.toHump = exports.Mixin = exports.omit = exports.pick = exports.deepClone = exports.deepMerge = void 0;
|
|
27
|
+
// 合并对象/数组
|
|
28
|
+
const crypto = __importStar(require("crypto"));
|
|
29
|
+
function deepMerge(base, ...from) {
|
|
30
|
+
if (from.length === 0) {
|
|
31
|
+
return base;
|
|
32
|
+
}
|
|
33
|
+
if (typeof base !== 'object') {
|
|
34
|
+
return base;
|
|
35
|
+
}
|
|
36
|
+
if (Array.isArray(base)) {
|
|
37
|
+
return base.concat(...from);
|
|
38
|
+
}
|
|
39
|
+
for (const item of from) {
|
|
40
|
+
for (const key in item) {
|
|
41
|
+
if (base.hasOwnProperty(key)) {
|
|
42
|
+
if (typeof base[key] === 'object') {
|
|
43
|
+
base[key] = deepMerge(base[key], item[key]);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
base[key] = item[key];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
base[key] = item[key];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return base;
|
|
55
|
+
}
|
|
56
|
+
exports.deepMerge = deepMerge;
|
|
57
|
+
// 深拷贝
|
|
58
|
+
function deepClone(obj) {
|
|
59
|
+
if (typeof obj !== 'object')
|
|
60
|
+
return obj;
|
|
61
|
+
if (!obj)
|
|
62
|
+
return obj;
|
|
63
|
+
//判断拷贝的obj是对象还是数组
|
|
64
|
+
if (Array.isArray(obj))
|
|
65
|
+
return obj.map((item) => deepClone(item));
|
|
66
|
+
const objClone = {};
|
|
67
|
+
for (const key in obj) {
|
|
68
|
+
if (obj.hasOwnProperty(key)) {
|
|
69
|
+
if (obj[key] && typeof obj[key] === "object") {
|
|
70
|
+
objClone[key] = deepClone(obj[key]);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
objClone[key] = obj[key];
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return objClone;
|
|
78
|
+
}
|
|
79
|
+
exports.deepClone = deepClone;
|
|
80
|
+
function pick(source, keys, forced) {
|
|
81
|
+
if (!keys)
|
|
82
|
+
return { ...source };
|
|
83
|
+
const result = {};
|
|
84
|
+
for (const key of keys) {
|
|
85
|
+
if (forced || key in source)
|
|
86
|
+
result[key] = source[key];
|
|
87
|
+
}
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
exports.pick = pick;
|
|
91
|
+
function omit(source, keys) {
|
|
92
|
+
if (!keys)
|
|
93
|
+
return { ...source };
|
|
94
|
+
const result = { ...source };
|
|
95
|
+
for (const key of keys) {
|
|
96
|
+
Reflect.deleteProperty(result, key);
|
|
97
|
+
}
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
exports.omit = omit;
|
|
101
|
+
function Mixin(base, ...classes) {
|
|
102
|
+
classes.forEach(ctr => {
|
|
103
|
+
Object.getOwnPropertyNames(ctr.prototype).forEach(name => {
|
|
104
|
+
if (name === 'constructor')
|
|
105
|
+
return;
|
|
106
|
+
base.prototype[name] = ctr.prototype[name];
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
return base;
|
|
110
|
+
}
|
|
111
|
+
exports.Mixin = Mixin;
|
|
112
|
+
function toHump(action) {
|
|
113
|
+
return action.replace(/_[\w]/g, (s) => {
|
|
114
|
+
return s[1].toUpperCase();
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
exports.toHump = toHump;
|
|
118
|
+
function toLine(name) {
|
|
119
|
+
return name.replace(/([A-Z])/g, "_$1").toLowerCase();
|
|
120
|
+
}
|
|
121
|
+
exports.toLine = toLine;
|
|
122
|
+
function toBool(v) {
|
|
123
|
+
if (v === "0" || v === "false")
|
|
124
|
+
v = false;
|
|
125
|
+
return Boolean(v);
|
|
126
|
+
}
|
|
127
|
+
exports.toBool = toBool;
|
|
128
|
+
function uuid() {
|
|
129
|
+
let hex = crypto.randomBytes(16).toString("hex");
|
|
130
|
+
return hex.substr(0, 8) + "-" + hex.substr(8, 4) + "-" + hex.substr(12, 4) + "-" + hex.substr(16, 4) + "-" + hex.substr(20);
|
|
131
|
+
}
|
|
132
|
+
exports.uuid = uuid;
|
|
133
|
+
function getProperties(obj) {
|
|
134
|
+
if (obj.__proto__ === null) { //说明该对象已经是最顶层的对象
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
return Object.getOwnPropertyNames(obj).concat(getProperties(obj.__proto__));
|
|
138
|
+
}
|
|
139
|
+
exports.getProperties = getProperties;
|