onebots
Version:
基于icqq的多例oneBot实现
419 lines (418 loc) • 17.5 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var _IcqqAdapter_password, _IcqqAdapter_disposes;
Object.defineProperty(exports, "__esModule", { value: true });
exports.defaultIcqqConfig = void 0;
const adapter_1 = require("../../adapter");
const icqq_1 = require("@icqqjs/icqq");
const process_1 = __importDefault(require("process"));
const fs_1 = require("fs");
const onebot_1 = require("../../onebot");
const path = __importStar(require("path"));
const message_1 = require("@icqqjs/icqq/lib/message");
const utils_1 = require("../../adapters/icqq/utils");
class IcqqAdapter extends adapter_1.Adapter {
constructor(app, config) {
super(app, "icqq", config);
_IcqqAdapter_password.set(this, void 0);
_IcqqAdapter_disposes.set(this, new Map());
this.icon = `https://qzonestyle.gtimg.cn/qzone/qzact/act/external/tiqq/logo.png`;
}
async setOnline(uin) {
const oneBot = this.getOneBot(uin);
if (!oneBot)
throw new Error("No one");
await oneBot.internal.login(parseInt(uin), __classPrivateFieldGet(this, _IcqqAdapter_password, "f"));
}
async setOffline(uin) {
const oneBot = this.getOneBot(uin);
if (!oneBot)
throw new Error("No one");
await oneBot.internal.logout();
oneBot.status = onebot_1.OneBotStatus.OffLine;
}
callApi(uin, version, [name, args]) {
const oneBot = this.getOneBot(uin);
if (!oneBot)
throw new Error("No one");
if (!oneBot.internal[name])
throw new Error(`internal no api ${name}`);
return oneBot.internal[name](...args);
}
createOneBot(uin, protocol, versions) {
const oneBot = super.createOneBot(uin, protocol, versions);
__classPrivateFieldSet(this, _IcqqAdapter_password, this.app.config[`icqq.${uin}`].password, "f");
oneBot.avatar = `https://q1.qlogo.cn/g?b=qq&s=100&nk=` + uin;
const pkg = require(path.resolve(path.dirname(require.resolve("@icqqjs/icqq")), "../package.json"));
oneBot.dependency = `icqq v${pkg.version}`;
oneBot.status = onebot_1.OneBotStatus.Pending;
oneBot.internal = new icqq_1.Client({
...exports.defaultIcqqConfig,
log_level: this.app.config.log_level,
...protocol,
});
return oneBot;
}
formatEventPayload(uin, version, event, data) {
const oneBot = this.getOneBot(uin);
const result = {
id: data.id || Math.random().toString(36).slice(2),
type: event,
version: version,
self: {
platform: "qq",
user_id: data.self_id,
},
detail_type: data.message_type || data.notice_type || data.request_type,
platform: "qq",
...data,
sender: {
...(data?.sender || {}),
user_id: data?.sender?.user_id || data?.sender?.tiny_id,
},
user_id: data.user_id || data.sender?.user_id || data.sender?.tiny_id,
};
delete result["group"];
delete result["member"];
delete result["discuss"];
delete result["friend"];
if (data.source) {
const message_id = data.message_type === "group"
? (0, message_1.genGroupMessageId)(data.group_id, data.sender.user_id, data.source?.seq, data.source?.rand, data.source?.time, data.source?.pktnum)
: (0, message_1.genDmMessageId)(data.sender.user_id, data.source?.seq, data.source?.rand, data.source?.time);
const replyEl = {
type: "reply",
id: version === "V11"
? oneBot.V11.transformToInt("message_id", message_id)
: message_id,
};
/* 去除群聊消息的第一个引用消息段 */
if (result.detail_type === "group" && data.message[0]?.type === "at") {
data.message[0] = replyEl;
}
else {
data.message.unshift(replyEl);
}
}
if (event === "message") {
result.alt_message = result.raw_message || "";
}
if (version === "V11" && result.message_id) {
result.message_id = oneBot.V11.transformToInt("message_id", result.message_id);
}
return Object.fromEntries(Object.entries(result).filter(([_, value]) => {
return typeof value !== "function";
}));
}
async sendPrivateMessage(uin, version, args) {
const [user_id, message, source] = args;
const client = this.oneBots.get(uin)?.internal;
let quote;
if (source)
quote = await client.getMsg(source);
const result = await client.sendPrivateMsg(parseInt(user_id), await utils_1.processMessages.call(this, uin, user_id, "private", message), quote);
return {
message_id: version === "V11"
? this.oneBots.get(uin).V11.transformToInt("message_id", result.message_id)
: result.message_id,
};
}
deleteMessage(uin, version, args) {
const bot = this.getOneBot(uin).internal;
return bot.deleteMsg(args[0]);
}
async sendGroupMessage(uin, version, args) {
const [group_id, message, source] = args;
const client = this.oneBots.get(uin)?.internal;
let quote;
if (source)
quote = await client.getMsg(source);
const result = await client.sendGroupMsg(parseInt(group_id), await utils_1.processMessages.call(this, uin, group_id, "group", message), quote);
return {
message_id: version === "V11"
? this.oneBots.get(uin).V11.transformToInt("message_id", result.message_id)
: result.message_id,
};
}
async sendGuildMessage(uin, version, args) {
const [guild_id, channel_id, message, source] = args;
const client = this.oneBots.get(uin)?.internal;
const result = await client.sendGuildMsg(guild_id, channel_id, await utils_1.processMessages.call(this, uin, Number(channel_id), "guild", message));
const message_id = `${result.seq}:${result.rand}:${result.time}`;
return {
message_id: version === "V11"
? this.oneBots.get(uin).V11.transformToInt("message_id", message_id)
: message_id,
};
}
async sendPrivateForwardMessage(uin, version, [user_id, messages]) {
return this.sendPrivateMessage(uin, version, [
user_id,
this.fromSegment(this.getOneBot(uin), version, messages.map(message => {
return {
type: "node",
data: {
user_id: message.uin || message.user_id,
nickname: message.name || message.nickname,
message: message.content,
},
};
})),
]);
}
async sendGroupForwardMessage(uin, version, [group_id, messages]) {
return this.sendGroupMessage(uin, version, [
group_id,
this.fromSegment(this.getOneBot(uin), version, messages.map(message => {
return {
type: "node",
data: {
user_id: message.uin,
nickname: message.name,
message: message.content,
},
};
})),
]);
}
async getMessage(uin, version, [message_id]) {
const oneBot = this.getOneBot(uin);
if (!oneBot)
throw new Error("No one");
let { message, ...result } = await oneBot.internal.getMsg.call(oneBot.internal, message_id);
const segments = version === "V11" ? message : this.toSegment(version, message);
return {
...result,
message: segments,
};
}
call(uin, version, method, args = []) {
try {
if (this[method])
return this[method](uin, version, args);
const client = this.oneBots.get(uin)?.internal;
return client[method].call(client, ...args);
}
catch {
throw onebot_1.OneBot.UnsupportedMethodError;
}
}
fromSegment(onebot, version, segment) {
return []
.concat(segment)
.map(segment => {
if (version === "V12" && ["image", "video", "audio"].includes(segment.type)) {
const result = onebot.V12.transformMedia(segment);
result.data["file"] =
result.data["file"] || result.data["file_id"] || result.data["url"];
return result;
}
return segment;
})
.map(item => {
if (typeof item === "string")
return item;
const { type, data } = item;
if (type === "node")
return {
type,
user_id: data.user_id,
nickname: data.nickname,
message: this.fromSegment(onebot, version, data.message),
};
return { type, ...data };
});
}
toSegment(version, message) {
return [].concat(message).map(item => {
if (typeof item !== "object")
item = {
type: "text",
data: {
text: item,
},
};
const { type, ...data } = item;
if (type === "node")
return {
type,
data: {
...data,
message: this.toSegment(version, data.message),
},
};
return {
type,
data,
};
});
}
getSelfInfo(uin, version) {
const client = this.oneBots.get(uin).internal;
return {
nickname: client.nickname,
status: this.oneBots.get(uin).status,
};
}
async startOneBot(oneBot) {
const _this = this;
const disposeArr = [];
const client = oneBot.internal;
client.on("system.login.qrcode", function qrcodeHelper() {
_this.logger.log("扫码后回车继续");
process_1.default.stdin.once("data", () => {
client.login();
});
disposeArr.push(() => {
client.off("system.login.qrcode");
});
});
client.on("system.login.device", function deviceHelper(e) {
_this.logger.mark("请选择验证方式:1.短信验证 2.url验证");
process_1.default.stdin.once("data", buf => {
const input = buf.toString().trim();
if (input === "1") {
client.sendSmsCode();
_this.logger.mark("请输入短信验证码:");
const terminalInputHandler = buf => {
client.submitSmsCode(buf.toString().trim());
};
process_1.default.stdin.once("data", terminalInputHandler);
}
else {
_this.logger.mark(`请前往:${e.url} 完成验证后回车继续`);
const terminalInputHandler = () => {
client.login();
};
process_1.default.stdin.once("data", terminalInputHandler);
}
});
disposeArr.push(() => {
client.off("system.login.device");
});
});
client.on("system.login.slider", function sliderHelper(e) {
_this.logger.mark("请输入滑块验证返回的ticket");
process_1.default.stdin.once("data", e => {
client.submitSlider(e.toString().trim());
});
disposeArr.push(() => {
client.off("system.login.slider");
});
});
disposeArr.push(client.on("message", event => {
this.emit("message.receive", oneBot.uin, event);
}));
disposeArr.push(client.on("notice", event => {
this.emit("notice.receive", oneBot.uin, event);
}));
disposeArr.push(client.on("request", event => {
this.emit("request.receive", oneBot.uin, event);
}));
await this.setOnline(oneBot.uin);
return new Promise((resolve, reject) => {
client.on("system.login.error", function errorHandler(e) {
if (e.message.includes("密码错误")) {
process_1.default.stdin.once("data", e => {
client.login(e.toString().trim());
});
}
else {
_this.logger.error(e.message);
oneBot.status = onebot_1.OneBotStatus.OffLine;
clean();
}
client.off("system.login.error");
});
const clean = () => {
clearTimeout(timer);
while (disposeArr.length) {
disposeArr.shift()();
}
};
client.on("system.online", () => {
oneBot.nickname = client.nickname;
oneBot.status = onebot_1.OneBotStatus.Online;
this.app.ws.clients.forEach(client => {
client.send(JSON.stringify({
event: "bot.change",
data: oneBot.info,
}));
});
clearTimeout(timer);
resolve(clean);
});
const timer = setTimeout(() => {
oneBot.status = onebot_1.OneBotStatus.OffLine;
clean();
reject("登录超时");
}, this.app.config.timeout * 1000);
});
}
async start(uin) {
const startOneBots = [...this.oneBots.values()].filter(oneBot => {
return uin ? oneBot.uin === uin : true;
});
for (const oneBot of startOneBots) {
__classPrivateFieldGet(this, _IcqqAdapter_disposes, "f").set(oneBot.uin, await this.startOneBot(oneBot));
}
await super.start();
}
async stop(uin, force) {
const stopOneBots = [...this.oneBots.values()].filter(oneBot => {
return uin ? oneBot.uin === uin : true;
});
for (const oneBot of stopOneBots) {
const dispose = __classPrivateFieldGet(this, _IcqqAdapter_disposes, "f").get(oneBot.uin);
if (dispose) {
dispose();
}
if (force) {
(0, fs_1.rmSync)(oneBot.internal.dir, { force: true, recursive: true });
}
}
await super.stop();
}
}
_IcqqAdapter_password = new WeakMap(), _IcqqAdapter_disposes = new WeakMap();
exports.default = IcqqAdapter;
exports.defaultIcqqConfig = {
platform: 2,
data_dir: path.join(process_1.default.cwd(), "data"),
};