feat: 支持回复消息

This commit is contained in:
linyuchen 2023-11-10 21:21:27 +08:00
parent c7e41ad5c4
commit e17882d067
6 changed files with 72 additions and 8 deletions

8
src/global.d.ts vendored
View File

@ -11,21 +11,21 @@ declare var LLAPI: {
// uid是一串加密的字符串, 收到群消息的时候可以用此函数获取群成员的qq号
getUserInfo(uid: string): Promise<User>;
sendMessage(peer: Peer, message: SendMessage[]): Promise<void>;
sendMessage(peer: Peer, message: SendMessage[]): Promise<any>;
recallMessage(peer: Peer, msgIds: string[]): Promise<void>;
getGroupsList(forced: boolean): Promise<Group[]>
getFriendsList(forced: boolean): Promise<User[]>
getGroupMemberList(group_id: string, num: number): Promise<{result: { infos: Map<string, GroupMemberInfo> }}>
getPeer(): Promise<Peer>
add_qmenu(func: (qContextMenu: Node)=>void): void
};
declare var llonebot: {
postData: (data: any) => void
listenSendMessage: (handle: (msg: PostDataSendMsg) => void) => void
listenRecallMessage: (handle: (msg: {message_id: string}) => void) => void
updateGroups: (groups: Group[]) => void
updateFriends: (friends: User[]) => void
updateGroupMembers: (data: { groupMembers: User[], group_id: string }) => void

View File

@ -337,13 +337,14 @@ class Api extends EventEmitter {
}]
*/
async sendMessage(peer, elements) {
ntCall("ns-ntApi", "nodeIKernelMsgService/sendMsg", [
return ntCall("ns-ntApi", "nodeIKernelMsgService/sendMsg", [
{
msgId: "0",
peer: destructor.destructPeer(peer),
msgElements: await Promise.all(
elements.map(async (element) => {
if (element.type == "text") return destructor.destructTextElement(element);
else if (element.type == "reply") return destructor.destructReplyElement(element);
else if (element.type == "image") return destructor.destructImageElement(element, await media.prepareImageElement(element.file));
else if (element.type == "voice") return destructor.destructPttElement(element, await media.prepareVoiceElement(element.file));
else if (element.type == "face") return destructor.destructFaceElement(element);
@ -355,6 +356,15 @@ class Api extends EventEmitter {
null,
]);
}
async recallMessage(peer, msgIds) {
ntCall("ns-ntApi", "nodeIKernelMsgService/recallMsg", [
{
msgIds,
peer: destructor.destructPeer(peer),
},
null,
]);
}
/**
* @description 转发消息
* @param {Peer} peer 对方的ID
@ -654,6 +664,18 @@ class Destructor {
pttElement
}
}
destructReplyElement(element) {
return {
elementType: 7,
elementId: "",
replyElement: {
replayMsgSeq: element.msgSeq, // raw.msgSeq
replayMsgId: element.msgId, // raw.msgId
senderUin: element.senderUin,
senderUinStr: element.senderUinStr,
}
}
}
destructFaceElement(element) {
return {

View File

@ -6,6 +6,7 @@ const express = require("express");
import {Group, PostDataSendMsg, User} from "./types";
const CHANNEL_SEND_MSG = "llonebot_sendMsg"
const CHANNEL_RECALL_MSG = "llonebot_recallMsg"
let groups: Group[] = []
let friends: User[] = []
@ -114,6 +115,9 @@ function startExpress(event: any) {
}
})
}
else if (jsonData.action == "delete_msg"){
sendIPCMsg(CHANNEL_RECALL_MSG, jsonData as {message_id: string})
}
return resData
}
// 处理POST请求的路由
@ -153,6 +157,12 @@ function startExpress(event: any) {
let resData = handlePost(jsonData)
res.send(resData)
})
app.post('/delete_msg', (req: any, res: any) => {
let jsonData: PostDataSendMsg = req.body;
jsonData.action = "delete_msg"
let resData = handlePost(jsonData)
res.send(resData)
})
app.listen(port,"0.0.0.0", () => {
console.log(`服务器已启动,监听端口 ${port}`);
});

View File

@ -10,6 +10,7 @@ const {ipcRenderer} = require('electron');
// 在window对象下导出只读对象
contextBridge.exposeInMainWorld("llonebot", {
postData: (data: any) => {
ipcRenderer.send("postOnebotData", data);
},
@ -24,6 +25,11 @@ contextBridge.exposeInMainWorld("llonebot", {
handle(args)
})
},
listenRecallMessage: (handle: (jsonData: {message_id: string}) => void) => {
ipcRenderer.on("llonebot_recallMsg", (event: any, args: {message_id: string}) => {
handle(args)
})
},
startExpress: () => {
ipcRenderer.send("startExpress");
},

View File

@ -10,6 +10,7 @@ const host = "http://localhost:5000"
let self_qq: string = ""
let groups: Group[] = []
let friends: User[] = []
let msgHistory: MessageElement[] = []
let uid_maps: Record<string, User> = {} // 一串加密的字符串 -> qq号
async function getUserInfo(uid: string): Promise<User> {
let user = uid_maps[uid]
@ -97,6 +98,7 @@ async function forwardMessage(message: MessageElement) {
post_type: "message",
message_type: message.peer.chatType,
detail_type: message.peer.chatType,
message_id: message.raw.msgId,
sub_type: "",
message: []
}
@ -140,7 +142,7 @@ async function forwardMessage(message: MessageElement) {
}
onebot_message_data.message.push(message_data)
}
msgHistory.push(message)
console.log("发送上传消息给ipc main", onebot_message_data)
window.llonebot.postData(onebot_message_data);
} catch (e) {
@ -206,6 +208,12 @@ async function listenSendMessage(postData: PostDataSendMsg) {
else if (message.type == "image" || message.type == "voice"){
message.file = message.data?.file || message.file
}
else if (message.type == "reply"){
let msgId = message.data?.id || message.msgId
let replyMessage = msgHistory.find(msg => msg.raw.msgId == msgId)
message.msgId = msgId
message.msgSeq = replyMessage?.raw.msgSeq || ""
}
}
console.log("发送消息", postData)
window.LLAPI.sendMessage(peer, postData.params.message).then(res => console.log("消息发送成功:", res),
@ -214,6 +222,11 @@ async function listenSendMessage(postData: PostDataSendMsg) {
}
}
function recallMessage(msgId: string) {
let msg = msgHistory.find(msg => msg.raw.msgId == msgId)
window.LLAPI.recallMessage(msg.peer, [msgId]).then()
}
let chatListEle: HTMLCollectionOf<Element>
function onLoad() {
@ -221,6 +234,9 @@ function onLoad() {
window.llonebot.listenSendMessage((postData: PostDataSendMsg) => {
listenSendMessage(postData).then()
});
window.llonebot.listenRecallMessage((arg: { message_id: string }) => {
recallMessage(arg.message_id)
})
async function getGroupsMembers(groupsArg: Group[]) {
// 批量获取群成员列表

View File

@ -2,6 +2,7 @@ export enum AtType {
notAt = 0,
atUser = 2
}
export type GroupMemberInfo = {
avatarPath: string;
cardName: string;
@ -38,8 +39,9 @@ export type Peer = {
export type MessageElement = {
raw: {
msgId: string,
msgSeq: string,
elements: {
replyElement: {
senderUid: string, // 原消息发送者QQ号
sourceMsgIsIncPic: boolean; // 原消息是否有图片
@ -114,10 +116,18 @@ export type SendMessage = {
data?: {
qq: string // at的qq号
}
} | {
type: "reply",
msgId: string,
msgSeq: string,
senderUin: string,
data: {
id: string,
}
}
export type PostDataSendMsg = {
action: "send_private_msg" | "send_group_msg" | "get_group_list",
action: "send_private_msg" | "send_group_msg" | "get_group_list" | "get_friend_list" | "delete_msg",
message_type?: "private" | "group"
params?: {
user_id: string,