feat: group admin change notice

This commit is contained in:
linyuchen
2024-02-23 04:08:20 +08:00
parent b27dadbbca
commit 1f0dad786c
9 changed files with 146 additions and 36 deletions

View File

@@ -2,6 +2,8 @@ import fs from "fs";
import {Config, OB11Config} from "./types";
import {mergeNewProperties} from "./utils";
export const HOOK_LOG = false;
export class ConfigUtil {
private readonly configPath: string;
private config: Config | null = null;

View File

@@ -43,7 +43,7 @@ export async function getGroup(qq: string): Promise<Group | undefined> {
return group
}
export async function getGroupMember(groupQQ: string, memberQQ: string=null, memberUid: string=null) {
export async function getGroupMember(groupQQ: string, memberQQ: string, memberUid: string=null) {
const group = await getGroup(groupQQ)
if (group) {
let filterFunc: (member: GroupMember) => boolean

View File

@@ -6,17 +6,17 @@ import {Config} from "../common/types";
import {CHANNEL_GET_CONFIG, CHANNEL_LOG, CHANNEL_SET_CONFIG,} from "../common/channels";
import {ob11WebsocketServer} from "../onebot11/server/ws/WebsocketServer";
import {CONFIG_DIR, getConfigUtil, log} from "../common/utils";
import {addHistoryMsg, getGroupMember, msgHistory, selfInfo} from "../common/data";
import {addHistoryMsg, getGroup, getGroupMember, msgHistory, selfInfo} from "../common/data";
import {hookNTQQApiCall, hookNTQQApiReceive, ReceiveCmd, registerReceiveHook} from "../ntqqapi/hook";
import {OB11Constructor} from "../onebot11/constructor";
import {NTQQApi} from "../ntqqapi/ntcall";
import {ChatType, RawMessage} from "../ntqqapi/types";
import {ChatType, GroupNotify, GroupNotifyTypes, RawMessage} from "../ntqqapi/types";
import {ob11HTTPServer} from "../onebot11/server/http";
import {OB11FriendRecallNoticeEvent} from "../onebot11/event/notice/OB11FriendRecallNoticeEvent";
import {OB11GroupRecallNoticeEvent} from "../onebot11/event/notice/OB11GroupRecallNoticeEvent";
import {postEvent} from "../onebot11/server/postevent";
import {ob11ReverseWebsockets} from "../onebot11/server/ws/ReverseWebsocket";
import {EventType} from "../onebot11/event/OB11BaseEvent";
import {OB11GroupAdminNoticeEvent} from "../onebot11/event/notice/OB11GroupAdminNoticeEvent";
let running = false;
@@ -105,8 +105,7 @@ function onLoad() {
}
}
async function start() {
async function startReceiveHook() {
registerReceiveHook<{ msgList: Array<RawMessage> }>(ReceiveCmd.NEW_MSG, (payload) => {
try {
postReceiveMsg(payload.msgList);
@@ -159,6 +158,55 @@ function onLoad() {
log("report self message error: ", e.toString());
}
})
registerReceiveHook<{
"doubt": boolean,
"oldestUnreadSeq": string,
"unreadCount": number
}>(ReceiveCmd.UNREAD_GROUP_NOTIFY, async (payload) => {
if (payload.unreadCount) {
log("开始获取群通知详情")
let notify: GroupNotify;
try {
notify = await NTQQApi.getGroupNotifies();
}catch (e) {
// log("获取群通知详情失败", e);
return
}
const notifies = notify.notifies.slice(0, payload.unreadCount)
log("获取群通知详情完成", notifies, payload);
try {
for (const notify of notifies) {
if (parseInt(notify.seq) / 1000 < startTime){
continue;
}
if ([GroupNotifyTypes.ADMIN_SET, GroupNotifyTypes.ADMIN_UNSET].includes(notify.type)) {
log("有管理员变动通知");
let groupAdminNoticeEvent = new OB11GroupAdminNoticeEvent()
groupAdminNoticeEvent.group_id = parseInt(notify.group.groupCode);
log("开始获取变动的管理员")
const member = await getGroupMember(notify.group.groupCode, null, notify.user1.uid);
if(member){
log("变动管理员获取成功")
groupAdminNoticeEvent.user_id = parseInt(member.uin);
groupAdminNoticeEvent.sub_type = notify.type == GroupNotifyTypes.ADMIN_UNSET ? "unset" : "set";
postEvent(groupAdminNoticeEvent, true);
}
else{
log("获取群通知的成员信息失败", notify, getGroup(notify.group.groupCode));
}
}
}
}catch (e) {
log("解析群通知失败", e.stack);
}
}
})
}
let startTime = 0;
async function start() {
startTime = Date.now();
startReceiveHook().then();
NTQQApi.getGroups(true).then()
const config = getConfigUtil().getConfig()
if (config.ob11.enableHttp) {
@@ -168,16 +216,17 @@ function onLoad() {
log("http server start failed", e);
}
}
if (config.ob11.enableWs){
if (config.ob11.enableWs) {
ob11WebsocketServer.start(config.ob11.wsPort);
}
if (config.ob11.enableWsReverse){
if (config.ob11.enableWsReverse) {
ob11ReverseWebsockets.start();
}
log("LLOneBot start")
}
let getSelfNickCount = 0;
const init = async () => {
try {
const _ = await NTQQApi.getSelfInfo();
@@ -194,7 +243,10 @@ function onLoad() {
if (userInfo) {
selfInfo.nick = userInfo.nick;
} else {
return setTimeout(init, 1000);
getSelfNickCount++;
if (getSelfNickCount < 10){
return setTimeout(init, 1000);
}
}
} catch (e) {
log("get self nickname failed", e.toString());

View File

@@ -7,6 +7,7 @@ import {OB11GroupDecreaseEvent} from "../onebot11/event/notice/OB11GroupDecrease
import {OB11GroupIncreaseEvent} from "../onebot11/event/notice/OB11GroupIncreaseEvent";
import {v4 as uuidv4} from "uuid"
import {postEvent} from "../onebot11/server/postevent";
import {HOOK_LOG} from "../common/config";
export let hookApiCallbacks: Record<string, (apiReturn: any) => void> = {}
@@ -19,7 +20,8 @@ export enum ReceiveCmd {
GROUPS_UNIX = "onGroupListUpdate",
FRIENDS = "onBuddyListChange",
MEDIA_DOWNLOAD_COMPLETE = "nodeIKernelMsgListener/onRichMediaDownloadComplete",
UNREAD_GROUP_NOTICE = "nodeIKernelGroupListener/onGroupNotifiesUnreadCountUpdated"
UNREAD_GROUP_NOTIFY = "nodeIKernelGroupListener/onGroupNotifiesUnreadCountUpdated",
GROUP_NOTIFY = "nodeIKernelGroupListener/onGroupSingleScreenNotifies"
}
interface NTQQApiReturnData<PayloadType = unknown> extends Array<any> {
@@ -45,7 +47,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))
HOOK_LOG && log(`received ntqq api message: ${channel}`, JSON.stringify(args))
if (args?.[1] instanceof Array) {
for (let receiveData of args?.[1]) {
const ntQQApiMethodName = receiveData.cmdName;
@@ -89,15 +91,15 @@ export function hookNTQQApiCall(window: BrowserWindow) {
const proxyIpcMsg = new Proxy(ipc_message_proxy, {
apply(target, thisArg, args) {
log("call NTQQ api", thisArg, args);
HOOK_LOG && log("call NTQQ api", thisArg, args);
return target.apply(thisArg, args);
},
});
// if (webContents._events["-ipc-message"]?.[0]) {
// webContents._events["-ipc-message"][0] = proxyIpcMsg;
// } else {
// webContents._events["-ipc-message"] = proxyIpcMsg;
// }
if (webContents._events["-ipc-message"]?.[0]) {
webContents._events["-ipc-message"][0] = proxyIpcMsg;
} else {
webContents._events["-ipc-message"] = proxyIpcMsg;
}
}
export function registerReceiveHook<PayloadType>(method: ReceiveCmd, hookFunc: (payload: PayloadType) => void): string {
@@ -253,9 +255,3 @@ registerReceiveHook<{ msgRecord: RawMessage }>(ReceiveCmd.SELF_SEND_MSG, ({msgRe
}
})
registerReceiveHook<{"doubt": boolean,"oldestUnreadSeq": string,"unreadCount": number}>(ReceiveCmd.UNREAD_GROUP_NOTICE, (payload)=>{
log("收到群通知", payload);
if (payload.unreadCount){
}
})

View File

@@ -1,7 +1,17 @@
import {ipcMain} from "electron";
import {hookApiCallbacks, ReceiveCmd, registerReceiveHook, removeReceiveHook} from "./hook";
import {log} from "../common/utils";
import {ChatType, Friend, Group, GroupMember, RawMessage, SelfInfo, SendMessageElement, User} from "./types";
import {
ChatType,
Friend,
Group,
GroupMember,
GroupNotify,
RawMessage,
SelfInfo,
SendMessageElement,
User
} from "./types";
import * as fs from "fs";
import {addHistoryMsg, msgHistory, selfInfo} from "../common/data";
import {v4 as uuidv4} from "uuid"
@@ -42,7 +52,7 @@ export enum NTQQApiMethod {
SEND_MSG = "nodeIKernelMsgService/sendMsg",
DOWNLOAD_MEDIA = "nodeIKernelMsgService/downloadRichMedia",
MULTI_FORWARD_MSG = "nodeIKernelMsgService/multiForwardMsgWithComment", // 合并转发
GET_GROUP_NOTICE = "nodeIKernelGroupListener/onGroupSingleScreenNotifies",
GET_GROUP_NOTICE = "nodeIKernelGroupService/getSingleScreenNotifies",
}
enum NTQQApiChannel {
@@ -63,7 +73,7 @@ enum CallBackType {
}
interface NTQQApiParams {
methodName: NTQQApiMethod,
methodName: NTQQApiMethod | string,
className?: NTQQApiClass,
channel?: NTQQApiChannel,
classNameIsRegister?: boolean
@@ -77,7 +87,7 @@ function callNTQQApi<ReturnType>(params: NTQQApiParams) {
let {
className, methodName, channel, args,
cbCmd, timeoutSecond: timeout,
cmdCB
classNameIsRegister, cmdCB
} = params;
className = className ?? NTQQApiClass.NT_API;
channel = channel ?? NTQQApiChannel.IPC_UP_2;
@@ -89,6 +99,11 @@ function callNTQQApi<ReturnType>(params: NTQQApiParams) {
// log("callNTQQApiPromise", channel, className, methodName, args, uuid)
const _timeout = timeout * 1000
let success = false
let eventName = className + "-" + channel[channel.length - 1];
if (classNameIsRegister) {
eventName += "-register";
}
const apiArgs = [methodName, ...args]
if (!cbCmd) {
// QQ后端会返回结果并且可以插根据uuid识别
hookApiCallbacks[uuid] = (r: ReturnType) => {
@@ -123,12 +138,11 @@ function callNTQQApi<ReturnType>(params: NTQQApiParams) {
setTimeout(() => {
// log("ntqq api timeout", success, channel, className, methodName)
if (!success) {
log(`ntqq api timeout ${channel}, ${className}, ${methodName}`)
reject(`ntqq api timeout ${channel}, ${className}, ${methodName}`)
log(`ntqq api timeout ${channel}, ${eventName}, ${methodName}`, apiArgs);
reject(`ntqq api timeout ${channel}, ${eventName}, ${methodName}, ${apiArgs}`)
}
}, _timeout)
const eventName = className + "-" + channel[channel.length - 1];
const apiArgs = [methodName, ...args]
ipcMain.emit(
channel,
{},
@@ -242,6 +256,7 @@ export class NTQQApi {
}
// log(uidMaps);
// log("members info", values);
log(`get group ${groupQQ} members success`)
return members
} catch (e) {
log(`get group ${groupQQ} members failed`, e)
@@ -481,4 +496,21 @@ export class NTQQApi {
})
})
}
static async getGroupNotifies() {
// 获取管理员变更
// 加群通知,退出通知,需要管理员权限
await callNTQQApi<GeneralCallResult>({
methodName: ReceiveCmd.GROUP_NOTIFY,
classNameIsRegister: true,
})
return await callNTQQApi<GroupNotify>({
methodName: NTQQApiMethod.GET_GROUP_NOTICE,
cbCmd: ReceiveCmd.GROUP_NOTIFY,
args:[
{"doubt":false,"startSeq":"","number":14},
null
]
});
}
}

View File

@@ -241,3 +241,30 @@ export interface RawMessage {
faceElement: FaceElement;
}[];
}
export enum GroupNotifyTypes{
ADMIN_SET = 8,
ADMIN_UNSET = 12
}
export interface GroupNotify {
doubt: boolean,
nextStartSeq: string,
notifies: [{
seq: string, // 转成数字再除以1000应该就是时间戳
type: GroupNotifyTypes,
status: 0, // 未知
group: { groupCode: string, groupName: string },
user1: { uid: string, nickName: string }, // 被设置管理员的人
user2: { uid: string, nickName: string }, // 操作者
actionUser: { uid: string, nickName: string }, //未知
actionTime: string,
invitationExt: {
srcType: number, // 0?未知
groupCode: string, waitStatus: number
},
postscript: string,
repeatSeqs: [],
warningTips: string
}]
}

View File

@@ -114,7 +114,7 @@ export class OB11Constructor {
message_data["type"] = "reply"
const replyMsg = getHistoryMsgBySeq(element.replyElement.replayMsgSeq)
if (replyMsg) {
message_data["data"]["id"] = replyMsg.msgShortId
message_data["data"]["id"] = replyMsg.msgShortId.toString()
} else {
continue
}

View File

@@ -1,6 +1,7 @@
import {OB11BaseNoticeEvent} from "./OB11BaseNoticeEvent";
import {OB11GroupNoticeEvent} from "./OB11GroupNoticeEvent";
export class OB11GroupAdminNoticeEvent extends OB11BaseNoticeEvent {
export class OB11GroupAdminNoticeEvent extends OB11GroupNoticeEvent {
notice_type = "group_admin"
sub_type: string // "set" | "unset"
sub_type: "set" | "unset" // "set" | "unset"
}

View File

@@ -29,10 +29,10 @@ export function postWsEvent(event: PostEventType) {
}
}
export function postEvent(msg: PostEventType) {
export function postEvent(msg: PostEventType, reportSelf=false) {
const config = getConfigUtil().getConfig();
// 判断msg是否是event
if (!config.reportSelfMessage) {
if (!config.reportSelfMessage && !reportSelf) {
if ((msg as OB11Message).user_id.toString() == selfInfo.uin) {
return
}