From e2759417f5b6504e8c0782965b1cb26f0c437563 Mon Sep 17 00:00:00 2001 From: linyuchen Date: Wed, 1 Nov 2023 17:46:46 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BE=A4=E6=88=90=E5=91=98=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E7=A0=94=E7=A9=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 +- src/global.d.ts | 85 ++++-------------------- src/main.ts | 11 +++- src/preload.ts | 5 ++ src/renderer.ts | 169 ++++++++++++++++++++++++++---------------------- src/types.ts | 89 +++++++++++++++++++++++++ 6 files changed, 209 insertions(+), 153 deletions(-) create mode 100644 src/types.ts diff --git a/package.json b/package.json index 50c4fc2..66e0fda 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "build": "tsc" + "build-mac": "tsc && npm run deploy-mac", + "deploy-mac": "cp dist/* ~/Library/Containers/com.tencent.qq/Data/Documents/LiteLoaderQQNT/plugins/LLOnebot/" }, "author": "", "license": "ISC", diff --git a/src/global.d.ts b/src/global.d.ts index ef462b2..a71eb49 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -1,68 +1,6 @@ -declare enum AtType { - notAt = 0, - atUser = 2 -} +import {Group, GroupMemberInfo, MessageElement, Peer, PostDataSendMsg, SendMessage, User} from "./types"; -declare type Peer = { - chatType: "private" | "group" - name: string - uid: string // qq号 -} -interface MessageElement { - raw: { - elements: { - - replyElement: { - senderUid: string, // 原消息发送者QQ号 - sourceMsgIsIncPic: boolean; // 原消息是否有图片 - sourceMsgText: string; - sourceMsgIdInRecords: string; // 原消息id - }, - textElement: { - atType: AtType - atUid: string, - content: string - }, - picElement: { - sourcePath: string // 图片本地路径 - picWidth: number - picHeight: number - fileSize: number - fileName: string - fileUuid: string - } - }[] - } - - peer: Peer, - sender: { - uid: string // 一串加密的字符串 - memberName: string - nickname: string - } -} - -declare type User = { - avatarUrl?: string; - bio?: string; // 签名 - nickName: string; - uid?: string; // 加密的字符串 - uin: string; // QQ号 -} - -declare type Group = { - uid: string; // 群号 - name: string; -} - -declare type SendMessage = { - type: "text", - content: string, -} | { - type: "image", - file: string, // 这是本地路径? -} declare var LLAPI: { on(event: "new-messages", callback: (data: MessageElement[]) => void): void; @@ -76,16 +14,12 @@ declare var LLAPI: { sendMessage(peer: Peer, message: SendMessage[]): Promise; getGroupsList(forced: boolean): Promise getFriendsList(forced: boolean): Promise + getGroupMemberList(group_id: string, num: number): Promise<{result: { infos: Record }}> }; -declare type PostDataSendMsg = { - action: "send_private_msg" | "send_group_msg" | "get_group_list", - params: { - user_id: string, - group_id: string, - message: SendMessage[]; - } -} + + + declare var llonebot: { postData: (data: any) => void @@ -94,4 +28,11 @@ declare var llonebot: { updateFriends: (friends: User[]) => void updateGroupMembers: (data: { groupMembers: User[], group_id: string }) => void startExpress: () => void -}; \ No newline at end of file +}; + +declare global { + interface Window { + LLAPI: typeof LLAPI; + llonebot: typeof llonebot; + } +} \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 62c60da..4e7c262 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,7 @@ // 运行在 Electron 主进程 下的插件入口 +import {Group, PostDataSendMsg, User} from "./types"; + const express = require("express") const {ipcMain, webContents} = require('electron'); const fs = require('fs'); @@ -24,8 +26,9 @@ function sendIPCCallSendQQMsg(postData: PostDataSendMsg) { sendIPCMsg(CHANNEL_SEND_MSG, postData); } -function log(msg: string){ - fs.appendFile("d:\\llonebot.log", msg + "\n", (err: any) => { +function log(msg: any){ + let currentDateTime = new Date().toLocaleString(); + fs.appendFile("./llonebot.log", currentDateTime + ":" + msg + "\n", (err: any) => { }) } @@ -143,6 +146,10 @@ function onLoad(plugin: any) { log(e.toString()) } }) + + ipcMain.on("llonebot_log", (event: any, arg: any) => { + log(arg) + }) } diff --git a/src/preload.ts b/src/preload.ts index 332966b..bc183f7 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -1,5 +1,7 @@ // Electron 主进程 与 渲染进程 交互的桥梁 +import {Group, PostDataSendMsg, User} from "./types"; + const {contextBridge} = require("electron"); const {ipcRenderer} = require('electron'); @@ -24,6 +26,9 @@ contextBridge.exposeInMainWorld("llonebot", { }, startExpress: () => { ipcRenderer.send("startExpress"); + }, + log: (data: any) => { + ipcRenderer.send("log", data); } // startExpress, }); \ No newline at end of file diff --git a/src/renderer.ts b/src/renderer.ts index fad3557..bbc46fe 100644 --- a/src/renderer.ts +++ b/src/renderer.ts @@ -2,16 +2,23 @@ // import express from "express"; // const { ipcRenderer } = require('electron'); -enum AtType { - notAt = 0, - atUser = 2 -} +import {AtType, Group, MessageElement, Peer, PostDataSendMsg, User} from "./types"; const host = "http://localhost:5000" +let self_qq: string = "" let groups: Group[] = [] let friends: User[] = [] -let groupMembers: { group_id: string, groupMembers: User[] }[] = [] +let uid_maps: Record = {} // 一串加密的字符串 -> qq号 +async function getUserInfo(uid: string): Promise{ + let user = uid_maps[uid] + if (!user){ + // 从服务器获取用户信息 + user = await window.LLAPI.getUserInfo(uid) + uid_maps[uid] = user + } + return user +} function getFriend(qq: string) { return friends.find(friend => friend.uid == qq) @@ -21,9 +28,7 @@ function getGroup(qq: string) { return groups.find(group => group.uid == qq) } -let self_qq: string = "" -let uid_maps: Record = {} // 一串加密的字符串 -> qq号 function forwardMessage(message: MessageElement) { try { @@ -36,79 +41,92 @@ function forwardMessage(message: MessageElement) { type: "message", detail_type: message.peer.chatType, sub_type: "", - message: message.raw.elements.map(element => { - let message_data: any = { - data: {} - } - if (element.textElement?.atType == AtType.atUser) { - message_data["type"] = "at" - message_data["data"]["mention"] = element.textElement.atUid - } else if (element.textElement) { - message_data["type"] = "text" - message_data["data"]["text"] = element.textElement.content - } else if (element.picElement) { - message_data["type"] = "image" - message_data["data"]["file_id"] = element.picElement.fileUuid - message_data["data"]["path"] = element.picElement.sourcePath - } else if (element.replyElement) { - message_data["type"] = "reply" - message_data["data"]["reply"] = element.replyElement.sourceMsgIdInRecords - } - return message_data - }) + message: [] } - + let group: Group if (message.peer.chatType == "group") { + let group_id = message.peer.uid + group = groups.find(group => group.uid == group_id)! onebot_message_data["group_id"] = message.peer.uid - // todo: 将加密的uid转成qq号 - let groupMember = groupMembers.find(group => group.group_id == message.peer.uid)?.groupMembers.find(member => member.uid == message.sender.uid) - onebot_message_data["user_id"] = groupMember!.uin + let groupMember = group.members!.find(member => member.uid == message.sender.uid) + if (groupMember) { + console.log("群成员信息存在,使用群成员信息") + onebot_message_data["user_id"] = groupMember.uin + } + else{ + console.log("群成员信息不存在,使用原始uid") + onebot_message_data["user_id"] = message.sender.uid + } console.log("收到群消息", onebot_message_data) } else if (message.peer.chatType == "private") { onebot_message_data["user_id"] = message.peer.uid } - console.log("发送上传消息给ipcmain", onebot_message_data) - llonebot.postData(onebot_message_data); + for (let element of message.raw.elements) { + let message_data: any = { + data: {} + } + + if (element.textElement?.atType == AtType.atUser) { + message_data["type"] = "at" + if (element.textElement.atUid != "0") { + message_data["data"]["mention"] = element.textElement.atUid + } else { + let uid = element.textElement.atNtUid + let atMember = group!.members!.find(member => member.uid == uid) + message_data["data"]["mention"] = atMember!.uin + } + } else if (element.textElement) { + message_data["type"] = "text" + message_data["data"]["text"] = element.textElement.content + } else if (element.picElement) { + message_data["type"] = "image" + message_data["data"]["file_id"] = element.picElement.fileUuid + message_data["data"]["path"] = element.picElement.sourcePath + } else if (element.replyElement) { + message_data["type"] = "reply" + message_data["data"]["reply"] = element.replyElement.sourceMsgIdInRecords + } + onebot_message_data.message.push(message_data) + } + + console.log("发送上传消息给ipc main", onebot_message_data) + window.llonebot.postData(onebot_message_data); } catch (e) { console.log("上传消息事件失败", e) } } -function handleNewMessage(messages: MessageElement[]) { - messages.forEach(message => { +async function handleNewMessage(messages: MessageElement[]) { + for (let message of messages) { if (message.peer.chatType == "group") { - let group = groupMembers.find(group => group.group_id == message.peer.uid) + let group = groups.find(group => group.uid == message.peer.uid) if (!group) { + let members = (await window.LLAPI.getGroupMemberList(message.peer.uid + "_groupMemberList_MainWindow", 5000)).result.infos + let membersList = Object.values(members) group = { - group_id: message.peer.uid, - groupMembers: [] + name: message.peer.name, + uid: message.peer.uid, + members: membersList } - groupMembers.push(group) - } - let existMember = group!.groupMembers.find(member => member.uid == message.sender.uid) - if (!existMember) { - window.LLAPI.getUserInfo(message.sender.uid).then(user => { - let member = {memberName: message.sender.memberName, uid: user.uin, nickName: user.nickName} - // group!.groupMembers.push(member) - group!.groupMembers.push(user) - llonebot.updateGroupMembers(group!) - forwardMessage(message) - }).catch(err => { - console.log("获取群成员信息失败", err) - }) - }else{ - forwardMessage(message) + groups.push(group) + window.llonebot.updateGroups(groups); } } - else{ - forwardMessage(message); - } - }) + forwardMessage(message); + } +} + +async function getGroups(){ + groups = await window.LLAPI.getGroupsList(false) + for (let group of groups) { + group.members = []; + } + window.llonebot.updateGroups(groups) } function onLoad() { - llonebot.startExpress(); - llonebot.listenSendMessage((postData: PostDataSendMsg) => { + window.llonebot.startExpress(); + window.llonebot.listenSendMessage((postData: PostDataSendMsg) => { if (postData.action == "send_private_msg" || postData.action == "send_group_msg") { let peer: Peer | null = null; if (postData.action == "send_private_msg") { @@ -131,30 +149,25 @@ function onLoad() { } } if (peer) { - LLAPI.sendMessage(peer, postData.params.message).then(res => console.log("消息发送成功:", res), + window.LLAPI.sendMessage(peer, postData.params.message).then(res => console.log("消息发送成功:", res), err => console.log("消息发送失败", postData, err)) } } }); - - window.LLAPI.getGroupsList(false).then(groupsList => { - groups = groupsList - llonebot.updateGroups(groupsList) - }) - - window.LLAPI.on("new-messages", (messages) => { - console.log("收到新消息", messages) - // 往groupMembers里面添加群成员 - if (!self_qq){ - window.LLAPI.getAccountInfo().then(accountInfo => { - console.log("getAccountInfo", accountInfo) - self_qq = accountInfo.uin - handleNewMessage(messages) - }) - }else{ - handleNewMessage(messages) + getGroups().then() + function onNewMessages(messages: MessageElement[]){ + async function func(messages: MessageElement[]){ + console.log("收到新消息", messages) + if (!self_qq) { + self_qq = (await window.LLAPI.getAccountInfo()).uin + } + await handleNewMessage(messages); } - }); + func(messages).then(() => {}) + } + + window.LLAPI.on("new-messages", onNewMessages); + // console.log("getAccountInfo", LLAPI.getAccountInfo()); } diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..6a6c11e --- /dev/null +++ b/src/types.ts @@ -0,0 +1,89 @@ +export enum AtType { + notAt = 0, + atUser = 2 +} +export type GroupMemberInfo = { + avatarPath: string; + cardName: string; + cardType: number; + isDelete: boolean; + nick: string; + qid: string; + remark: string; + role: number; // 群主:4, 管理员:3,群员:2 + shutUpTime: number; // 禁言时间,单位是什么暂时不清楚 + uid: string; // 加密的字符串 + uin: string; // QQ号 +} + +export type User = { + avatarUrl?: string; + bio?: string; // 签名 + nickName: string; + uid?: string; // 加密的字符串 + uin: string; // QQ号 +} + +export type Group = { + uid: string; // 群号 + name: string; + members?: GroupMemberInfo[]; +} + +export type Peer = { + chatType: "private" | "group" + name: string + uid: string // qq号 +} + +export type MessageElement = { + raw: { + elements: { + + replyElement: { + senderUid: string, // 原消息发送者QQ号 + sourceMsgIsIncPic: boolean; // 原消息是否有图片 + sourceMsgText: string; + sourceMsgIdInRecords: string; // 原消息id + }, + textElement: { + atType: AtType + atUid: string, + content: string, + atNtUid: string + }, + picElement: { + sourcePath: string // 图片本地路径 + picWidth: number + picHeight: number + fileSize: number + fileName: string + fileUuid: string + } + }[] + } + + peer: Peer, + sender: { + uid: string // 一串加密的字符串 + memberName: string + nickname: string + } +} + +export type SendMessage = { + type: "text", + content: string, +} | { + type: "image", + file: string, // 本地路径 +} + +export type PostDataSendMsg = { + action: "send_private_msg" | "send_group_msg" | "get_group_list", + params: { + user_id: string, + group_id: string, + message: SendMessage[]; + } +} \ No newline at end of file