mirror of
https://github.com/LLOneBot/LLOneBot.git
synced 2024-11-22 01:56:33 +00:00
feat: 预添加群成员变动事件
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
import { BrowserWindow } from 'electron';
|
||||
import { getConfigUtil, log } from "../common/utils";
|
||||
import { NTQQApi, NTQQApiClass, sendMessagePool } from "./ntcall";
|
||||
import { Group, User } from "./types";
|
||||
import { RawMessage } from "./types";
|
||||
import { addHistoryMsg, friends, groups, msgHistory } from "../common/data";
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import {BrowserWindow} from 'electron';
|
||||
import {log} from "../common/utils";
|
||||
import {NTQQApi, NTQQApiClass, sendMessagePool} from "./ntcall";
|
||||
import {Group, GroupMember, RawMessage, User} from "./types";
|
||||
import {addHistoryMsg, friends, groups, msgHistory} from "../common/data";
|
||||
import {v4 as uuidv4} from 'uuid';
|
||||
import {callEvent, EventType} from "../onebot11/event";
|
||||
import {OB11Message} from "../onebot11/types";
|
||||
import {OB11Constructor} from "../onebot11/constructor";
|
||||
|
||||
export let hookApiCallbacks: Record<string, (apiReturn: any) => void> = {}
|
||||
|
||||
@@ -41,7 +43,7 @@ let receiveHooks: Array<{
|
||||
export function hookNTQQApiReceive(window: BrowserWindow) {
|
||||
const originalSend = window.webContents.send;
|
||||
const patchSend = (channel: string, ...args: NTQQApiReturnData) => {
|
||||
// log(`received ntqq api message: ${channel}`, JSON.stringify(args))
|
||||
// console.log(`received ntqq api message: ${channel}`, JSON.stringify(args))
|
||||
if (args?.[1] instanceof Array) {
|
||||
for (let receiveData of args?.[1]) {
|
||||
const ntQQApiMethodName = receiveData.cmdName;
|
||||
@@ -90,25 +92,91 @@ export function removeReceiveHook(id: string) {
|
||||
receiveHooks.splice(index, 1);
|
||||
}
|
||||
|
||||
async function updateGroups(_groups: Group[]) {
|
||||
async function updateGroups(_groups: Group[], needUpdate: boolean = true) {
|
||||
for (let group of _groups) {
|
||||
let existGroup = groups.find(g => g.groupCode == group.groupCode)
|
||||
if (!existGroup) {
|
||||
NTQQApi.getGroupMembers(group.groupCode).then(members => {
|
||||
if (members) {
|
||||
group.members = members
|
||||
}
|
||||
})
|
||||
groups.push(group)
|
||||
log("update group members", group.members)
|
||||
} else {
|
||||
Object.assign(existGroup, group)
|
||||
let existGroup = groups.find(g => g.groupCode == group.groupCode);
|
||||
if (existGroup) {
|
||||
Object.assign(existGroup, group);
|
||||
}
|
||||
else {
|
||||
groups.push(group);
|
||||
}
|
||||
|
||||
if (needUpdate) {
|
||||
const members = await NTQQApi.getGroupMembers(group.groupCode);
|
||||
|
||||
if (members) {
|
||||
group.members = members;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerReceiveHook<{ groupList: Group[] }>(ReceiveCmd.GROUPS, (payload) => updateGroups(payload.groupList).then())
|
||||
registerReceiveHook<{ groupList: Group[] }>(ReceiveCmd.GROUPS_UNIX, (payload) => updateGroups(payload.groupList).then())
|
||||
async function processGroupEvent(payload) {
|
||||
const newGroupList = payload.groupList;
|
||||
for (const group of newGroupList) {
|
||||
let existGroup = groups.find(g => g.groupCode == group.groupCode);
|
||||
console.log(existGroup.members);
|
||||
if (existGroup) {
|
||||
if (existGroup.memberCount > group.memberCount) {
|
||||
console.log("群人数减少力!");
|
||||
const oldMembers = existGroup.members;
|
||||
const newMembers = await NTQQApi.getGroupMembers(group.groupCode);
|
||||
group.members = newMembers;
|
||||
const newMembersSet = new Set<string>(); // 建立索引降低时间复杂度
|
||||
|
||||
for (const member of newMembers) {
|
||||
newMembersSet.add(member.uin);
|
||||
}
|
||||
|
||||
console.log(oldMembers);
|
||||
for (const member of oldMembers) {
|
||||
if (!newMembersSet.has(member.uin)) {
|
||||
console.log("减少的群员是:" + member.uin);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (existGroup.memberCount < group.memberCount) {
|
||||
console.log("群人数增加力!");
|
||||
|
||||
const oldMembersSet = new Set<string>();
|
||||
for (const member of existGroup.members) {
|
||||
oldMembersSet.add(member.uin);
|
||||
}
|
||||
|
||||
const newMembers = await NTQQApi.getGroupMembers(group.groupCode);
|
||||
group.members = newMembers;
|
||||
for (const member of newMembers) {
|
||||
if (!oldMembersSet.has(member.uin)) {
|
||||
console.log("增加的群员是:" + member.uin);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateGroups(newGroupList, false).then();
|
||||
}
|
||||
|
||||
registerReceiveHook<{ groupList: Group[], updateType: number }>(ReceiveCmd.GROUPS, (payload) => {
|
||||
if (payload.updateType != 2) {
|
||||
updateGroups(payload.groupList).then();
|
||||
}
|
||||
else {
|
||||
processGroupEvent(payload).then();
|
||||
}
|
||||
})
|
||||
registerReceiveHook<{ groupList: Group[], updateType: number }>(ReceiveCmd.GROUPS_UNIX, (payload) => {
|
||||
if (payload.updateType != 2) {
|
||||
updateGroups(payload.groupList).then();
|
||||
}
|
||||
else {
|
||||
processGroupEvent(payload).then();
|
||||
}
|
||||
})
|
||||
registerReceiveHook<{
|
||||
data: { categoryId: number, categroyName: string, categroyMbCount: number, buddyList: User[] }[]
|
||||
}>(ReceiveCmd.FRIENDS, payload => {
|
||||
@@ -125,10 +193,6 @@ registerReceiveHook<{
|
||||
}
|
||||
})
|
||||
|
||||
// registerReceiveHook<any>(ReceiveCmd.USER_INFO, (payload)=>{
|
||||
// log("user info", payload);
|
||||
// })
|
||||
|
||||
registerReceiveHook<{ msgList: Array<RawMessage> }>(ReceiveCmd.UPDATE_MSG, (payload) => {
|
||||
for (const message of payload.msgList) {
|
||||
addHistoryMsg(message)
|
||||
@@ -138,6 +202,12 @@ registerReceiveHook<{ msgList: Array<RawMessage> }>(ReceiveCmd.UPDATE_MSG, (payl
|
||||
registerReceiveHook<{ msgList: Array<RawMessage> }>(ReceiveCmd.NEW_MSG, (payload) => {
|
||||
for (const message of payload.msgList) {
|
||||
// log("收到新消息,push到历史记录", message)
|
||||
OB11Constructor.message(message).then(
|
||||
function (message) {
|
||||
callEvent<OB11Message>(EventType.MESSAGE, message);
|
||||
}
|
||||
);
|
||||
|
||||
addHistoryMsg(message)
|
||||
}
|
||||
const msgIds = Object.keys(msgHistory);
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import { getHistoryMsgByShortId, msgHistory } from "../../common/data";
|
||||
import { OB11Message } from '../types';
|
||||
import { OB11Constructor } from "../constructor";
|
||||
import { log } from "../../common/utils";
|
||||
import BaseAction from "./BaseAction";
|
||||
import { ActionName } from "./types";
|
||||
|
||||
|
38
src/onebot11/event.ts
Normal file
38
src/onebot11/event.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import {selfInfo} from "../common/data";
|
||||
|
||||
const websocketList = [];
|
||||
|
||||
export enum EventType {
|
||||
META = "meta_event",
|
||||
REQUEST = "request",
|
||||
NOTICE = "notice",
|
||||
MESSAGE = "message"
|
||||
}
|
||||
|
||||
export function registerEventSender(ws) {
|
||||
websocketList.push(ws);
|
||||
}
|
||||
|
||||
export function unregisterEventSender(ws) {
|
||||
let index = websocketList.indexOf(ws);
|
||||
if (index !== -1) {
|
||||
websocketList.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
export function callEvent<DataType>(type: EventType, data: DataType) {
|
||||
const basicEvent = {
|
||||
time: new Date().getTime(),
|
||||
self_id: selfInfo.uin,
|
||||
post_type: type
|
||||
}
|
||||
|
||||
|
||||
for (const ws of websocketList) {
|
||||
ws.send(
|
||||
JSON.stringify(
|
||||
Object.assign(basicEvent, data)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@@ -11,6 +11,7 @@ import { selfInfo } from "../common/data";
|
||||
import { OB11Message, OB11Return, OB11MessageData } from './types';
|
||||
import {actionHandlers, actionMap} from "./actions";
|
||||
import {OB11Response, OB11WebsocketResponse} from "./actions/utils";
|
||||
import {registerEventSender, unregisterEventSender} from "./event";
|
||||
|
||||
|
||||
// @SiberianHusky 2021-08-15
|
||||
@@ -100,8 +101,8 @@ export function startWebsocketServer(port: number) {
|
||||
|
||||
export function initWebsocket() {
|
||||
if (getConfigUtil().getConfig().enableWs) {
|
||||
expressWsApp.ws("/api", onWebsocketMessage);
|
||||
expressWsApp.ws("/", onWebsocketMessage);
|
||||
expressWsApp.ws("/api", initWebsocketServer);
|
||||
expressWsApp.ws("/", initWebsocketServer);
|
||||
}
|
||||
|
||||
initReverseWebsocket();
|
||||
@@ -114,8 +115,10 @@ function initReverseWebsocket() {
|
||||
try {
|
||||
const wsClient = new WebSocket(url);
|
||||
websocketClientConnections.push(wsClient);
|
||||
registerEventSender(wsClient);
|
||||
|
||||
wsClient.onclose = function (ev) {
|
||||
unregisterEventSender(wsClient);
|
||||
let index = websocketClientConnections.indexOf(wsClient);
|
||||
if (index !== -1) {
|
||||
websocketClientConnections.splice(index, 1);
|
||||
@@ -149,7 +152,9 @@ function initReverseWebsocket() {
|
||||
}
|
||||
}
|
||||
|
||||
function onWebsocketMessage(ws, req) {
|
||||
function initWebsocketServer(ws, req) {
|
||||
registerEventSender(ws);
|
||||
|
||||
ws.on("message", async function (message) {
|
||||
try {
|
||||
let recv = JSON.parse(message);
|
||||
@@ -167,7 +172,11 @@ function onWebsocketMessage(ws, req) {
|
||||
log(e.stack);
|
||||
ws.send(JSON.stringify(OB11WebsocketResponse.error(e.stack.toString(), 1200)));
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
ws.on("close", function (ev) {
|
||||
unregisterEventSender(ws);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,19 +1,19 @@
|
||||
import { AtType } from "../ntqqapi/types";
|
||||
import { RawMessage } from "../ntqqapi/types";
|
||||
|
||||
export interface OB11User{
|
||||
export interface OB11User {
|
||||
user_id: string;
|
||||
nickname: string;
|
||||
remark?: string
|
||||
}
|
||||
|
||||
export enum OB11UserSex{
|
||||
export enum OB11UserSex {
|
||||
male = "male",
|
||||
female = "female",
|
||||
unknown = "unknown"
|
||||
}
|
||||
|
||||
export enum OB11GroupMemberRole{
|
||||
export enum OB11GroupMemberRole {
|
||||
owner = "owner",
|
||||
admin = "admin",
|
||||
member = "member",
|
||||
@@ -33,7 +33,7 @@ export interface OB11GroupMember {
|
||||
title?: string
|
||||
}
|
||||
|
||||
export interface OB11Group{
|
||||
export interface OB11Group {
|
||||
group_id: string
|
||||
group_name: string
|
||||
member_count?: number
|
||||
|
134
src/renderer.ts
134
src/renderer.ts
@@ -6,11 +6,11 @@ async function onSettingWindowCreated(view: Element) {
|
||||
window.llonebot.log("setting window created");
|
||||
let config = await window.llonebot.getConfig()
|
||||
|
||||
function creatHostEleStr(host: string) {
|
||||
function createHttpHostEleStr(host: string) {
|
||||
let eleStr = `
|
||||
<setting-item data-direction="row" class="hostItem vertical-list-item">
|
||||
<h2>事件上报地址(http)</h2>
|
||||
<input class="host input-text" type="text" value="${host}"
|
||||
<input class="httpHost input-text" type="text" value="${host}"
|
||||
style="width:60%;padding: 5px"
|
||||
placeholder="如果localhost上报失败试试局域网ip"/>
|
||||
</setting-item>
|
||||
@@ -19,29 +19,87 @@ async function onSettingWindowCreated(view: Element) {
|
||||
return eleStr
|
||||
}
|
||||
|
||||
let hostsEleStr = ""
|
||||
for (const host of config.httpHosts) {
|
||||
hostsEleStr += creatHostEleStr(host);
|
||||
function createWsHostEleStr(host: string) {
|
||||
let eleStr = `
|
||||
<setting-item data-direction="row" class="hostItem vertical-list-item">
|
||||
<h2>事件上报地址(反向websocket)</h2>
|
||||
<input class="wsHost input-text" type="text" value="${host}"
|
||||
style="width:60%;padding: 5px"
|
||||
placeholder="如果localhost上报失败试试局域网ip"/>
|
||||
</setting-item>
|
||||
|
||||
`
|
||||
return eleStr
|
||||
}
|
||||
|
||||
let httpHostsEleStr = ""
|
||||
for (const host of config.httpHosts) {
|
||||
httpHostsEleStr += createHttpHostEleStr(host);
|
||||
}
|
||||
|
||||
let wsHostsEleStr = ""
|
||||
for (const host of config.wsHosts) {
|
||||
wsHostsEleStr += createWsHostEleStr(host);
|
||||
}
|
||||
|
||||
let html = `
|
||||
<div class="config_view llonebot">
|
||||
<setting-section>
|
||||
<setting-panel>
|
||||
<setting-list class="wrap">
|
||||
<setting-item class="vertical-list-item" data-direction="row">
|
||||
<setting-text>监听端口</setting-text>
|
||||
<input id="port" type="number" value="${config.httpPort}"/>
|
||||
<setting-text>HTTP监听端口</setting-text>
|
||||
<input id="httpPort" type="number" value="${config.httpPort}"/>
|
||||
</setting-item>
|
||||
<div>
|
||||
<button id="addHost" class="q-button">添加上报地址</button>
|
||||
<button id="addHttpHost" class="q-button">添加HTTP POST上报地址</button>
|
||||
</div>
|
||||
<div id="hostItems">
|
||||
${hostsEleStr}
|
||||
<div id="httpHostItems">
|
||||
${httpHostsEleStr}
|
||||
</div>
|
||||
|
||||
<setting-item class="vertical-list-item" data-direction="row">
|
||||
<setting-text>正向Websocket监听端口</setting-text>
|
||||
<input id="wsPort" type="number" value="${config.wsPort}"/>
|
||||
</setting-item>
|
||||
<div>
|
||||
<button id="addWsHost" class="q-button">添加反向Websocket上报地址</button>
|
||||
</div>
|
||||
<div id="wsHostItems">
|
||||
${wsHostsEleStr}
|
||||
</div>
|
||||
<button id="save" class="q-button">保存(监听端口重启QQ后生效)</button>
|
||||
</setting-list>
|
||||
</setting-panel>
|
||||
<setting-panel>
|
||||
<setting-item data-direction="row" class="hostItem vertical-list-item">
|
||||
<div>
|
||||
<div>启用HTTP支持</div>
|
||||
<div class="tips">修改后须重启QQ生效</div>
|
||||
</div>
|
||||
<setting-switch id="http" ${config.enableHttp ? "is-active" : ""}></setting-switch>
|
||||
</setting-item>
|
||||
<setting-item data-direction="row" class="hostItem vertical-list-item">
|
||||
<div>
|
||||
<div>启用HTTP POST支持</div>
|
||||
<div class="tips">修改后须重启QQ生效</div>
|
||||
</div>
|
||||
<setting-switch id="httpPost" ${config.enableHttpPost ? "is-active" : ""}></setting-switch>
|
||||
</setting-item>
|
||||
<setting-item data-direction="row" class="hostItem vertical-list-item">
|
||||
<div>
|
||||
<div>启用正向Websocket支持</div>
|
||||
<div class="tips">修改后须重启QQ生效</div>
|
||||
</div>
|
||||
<setting-switch id="websocket" ${config.enableWs ? "is-active" : ""}></setting-switch>
|
||||
</setting-item>
|
||||
<setting-item data-direction="row" class="hostItem vertical-list-item">
|
||||
<div>
|
||||
<div>启用反向Websocket支持</div>
|
||||
<div class="tips">修改后须重启QQ生效</div>
|
||||
</div>
|
||||
<setting-switch id="websocketReverse" ${config.enableWsReverse ? "is-active" : ""}></setting-switch>
|
||||
</setting-item>
|
||||
<setting-item data-direction="row" class="hostItem vertical-list-item">
|
||||
<div>
|
||||
<div>上报文件进行base64编码</div>
|
||||
@@ -92,15 +150,23 @@ async function onSettingWindowCreated(view: Element) {
|
||||
const doc = parser.parseFromString(html, "text/html");
|
||||
|
||||
|
||||
function addHostEle(initValue: string = "") {
|
||||
let addressDoc = parser.parseFromString(creatHostEleStr(initValue), "text/html");
|
||||
function addHostEle(type: string, initValue: string = "") {
|
||||
let addressDoc = parser.parseFromString(createHttpHostEleStr(initValue), "text/html");
|
||||
let addressEle = addressDoc.querySelector("setting-item")
|
||||
let hostItemsEle = document.getElementById("hostItems");
|
||||
let hostItemsEle;
|
||||
if (type === "ws") {
|
||||
hostItemsEle = document.getElementById("wsHostItems");
|
||||
}
|
||||
else {
|
||||
hostItemsEle = document.getElementById("httpHostItems");
|
||||
}
|
||||
|
||||
hostItemsEle.appendChild(addressEle);
|
||||
}
|
||||
|
||||
|
||||
doc.getElementById("addHost").addEventListener("click", () => addHostEle())
|
||||
doc.getElementById("addHttpHost").addEventListener("click", () => addHostEle("http"))
|
||||
doc.getElementById("addWsHost").addEventListener("click", () => addHostEle("ws"))
|
||||
|
||||
function switchClick(eleId: string, configKey: string) {
|
||||
doc.getElementById(eleId)?.addEventListener("click", (e) => {
|
||||
@@ -116,6 +182,10 @@ async function onSettingWindowCreated(view: Element) {
|
||||
})
|
||||
}
|
||||
|
||||
switchClick("http", "enableHttp");
|
||||
switchClick("httpPost", "enableHttpPost");
|
||||
switchClick("websocket", "enableWs");
|
||||
switchClick("websocketReverse", "enableWsReverse");
|
||||
switchClick("debug", "debug");
|
||||
switchClick("switchBase64", "enableBase64");
|
||||
switchClick("reportSelfMessage", "reportSelfMessage");
|
||||
@@ -123,20 +193,35 @@ async function onSettingWindowCreated(view: Element) {
|
||||
|
||||
doc.getElementById("save")?.addEventListener("click",
|
||||
() => {
|
||||
const portEle: HTMLInputElement = document.getElementById("port") as HTMLInputElement
|
||||
const hostEles: HTMLCollectionOf<HTMLInputElement> = document.getElementsByClassName("host") as HTMLCollectionOf<HTMLInputElement>;
|
||||
// const port = doc.querySelector("input[type=number]")?.value
|
||||
// const host = doc.querySelector("input[type=text]")?.value
|
||||
const httpPortEle: HTMLInputElement = document.getElementById("httpPort") as HTMLInputElement;
|
||||
const httpHostEles: HTMLCollectionOf<HTMLInputElement> = document.getElementsByClassName("httpHost") as HTMLCollectionOf<HTMLInputElement>;
|
||||
const wsPortEle: HTMLInputElement = document.getElementById("wsPort") as HTMLInputElement;
|
||||
const wsHostEles: HTMLCollectionOf<HTMLInputElement> = document.getElementsByClassName("wsHost") as HTMLCollectionOf<HTMLInputElement>;
|
||||
|
||||
// 获取端口和host
|
||||
const port = portEle.value
|
||||
let hosts: string[] = [];
|
||||
for (const hostEle of hostEles) {
|
||||
const httpPort = httpPortEle.value
|
||||
let httpHosts: string[] = [];
|
||||
|
||||
for (const hostEle of httpHostEles) {
|
||||
if (hostEle.value) {
|
||||
hosts.push(hostEle.value);
|
||||
httpHosts.push(hostEle.value);
|
||||
}
|
||||
}
|
||||
config.httpPort = parseInt(port);
|
||||
config.httpHosts = hosts;
|
||||
|
||||
const wsPort = wsPortEle.value
|
||||
let wsHosts: string[] = [];
|
||||
|
||||
for (const hostEle of wsHostEles) {
|
||||
if (hostEle.value) {
|
||||
wsHosts.push(hostEle.value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
config.httpPort = parseInt(httpPort);
|
||||
config.httpHosts = httpHosts;
|
||||
config.wsPort = parseInt(wsPort);
|
||||
config.wsHosts = wsHosts;
|
||||
window.llonebot.setConfig(config);
|
||||
alert("保存成功");
|
||||
})
|
||||
@@ -146,7 +231,6 @@ async function onSettingWindowCreated(view: Element) {
|
||||
view.appendChild(node);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user