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", "license": "ISC",
"dependencies": { "dependencies": {
"electron": "^27.0.2", "electron": "^27.0.2",
"electron-fetch": "^1.9.1",
"express": "^4.18.2", "express": "^4.18.2",
"path": "^0.12.7", "path": "^0.12.7",
"stream": "^0.0.2", "stream": "^0.0.2",
@ -1370,6 +1371,17 @@
"node": ">= 12.20.55" "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": { "node_modules/electron-to-chromium": {
"version": "1.4.567", "version": "1.4.567",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.567.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.567.tgz",
@ -1397,6 +1409,25 @@
"node": ">= 0.8" "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": { "node_modules/end-of-stream": {
"version": "1.4.4", "version": "1.4.4",
"resolved": "https://mirrors.cloud.tencent.com/npm/end-of-stream/-/end-of-stream-1.4.4.tgz", "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 { interface MessageElement {
raw: { raw: {
elements: { elements: {
raw: {
replyElement: { replyElement: {
senderUid: string, // 原消息发送者QQ号 senderUid: string, // 原消息发送者QQ号
sourceMsgIsIncPic: boolean; // 原消息是否有图片 sourceMsgIsIncPic: boolean; // 原消息是否有图片
sourceMsgText: string; sourceMsgText: string;
sourceMsgIdInRecords: string; // 原消息id sourceMsgIdInRecords: string; // 原消息id
}, },
textElement: { textElement: {
atType: AtType atType: AtType
atUid: string, atUid: string,
content: string content: string
}, },
picElement: { picElement: {
sourcePath: string // 图片本地路径 sourcePath: string // 图片本地路径
picWidth: number picWidth: number
picHeight: number picHeight: number
fileSize: number fileSize: number
fileName: string fileName: string
fileUuid: string fileUuid: string
}
} }
}[] }[]
} }
@ -45,10 +44,10 @@ interface MessageElement {
} }
declare type User = { declare type User = {
avatarUrl: string; avatarUrl?: string;
bio: string; // 签名 bio?: string; // 签名
nickName: string; nickName: string;
uid: string; // 加密的字符串 uid?: string; // 加密的字符串
uin: string; // QQ号 uin: string; // QQ号
} }
@ -62,7 +61,7 @@ declare type SendMessage = {
content: string, content: string,
} | { } | {
type: "image", type: "image",
file: string, file: string, // 这是本地路径?
} }
declare var LLAPI: { declare var LLAPI: {
@ -89,6 +88,10 @@ declare type PostDataSendMsg = {
} }
declare var llonebot: { declare var llonebot: {
postData: (data: any) => void
listenSendMessage: (handle: (msg: PostDataSendMsg) => void) => 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 startExpress: () => void
}; };

View File

@ -2,19 +2,36 @@
const express = require("express") const express = require("express")
const {ipcMain, webContents} = require('electron'); const {ipcMain, webContents} = require('electron');
const fs = require('fs');
const CHANNEL_SEND_MSG = "llonebot_sendMsg" 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(); let contents = webContents.getAllWebContents();
for (const content of contents) { for (const content of contents) {
try { try {
content.send(CHANNEL_SEND_MSG, postData) content.send(channel, data)
} catch (e) { } 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) { function startExpress(event: any) {
// const original_send = (window.webContents.__qqntim_original_object && window.webContents.__qqntim_original_object.send) || window.webContents.send; // const original_send = (window.webContents.__qqntim_original_object && window.webContents.__qqntim_original_object.send) || window.webContents.send;
const app = express(); const app = express();
@ -30,8 +47,48 @@ function startExpress(event: any) {
// 处理POST请求的路由 // 处理POST请求的路由
app.post('/', (req: any, res: any) => { app.post('/', (req: any, res: any) => {
let jsonData: PostDataSendMsg = req.body; let jsonData: PostDataSendMsg = req.body;
sendIPCCallSendQQMsg(jsonData); let resData = {
res.send('POST请求已收到'); 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, () => { app.listen(port, () => {
console.log(`服务器已启动,监听端口 ${port}`); console.log(`服务器已启动,监听端口 ${port}`);
@ -44,6 +101,48 @@ function onLoad(plugin: any) {
ipcMain.on("startExpress", (event: any, arg: any) => { ipcMain.on("startExpress", (event: any, arg: any) => {
startExpress(event) 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对象下导出只读对象 // 在window对象下导出只读对象
contextBridge.exposeInMainWorld("llonebot", { 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) => { listenSendMessage: (handle: (jsonData: PostDataSendMsg) => void) => {
ipcRenderer.on("sendMsg", (event: any, args: PostDataSendMsg) => { ipcRenderer.on("llonebot_sendMsg", (event: any, args: PostDataSendMsg) => {
handle(args) handle(args)
}) })
}, },

View File

@ -2,12 +2,16 @@
// import express from "express"; // import express from "express";
// const { ipcRenderer } = require('electron'); // const { ipcRenderer } = require('electron');
enum AtType {
notAt = 0,
atUser = 2
}
const host = "http://localhost:5000" const host = "http://localhost:5000"
let groups: Group[] = [] let groups: Group[] = []
let friends: User[] = [] let friends: User[] = []
let groupMembers: { group_id: string, groupMembers: User[] }[] = []
function getFriend(qq: string) { function getFriend(qq: string) {
return friends.find(friend => friend.uid == qq) return friends.find(friend => friend.uid == qq)
@ -21,6 +25,87 @@ let self_qq: string = ""
let uid_maps: Record<string, string> = {} // 一串加密的字符串 -> qq号 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() { function onLoad() {
llonebot.startExpress(); llonebot.startExpress();
llonebot.listenSendMessage((postData: PostDataSendMsg) => { llonebot.listenSendMessage((postData: PostDataSendMsg) => {
@ -35,8 +120,7 @@ function onLoad() {
uid: friend.uin uid: friend.uin
} }
} }
} } else if (postData.action == "send_group_msg") {
else if (postData.action == "send_group_msg") {
let group = getGroup(postData.params.group_id) let group = getGroup(postData.params.group_id)
if (group) { if (group) {
peer = { peer = {
@ -51,76 +135,25 @@ function onLoad() {
err => console.log("消息发送失败", postData, err)) 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 => { window.LLAPI.getGroupsList(false).then(groupsList => {
groups = groupsList groups = groupsList
llonebot.updateGroups(groupsList)
}) })
window.LLAPI.on("new-messages", (messages) => { window.LLAPI.on("new-messages", (messages) => {
console.log("收到新消息", messages) console.log("收到新消息", messages)
messages.forEach(message => { // 往groupMembers里面添加群成员
let onebot_message_data: any = { if (!self_qq){
self: { window.LLAPI.getAccountInfo().then(accountInfo => {
platform: "qq", console.log("getAccountInfo", accountInfo)
user_id: self_qq self_qq = accountInfo.uin
}, handleNewMessage(messages)
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)
}) })
}); }else{
handleNewMessage(messages)
}
}); });
// console.log("getAccountInfo", LLAPI.getAccountInfo()); // console.log("getAccountInfo", LLAPI.getAccountInfo());
} }