UNPKG

@kotori-bot/kotori-plugin-adapter-onebot

Version:

Adapter For Onebot 11

270 lines (269 loc) 10.4 kB
/** * @Package @kotori-bot/kotori-plugin-adapter-onebot * @Version 2.1.1 * @Author Hotaru <me@hotaru.icu> * @Copyright 2024-2025 Hotaru. All rights reserved. * @License GPL-3.0 * @Link https://github.com/kotorijs/kotori * @Date 2026/2/14 21:24:52 */ "use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var adapter_exports = {}; __export(adapter_exports, { OnebotAdapter: () => OnebotAdapter, config: () => config, default: () => adapter_default }); module.exports = __toCommonJS(adapter_exports); var import_kotori_bot = require("kotori-bot"); var import_ws = __toESM(require("ws")); var import_api = __toESM(require("./api")); var import_elements = __toESM(require("./elements")); const config = import_kotori_bot.Tsu.Union( import_kotori_bot.Tsu.Object({ mode: import_kotori_bot.Tsu.Literal("ws").describe("Connect mode: WebSocket"), port: import_kotori_bot.Tsu.Number().port().describe("WebSocket server port"), address: import_kotori_bot.Tsu.String().regexp(/^ws(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-./?%&=]*)?$/).default("ws://127.0.0.1").describe("WebSocket address"), retry: import_kotori_bot.Tsu.Number().int().min(1).default(10).describe("try reconnect times when disconnected") }), import_kotori_bot.Tsu.Object({ mode: import_kotori_bot.Tsu.Literal("ws-reverse").describe("Connect mode: WebSocket Reverse") }) ); const handleMsg = (msg) => msg.replace(/\[CQ:at,qq=(.*?)\]/g, "$1"); class OnebotAdapter extends import_kotori_bot.Adapters.WebSocket { address; isReverse; config; elements; api; platform = "onebot"; pendingRequests = /* @__PURE__ */ new Map(); constructor(ctx, config2, identity) { super(ctx, config2, identity); this.config = config2; this.api = new import_api.default(this); this.elements = new import_elements.default(this); this.address = this.config.mode === "ws" ? `${this.config.address ?? "ws://127.0.0.1"}:${this.config.port}` : ""; this.isReverse = !this.address; if (!this.isReverse) return; this.connection = (ws) => { this.socket = ws; this.online(); }; } handle(data) { if ("echo" in data) { if (!this.pendingRequests.has(data.echo)) return; const { resolve, reject, timer } = this.pendingRequests.get(data.echo); clearTimeout(timer); this.pendingRequests.delete(data.echo); if (data.status === "ok") { resolve(data.data); } else { reject(data); } return; } if (data.post_type === "message" && data.message_type === "private") { this.session("on_message", { type: import_kotori_bot.MessageScope.PRIVATE, userId: String(data.user_id), messageId: String(data.message_id), message: handleMsg(data.raw_message), messageAlt: data.raw_message, sender: { nickname: data.sender.nickname }, groupId: String(data.group_id), time: data.time }); } else if (data.post_type === "message" && data.message_type === "group") { this.session("on_message", { type: import_kotori_bot.MessageScope.GROUP, userId: String(data.user_id), messageId: String(data.message_id), message: handleMsg(data.raw_message), messageAlt: data.raw_message, sender: { nickname: data.sender.nickname, role: data.sender.role ?? "member" }, groupId: String(data.group_id), time: data.time }); } else if (data.post_type === "notice" && data.notice_type === "private_recall") { this.session("on_message_delete", { type: import_kotori_bot.MessageScope.PRIVATE, userId: String(data.user_id), messageId: String(data.message_id), time: data.time }); } else if (data.post_type === "notice" && data.notice_type === "group_recall") { this.session("on_message_delete", { type: import_kotori_bot.MessageScope.GROUP, userId: String(data.user_id), messageId: String(data.message_id), groupId: String(data.group_id), operatorId: String(data.user_id), time: data.time }); } else if (data.post_type === "request" && data.request_type === "private") { this.session("on_request", { type: import_kotori_bot.MessageScope.PRIVATE, userId: String(data.user_id), comment: String(data.comment), time: data.time, approve: (approve = true, remark = "") => this.call("set_friend_add_request", { flag: data.flag, approve, remark }) }); } else if (data.post_type === "request" && data.request_type === "group") { this.session("on_request", { type: import_kotori_bot.MessageScope.GROUP, userId: String(data.user_id), groupId: String(data.group_id), operatorId: String(data.operator_id) || String(data.user_id), comment: String(data.comment), approve: (approve = true, reason = "") => this.call("set_friend_add_request", { flag: data.flag, approve, reason, type: data.sub_type }), time: data.time }); } else if (data.post_type === "notice" && data.notice_type === "group_increase") { this.session("on_group_increase", { type: import_kotori_bot.MessageScope.GROUP, userId: String(data.user_id), groupId: String(data.group_id), operatorId: String(data.operator_id) ?? String(data.user_id), time: data.time }); } else if (data.post_type === "notice" && data.notice_type === "group_decrease") { this.session("on_group_decrease", { type: import_kotori_bot.MessageScope.GROUP, userId: String(data.user_id), groupId: String(data.group_id), operatorId: String(data.operator_id) ?? String(data.user_id), time: data.time }); } else if (data.post_type === "notice" && data.notice_type === "group_admin") { this.session("on_group_admin", { type: import_kotori_bot.MessageScope.GROUP, userId: String(data.user_id), groupId: String(data.group_id), operation: data.sub_type === "set" ? "set" : "unset", time: data.time }); } else if (data.post_type === "notice" && data.notice_type === "group_ban") { this.session("on_group_ban", { type: import_kotori_bot.MessageScope.GROUP, userId: String(data.user_id), groupId: String(data.group_id), operatorId: String(data.operator_id), duration: Number(data.duration), time: data.time }); } else if (data.post_type === "meta_event" && data.meta_event_type === "heartbeat") { if (data.status.online) { this.online(); if (this.onlineTimerId) clearTimeout(this.onlineTimerId); } if (this.selfId === "" && typeof data.self_id === "number") { this.selfId = String(data.self_id); } } else if (data.post_type === "notice" && data.notice_type === "notify" && data.sub_type === "poke" && data.target_id) { this.session("onebot_poke", { type: data.message_type === "private" ? import_kotori_bot.MessageScope.PRIVATE : import_kotori_bot.MessageScope.GROUP, userId: String(data.user_id), targetId: String(data.target_id), groupId: String(data.group_id), time: data.time }); } if (!this.onlineTimerId) this.onlineTimerId = setTimeout(() => this.offline(), 50 * 1e3); } start() { if (this.isReverse) { this.setup(); return; } this.ctx.emit("connect", { type: "connect", mode: "ws", adapter: this, normal: true, address: this.address }); this.socket = new import_ws.default(`${this.address}`); this.socket.on("close", () => { this.ctx.emit("connect", { type: "disconnect", adapter: this, normal: false, mode: "ws", address: this.address }); }); this.socket.on("message", (raw) => this.handle(JSON.parse(raw.toString()))); } stop() { if (this.isReverse) { super.stop(); return; } this.ctx.emit("connect", { type: "disconnect", adapter: this, normal: true, address: this.address, mode: "ws" }); this.socket?.close(); } send(content, operation) { this.socket?.send(JSON.stringify({ content, operation })); } call(action, params) { return new Promise((resolve, reject) => { const echo = `${Date.now()}_${Math.random().toString(36)}`; const timer = setTimeout(() => { this.pendingRequests.delete(echo); reject(new import_kotori_bot.KotoriError(`Request timeout: ${action}`)); }, 60 * 1e3); this.pendingRequests.set(echo, { resolve, reject, timer }); this.socket?.send(JSON.stringify({ action, params, echo })); }); } socket = null; /* global NodeJS */ onlineTimerId = null; } var adapter_default = OnebotAdapter; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { OnebotAdapter, config });