onebot http接口

This commit is contained in:
linyuchen 2023-11-01 00:24:27 +08:00
parent 455529f7fd
commit 7a7d21d533
5 changed files with 272 additions and 94 deletions

31
package-lock.json generated
View File

@ -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",

51
src/global.d.ts vendored
View File

@ -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
};

View File

@ -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())
}
})
}

View File

@ -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)
})
},

View File

@ -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<string, string> = {} // 一串加密的字符串 -> 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());
}