2024-06-04 23:06:53 +08:00

180 lines
6.4 KiB
TypeScript

import BaseAction from '@/onebot11/action/BaseAction';
import {
OB11MessageData,
OB11MessageDataType,
OB11MessageMixType,
OB11MessageNode,
OB11PostSendMsg
} from '@/onebot11/types';
import { ActionName, BaseCheckResult } from '@/onebot11/action/types';
import { getFriend, getGroup } from '@/core/data';
import { dbUtil } from '@/common/utils/db';
import { ChatType, ElementType, Group, NTQQMsgApi, NTQQUserApi, Peer, SendMessageElement, } from '@/core';
import fs from 'node:fs';
import { logDebug, logError } from '@/common/utils/log';
import { decodeCQCode } from '@/onebot11/cqcode';
import createSendElements from './create-send-elements';
import { handleForwardNode } from '@/onebot11/action/msg/SendMsg/handle-forward-node';
const ALLOW_SEND_TEMP_MSG = false;
export interface ReturnDataType {
message_id: number;
}
// Normalizes a mixed type (CQCode/a single segment/segment array) into a segment array.
export function normalize(message: OB11MessageMixType, autoEscape = false): OB11MessageData[] {
return typeof message === 'string' ? (
autoEscape ?
[{ type: OB11MessageDataType.text, data: { text: message } }] :
decodeCQCode(message)
) : Array.isArray(message) ? message : [message];
}
export { createSendElements };
export async function sendMsg(peer: Peer, sendElements: SendMessageElement[], deleteAfterSentFiles: string[], waitComplete = true) {
if (!sendElements.length) {
throw ('消息体无法解析, 请检查是否发送了不支持的消息类型');
}
let totalSize = 0;
let timeout = 5000;
try {
for (const fileElement of sendElements) {
if (fileElement.elementType === ElementType.PTT) {
totalSize += fs.statSync(fileElement.pttElement.filePath).size;
}
if (fileElement.elementType === ElementType.FILE) {
totalSize += fs.statSync(fileElement.fileElement.filePath).size;
}
if (fileElement.elementType === ElementType.VIDEO) {
totalSize += fs.statSync(fileElement.videoElement.filePath).size;
}
if (fileElement.elementType === ElementType.PIC) {
totalSize += fs.statSync(fileElement.picElement.sourcePath).size;
}
}
//且 PredictTime ((totalSize / 1024 / 512) * 1000)不等于Nan
const PredictTime = totalSize / 1024 / 256 * 1000;
if (!Number.isNaN(PredictTime)) {
timeout += PredictTime;// 5S Basic Timeout + PredictTime( For File 512kb/s )
}
} catch (e) {
logError('发送消息计算预计时间异常', e);
}
const returnMsg = await NTQQMsgApi.sendMsg(peer, sendElements, waitComplete, timeout);
try {
returnMsg.id = await dbUtil.addMsg(returnMsg, false);
} catch (e: any) {
logDebug('发送消息id获取失败', e);
returnMsg.id = 0;
}
deleteAfterSentFiles.map(f => fs.unlinkSync(f));
return returnMsg;
}
async function createContext(payload: OB11PostSendMsg): Promise<{
peer: Peer, group?: Group
}> {
// This function determines the type of message by the existence of user_id / group_id,
// not message_type.
// This redundant design of Ob11 here should be blamed.
if (payload.group_id) { // take this as a group message
const group = (await getGroup(payload.group_id))!; // checked before
return {
peer: {
chatType: ChatType.group,
peerUid: group.groupCode
},
group: group,
};
} else if (payload.user_id) { // take this as a private message
const friend = await getFriend(payload.user_id.toString());
if (!friend) {
if (ALLOW_SEND_TEMP_MSG) {
//const tempUid = getUidByUin(payload.user_id.toString());
const tempUid = await NTQQUserApi.getUidByUin(payload.user_id.toString());
if (tempUid) return {
peer: {
chatType: ChatType.temp,
peerUid: tempUid
},
};
}
throw `找不到私聊对象 ${payload.user_id}`;
}
return {
peer: {
chatType: ChatType.friend,
peerUid: friend.uid
},
};
}
throw '请指定 group_id 或 user_id';
}
function getSpecialMsgNum(payload: OB11PostSendMsg, msgType: OB11MessageDataType): number {
if (Array.isArray(payload.message)) {
return payload.message.filter(msg => msg.type == msgType).length;
}
return 0;
}
export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
actionName = ActionName.SendMsg;
protected async check(payload: OB11PostSendMsg): Promise<BaseCheckResult> {
const messages = normalize(payload.message);
const nodeElementLength = getSpecialMsgNum(payload, OB11MessageDataType.node);
if (nodeElementLength > 0 && nodeElementLength != messages.length) {
return { valid: false, message: '转发消息不能和普通消息混在一起发送,转发需要保证message只有type为node的元素' };
}
if (payload.message_type !== 'private' && payload.group_id && !(await getGroup(payload.group_id))) {
return { valid: false, message: `${payload.group_id}不存在` };
}
if (payload.user_id && payload.message_type !== 'group') {
if (!(await getFriend(payload.user_id))) {
if (
!ALLOW_SEND_TEMP_MSG &&
!(await dbUtil.getUidByTempUin(payload.user_id))
) {
return { valid: false, message: '不能发送临时消息' };
}
}
}
return { valid: true, };
}
protected async _handle(payload: OB11PostSendMsg): Promise<{ message_id: number }> {
const { peer, group } = await createContext(payload);
const messages = normalize(
payload.message,
payload.auto_escape === true || payload.auto_escape === 'true'
);
if (getSpecialMsgNum(payload, OB11MessageDataType.node)) {
const returnMsg = await handleForwardNode(peer, messages as OB11MessageNode[], group);
if (returnMsg) {
const msgShortId = await dbUtil.addMsg(returnMsg!, false);
return { message_id: msgShortId };
} else {
throw Error('发送转发消息失败');
}
} else {
// if (getSpecialMsgNum(payload, OB11MessageDataType.music)) {
// const music: OB11MessageCustomMusic = messages[0] as OB11MessageCustomMusic;
// if (music) {
// }
// }
}
// log("send msg:", peer, sendElements)
const { sendElements, deleteAfterSentFiles } = await createSendElements(messages, group);
const returnMsg = await sendMsg(peer, sendElements, deleteAfterSentFiles);
return { message_id: returnMsg.id! };
}
}
export default SendMsg;