import Instance from '../models/Instance'; import Telegram from '../client/Telegram'; import OicqClient from '../client/OicqClient'; import { AtElem, Group, GroupMessageEvent, PrivateMessageEvent, Sendable } from 'oicq'; import { Pair } from '../models/Pair'; import { Api } from 'telegram'; import db from '../models/db'; import BigInteger from 'big-integer'; import helper from '../helpers/forwardHelper'; import { getLogger, Logger } from 'log4js'; type ActionSubjectTg = { name: string; id: Api.TypeInputUser | Api.InputPeerUser; from: 'tg'; } type ActionSubjectQq = { name: string; id: number; from: 'qq'; } type ActionSubject = ActionSubjectTg | ActionSubjectQq; const COMMAND_REGEX = /^\/([\u4e00-\u9fa5][\u4e00-\u9fa5\w]*)|\$(\w[\u4e00-\u9fa5\w]*)/; // /抱 /$rua export default class { private readonly log: Logger; constructor(private readonly instance: Instance, private readonly tgBot: Telegram, private readonly oicq: OicqClient) { this.log = getLogger(`HugController - ${instance.id}`); oicq.addNewMessageEventHandler(this.onQqMessage); tgBot.addNewMessageEventHandler(this.onTelegramMessage); } private onQqMessage = async (event: PrivateMessageEvent | GroupMessageEvent) => { if (event.message_type !== 'group') return; const pair = this.instance.forwardPairs.find(event.group); if (!pair) return; const chain = [...event.message]; while (chain.length && chain[0].type !== 'text') { chain.shift(); } const firstElem = chain[0]; if (firstElem?.type !== 'text') return; const exec = COMMAND_REGEX.exec(firstElem.text.trim()); if (!exec) return; const action = exec[1] || exec[2]; if (!action) return; const from: ActionSubject = { from: 'qq', name: event.nickname, id: event.sender.user_id, }; let to: ActionSubject; const ats = chain.filter(it => it.type === 'at') as AtElem[]; if (ats.length) { const atName = ats[0].text.startsWith('@') ? ats[0].text.substring(1) : ats[0].text; to = { from: 'qq', name: atName, id: ats[0].qq as number, }; } else if (event.source && event.source.user_id === this.oicq.uin) { // 来自 tg const sourceMessage = await db.message.findFirst({ where: { instanceId: this.instance.id, qqRoomId: pair.qqRoomId, qqSenderId: event.source.user_id, seq: event.source.seq, rand: event.source.rand, }, }); if (!sourceMessage) { this.log.error('找不到 sourceMessage') return true; } to = { from: 'tg', id: (await this.tgBot.getChat(BigInteger(sourceMessage.tgSenderId))).inputPeer as Api.InputPeerUser, name: sourceMessage.nick, }; } else if (event.source) { const sourceMember = (pair.qq as Group).pickMember(event.source.user_id); to = { from: 'qq', name: sourceMember.card || (await sourceMember.getSimpleInfo()).nickname, id: event.source.user_id, }; } else { to = { from: 'qq', name: '自己', id: event.sender.user_id, }; } await this.sendAction(pair, from, to, action); return true; }; private onTelegramMessage = async (message: Api.Message) => { const pair = this.instance.forwardPairs.find(message.chat); if (!pair) return; const exec = COMMAND_REGEX.exec(message.message); if (!exec) return; const action = exec[1] || exec[2]; if (!action) return; const from: ActionSubject = { from: 'tg', name: helper.getUserDisplayName(message.sender), id: (await this.tgBot.getChat(message.senderId)).inputPeer as Api.InputPeerUser, }; let to: ActionSubject; if (message.replyTo) { const sourceMessage = await db.message.findFirst({ where: { instanceId: this.instance.id, tgChatId: pair.tgId, tgMsgId: message.replyToMsgId, }, }); if (!sourceMessage) { this.log.error('找不到 sourceMessage') return true; } if (this.tgBot.me.id.eq(sourceMessage.tgSenderId)) { // from qq to = { from: 'qq', name: sourceMessage.nick, id: Number(sourceMessage.qqSenderId), }; } else { to = { from: 'tg', id: (await this.tgBot.getChat(BigInteger(sourceMessage.tgSenderId))).inputPeer as Api.InputPeerUser, name: sourceMessage.nick, }; } } else { to = { from: 'tg', name: '自己', id: (await this.tgBot.getChat(message.senderId)).inputPeer as Api.InputPeerUser, }; } await this.sendAction(pair, from, to, action); return true; }; private async sendAction(pair: Pair, from: ActionSubject, to: ActionSubject, action: string) { let tgText = ''; const tgEntities: Api.TypeMessageEntity[] = []; const qqMessageContent: Sendable = []; const addSubject = (subject: ActionSubject) => { if (subject.from === 'tg') { tgEntities.push(new Api.InputMessageEntityMentionName({ offset: tgText.length, length: subject.name.length, userId: subject.id as Api.TypeInputUser, })); qqMessageContent.push(subject.name); } else { qqMessageContent.push({ type: 'at', text: subject.name, qq: subject.id, }); } tgText += subject.name; }; const addText = (text: string) => { tgText += text; qqMessageContent.push(text); }; addSubject(from); addText(' '); addText(action); if (!/[\u4e00-\u9fa5]$/.test(action)) { // 英文之后加上空格 addText(' '); } addText('了 '); addSubject(to); addText('!'); const tgMessage = await pair.tg.sendMessage({ message: tgText, formattingEntities: tgEntities, }); const qqMessage = await pair.qq.sendMsg(qqMessageContent); await db.message.create({ data: { qqRoomId: pair.qqRoomId, qqSenderId: this.oicq.uin, time: qqMessage.time, brief: tgText, seq: qqMessage.seq, rand: qqMessage.rand, pktnum: 1, tgChatId: pair.tgId, tgMsgId: tgMessage.id, instanceId: this.instance.id, tgMessageText: tgMessage.message, nick: '系统', tgSenderId: BigInt(this.tgBot.me.id.toString()), }, }); } }