feat: 好友请求时间,处理还有请求api

This commit is contained in:
linyuchen 2024-02-25 01:27:25 +08:00
parent cfb066971f
commit 62870576a1
14 changed files with 215 additions and 43 deletions

View File

@ -1,5 +1,5 @@
import {NTQQApi} from '../ntqqapi/ntcall';
import {Friend, Group, GroupMember, GroupNotify, RawMessage, SelfInfo} from "../ntqqapi/types";
import {Friend, FriendRequest, Group, GroupMember, GroupNotify, RawMessage, SelfInfo} from "../ntqqapi/types";
export let groups: Group[] = []
export let friends: Friend[] = []
@ -88,4 +88,5 @@ export function getUidByUin(uin: string) {
export const version = "3.7.0"
export let groupNotifies: Map<string, GroupNotify> = new Map();
export let groupNotifies: Map<string, GroupNotify> = new Map<string, GroupNotify>();
export let friendRequests: Map<number, FriendRequest> = new Map<number, FriendRequest>();

View File

@ -6,19 +6,35 @@ 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, getGroup, getGroupMember, groupNotifies, msgHistory, selfInfo} from "../common/data";
import {
addHistoryMsg,
friendRequests,
getGroup,
getGroupMember,
groupNotifies,
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, GroupMember, GroupNotifies, GroupNotifyTypes, RawMessage} from "../ntqqapi/types";
import {
ChatType,
FriendRequestNotify,
GroupMember,
GroupNotifies,
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 {postOB11Event} from "../onebot11/server/postOB11Event";
import {ob11ReverseWebsockets} from "../onebot11/server/ws/ReverseWebsocket";
import {OB11GroupAdminNoticeEvent} from "../onebot11/event/notice/OB11GroupAdminNoticeEvent";
import {OB11GroupDecreaseEvent} from "../onebot11/event/notice/OB11GroupDecreaseEvent";
import {OB11GroupRequestEvent} from "../onebot11/event/request/OB11GroupRequest";
import {OB11FriendRequestEvent} from "../onebot11/event/request/OB11FriendRequest";
let running = false;
@ -101,7 +117,7 @@ function onLoad() {
if (isSelfMsg && !reportSelfMessage) {
return
}
postEvent(msg);
postOB11Event(msg);
// log("post msg", msg)
}).catch(e => log("constructMessage error: ", e.toString()));
}
@ -126,7 +142,7 @@ function onLoad() {
}
if (message.chatType == ChatType.friend) {
const friendRecallEvent = new OB11FriendRecallNoticeEvent(parseInt(message.senderUin), oriMessage.msgShortId);
postEvent(friendRecallEvent);
postOB11Event(friendRecallEvent);
} else if (message.chatType == ChatType.group) {
let operatorId = message.senderUin
for (const element of message.elements) {
@ -141,7 +157,7 @@ function onLoad() {
oriMessage.msgShortId
)
postEvent(groupRecallEvent);
postOB11Event(groupRecallEvent);
}
continue
}
@ -179,7 +195,9 @@ function onLoad() {
log("获取群通知详情完成", notifies, payload);
try {
for (const notify of notifies) {
if (parseInt(notify.seq) / 1000 < startTime){
const notifyTime = parseInt(notify.seq) / 1000
log(`加群通知时间${notifyTime}`, `LLOneBot启动时间${startTime}`);
if ( notifyTime < startTime){
continue;
}
const member1 = await getGroupMember(notify.group.groupCode, null, notify.user1.uid);
@ -196,7 +214,7 @@ function onLoad() {
log("变动管理员获取成功")
groupAdminNoticeEvent.user_id = parseInt(member1.uin);
groupAdminNoticeEvent.sub_type = notify.type == GroupNotifyTypes.ADMIN_UNSET ? "unset" : "set";
postEvent(groupAdminNoticeEvent, true);
postOB11Event(groupAdminNoticeEvent, true);
}
else{
log("获取群通知的成员信息失败", notify, getGroup(notify.group.groupCode));
@ -214,7 +232,7 @@ function onLoad() {
groupRequestEvent.group_id = parseInt(notify.group.groupCode);
let requestQQ = ""
try {
requestQQ = (await NTQQApi.getUserInfo(notify.user1.uid)).uin;
requestQQ = (await NTQQApi.getUserDetailInfo(notify.user1.uid)).uin;
}catch (e) {
log("获取加群人QQ号失败", e)
}
@ -222,7 +240,7 @@ function onLoad() {
groupRequestEvent.sub_type = "add"
groupRequestEvent.comment = notify.postscript;
groupRequestEvent.flag = notify.seq;
postEvent(groupRequestEvent);
postOB11Event(groupRequestEvent);
}
}
}catch (e) {
@ -230,6 +248,25 @@ function onLoad() {
}
}
})
registerReceiveHook<FriendRequestNotify>(ReceiveCmd.FRIEND_REQUEST, async (payload) => {
for(const req of payload.data.buddyReqs){
if (req.isUnread && !friendRequests[req.sourceId] && (parseInt(req.reqTime) > startTime / 1000)){
friendRequests[req.sourceId] = req;
log("有新的好友请求", req);
let friendRequestEvent = new OB11FriendRequestEvent();
try{
let requester = await NTQQApi.getUserDetailInfo(req.friendUid)
friendRequestEvent.user_id = parseInt(requester.uin);
}catch (e) {
log("获取加好友者QQ号失败", e);
}
friendRequestEvent.flag = req.sourceId.toString();
friendRequestEvent.comment = req.extWords;
postOB11Event(friendRequestEvent);
}
}
})
}
let startTime = 0;
async function start() {

View File

@ -6,7 +6,7 @@ import {addHistoryMsg, friends, groups, msgHistory} from "../common/data";
import {OB11GroupDecreaseEvent} from "../onebot11/event/notice/OB11GroupDecreaseEvent";
import {OB11GroupIncreaseEvent} from "../onebot11/event/notice/OB11GroupIncreaseEvent";
import {v4 as uuidv4} from "uuid"
import {postEvent} from "../onebot11/server/postevent";
import {postOB11Event} from "../onebot11/server/postOB11Event";
import {HOOK_LOG} from "../common/config";
export let hookApiCallbacks: Record<string, (apiReturn: any) => void> = {}
@ -16,12 +16,14 @@ export enum ReceiveCmd {
NEW_MSG = "nodeIKernelMsgListener/onRecvMsg",
SELF_SEND_MSG = "nodeIKernelMsgListener/onAddSendMsg",
USER_INFO = "nodeIKernelProfileListener/onProfileSimpleChanged",
USER_DETAIL_INFO = "nodeIKernelProfileListener/onProfileDetailInfoChanged",
GROUPS = "nodeIKernelGroupListener/onGroupListUpdate",
GROUPS_UNIX = "onGroupListUpdate",
FRIENDS = "onBuddyListChange",
MEDIA_DOWNLOAD_COMPLETE = "nodeIKernelMsgListener/onRichMediaDownloadComplete",
UNREAD_GROUP_NOTIFY = "nodeIKernelGroupListener/onGroupNotifiesUnreadCountUpdated",
GROUP_NOTIFY = "nodeIKernelGroupListener/onGroupSingleScreenNotifies"
GROUP_NOTIFY = "nodeIKernelGroupListener/onGroupSingleScreenNotifies",
FRIEND_REQUEST = "nodeIKernelBuddyListener/onBuddyReqChange"
}
interface NTQQApiReturnData<PayloadType = unknown> extends Array<any> {
@ -159,7 +161,7 @@ async function processGroupEvent(payload) {
for (const member of oldMembers) {
if (!newMembersSet.has(member.uin)) {
postEvent(new OB11GroupDecreaseEvent(group.groupCode, parseInt(member.uin)));
postOB11Event(new OB11GroupDecreaseEvent(group.groupCode, parseInt(member.uin)));
break;
}
}
@ -178,7 +180,7 @@ async function processGroupEvent(payload) {
group.members = newMembers;
for (const member of newMembers) {
if (!oldMembersSet.has(member.uin)) {
postEvent(new OB11GroupIncreaseEvent(group.groupCode, parseInt(member.uin)));
postOB11Event(new OB11GroupIncreaseEvent(group.groupCode, parseInt(member.uin)));
break;
}
}
@ -214,6 +216,7 @@ registerReceiveHook<{ groupList: Group[], updateType: number }>(ReceiveCmd.GROUP
}
}
})
registerReceiveHook<{
data: { categoryId: number, categroyName: string, categroyMbCount: number, buddyList: User[] }[]
}>(ReceiveCmd.FRIENDS, payload => {

View File

@ -3,17 +3,19 @@ import {hookApiCallbacks, ReceiveCmd, registerReceiveHook, removeReceiveHook} fr
import {log} from "../common/utils";
import {
ChatType,
Friend,
Friend, FriendRequest,
Group,
GroupMember,
GroupNotifies, GroupNotify, GroupRequestOperateTypes,
GroupNotifies,
GroupNotify,
GroupRequestOperateTypes,
RawMessage,
SelfInfo,
SendMessageElement,
User
} from "./types";
import * as fs from "fs";
import {addHistoryMsg, groupNotifies, msgHistory, selfInfo} from "../common/data";
import {addHistoryMsg, friendRequests, groupNotifies, msgHistory, selfInfo} from "../common/data";
import {v4 as uuidv4} from "uuid"
interface IPCReceiveEvent {
@ -42,6 +44,7 @@ export enum NTQQApiMethod {
GROUP_MEMBER_SCENE = "nodeIKernelGroupService/createMemberListScene",
GROUP_MEMBERS = "nodeIKernelGroupService/getNextMemberList",
USER_INFO = "nodeIKernelProfileService/getUserSimpleInfo",
USER_DETAIL_INFO = "nodeIKernelProfileService/getUserDetailInfo",
FILE_TYPE = "getFileType",
FILE_MD5 = "getFileMd5",
FILE_COPY = "copyFile",
@ -55,6 +58,8 @@ export enum NTQQApiMethod {
GET_GROUP_NOTICE = "nodeIKernelGroupService/getSingleScreenNotifies",
HANDLE_GROUP_REQUEST = "nodeIKernelGroupService/operateSysNotify",
QUIT_GROUP = "nodeIKernelGroupService/quitGroup",
// READ_FRIEND_REQUEST = "nodeIKernelBuddyListener/onDoubtBuddyReqUnreadNumChange"
HANDLE_FRIEND_REQUEST = "nodeIKernelBuddyService/approvalFriendRequest",
}
enum NTQQApiChannel {
@ -77,6 +82,7 @@ interface NTQQApiParams {
args?: unknown[],
cbCmd?: ReceiveCmd | null,
cmdCB?: (payload: any) => boolean;
afterFirstCmd?: boolean, // 是否在methodName调用完之后再去hook cbCmd
timeoutSecond?: number,
}
@ -84,12 +90,13 @@ function callNTQQApi<ReturnType>(params: NTQQApiParams) {
let {
className, methodName, channel, args,
cbCmd, timeoutSecond: timeout,
classNameIsRegister, cmdCB
classNameIsRegister, cmdCB, afterFirstCmd
} = params;
className = className ?? NTQQApiClass.NT_API;
channel = channel ?? NTQQApiChannel.IPC_UP_2;
args = args ?? [];
timeout = timeout ?? 5;
afterFirstCmd = afterFirstCmd ?? true;
const uuid = uuidv4();
// log("callNTQQApi", channel, className, methodName, args, uuid)
return new Promise((resolve: (data: ReturnType) => void, reject) => {
@ -109,12 +116,10 @@ function callNTQQApi<ReturnType>(params: NTQQApiParams) {
};
} else {
// 这里的callback比较特殊QQ后端先返回是否调用成功再返回一条结果数据
hookApiCallbacks[uuid] = (result: GeneralCallResult) => {
log(`${methodName} callback`, result)
if (result?.result == 0 || result === undefined) {
const secondCallback = () => {
const hookId = registerReceiveHook<ReturnType>(cbCmd, (payload) => {
log(methodName, "second callback", cbCmd, payload);
if (cmdCB) {
// log(methodName, "second callback", cbCmd, payload, cmdCB);
if (!!cmdCB) {
if (cmdCB(payload)) {
removeReceiveHook(hookId);
success = true
@ -126,6 +131,12 @@ function callNTQQApi<ReturnType>(params: NTQQApiParams) {
resolve(payload);
}
})
}
!afterFirstCmd && secondCallback();
hookApiCallbacks[uuid] = (result: GeneralCallResult) => {
log(`${methodName} callback`, result)
if (result?.result == 0 || result === undefined) {
afterFirstCmd && secondCallback();
} else {
success = true
reject(`ntqq api call failed, ${result.errMsg}`);
@ -190,6 +201,26 @@ export class NTQQApi {
return result.profiles.get(uid)
}
static async getUserDetailInfo(uid: string) {
const result = await callNTQQApi<{ info: User }>({
methodName: NTQQApiMethod.USER_DETAIL_INFO,
cbCmd: ReceiveCmd.USER_DETAIL_INFO,
afterFirstCmd: false,
cmdCB: (payload) => {
const success = payload.info.uid == uid
// log("get user detail info", success, uid, payload)
return success
},
args: [
{
uid
},
null
]
})
return result.info
}
static async getFriends(forced = false) {
const data = await callNTQQApi<{
data: {
@ -497,13 +528,14 @@ export class NTQQApi {
static async getGroupNotifies() {
// 获取管理员变更
// 加群通知,退出通知,需要管理员权限
await callNTQQApi<GeneralCallResult>({
callNTQQApi<GeneralCallResult>({
methodName: ReceiveCmd.GROUP_NOTIFY,
classNameIsRegister: true,
})
}).then()
return await callNTQQApi<GroupNotifies>({
methodName: NTQQApiMethod.GET_GROUP_NOTICE,
cbCmd: ReceiveCmd.GROUP_NOTIFY,
afterFirstCmd: false,
args: [
{"doubt": false, "startSeq": "", "number": 14},
null
@ -513,7 +545,7 @@ export class NTQQApi {
static async handleGroupRequest(seq: string, operateType: GroupRequestOperateTypes, reason?: string) {
const notify: GroupNotify = groupNotifies[seq];
if (!notify){
if (!notify) {
throw `${seq}对应的加群通知不存在`
}
return await callNTQQApi<GeneralCallResult>({
@ -536,13 +568,34 @@ export class NTQQApi {
});
}
static async quitGroup(groupQQ: string){
static async quitGroup(groupQQ: string) {
await callNTQQApi<GeneralCallResult>({
methodName: NTQQApiMethod.QUIT_GROUP,
args:[
args: [
{"groupCode": groupQQ},
null
]
})
}
static async handleFriendRequest(sourceId: number, accept: boolean,) {
const request: FriendRequest = friendRequests[sourceId]
if (!request){
throw `sourceId ${sourceId}, 对应的好友请求不存在`
}
const result = await callNTQQApi<GeneralCallResult>({
methodName: NTQQApiMethod.HANDLE_FRIEND_REQUEST,
args: [
{
"approvalInfo": {
"friendUid": request.friendUid,
"reqTime": request.reqTime,
accept
}
}
]
})
delete friendRequests[sourceId];
return result;
}
}

View File

@ -280,3 +280,19 @@ export enum GroupRequestOperateTypes{
approve = 1,
reject = 2
}
export interface FriendRequest{
friendUid: string,
reqTime: string, // 时间戳,秒
extWords: string, // 申请人填写的验证消息
isUnread: boolean,
friendNick: string,
sourceId: number,
groupCode: string
}
export interface FriendRequestNotify{
data: {
unreadNums: number,
buddyReqs: FriendRequest[]
}
}

View File

@ -0,0 +1,28 @@
import BaseAction from "./BaseAction";
import {NTQQApi} from "../../ntqqapi/ntcall";
import {friends} from "../../common/data";
import {ActionName} from "./types";
import {log} from "../../common/utils";
interface Payload{
method: string,
args: any[],
}
export default class Debug extends BaseAction<Payload, any>{
actionName = ActionName.Debug
protected async _handle(payload: Payload): Promise<any> {
log("debug call ntqq api", payload);
const method = NTQQApi[payload.method]
if (!method){
throw `${method} 不存在`
}
const result = method(...payload.args);
if (method.constructor.name === "AsyncFunction"){
return await result
}
return result
// const info = await NTQQApi.getUserDetailInfo(friends[0].uid);
// return info
}
}

View File

@ -0,0 +1,18 @@
import BaseAction from "./BaseAction";
import {NTQQApi} from "../../ntqqapi/ntcall";
import {ActionName} from "./types";
interface Payload {
flag: string,
approve: boolean,
remark?: string,
}
export default class SetFriendAddRequest extends BaseAction<Payload, null> {
actionName = ActionName.SetFriendAddRequest;
protected async _handle(payload: Payload): Promise<null> {
await NTQQApi.handleFriendRequest(parseInt(payload.flag), payload.approve)
return null;
}
}

View File

@ -20,8 +20,11 @@ import SendLike from "./SendLike";
import SetGroupAddRequest from "./SetGroupAddRequest";
import SetGroupLeave from "./SetGroupLeave";
import GetGuildList from "./GetGuildList";
import Debug from "./Debug";
import SetFriendAddRequest from "./SetFriendAddRequest";
export const actionHandlers = [
new Debug(),
new SendLike(),
new GetMsg(),
new GetLoginInfo(),
@ -30,6 +33,7 @@ export const actionHandlers = [
new SendGroupMsg(), new SendPrivateMsg(), new SendMsg(),
new DeleteMsg(),
new SetGroupAddRequest(),
new SetFriendAddRequest(),
new SetGroupLeave(),
new GetVersionInfo(),
new CanSendRecord(),

View File

@ -14,7 +14,7 @@ export interface InvalidCheckResult {
}
export enum ActionName {
TestForwardMsg = "test_forward_msg",
Debug = "llonebot_debug",
SendLike = "send_like",
GetLoginInfo = "get_login_info",
GetFriendList = "get_friend_list",
@ -28,6 +28,7 @@ export enum ActionName {
SendPrivateMsg = "send_private_msg",
DeleteMsg = "delete_msg",
SetGroupAddRequest = "set_group_add_request",
SetFriendAddRequest = "set_friend_add_request",
SetGroupLeave = "set_group_leave",
GetVersionInfo = "get_version_info",
GetStatus = "get_status",

View File

@ -0,0 +1,11 @@
import {OB11BaseNoticeEvent} from "../notice/OB11BaseNoticeEvent";
import {EventType} from "../OB11BaseEvent";
export class OB11FriendRequestEvent extends OB11BaseNoticeEvent {
post_type = EventType.REQUEST
user_id: number;
request_type: "friend" = "friend";
comment: string;
flag: string;
}

View File

@ -29,7 +29,7 @@ export function postWsEvent(event: PostEventType) {
}
}
export function postEvent(msg: PostEventType, reportSelf=false) {
export function postOB11Event(msg: PostEventType, reportSelf=false) {
const config = getConfigUtil().getConfig();
// 判断msg是否是event
if (!config.reportSelfMessage && !reportSelf) {

View File

@ -7,7 +7,7 @@ import {ActionName} from "../../action/types";
import {OB11Response} from "../../action/utils";
import BaseAction from "../../action/BaseAction";
import {actionMap} from "../../action";
import {registerWsEventSender, unregisterWsEventSender} from "../postevent";
import {registerWsEventSender, unregisterWsEventSender} from "../postOB11Event";
import {wsReply} from "./reply";
export let rwsList: ReverseWebsocket[] = [];

View File

@ -2,7 +2,7 @@ import {WebSocket} from "ws";
import {getConfigUtil, log} from "../../../common/utils";
import {actionMap} from "../../action";
import {OB11Response} from "../../action/utils";
import {postWsEvent, registerWsEventSender, unregisterWsEventSender} from "../postevent";
import {postWsEvent, registerWsEventSender, unregisterWsEventSender} from "../postOB11Event";
import {ActionName} from "../../action/types";
import BaseAction from "../../action/BaseAction";
import {LifeCycleSubType, OB11LifeCycleEvent} from "../../event/meta/OB11LifeCycleEvent";

View File

@ -1,6 +1,6 @@
import * as websocket from "ws";
import {OB11Response} from "../../action/utils";
import {PostEventType} from "../postevent";
import {PostEventType} from "../postOB11Event";
import {isNull, log} from "../../../common/utils";
export function wsReply(wsClient: websocket.WebSocket, data: OB11Response | PostEventType) {