mirror of
https://github.com/LLOneBot/LLOneBot.git
synced 2024-11-22 01:56:33 +00:00
feat: http post quick operation
This commit is contained in:
parent
89c3f07cba
commit
1735babb7d
@ -6,7 +6,7 @@ import path from "node:path";
|
|||||||
import {selfInfo} from "./data";
|
import {selfInfo} from "./data";
|
||||||
import {DATA_DIR} from "./utils";
|
import {DATA_DIR} from "./utils";
|
||||||
|
|
||||||
export const HOOK_LOG = true;
|
export const HOOK_LOG = false;
|
||||||
|
|
||||||
export const ALLOW_SEND_TEMP_MSG = false;
|
export const ALLOW_SEND_TEMP_MSG = false;
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ import {ReceiveCmdS} from "../hook";
|
|||||||
import {Group, GroupMember, GroupMemberRole, GroupNotifies, GroupNotify, GroupRequestOperateTypes} from "../types";
|
import {Group, GroupMember, GroupMemberRole, GroupNotifies, GroupNotify, GroupRequestOperateTypes} from "../types";
|
||||||
import {callNTQQApi, GeneralCallResult, NTQQApiClass, NTQQApiMethod} from "../ntcall";
|
import {callNTQQApi, GeneralCallResult, NTQQApiClass, NTQQApiMethod} from "../ntcall";
|
||||||
import {uidMaps} from "../../common/data";
|
import {uidMaps} from "../../common/data";
|
||||||
import {BrowserWindow} from "electron";
|
|
||||||
import {dbUtil} from "../../common/db";
|
import {dbUtil} from "../../common/db";
|
||||||
import {log} from "../../common/utils/log";
|
import {log} from "../../common/utils/log";
|
||||||
import {NTQQWindowApi, NTQQWindows} from "./window";
|
import {NTQQWindowApi, NTQQWindows} from "./window";
|
||||||
|
@ -1,5 +1,14 @@
|
|||||||
import BaseAction from "../BaseAction";
|
import BaseAction from "../BaseAction";
|
||||||
import * as ntqqApi from "../../../ntqqapi/api";
|
// import * as ntqqApi from "../../../ntqqapi/api";
|
||||||
|
import {
|
||||||
|
NTQQMsgApi,
|
||||||
|
NTQQFriendApi,
|
||||||
|
NTQQGroupApi,
|
||||||
|
NTQQUserApi,
|
||||||
|
NTQQFileApi,
|
||||||
|
NTQQFileCacheApi,
|
||||||
|
NTQQWindowApi,
|
||||||
|
} from "../../../ntqqapi/api";
|
||||||
import {ActionName} from "../types";
|
import {ActionName} from "../types";
|
||||||
import {log} from "../../../common/utils/log";
|
import {log} from "../../../common/utils/log";
|
||||||
|
|
||||||
@ -13,8 +22,10 @@ export default class Debug extends BaseAction<Payload, any> {
|
|||||||
|
|
||||||
protected async _handle(payload: Payload): Promise<any> {
|
protected async _handle(payload: Payload): Promise<any> {
|
||||||
log("debug call ntqq api", payload);
|
log("debug call ntqq api", payload);
|
||||||
for (const ntqqApiClass in ntqqApi) {
|
const ntqqApi = [NTQQMsgApi, NTQQFriendApi, NTQQGroupApi, NTQQUserApi, NTQQFileApi, NTQQFileCacheApi, NTQQWindowApi]
|
||||||
const method = ntqqApi[ntqqApiClass][payload.method]
|
for (const ntqqApiClass of ntqqApi) {
|
||||||
|
log("ntqqApiClass", ntqqApiClass)
|
||||||
|
const method = ntqqApiClass[payload.method]
|
||||||
if (method) {
|
if (method) {
|
||||||
const result = method(...payload.args);
|
const result = method(...payload.args);
|
||||||
if (method.constructor.name === "AsyncFunction") {
|
if (method.constructor.name === "AsyncFunction") {
|
||||||
|
@ -75,11 +75,156 @@ export interface ReturnDataType {
|
|||||||
message_id: number
|
message_id: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function convertMessage2List(message: OB11MessageMixType, autoEscape = false) {
|
||||||
|
if (typeof message === "string") {
|
||||||
|
if (!autoEscape) {
|
||||||
|
message = decodeCQCode(message.toString())
|
||||||
|
} else {
|
||||||
|
message = [{
|
||||||
|
type: OB11MessageDataType.text,
|
||||||
|
data: {
|
||||||
|
text: message
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
} else if (!Array.isArray(message)) {
|
||||||
|
message = [message]
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createSendElements(messageData: OB11MessageData[], group: Group | undefined, ignoreTypes: OB11MessageDataType[] = []) {
|
||||||
|
let sendElements: SendMessageElement[] = []
|
||||||
|
let deleteAfterSentFiles: string[] = []
|
||||||
|
for (let sendMsg of messageData) {
|
||||||
|
if (ignoreTypes.includes(sendMsg.type)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch (sendMsg.type) {
|
||||||
|
case OB11MessageDataType.text: {
|
||||||
|
const text = sendMsg.data?.text;
|
||||||
|
if (text) {
|
||||||
|
sendElements.push(SendMsgElementConstructor.text(sendMsg.data!.text))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OB11MessageDataType.at: {
|
||||||
|
if (!group) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
let atQQ = sendMsg.data?.qq;
|
||||||
|
if (atQQ) {
|
||||||
|
atQQ = atQQ.toString()
|
||||||
|
if (atQQ === "all") {
|
||||||
|
sendElements.push(SendMsgElementConstructor.at(atQQ, atQQ, AtType.atAll, "全体成员"))
|
||||||
|
} else {
|
||||||
|
// const atMember = group?.members.find(m => m.uin == atQQ)
|
||||||
|
const atMember = await getGroupMember(group?.groupCode, atQQ);
|
||||||
|
if (atMember) {
|
||||||
|
sendElements.push(SendMsgElementConstructor.at(atQQ, atMember.uid, AtType.atUser, atMember.cardName || atMember.nick))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OB11MessageDataType.reply: {
|
||||||
|
let replyMsgId = sendMsg.data.id;
|
||||||
|
if (replyMsgId) {
|
||||||
|
const replyMsg = await dbUtil.getMsgByShortId(parseInt(replyMsgId))
|
||||||
|
if (replyMsg) {
|
||||||
|
sendElements.push(SendMsgElementConstructor.reply(replyMsg.msgSeq, replyMsg.msgId, replyMsg.senderUin, replyMsg.senderUin))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OB11MessageDataType.face: {
|
||||||
|
const faceId = sendMsg.data?.id
|
||||||
|
if (faceId) {
|
||||||
|
sendElements.push(SendMsgElementConstructor.face(parseInt(faceId)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OB11MessageDataType.image:
|
||||||
|
case OB11MessageDataType.file:
|
||||||
|
case OB11MessageDataType.video:
|
||||||
|
case OB11MessageDataType.voice: {
|
||||||
|
let file = sendMsg.data?.file
|
||||||
|
const payloadFileName = sendMsg.data?.name
|
||||||
|
if (file) {
|
||||||
|
const cache = await dbUtil.getFileCache(file)
|
||||||
|
if (cache) {
|
||||||
|
if (fs.existsSync(cache.filePath)) {
|
||||||
|
file = "file://" + cache.filePath
|
||||||
|
} else if (cache.downloadFunc) {
|
||||||
|
await cache.downloadFunc()
|
||||||
|
file = cache.filePath;
|
||||||
|
} else if (cache.url) {
|
||||||
|
file = cache.url
|
||||||
|
}
|
||||||
|
log("找到文件缓存", file);
|
||||||
|
}
|
||||||
|
const {path, isLocal, fileName, errMsg} = (await uri2local(file))
|
||||||
|
if (errMsg) {
|
||||||
|
throw errMsg
|
||||||
|
}
|
||||||
|
if (path) {
|
||||||
|
if (!isLocal) { // 只删除http和base64转过来的文件
|
||||||
|
deleteAfterSentFiles.push(path)
|
||||||
|
}
|
||||||
|
if (sendMsg.type === OB11MessageDataType.file) {
|
||||||
|
log("发送文件", path, payloadFileName || fileName)
|
||||||
|
sendElements.push(await SendMsgElementConstructor.file(path, payloadFileName || fileName));
|
||||||
|
} else if (sendMsg.type === OB11MessageDataType.video) {
|
||||||
|
log("发送视频", path, payloadFileName || fileName)
|
||||||
|
let thumb = sendMsg.data?.thumb;
|
||||||
|
if (thumb) {
|
||||||
|
let uri2LocalRes = await uri2local(thumb)
|
||||||
|
if (uri2LocalRes.success) {
|
||||||
|
thumb = uri2LocalRes.path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sendElements.push(await SendMsgElementConstructor.video(path, payloadFileName || fileName, thumb));
|
||||||
|
} else if (sendMsg.type === OB11MessageDataType.voice) {
|
||||||
|
sendElements.push(await SendMsgElementConstructor.ptt(path));
|
||||||
|
} else if (sendMsg.type === OB11MessageDataType.image) {
|
||||||
|
sendElements.push(await SendMsgElementConstructor.pic(path, sendMsg.data.summary || ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OB11MessageDataType.json: {
|
||||||
|
sendElements.push(SendMsgElementConstructor.ark(sendMsg.data.data))
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
sendElements,
|
||||||
|
deleteAfterSentFiles
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sendMsg(peer: Peer, sendElements: SendMessageElement[], deleteAfterSentFiles: string[], waitComplete = true) {
|
||||||
|
if (!sendElements.length) {
|
||||||
|
throw ("消息体无法解析")
|
||||||
|
}
|
||||||
|
const returnMsg = await NTQQMsgApi.sendMsg(peer, sendElements, waitComplete, 20000);
|
||||||
|
log("消息发送结果", returnMsg)
|
||||||
|
returnMsg.msgShortId = await dbUtil.addMsg(returnMsg)
|
||||||
|
deleteAfterSentFiles.map(f => fs.unlink(f, () => {
|
||||||
|
}))
|
||||||
|
return returnMsg
|
||||||
|
}
|
||||||
|
|
||||||
export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
||||||
actionName = ActionName.SendMsg
|
actionName = ActionName.SendMsg
|
||||||
|
|
||||||
protected async check(payload: OB11PostSendMsg): Promise<BaseCheckResult> {
|
protected async check(payload: OB11PostSendMsg): Promise<BaseCheckResult> {
|
||||||
const messages = this.convertMessage2List(payload.message);
|
const messages = convertMessage2List(payload.message);
|
||||||
const fmNum = this.getSpecialMsgNum(payload, OB11MessageDataType.node)
|
const fmNum = this.getSpecialMsgNum(payload, OB11MessageDataType.node)
|
||||||
if (fmNum && fmNum != messages.length) {
|
if (fmNum && fmNum != messages.length) {
|
||||||
return {
|
return {
|
||||||
@ -149,7 +294,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
} else {
|
} else {
|
||||||
throw ("发送消息参数错误, 请指定group_id或user_id")
|
throw ("发送消息参数错误, 请指定group_id或user_id")
|
||||||
}
|
}
|
||||||
const messages = this.convertMessage2List(payload.message);
|
const messages = convertMessage2List(payload.message);
|
||||||
if (this.getSpecialMsgNum(payload, OB11MessageDataType.node)) {
|
if (this.getSpecialMsgNum(payload, OB11MessageDataType.node)) {
|
||||||
try {
|
try {
|
||||||
const returnMsg = await this.handleForwardNode(peer, messages as OB11MessageNode[], group)
|
const returnMsg = await this.handleForwardNode(peer, messages as OB11MessageNode[], group)
|
||||||
@ -173,27 +318,13 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// log("send msg:", peer, sendElements)
|
// log("send msg:", peer, sendElements)
|
||||||
const {sendElements, deleteAfterSentFiles} = await this.createSendElements(messages, group)
|
const {sendElements, deleteAfterSentFiles} = await createSendElements(messages, group)
|
||||||
const returnMsg = await this.send(peer, sendElements, deleteAfterSentFiles)
|
const returnMsg = await sendMsg(peer, sendElements, deleteAfterSentFiles)
|
||||||
deleteAfterSentFiles.map(f => fs.unlink(f, () => {
|
deleteAfterSentFiles.map(f => fs.unlink(f, () => {
|
||||||
}));
|
}));
|
||||||
return {message_id: returnMsg.msgShortId}
|
return {message_id: returnMsg.msgShortId}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected convertMessage2List(message: OB11MessageMixType) {
|
|
||||||
if (typeof message === "string") {
|
|
||||||
// message = [{
|
|
||||||
// type: OB11MessageDataType.text,
|
|
||||||
// data: {
|
|
||||||
// text: message
|
|
||||||
// }
|
|
||||||
// }] as OB11MessageData[]
|
|
||||||
message = decodeCQCode(message.toString())
|
|
||||||
} else if (!Array.isArray(message)) {
|
|
||||||
message = [message]
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
private getSpecialMsgNum(payload: OB11PostSendMsg, msgType: OB11MessageDataType): number {
|
private getSpecialMsgNum(payload: OB11PostSendMsg, msgType: OB11MessageDataType): number {
|
||||||
if (Array.isArray(payload.message)) {
|
if (Array.isArray(payload.message)) {
|
||||||
@ -262,7 +393,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
const {
|
const {
|
||||||
sendElements,
|
sendElements,
|
||||||
deleteAfterSentFiles
|
deleteAfterSentFiles
|
||||||
} = await this.createSendElements(this.convertMessage2List(messageNode.data.content), group);
|
} = await createSendElements(convertMessage2List(messageNode.data.content), group);
|
||||||
log("开始生成转发节点", sendElements);
|
log("开始生成转发节点", sendElements);
|
||||||
let sendElementsSplit: SendMessageElement[][] = []
|
let sendElementsSplit: SendMessageElement[][] = []
|
||||||
let splitIndex = 0;
|
let splitIndex = 0;
|
||||||
@ -284,7 +415,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
}
|
}
|
||||||
// log("分割后的转发节点", sendElementsSplit)
|
// log("分割后的转发节点", sendElementsSplit)
|
||||||
for (const eles of sendElementsSplit) {
|
for (const eles of sendElementsSplit) {
|
||||||
const nodeMsg = await this.send(selfPeer, eles, [], true);
|
const nodeMsg = await sendMsg(selfPeer, eles, [], true);
|
||||||
nodeMsgIds.push(nodeMsg.msgId)
|
nodeMsgIds.push(nodeMsg.msgId)
|
||||||
await sleep(500);
|
await sleep(500);
|
||||||
log("转发节点生成成功", nodeMsg.msgId);
|
log("转发节点生成成功", nodeMsg.msgId);
|
||||||
@ -346,130 +477,8 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createSendElements(messageData: OB11MessageData[], group: Group | undefined, ignoreTypes: OB11MessageDataType[] = []) {
|
|
||||||
let sendElements: SendMessageElement[] = []
|
|
||||||
let deleteAfterSentFiles: string[] = []
|
|
||||||
for (let sendMsg of messageData) {
|
|
||||||
if (ignoreTypes.includes(sendMsg.type)) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
switch (sendMsg.type) {
|
|
||||||
case OB11MessageDataType.text: {
|
|
||||||
const text = sendMsg.data?.text;
|
|
||||||
if (text) {
|
|
||||||
sendElements.push(SendMsgElementConstructor.text(sendMsg.data!.text))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case OB11MessageDataType.at: {
|
|
||||||
if (!group) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
let atQQ = sendMsg.data?.qq;
|
|
||||||
if (atQQ) {
|
|
||||||
atQQ = atQQ.toString()
|
|
||||||
if (atQQ === "all") {
|
|
||||||
sendElements.push(SendMsgElementConstructor.at(atQQ, atQQ, AtType.atAll, "全体成员"))
|
|
||||||
} else {
|
|
||||||
// const atMember = group?.members.find(m => m.uin == atQQ)
|
|
||||||
const atMember = await getGroupMember(group?.groupCode, atQQ);
|
|
||||||
if (atMember) {
|
|
||||||
sendElements.push(SendMsgElementConstructor.at(atQQ, atMember.uid, AtType.atUser, atMember.cardName || atMember.nick))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case OB11MessageDataType.reply: {
|
|
||||||
let replyMsgId = sendMsg.data.id;
|
|
||||||
if (replyMsgId) {
|
|
||||||
const replyMsg = await dbUtil.getMsgByShortId(parseInt(replyMsgId))
|
|
||||||
if (replyMsg) {
|
|
||||||
sendElements.push(SendMsgElementConstructor.reply(replyMsg.msgSeq, replyMsg.msgId, replyMsg.senderUin, replyMsg.senderUin))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case OB11MessageDataType.face: {
|
|
||||||
const faceId = sendMsg.data?.id
|
|
||||||
if (faceId) {
|
|
||||||
sendElements.push(SendMsgElementConstructor.face(parseInt(faceId)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OB11MessageDataType.image:
|
|
||||||
case OB11MessageDataType.file:
|
|
||||||
case OB11MessageDataType.video:
|
|
||||||
case OB11MessageDataType.voice: {
|
|
||||||
let file = sendMsg.data?.file
|
|
||||||
const payloadFileName = sendMsg.data?.name
|
|
||||||
if (file) {
|
|
||||||
const cache = await dbUtil.getFileCache(file)
|
|
||||||
if (cache) {
|
|
||||||
if (fs.existsSync(cache.filePath)) {
|
|
||||||
file = "file://" + cache.filePath
|
|
||||||
} else if (cache.downloadFunc) {
|
|
||||||
await cache.downloadFunc()
|
|
||||||
file = cache.filePath;
|
|
||||||
} else if (cache.url) {
|
|
||||||
file = cache.url
|
|
||||||
}
|
|
||||||
log("找到文件缓存", file);
|
|
||||||
}
|
|
||||||
const {path, isLocal, fileName, errMsg} = (await uri2local(file))
|
|
||||||
if (errMsg) {
|
|
||||||
throw errMsg
|
|
||||||
}
|
|
||||||
if (path) {
|
|
||||||
if (!isLocal) { // 只删除http和base64转过来的文件
|
|
||||||
deleteAfterSentFiles.push(path)
|
|
||||||
}
|
|
||||||
if (sendMsg.type === OB11MessageDataType.file) {
|
|
||||||
log("发送文件", path, payloadFileName || fileName)
|
|
||||||
sendElements.push(await SendMsgElementConstructor.file(path, payloadFileName || fileName));
|
|
||||||
} else if (sendMsg.type === OB11MessageDataType.video) {
|
|
||||||
log("发送视频", path, payloadFileName || fileName)
|
|
||||||
let thumb = sendMsg.data?.thumb;
|
|
||||||
if (thumb){
|
|
||||||
let uri2LocalRes = await uri2local(thumb)
|
|
||||||
if (uri2LocalRes.success){
|
|
||||||
thumb = uri2LocalRes.path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sendElements.push(await SendMsgElementConstructor.video(path, payloadFileName || fileName, thumb));
|
|
||||||
} else if (sendMsg.type === OB11MessageDataType.voice) {
|
|
||||||
sendElements.push(await SendMsgElementConstructor.ptt(path));
|
|
||||||
}else if (sendMsg.type === OB11MessageDataType.image) {
|
|
||||||
sendElements.push(await SendMsgElementConstructor.pic(path, sendMsg.data.summary || ""));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case OB11MessageDataType.json: {
|
|
||||||
sendElements.push(SendMsgElementConstructor.ark(sendMsg.data.data))
|
|
||||||
}break
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
sendElements,
|
|
||||||
deleteAfterSentFiles
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async send(peer: Peer, sendElements: SendMessageElement[], deleteAfterSentFiles: string[], waitComplete = true) {
|
|
||||||
if (!sendElements.length) {
|
|
||||||
throw ("消息体无法解析")
|
|
||||||
}
|
|
||||||
const returnMsg = await NTQQMsgApi.sendMsg(peer, sendElements, waitComplete, 20000);
|
|
||||||
log("消息发送结果", returnMsg)
|
|
||||||
returnMsg.msgShortId = await dbUtil.addMsg(returnMsg)
|
|
||||||
deleteAfterSentFiles.map(f => fs.unlink(f, () => {
|
|
||||||
}))
|
|
||||||
return returnMsg
|
|
||||||
}
|
|
||||||
|
|
||||||
private genMusicElement(url: string, audio: string, title: string, content: string, image: string): SendArkElement {
|
private genMusicElement(url: string, audio: string, title: string, content: string, image: string): SendArkElement {
|
||||||
const musicJson = {
|
const musicJson = {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import {OB11Message} from "../types";
|
import {OB11Message, OB11MessageAt, OB11MessageData} from "../types";
|
||||||
import {selfInfo} from "../../common/data";
|
import {getGroup, selfInfo} from "../../common/data";
|
||||||
import {OB11BaseMetaEvent} from "../event/meta/OB11BaseMetaEvent";
|
import {OB11BaseMetaEvent} from "../event/meta/OB11BaseMetaEvent";
|
||||||
import {OB11BaseNoticeEvent} from "../event/notice/OB11BaseNoticeEvent";
|
import {OB11BaseNoticeEvent} from "../event/notice/OB11BaseNoticeEvent";
|
||||||
import {WebSocket as WebSocketClass} from "ws";
|
import {WebSocket as WebSocketClass} from "ws";
|
||||||
@ -7,9 +7,47 @@ import {wsReply} from "./ws/reply";
|
|||||||
import {log} from "../../common/utils/log";
|
import {log} from "../../common/utils/log";
|
||||||
import {getConfigUtil} from "../../common/config";
|
import {getConfigUtil} from "../../common/config";
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
|
import {NTQQFriendApi, NTQQGroupApi, NTQQMsgApi, Peer} from "../../ntqqapi/api";
|
||||||
|
import {ChatType, Group, GroupRequestOperateTypes} from "../../ntqqapi/types";
|
||||||
|
import {convertMessage2List, createSendElements, sendMsg} from "../action/msg/SendMsg";
|
||||||
|
import {dbUtil} from "../../common/db";
|
||||||
|
import {OB11FriendRequestEvent} from "../event/request/OB11FriendRequest";
|
||||||
|
import {OB11GroupRequestEvent} from "../event/request/OB11GroupRequest";
|
||||||
|
import {isNull} from "../../common/utils";
|
||||||
|
|
||||||
export type PostEventType = OB11Message | OB11BaseMetaEvent | OB11BaseNoticeEvent
|
export type PostEventType = OB11Message | OB11BaseMetaEvent | OB11BaseNoticeEvent
|
||||||
|
|
||||||
|
interface QuickActionPrivateMessage {
|
||||||
|
reply?: string;
|
||||||
|
auto_escape?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface QuickActionGroupMessage extends QuickActionPrivateMessage {
|
||||||
|
// 回复群消息
|
||||||
|
at_sender?: boolean
|
||||||
|
delete?: boolean
|
||||||
|
kick?: boolean
|
||||||
|
ban?: boolean
|
||||||
|
ban_duration?: number
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
interface QuickActionFriendRequest {
|
||||||
|
approve?: boolean
|
||||||
|
remark?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface QuickActionGroupRequest {
|
||||||
|
approve?: boolean
|
||||||
|
reason?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type QuickAction =
|
||||||
|
QuickActionPrivateMessage
|
||||||
|
& QuickActionGroupMessage
|
||||||
|
& QuickActionFriendRequest
|
||||||
|
& QuickActionGroupRequest
|
||||||
|
|
||||||
const eventWSList: WebSocketClass[] = [];
|
const eventWSList: WebSocketClass[] = [];
|
||||||
|
|
||||||
export function registerWsEventSender(ws: WebSocketClass) {
|
export function registerWsEventSender(ws: WebSocketClass) {
|
||||||
@ -56,8 +94,77 @@ export function postOB11Event(msg: PostEventType, reportSelf = false) {
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
headers,
|
headers,
|
||||||
body: msgStr
|
body: msgStr
|
||||||
}).then((res: any) => {
|
}).then(async (res) => {
|
||||||
log(`新消息事件HTTP上报成功: ${host} ` + msgStr);
|
log(`新消息事件HTTP上报成功: ${host} `, msgStr);
|
||||||
|
// todo: 处理不够优雅,应该使用高级泛型进行QuickAction类型识别
|
||||||
|
let resJson: QuickAction;
|
||||||
|
try {
|
||||||
|
resJson = await res.json();
|
||||||
|
log(`新消息事件HTTP上报返回快速操作: `, JSON.stringify(resJson))
|
||||||
|
} catch (e) {
|
||||||
|
log(`新消息事件HTTP上报没有返回快速操作,不需要处理`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (msg.post_type === "message") {
|
||||||
|
msg = msg as OB11Message;
|
||||||
|
const rawMessage = await dbUtil.getMsgByShortId(msg.message_id)
|
||||||
|
resJson = resJson as QuickActionPrivateMessage | QuickActionGroupMessage
|
||||||
|
const reply = resJson.reply
|
||||||
|
let peer: Peer = {
|
||||||
|
chatType: ChatType.friend,
|
||||||
|
peerUid: msg.user_id.toString()
|
||||||
|
}
|
||||||
|
if (msg.message_type == "private") {
|
||||||
|
if (msg.sub_type === "group") {
|
||||||
|
peer.chatType = ChatType.temp
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
peer.chatType = ChatType.group
|
||||||
|
peer.peerUid = msg.group_id.toString()
|
||||||
|
}
|
||||||
|
if (reply) {
|
||||||
|
let group: Group = null
|
||||||
|
let replyMessage: OB11MessageData[] = []
|
||||||
|
|
||||||
|
if (msg.message_type == "group") {
|
||||||
|
group = await getGroup(msg.group_id.toString())
|
||||||
|
if ((resJson as QuickActionGroupMessage).at_sender) {
|
||||||
|
replyMessage.push({
|
||||||
|
type: "at",
|
||||||
|
data: {
|
||||||
|
qq: msg.user_id.toString()
|
||||||
|
}
|
||||||
|
} as OB11MessageAt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
replyMessage = replyMessage.concat(convertMessage2List(reply, resJson.auto_escape))
|
||||||
|
const {sendElements, deleteAfterSentFiles} = await createSendElements(replyMessage, group)
|
||||||
|
sendMsg(peer, sendElements, deleteAfterSentFiles, false).then()
|
||||||
|
} else if (resJson.delete) {
|
||||||
|
NTQQMsgApi.recallMsg(peer, [rawMessage.msgId]).then()
|
||||||
|
} else if (resJson.kick) {
|
||||||
|
NTQQGroupApi.kickMember(peer.peerUid, [rawMessage.senderUid]).then()
|
||||||
|
} else if (resJson.ban) {
|
||||||
|
NTQQGroupApi.banMember(peer.peerUid, [{
|
||||||
|
uid: rawMessage.senderUid,
|
||||||
|
timeStamp: resJson.ban_duration || 60 * 30
|
||||||
|
}],).then()
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (msg.post_type === "request") {
|
||||||
|
if ((msg as OB11FriendRequestEvent).request_type === "friend") {
|
||||||
|
resJson = resJson as QuickActionFriendRequest
|
||||||
|
if (!isNull(resJson.approve)) {
|
||||||
|
// todo: set remark
|
||||||
|
NTQQFriendApi.handleFriendRequest(parseInt((msg as OB11FriendRequestEvent).flag), resJson.approve).then()
|
||||||
|
}
|
||||||
|
} else if ((msg as OB11GroupRequestEvent).request_type === "group") {
|
||||||
|
resJson = resJson as QuickActionGroupRequest
|
||||||
|
if (!isNull(resJson.approve)) {
|
||||||
|
NTQQGroupApi.handleGroupRequest((msg as OB11FriendRequestEvent).flag, resJson.approve ? GroupRequestOperateTypes.approve : GroupRequestOperateTypes.reject, resJson.reason).then()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}, (err: any) => {
|
}, (err: any) => {
|
||||||
log(`新消息事件HTTP上报失败: ${host} `, err, msg);
|
log(`新消息事件HTTP上报失败: ${host} `, err, msg);
|
||||||
});
|
});
|
||||||
|
29
test/quick_action/server.py
Normal file
29
test/quick_action/server.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import uvicorn
|
||||||
|
from fastapi import FastAPI, Request
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
@app.post("/")
|
||||||
|
async def root(request: Request):
|
||||||
|
data = await request.json()
|
||||||
|
print(data)
|
||||||
|
if (data["post_type"] == "message"):
|
||||||
|
text = list(filter(lambda x: x["type"] == "text", data["message"]))[0]["data"]["text"]
|
||||||
|
if text == "禁言":
|
||||||
|
return {"ban": True, "ban_duration": 10}
|
||||||
|
elif text == "踢我":
|
||||||
|
return {"kick": True}
|
||||||
|
elif text == "撤回":
|
||||||
|
return {"delete": True}
|
||||||
|
# print(data["message"])
|
||||||
|
return {"reply": "Hello World"}
|
||||||
|
elif data["post_type"] == "request":
|
||||||
|
if data["request_type"] == "group":
|
||||||
|
return {"approve": False, "reason": "不让你进群"}
|
||||||
|
else:
|
||||||
|
# 加好友
|
||||||
|
return {"approve": True}
|
||||||
|
return {}
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
uvicorn.run(app, host="", port=8000)
|
Loading…
x
Reference in New Issue
Block a user