diff --git a/package-lock.json b/package-lock.json index e8d4f4b..951365d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "ISC", "dependencies": { "electron": "^27.0.2", + "electron-fetch": "^1.9.1", "express": "^4.18.2", "path": "^0.12.7", "stream": "^0.0.2", @@ -1370,6 +1371,17 @@ "node": ">= 12.20.55" } }, + "node_modules/electron-fetch": { + "version": "1.9.1", + "resolved": "https://mirrors.cloud.tencent.com/npm/electron-fetch/-/electron-fetch-1.9.1.tgz", + "integrity": "sha512-M9qw6oUILGVrcENMSRRefE1MbHPIz0h79EKIeJWK9v563aT9Qkh8aEHPO1H5vi970wPirNY+jO9OpFoLiMsMGA==", + "dependencies": { + "encoding": "^0.1.13" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.567", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.567.tgz", @@ -1397,6 +1409,25 @@ "node": ">= 0.8" } }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://mirrors.cloud.tencent.com/npm/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://mirrors.cloud.tencent.com/npm/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://mirrors.cloud.tencent.com/npm/end-of-stream/-/end-of-stream-1.4.4.tgz", diff --git a/src/global.d.ts b/src/global.d.ts index 61c53d6..ef462b2 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -12,26 +12,25 @@ declare type Peer = { interface MessageElement { raw: { elements: { - raw: { - 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 - } + + 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 } }[] } @@ -45,10 +44,10 @@ interface MessageElement { } declare type User = { - avatarUrl: string; - bio: string; // 签名 + avatarUrl?: string; + bio?: string; // 签名 nickName: string; - uid: string; // 加密的字符串 + uid?: string; // 加密的字符串 uin: string; // QQ号 } @@ -62,7 +61,7 @@ declare type SendMessage = { content: string, } | { type: "image", - file: string, + file: string, // 这是本地路径? } declare var LLAPI: { @@ -89,6 +88,10 @@ declare type PostDataSendMsg = { } declare var llonebot: { + postData: (data: any) => void listenSendMessage: (handle: (msg: PostDataSendMsg) => void) => void + updateGroups: (groups: Group[]) => void + updateFriends: (friends: User[]) => void + updateGroupMembers: (data: { groupMembers: User[], group_id: string }) => void startExpress: () => void }; \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 9d2ed45..62c60da 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,19 +2,36 @@ const express = require("express") const {ipcMain, webContents} = require('electron'); +const fs = require('fs'); const CHANNEL_SEND_MSG = "llonebot_sendMsg" -function sendIPCCallSendQQMsg(postData: PostDataSendMsg) { +let groups: Group[] = [] +let friends: User[] = [] +let groupMembers: {group_id: string, groupMembers: User[]}[] = [] + +function sendIPCMsg(channel: string, data: any){ let contents = webContents.getAllWebContents(); for (const content of contents) { try { - content.send(CHANNEL_SEND_MSG, postData) + content.send(channel, data) } catch (e) { } } } +function sendIPCCallSendQQMsg(postData: PostDataSendMsg) { + sendIPCMsg(CHANNEL_SEND_MSG, postData); +} + +function log(msg: string){ + fs.appendFile("d:\\llonebot.log", msg + "\n", (err: any) => { + + }) +} + + + function startExpress(event: any) { // const original_send = (window.webContents.__qqntim_original_object && window.webContents.__qqntim_original_object.send) || window.webContents.send; const app = express(); @@ -30,8 +47,48 @@ function startExpress(event: any) { // 处理POST请求的路由 app.post('/', (req: any, res: any) => { let jsonData: PostDataSendMsg = req.body; - sendIPCCallSendQQMsg(jsonData); - res.send('POST请求已收到'); + let resData = { + status: 0, + retcode: 0, + data: {}, + message: '' + } + if (jsonData.action == "send_private_msg" || jsonData.action == "send_group_msg") { + sendIPCCallSendQQMsg(jsonData); + } + else if (jsonData.action == "get_group_list"){ + resData["data"] = groups.map(group => { + return { + group_id: group.uid, + group_name: group.name + } + }) + } + else if (jsonData.action == "get_group_member_list"){ + let group = groupMembers.find(group => group.group_id == jsonData.params.group_id) + if (group){ + resData["data"] = group.groupMembers.map(member => { + return { + user_id: member.uin, + user_name: member.nickName, + user_display_name: "" + } + + }) + } + else{ + resData["data"] = [] + } + } + else if (jsonData.action == "get_friend_list"){ + resData["data"] = friends.map(friend=>{ + return { + user_id: friend.uin, + user_name: friend.nickName, + } + }) + } + res.send(resData) }); app.listen(port, () => { console.log(`服务器已启动,监听端口 ${port}`); @@ -44,6 +101,48 @@ function onLoad(plugin: any) { ipcMain.on("startExpress", (event: any, arg: any) => { startExpress(event) }) + + ipcMain.on("updateGroups", (event: any, arg: Group[]) => { + groups = arg + }) + + ipcMain.on("updateFriends", (event: any, arg: User[]) => { + friends = arg + }) + + ipcMain.on("updateGroupMembers", (event: any, arg: {groupMembers: User[], group_id: string}) => { + let existMembers = groupMembers.find(group => group.group_id == arg.group_id) + if (existMembers){ + existMembers.groupMembers = arg.groupMembers + } + else{ + groupMembers.push(arg); + } + }) + + ipcMain.on("postOnebotData", (event: any, arg: any) => { + // try { + // // const fetch2 = require("./electron-fetch"); + // }catch (e) { + // log(e) + // } + log("开始post新消息事件到服务器") + try { + fetch("http://192.168.1.5:5000/", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(arg) + }).then((res: any) => { + log("新消息事件上传"); + }, (err: any) => { + log("新消息事件上传失败:" + err + JSON.stringify(arg)); + }); + }catch (e: any){ + log(e.toString()) + } + }) } diff --git a/src/preload.ts b/src/preload.ts index bcb7294..332966b 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -5,8 +5,20 @@ const {ipcRenderer} = require('electron'); // 在window对象下导出只读对象 contextBridge.exposeInMainWorld("llonebot", { + postData: (data: any) => { + ipcRenderer.send("postOnebotData", data); + }, + updateGroups: (groups: Group[]) => { + ipcRenderer.send("updateGroups", groups); + }, + updateFriends: (friends: User[]) => { + ipcRenderer.send("updateFriends", friends); + }, + updateGroupMembers: (data: {groupMembers: User[], group_id: string}) => { + ipcRenderer.send("updateGroupMembers", data); + }, listenSendMessage: (handle: (jsonData: PostDataSendMsg) => void) => { - ipcRenderer.on("sendMsg", (event: any, args: PostDataSendMsg) => { + ipcRenderer.on("llonebot_sendMsg", (event: any, args: PostDataSendMsg) => { handle(args) }) }, diff --git a/src/renderer.ts b/src/renderer.ts index 7796ed2..fad3557 100644 --- a/src/renderer.ts +++ b/src/renderer.ts @@ -2,12 +2,16 @@ // import express from "express"; // const { ipcRenderer } = require('electron'); - +enum AtType { + notAt = 0, + atUser = 2 +} const host = "http://localhost:5000" let groups: Group[] = [] let friends: User[] = [] +let groupMembers: { group_id: string, groupMembers: User[] }[] = [] function getFriend(qq: string) { return friends.find(friend => friend.uid == qq) @@ -21,6 +25,87 @@ let self_qq: string = "" let uid_maps: Record = {} // 一串加密的字符串 -> qq号 +function forwardMessage(message: MessageElement) { + try { + let onebot_message_data: any = { + self: { + platform: "qq", + user_id: self_qq + }, + time: 0, + 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 + }) + } + + if (message.peer.chatType == "group") { + 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 + 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); + } catch (e) { + console.log("上传消息事件失败", e) + } +} + +function handleNewMessage(messages: MessageElement[]) { + messages.forEach(message => { + if (message.peer.chatType == "group") { + let group = groupMembers.find(group => group.group_id == message.peer.uid) + if (!group) { + group = { + group_id: message.peer.uid, + groupMembers: [] + } + 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) + } + } + else{ + forwardMessage(message); + } + }) +} + function onLoad() { llonebot.startExpress(); llonebot.listenSendMessage((postData: PostDataSendMsg) => { @@ -35,8 +120,7 @@ function onLoad() { uid: friend.uin } } - } - else if (postData.action == "send_group_msg") { + } else if (postData.action == "send_group_msg") { let group = getGroup(postData.params.group_id) if (group) { peer = { @@ -51,76 +135,25 @@ function onLoad() { err => console.log("消息发送失败", postData, err)) } } - else if (postData.action == "get_group_list"){ - let groupsData = groups.map(group => { - return { - group_id: group.uid, - group_name: group.name - } - }) - } - }); - window.LLAPI.getAccountInfo().then(accountInfo => { - self_qq = accountInfo.uid - }) window.LLAPI.getGroupsList(false).then(groupsList => { groups = groupsList + llonebot.updateGroups(groupsList) }) + window.LLAPI.on("new-messages", (messages) => { console.log("收到新消息", messages) - messages.forEach(message => { - let onebot_message_data: any = { - self: { - platform: "qq", - user_id: self_qq - }, - time: 0, - type: "message", - detail_type: message.peer.chatType, - sub_type: "", - message: message.raw.elements.map(element => { - let message_data: any = { - data: {} - } - if (element.raw.textElement?.atType == AtType.atUser) { - message_data["type"] = "at" - message_data["data"]["mention"] = element.raw.textElement.atUid - } else if (element.raw.textElement) { - message_data["type"] = "text" - message_data["data"]["text"] = element.raw.textElement.content - } else if (element.raw.picElement) { - message_data["type"] = "image" - message_data["data"]["file_id"] = element.raw.picElement.fileUuid - message_data["data"]["path"] = element.raw.picElement.sourcePath - } else if (element.raw.replyElement) { - message_data["type"] = "reply" - message_data["data"]["reply"] = element.raw.replyElement.sourceMsgIdInRecords - } - return message_data - }) - } - - if (message.peer.chatType == "group") { - onebot_message_data["group_id"] = message.peer.uid - // todo: 将加密的uid转成qq号 - onebot_message_data["user_id"] = message.sender.uid - } else if (message.peer.chatType == "private") { - onebot_message_data["user_id"] = message.peer.uid - } - - fetch(host + "", { - method: "POST", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify(onebot_message_data) - }).then(res => { - }, err => { - console.log(err) + // 往groupMembers里面添加群成员 + if (!self_qq){ + window.LLAPI.getAccountInfo().then(accountInfo => { + console.log("getAccountInfo", accountInfo) + self_qq = accountInfo.uin + handleNewMessage(messages) }) - }); + }else{ + handleNewMessage(messages) + } }); // console.log("getAccountInfo", LLAPI.getAccountInfo()); }