style: format

This commit is contained in:
linyuchen
2024-03-03 00:22:07 +08:00
parent f7b9d599c3
commit d1e4135442
55 changed files with 5229 additions and 3088 deletions

View File

@@ -1,71 +1,71 @@
import {BrowserWindow} from 'electron';
import {getConfigUtil, log, sleep} from "../common/utils";
import {NTQQApi, NTQQApiClass, sendMessagePool} from "./ntcall";
import {Group, RawMessage, User} from "./types";
import {addHistoryMsg, friends, groups, msgHistory, selfInfo} from "../common/data";
import {OB11GroupDecreaseEvent} from "../onebot11/event/notice/OB11GroupDecreaseEvent";
import {OB11GroupIncreaseEvent} from "../onebot11/event/notice/OB11GroupIncreaseEvent";
import {v4 as uuidv4} from "uuid"
import {postOB11Event} from "../onebot11/server/postOB11Event";
import {HOOK_LOG} from "../common/config";
import fs from "fs";
import {type BrowserWindow} from 'electron'
import {getConfigUtil, log, sleep} from '../common/utils'
import {NTQQApi, type NTQQApiClass, sendMessagePool} from './ntcall'
import {type Group, type RawMessage, type User} from './types'
import {addHistoryMsg, friends, groups, msgHistory, selfInfo} from '../common/data'
import {OB11GroupDecreaseEvent} from '../onebot11/event/notice/OB11GroupDecreaseEvent'
import {OB11GroupIncreaseEvent} from '../onebot11/event/notice/OB11GroupIncreaseEvent'
import {v4 as uuidv4} from 'uuid'
import {postOB11Event} from '../onebot11/server/postOB11Event'
import {HOOK_LOG} from '../common/config'
import fs from 'fs'
export let hookApiCallbacks: Record<string, (apiReturn: any) => void> = {}
export const hookApiCallbacks: Record<string, (apiReturn: any) => void> = {}
export enum ReceiveCmd {
UPDATE_MSG = "nodeIKernelMsgListener/onMsgInfoListUpdate",
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",
FRIEND_REQUEST = "nodeIKernelBuddyListener/onBuddyReqChange",
SELF_STATUS = "nodeIKernelProfileListener/onSelfStatusChanged",
UPDATE_MSG = 'nodeIKernelMsgListener/onMsgInfoListUpdate',
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',
FRIEND_REQUEST = 'nodeIKernelBuddyListener/onBuddyReqChange',
SELF_STATUS = 'nodeIKernelProfileListener/onSelfStatusChanged',
}
interface NTQQApiReturnData<PayloadType = unknown> extends Array<any> {
0: {
"type": "request",
"eventName": NTQQApiClass,
"callbackId"?: string
},
'type': 'request'
'eventName': NTQQApiClass
'callbackId'?: string
}
1:
{
cmdName: ReceiveCmd,
cmdType: "event",
Array<{
cmdName: ReceiveCmd
cmdType: 'event'
payload: PayloadType
}[]
}>
}
let receiveHooks: Array<{
method: ReceiveCmd,
const receiveHooks: Array<{
method: ReceiveCmd
hookFunc: ((payload: any) => void | Promise<void>)
id: string
}> = []
export function hookNTQQApiReceive(window: BrowserWindow) {
const originalSend = window.webContents.send;
const originalSend = window.webContents.send
const patchSend = (channel: string, ...args: NTQQApiReturnData) => {
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;
for (const receiveData of args?.[1]) {
const ntQQApiMethodName = receiveData.cmdName
// log(`received ntqq api message: ${channel} ${ntQQApiMethodName}`, JSON.stringify(receiveData))
for (let hook of receiveHooks) {
for (const hook of receiveHooks) {
if (hook.method === ntQQApiMethodName) {
new Promise((resolve, reject) => {
try {
let _ = hook.hookFunc(receiveData.payload)
if (hook.hookFunc.constructor.name === "AsyncFunction") {
const _ = hook.hookFunc(receiveData.payload)
if (hook.hookFunc.constructor.name === 'AsyncFunction') {
(_ as Promise<void>).then()
}
} catch (e) {
log("hook error", e, receiveData.payload)
log('hook error', e, receiveData.payload)
}
}).then()
}
@@ -74,35 +74,35 @@ export function hookNTQQApiReceive(window: BrowserWindow) {
}
if (args[0]?.callbackId) {
// log("hookApiCallback", hookApiCallbacks, args)
const callbackId = args[0].callbackId;
const callbackId = args[0].callbackId
if (hookApiCallbacks[callbackId]) {
// log("callback found")
new Promise((resolve, reject) => {
hookApiCallbacks[callbackId](args[1]);
hookApiCallbacks[callbackId](args[1])
}).then()
delete hookApiCallbacks[callbackId];
delete hookApiCallbacks[callbackId]
}
}
return originalSend.call(window.webContents, channel, ...args);
return originalSend.call(window.webContents, channel, ...args)
}
window.webContents.send = patchSend;
window.webContents.send = patchSend
}
export function hookNTQQApiCall(window: BrowserWindow) {
// 监听调用NTQQApi
let webContents = window.webContents as any;
const ipc_message_proxy = webContents._events["-ipc-message"]?.[0] || webContents._events["-ipc-message"];
const webContents = window.webContents as any
const ipc_message_proxy = webContents._events['-ipc-message']?.[0] || webContents._events['-ipc-message']
const proxyIpcMsg = new Proxy(ipc_message_proxy, {
apply(target, 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;
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;
webContents._events['-ipc-message'] = proxyIpcMsg
}
}
@@ -113,29 +113,29 @@ export function registerReceiveHook<PayloadType>(method: ReceiveCmd, hookFunc: (
hookFunc,
id
})
return id;
return id
}
export function removeReceiveHook(id: string) {
const index = receiveHooks.findIndex(h => h.id === id)
receiveHooks.splice(index, 1);
receiveHooks.splice(index, 1)
}
async function updateGroups(_groups: Group[], needUpdate: boolean = true) {
for (let group of _groups) {
let existGroup = groups.find(g => g.groupCode == group.groupCode);
for (const group of _groups) {
let existGroup = groups.find(g => g.groupCode == group.groupCode)
if (existGroup) {
Object.assign(existGroup, group);
Object.assign(existGroup, group)
} else {
groups.push(group);
existGroup = group;
groups.push(group)
existGroup = group
}
if (needUpdate) {
const members = await NTQQApi.getGroupMembers(group.groupCode);
const members = await NTQQApi.getGroupMembers(group.groupCode)
if (members) {
existGroup.members = members;
existGroup.members = members
}
}
}
@@ -143,84 +143,83 @@ async function updateGroups(_groups: Group[], needUpdate: boolean = true) {
async function processGroupEvent(payload) {
try {
const newGroupList = payload.groupList;
const newGroupList = payload.groupList
for (const group of newGroupList) {
let existGroup = groups.find(g => g.groupCode == group.groupCode);
const existGroup = groups.find(g => g.groupCode == group.groupCode)
if (existGroup) {
if (existGroup.memberCount > group.memberCount) {
const oldMembers = existGroup.members;
const oldMembers = existGroup.members
await sleep(200); // 如果请求QQ API的速度过快通常无法正确拉取到最新的群信息因此这里人为引入一个延时
const newMembers = await NTQQApi.getGroupMembers(group.groupCode);
await sleep(200) // 如果请求QQ API的速度过快通常无法正确拉取到最新的群信息因此这里人为引入一个延时
const newMembers = await NTQQApi.getGroupMembers(group.groupCode)
group.members = newMembers;
const newMembersSet = new Set<string>(); // 建立索引降低时间复杂度
group.members = newMembers
const newMembersSet = new Set<string>() // 建立索引降低时间复杂度
for (const member of newMembers) {
newMembersSet.add(member.uin);
newMembersSet.add(member.uin)
}
for (const member of oldMembers) {
if (!newMembersSet.has(member.uin)) {
postOB11Event(new OB11GroupDecreaseEvent(group.groupCode, parseInt(member.uin)));
break;
postOB11Event(new OB11GroupDecreaseEvent(group.groupCode, parseInt(member.uin)))
break
}
}
} else if (existGroup.memberCount < group.memberCount) {
const oldMembers = existGroup.members;
const oldMembersSet = new Set<string>();
const oldMembers = existGroup.members
const oldMembersSet = new Set<string>()
for (const member of oldMembers) {
oldMembersSet.add(member.uin);
oldMembersSet.add(member.uin)
}
await sleep(200);
const newMembers = await NTQQApi.getGroupMembers(group.groupCode);
await sleep(200)
const newMembers = await NTQQApi.getGroupMembers(group.groupCode)
group.members = newMembers;
group.members = newMembers
for (const member of newMembers) {
if (!oldMembersSet.has(member.uin)) {
postOB11Event(new OB11GroupIncreaseEvent(group.groupCode, parseInt(member.uin)));
break;
postOB11Event(new OB11GroupIncreaseEvent(group.groupCode, parseInt(member.uin)))
break
}
}
}
}
}
updateGroups(newGroupList, false).then();
updateGroups(newGroupList, false).then()
} catch (e) {
updateGroups(payload.groupList).then();
console.log(e);
updateGroups(payload.groupList).then()
console.log(e)
}
}
registerReceiveHook<{ groupList: Group[], updateType: number }>(ReceiveCmd.GROUPS, (payload) => {
if (payload.updateType != 2) {
updateGroups(payload.groupList).then();
updateGroups(payload.groupList).then()
} else {
if (process.platform == "win32") {
processGroupEvent(payload).then();
if (process.platform == 'win32') {
processGroupEvent(payload).then()
}
}
})
registerReceiveHook<{ groupList: Group[], updateType: number }>(ReceiveCmd.GROUPS_UNIX, (payload) => {
if (payload.updateType != 2) {
updateGroups(payload.groupList).then();
updateGroups(payload.groupList).then()
} else {
if (process.platform != "win32") {
processGroupEvent(payload).then();
if (process.platform != 'win32') {
processGroupEvent(payload).then()
}
}
})
registerReceiveHook<{
data: { categoryId: number, categroyName: string, categroyMbCount: number, buddyList: User[] }[]
data: Array<{ categoryId: number, categroyName: string, categroyMbCount: number, buddyList: User[] }>
}>(ReceiveCmd.FRIENDS, payload => {
for (const fData of payload.data) {
const _friends = fData.buddyList;
for (let friend of _friends) {
let existFriend = friends.find(f => f.uin == friend.uin)
const _friends = fData.buddyList
for (const friend of _friends) {
const existFriend = friends.find(f => f.uin == friend.uin)
if (!existFriend) {
friends.push(friend)
} else {
@@ -230,8 +229,8 @@ registerReceiveHook<{
}
})
registerReceiveHook<{ msgList: Array<RawMessage> }>(ReceiveCmd.NEW_MSG, (payload) => {
const {autoDeleteFile, autoDeleteFileSecond} = getConfigUtil().getConfig();
registerReceiveHook<{ msgList: RawMessage[] }>(ReceiveCmd.NEW_MSG, (payload) => {
const {autoDeleteFile, autoDeleteFileSecond} = getConfigUtil().getConfig()
for (const message of payload.msgList) {
// log("收到新消息push到历史记录", message)
addHistoryMsg(message)
@@ -241,43 +240,43 @@ registerReceiveHook<{ msgList: Array<RawMessage> }>(ReceiveCmd.NEW_MSG, (payload
}
for (const msgElement of message.elements) {
setTimeout(() => {
const picPath = msgElement.picElement?.sourcePath;
const pttPath = msgElement.pttElement?.filePath;
const pathList = [picPath, pttPath];
if (msgElement.picElement){
pathList.push(...Object.values(msgElement.picElement.thumbPath));
const picPath = msgElement.picElement?.sourcePath
const pttPath = msgElement.pttElement?.filePath
const pathList = [picPath, pttPath]
if (msgElement.picElement) {
pathList.push(...Object.values(msgElement.picElement.thumbPath))
}
// log("需要清理的文件", pathList);
for (const path of pathList) {
if (path) {
fs.unlink(picPath, () => {
log("删除文件成功", path)
});
log('删除文件成功', path)
})
}
}
}, autoDeleteFileSecond * 1000)
}
}
const msgIds = Object.keys(msgHistory);
const msgIds = Object.keys(msgHistory)
if (msgIds.length > 30000) {
delete msgHistory[msgIds.sort()[0]]
}
})
registerReceiveHook<{ msgRecord: RawMessage }>(ReceiveCmd.SELF_SEND_MSG, ({msgRecord}) => {
const message = msgRecord;
const peerUid = message.peerUid;
const message = msgRecord
const peerUid = message.peerUid
// log("收到自己发送成功的消息", Object.keys(sendMessagePool), message);
const sendCallback = sendMessagePool[peerUid];
const sendCallback = sendMessagePool[peerUid]
if (sendCallback) {
try {
sendCallback(message);
sendCallback(message)
} catch (e) {
log("receive self msg error", e.stack)
log('receive self msg error', e.stack)
}
}
})
registerReceiveHook<{info: {status: number}}>(ReceiveCmd.SELF_STATUS, (info)=>{
selfInfo.online = info.info.status !== 20;
})
registerReceiveHook<{ info: { status: number } }>(ReceiveCmd.SELF_STATUS, (info) => {
selfInfo.online = info.info.status !== 20
})

View File

@@ -1,26 +1,25 @@
import {ipcMain} from "electron";
import {hookApiCallbacks, ReceiveCmd, registerReceiveHook, removeReceiveHook} from "./hook";
import {log, sleep} from "../common/utils";
import {ipcMain} from 'electron'
import {hookApiCallbacks, ReceiveCmd, registerReceiveHook, removeReceiveHook} from './hook'
import {log, sleep} from '../common/utils'
import {
ChatType,
type ChatType,
ElementType,
Friend,
FriendRequest,
Group,
GroupMember,
GroupMemberRole,
GroupNotifies,
GroupNotify,
GroupRequestOperateTypes,
RawMessage,
SelfInfo,
SendMessageElement,
User
} from "./types";
import * as fs from "node:fs";
import {addHistoryMsg, friendRequests, groupNotifies, msgHistory, selfInfo} from "../common/data";
import {v4 as uuidv4} from "uuid"
import path from "path";
type Friend,
type FriendRequest,
type Group, GroupMember,
type GroupMemberRole,
type GroupNotifies,
type GroupNotify,
type GroupRequestOperateTypes,
type RawMessage,
type SelfInfo,
type SendMessageElement,
type User
} from './types'
import * as fs from 'node:fs'
import {addHistoryMsg, friendRequests, groupNotifies, msgHistory, selfInfo} from '../common/data'
import {v4 as uuidv4} from 'uuid'
import path from 'path'
interface IPCReceiveEvent {
eventName: string
@@ -35,88 +34,88 @@ export type IPCReceiveDetail = [
]
export enum NTQQApiClass {
NT_API = "ns-ntApi",
FS_API = "ns-FsApi",
GLOBAL_DATA = "ns-GlobalDataApi"
NT_API = 'ns-ntApi',
FS_API = 'ns-FsApi',
GLOBAL_DATA = 'ns-GlobalDataApi'
}
export enum NTQQApiMethod {
LIKE_FRIEND = "nodeIKernelProfileLikeService/setBuddyProfileLike",
SELF_INFO = "fetchAuthData",
FRIENDS = "nodeIKernelBuddyService/getBuddyList",
GROUPS = "nodeIKernelGroupService/getGroupList",
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",
IMAGE_SIZE = "getImageSizeFromPath",
FILE_SIZE = "getFileSize",
MEDIA_FILE_PATH = "nodeIKernelMsgService/getRichMediaFilePathForGuild",
RECALL_MSG = "nodeIKernelMsgService/recallMsg",
SEND_MSG = "nodeIKernelMsgService/sendMsg",
DOWNLOAD_MEDIA = "nodeIKernelMsgService/downloadRichMedia",
MULTI_FORWARD_MSG = "nodeIKernelMsgService/multiForwardMsgWithComment", // 合并转发
GET_GROUP_NOTICE = "nodeIKernelGroupService/getSingleScreenNotifies",
HANDLE_GROUP_REQUEST = "nodeIKernelGroupService/operateSysNotify",
QUIT_GROUP = "nodeIKernelGroupService/quitGroup",
LIKE_FRIEND = 'nodeIKernelProfileLikeService/setBuddyProfileLike',
SELF_INFO = 'fetchAuthData',
FRIENDS = 'nodeIKernelBuddyService/getBuddyList',
GROUPS = 'nodeIKernelGroupService/getGroupList',
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',
IMAGE_SIZE = 'getImageSizeFromPath',
FILE_SIZE = 'getFileSize',
MEDIA_FILE_PATH = 'nodeIKernelMsgService/getRichMediaFilePathForGuild',
RECALL_MSG = 'nodeIKernelMsgService/recallMsg',
SEND_MSG = 'nodeIKernelMsgService/sendMsg',
DOWNLOAD_MEDIA = 'nodeIKernelMsgService/downloadRichMedia',
MULTI_FORWARD_MSG = 'nodeIKernelMsgService/multiForwardMsgWithComment', // 合并转发
GET_GROUP_NOTICE = 'nodeIKernelGroupService/getSingleScreenNotifies',
HANDLE_GROUP_REQUEST = 'nodeIKernelGroupService/operateSysNotify',
QUIT_GROUP = 'nodeIKernelGroupService/quitGroup',
// READ_FRIEND_REQUEST = "nodeIKernelBuddyListener/onDoubtBuddyReqUnreadNumChange"
HANDLE_FRIEND_REQUEST = "nodeIKernelBuddyService/approvalFriendRequest",
KICK_MEMBER = "nodeIKernelGroupService/kickMember",
MUTE_MEMBER = "nodeIKernelGroupService/setMemberShutUp",
MUTE_GROUP = "nodeIKernelGroupService/setGroupShutUp",
SET_MEMBER_CARD = "nodeIKernelGroupService/modifyMemberCardName",
SET_MEMBER_ROLE = "nodeIKernelGroupService/modifyMemberRole",
PUBLISH_GROUP_BULLETIN = "nodeIKernelGroupService/publishGroupBulletinBulletin",
SET_GROUP_NAME = "nodeIKernelGroupService/modifyGroupName",
HANDLE_FRIEND_REQUEST = 'nodeIKernelBuddyService/approvalFriendRequest',
KICK_MEMBER = 'nodeIKernelGroupService/kickMember',
MUTE_MEMBER = 'nodeIKernelGroupService/setMemberShutUp',
MUTE_GROUP = 'nodeIKernelGroupService/setGroupShutUp',
SET_MEMBER_CARD = 'nodeIKernelGroupService/modifyMemberCardName',
SET_MEMBER_ROLE = 'nodeIKernelGroupService/modifyMemberRole',
PUBLISH_GROUP_BULLETIN = 'nodeIKernelGroupService/publishGroupBulletinBulletin',
SET_GROUP_NAME = 'nodeIKernelGroupService/modifyGroupName',
}
enum NTQQApiChannel {
IPC_UP_2 = "IPC_UP_2",
IPC_UP_3 = "IPC_UP_3",
IPC_UP_1 = "IPC_UP_1",
IPC_UP_2 = 'IPC_UP_2',
IPC_UP_3 = 'IPC_UP_3',
IPC_UP_1 = 'IPC_UP_1',
}
export interface Peer {
chatType: ChatType
peerUid: string // 如果是群聊uid为群号私聊uid就是加密的字符串
guildId?: ""
peerUid: string // 如果是群聊uid为群号私聊uid就是加密的字符串
guildId?: ''
}
interface NTQQApiParams {
methodName: NTQQApiMethod | string,
className?: NTQQApiClass,
channel?: NTQQApiChannel,
methodName: NTQQApiMethod | string
className?: NTQQApiClass
channel?: NTQQApiChannel
classNameIsRegister?: boolean
args?: unknown[],
cbCmd?: ReceiveCmd | null,
cmdCB?: (payload: any) => boolean;
afterFirstCmd?: boolean, // 是否在methodName调用完之后再去hook cbCmd
timeoutSecond?: number,
args?: unknown[]
cbCmd?: ReceiveCmd | null
cmdCB?: (payload: any) => boolean
afterFirstCmd?: boolean // 是否在methodName调用完之后再去hook cbCmd
timeoutSecond?: number
}
function callNTQQApi<ReturnType>(params: NTQQApiParams) {
async function callNTQQApi<ReturnType>(params: NTQQApiParams) {
let {
className, methodName, channel, args,
cbCmd, timeoutSecond: timeout,
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();
} = 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) => {
return await new Promise((resolve: (data: ReturnType) => void, reject) => {
// log("callNTQQApiPromise", channel, className, methodName, args, uuid)
const _timeout = timeout * 1000
let success = false
let eventName = className + "-" + channel[channel.length - 1];
let eventName = className + '-' + channel[channel.length - 1]
if (classNameIsRegister) {
eventName += "-register";
eventName += '-register'
}
const apiArgs = [methodName, ...args]
if (!cbCmd) {
@@ -124,40 +123,40 @@ function callNTQQApi<ReturnType>(params: NTQQApiParams) {
hookApiCallbacks[uuid] = (r: ReturnType) => {
success = true
resolve(r)
};
}
} else {
// 这里的callback比较特殊QQ后端先返回是否调用成功再返回一条结果数据
const secondCallback = () => {
const hookId = registerReceiveHook<ReturnType>(cbCmd, (payload) => {
// log(methodName, "second callback", cbCmd, payload, cmdCB);
if (!!cmdCB) {
if (cmdCB) {
if (cmdCB(payload)) {
removeReceiveHook(hookId);
removeReceiveHook(hookId)
success = true
resolve(payload);
resolve(payload)
}
} else {
removeReceiveHook(hookId);
removeReceiveHook(hookId)
success = true
resolve(payload);
resolve(payload)
}
})
}
!afterFirstCmd && secondCallback();
!afterFirstCmd && secondCallback()
hookApiCallbacks[uuid] = (result: GeneralCallResult) => {
log(`${methodName} callback`, result)
if (result?.result == 0 || result === undefined) {
afterFirstCmd && secondCallback();
afterFirstCmd && secondCallback()
} else {
success = true
reject(`ntqq api call failed, ${result.errMsg}`);
reject(`ntqq api call failed, ${result.errMsg}`)
}
}
}
setTimeout(() => {
// log("ntqq api timeout", success, channel, className, methodName)
if (!success) {
log(`ntqq api timeout ${channel}, ${eventName}, ${methodName}`, apiArgs);
log(`ntqq api timeout ${channel}, ${eventName}, ${methodName}`, apiArgs)
reject(`ntqq api timeout ${channel}, ${eventName}, ${methodName}, ${apiArgs}`)
}
}, _timeout)
@@ -171,19 +170,17 @@ function callNTQQApi<ReturnType>(params: NTQQApiParams) {
})
}
export let sendMessagePool: Record<string, ((sendSuccessMsg: RawMessage) => void) | null> = {}// peerUid: callbackFunnc
export const sendMessagePool: Record<string, ((sendSuccessMsg: RawMessage) => void) | null> = {}// peerUid: callbackFunnc
interface GeneralCallResult {
result: number, // 0: success
result: number // 0: success
errMsg: string
}
export class NTQQApi {
// static likeFriend = defineNTQQApi<void>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.LIKE_FRIEND)
static likeFriend(uid: string, count = 1) {
return callNTQQApi<GeneralCallResult>({
static async likeFriend(uid: string, count = 1) {
return await callNTQQApi<GeneralCallResult>({
methodName: NTQQApiMethod.LIKE_FRIEND,
args: [{
doLikeUserInfo: {
@@ -196,10 +193,12 @@ export class NTQQApi {
})
}
static getSelfInfo() {
return callNTQQApi<SelfInfo>({
static async getSelfInfo() {
return await callNTQQApi<SelfInfo>({
className: NTQQApiClass.GLOBAL_DATA,
methodName: NTQQApiMethod.SELF_INFO, timeoutSecond: 2
// channel: NTQQApiChannel.IPC_UP_3,
methodName: NTQQApiMethod.SELF_INFO,
timeoutSecond: 2
})
}
@@ -234,19 +233,19 @@ export class NTQQApi {
static async getFriends(forced = false) {
const data = await callNTQQApi<{
data: {
categoryId: number,
categroyName: string,
categroyMbCount: number,
data: Array<{
categoryId: number
categroyName: string
categroyMbCount: number
buddyList: Friend[]
}[]
}>
}>(
{
methodName: NTQQApiMethod.FRIENDS,
args: [{force_update: forced}, undefined],
cbCmd: ReceiveCmd.FRIENDS
})
let _friends: Friend[] = [];
const _friends: Friend[] = []
for (const fData of data.data) {
_friends.push(...fData.buddyList)
}
@@ -255,22 +254,22 @@ export class NTQQApi {
static async getGroups(forced = false) {
let cbCmd = ReceiveCmd.GROUPS
if (process.platform != "win32") {
if (process.platform != 'win32') {
cbCmd = ReceiveCmd.GROUPS_UNIX
}
const result = await callNTQQApi<{
updateType: number,
updateType: number
groupList: Group[]
}>({methodName: NTQQApiMethod.GROUPS, args: [{force_update: forced}, undefined], cbCmd})
return result.groupList
}
static async getGroupMembers(groupQQ: string, num = 3000) {
static async getGroupMembers(groupQQ: string, num = 3000): Promise<GroupMember[]> {
const sceneId = await callNTQQApi({
methodName: NTQQApiMethod.GROUP_MEMBER_SCENE,
args: [{
groupCode: groupQQ,
scene: "groupMemberList_MainWindow"
scene: 'groupMemberList_MainWindow'
}]
})
// log("get group member sceneId", sceneId);
@@ -280,16 +279,16 @@ export class NTQQApi {
}>({
methodName: NTQQApiMethod.GROUP_MEMBERS,
args: [{
sceneId: sceneId,
num: num
sceneId,
num
},
null
]
})
// log("members info", typeof result.result.infos, Object.keys(result.result.infos))
let values = result.result.infos.values()
const values = result.result.infos.values()
let members = Array.from(values) as GroupMember[]
const members: GroupMember[] = Array.from(values)
for (const member of members) {
// uidMaps[member.uid] = member.uin;
}
@@ -303,73 +302,74 @@ export class NTQQApi {
}
}
static getFileType(filePath: string) {
return callNTQQApi<{ ext: string }>({
static async getFileType(filePath: string) {
return await callNTQQApi<{ ext: string }>({
className: NTQQApiClass.FS_API, methodName: NTQQApiMethod.FILE_TYPE, args: [filePath]
})
}
static getFileMd5(filePath: string) {
return callNTQQApi<string>({
static async getFileMd5(filePath: string) {
return await callNTQQApi<string>({
className: NTQQApiClass.FS_API,
methodName: NTQQApiMethod.FILE_MD5,
args: [filePath]
})
}
static copyFile(filePath: string, destPath: string) {
return callNTQQApi<string>({
className: NTQQApiClass.FS_API, methodName: NTQQApiMethod.FILE_COPY, args: [{
static async copyFile(filePath: string, destPath: string) {
return await callNTQQApi<string>({
className: NTQQApiClass.FS_API,
methodName: NTQQApiMethod.FILE_COPY,
args: [{
fromPath: filePath,
toPath: destPath
}]
})
}
static getImageSize(filePath: string) {
return callNTQQApi<{ width: number, height: number }>({
static async getImageSize(filePath: string) {
return await callNTQQApi<{ width: number, height: number }>({
className: NTQQApiClass.FS_API, methodName: NTQQApiMethod.IMAGE_SIZE, args: [filePath]
})
}
static getFileSize(filePath: string) {
return callNTQQApi<number>({
static async getFileSize(filePath: string) {
return await callNTQQApi<number>({
className: NTQQApiClass.FS_API, methodName: NTQQApiMethod.FILE_SIZE, args: [filePath]
})
}
// 上传文件到QQ的文件夹
static async uploadFile(filePath: string, elementType: ElementType = ElementType.PIC) {
const md5 = await NTQQApi.getFileMd5(filePath);
const md5 = await NTQQApi.getFileMd5(filePath)
let ext = (await NTQQApi.getFileType(filePath))?.ext
if (ext) {
ext = "." + ext
ext = '.' + ext
} else {
ext = ""
ext = ''
}
let fileName = `${path.basename(filePath)}`;
if (fileName.indexOf(".") === -1) {
fileName += ext;
let fileName = `${path.basename(filePath)}`
if (!fileName.includes('.')) {
fileName += ext
}
const mediaPath = await callNTQQApi<string>({
methodName: NTQQApiMethod.MEDIA_FILE_PATH,
args: [{
path_info: {
md5HexStr: md5,
fileName: fileName,
elementType: elementType,
fileName,
elementType,
elementSubType: 0,
thumbSize: 0,
needCreate: true,
downloadType: 1,
file_uuid: ""
file_uuid: ''
}
}]
})
log("media path", mediaPath)
await NTQQApi.copyFile(filePath, mediaPath);
const fileSize = await NTQQApi.getFileSize(filePath);
log('media path', mediaPath)
await NTQQApi.copyFile(filePath, mediaPath)
const fileSize = await NTQQApi.getFileSize(filePath)
return {
md5,
fileName,
@@ -386,16 +386,16 @@ export class NTQQApi {
const apiParams = [
{
getReq: {
msgId: msgId,
chatType: chatType,
peerUid: peerUid,
elementId: elementId,
msgId,
chatType,
peerUid,
elementId,
thumbSize: 0,
downloadType: 1,
filePath: thumbPath,
},
filePath: thumbPath
}
},
undefined,
undefined
]
// log("需要下载media", sourcePath);
await callNTQQApi({
@@ -404,15 +404,16 @@ export class NTQQApi {
cbCmd: ReceiveCmd.MEDIA_DOWNLOAD_COMPLETE,
cmdCB: (payload: { notifyInfo: { filePath: string } }) => {
// log("media 下载完成判断", payload.notifyInfo.filePath, sourcePath);
return payload.notifyInfo.filePath == sourcePath;
return payload.notifyInfo.filePath == sourcePath
}
})
return sourcePath
}
static recallMsg(peer: Peer, msgIds: string[]) {
return callNTQQApi({
methodName: NTQQApiMethod.RECALL_MSG, args: [{
static async recallMsg(peer: Peer, msgIds: string[]) {
return await callNTQQApi({
methodName: NTQQApiMethod.RECALL_MSG,
args: [{
peer,
msgIds
}, null]
@@ -420,43 +421,43 @@ export class NTQQApi {
}
static async sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete = false, timeout = 10000) {
const peerUid = peer.peerUid;
const peerUid = peer.peerUid
// 等待上一个相同的peer发送完
let checkLastSendUsingTime = 0;
let checkLastSendUsingTime = 0
const waitLastSend = async () => {
if (checkLastSendUsingTime > timeout) {
throw ("发送超时")
throw ('发送超时')
}
let lastSending = sendMessagePool[peer.peerUid]
const lastSending = sendMessagePool[peer.peerUid]
if (lastSending) {
// log("有正在发送的消息,等待中...")
await sleep(500);
checkLastSendUsingTime += 500;
return await waitLastSend();
await sleep(500)
checkLastSendUsingTime += 500
return await waitLastSend()
} else {
return;
}
}
await waitLastSend();
await waitLastSend()
let sentMessage: RawMessage = null;
let sentMessage: RawMessage = null
sendMessagePool[peerUid] = async (rawMessage: RawMessage) => {
delete sendMessagePool[peerUid];
sentMessage = rawMessage;
delete sendMessagePool[peerUid]
sentMessage = rawMessage
}
let checkSendCompleteUsingTime = 0;
let checkSendCompleteUsingTime = 0
const checkSendComplete = async (): Promise<RawMessage> => {
if (sentMessage && msgHistory[sentMessage.msgId]?.sendStatus == 2) {
// log(`给${peerUid}发送消息成功`)
return sentMessage;
return sentMessage
} else {
checkSendCompleteUsingTime += 500;
checkSendCompleteUsingTime += 500
if (checkSendCompleteUsingTime > timeout) {
throw ("发送超时")
throw ('发送超时')
}
await sleep(500);
await sleep(500)
return await checkSendComplete()
}
}
@@ -464,16 +465,17 @@ export class NTQQApi {
callNTQQApi({
methodName: NTQQApiMethod.SEND_MSG,
args: [{
msgId: "0",
peer, msgElements,
msgAttributeInfos: new Map(),
msgId: '0',
peer,
msgElements,
msgAttributeInfos: new Map()
}, null]
}).then()
return checkSendComplete();
return await checkSendComplete()
}
static multiForwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]) {
let msgInfos = msgIds.map(id => {
static async multiForwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]) {
const msgInfos = msgIds.map(id => {
return {msgId: id, senderShowName: selfInfo.nick}
})
const apiArgs = [
@@ -484,42 +486,42 @@ export class NTQQApi {
commentElements: [],
msgAttributeInfos: new Map()
},
null,
null
]
return new Promise<RawMessage>((resolve, reject) => {
return await new Promise<RawMessage>((resolve, reject) => {
let complete = false
setTimeout(() => {
if (!complete) {
reject("转发消息超时");
reject('转发消息超时')
}
}, 5000)
registerReceiveHook(ReceiveCmd.SELF_SEND_MSG, (payload: { msgRecord: RawMessage }) => {
const msg = payload.msgRecord;
const msg = payload.msgRecord
// 需要判断它是转发的消息,并且识别到是当前转发的这一条
const arkElement = msg.elements.find(ele => ele.arkElement)
if (!arkElement) {
// log("收到的不是转发消息")
return
}
const forwardData: any = JSON.parse(arkElement.arkElement.bytesData);
if (forwardData.app != "com.tencent.multimsg") {
const forwardData: any = JSON.parse(arkElement.arkElement.bytesData)
if (forwardData.app != 'com.tencent.multimsg') {
return
}
if (msg.peerUid == destPeer.peerUid && msg.senderUid == selfInfo.uid) {
complete = true;
complete = true
addHistoryMsg(msg)
resolve(msg);
log("转发消息成功:", payload)
resolve(msg)
log('转发消息成功:', payload)
}
})
callNTQQApi<GeneralCallResult>({
methodName: NTQQApiMethod.MULTI_FORWARD_MSG,
args: apiArgs
}).then(result => {
log("转发消息结果:", result, apiArgs)
log('转发消息结果:', result, apiArgs)
if (result.result !== 0) {
complete = true;
reject("转发消息失败," + JSON.stringify(result));
complete = true
reject('转发消息失败,' + JSON.stringify(result))
}
})
})
@@ -530,56 +532,56 @@ export class NTQQApi {
// 加群通知,退出通知,需要管理员权限
callNTQQApi<GeneralCallResult>({
methodName: ReceiveCmd.GROUP_NOTIFY,
classNameIsRegister: true,
classNameIsRegister: true
}).then()
return await callNTQQApi<GroupNotifies>({
methodName: NTQQApiMethod.GET_GROUP_NOTICE,
cbCmd: ReceiveCmd.GROUP_NOTIFY,
afterFirstCmd: false,
args: [
{"doubt": false, "startSeq": "", "number": 14},
{doubt: false, startSeq: '', number: 14},
null
]
});
})
}
static async handleGroupRequest(seq: string, operateType: GroupRequestOperateTypes, reason?: string) {
const notify: GroupNotify = groupNotifies[seq];
const notify: GroupNotify = groupNotifies[seq]
if (!notify) {
throw `${seq}对应的加群通知不存在`
}
delete groupNotifies[seq];
delete groupNotifies[seq]
return await callNTQQApi<GeneralCallResult>({
methodName: NTQQApiMethod.HANDLE_GROUP_REQUEST,
args: [
{
"doubt": false,
"operateMsg": {
"operateType": operateType, // 2 拒绝
"targetMsg": {
"seq": seq, // 通知序列号
"type": notify.type,
"groupCode": notify.group.groupCode,
"postscript": reason
doubt: false,
operateMsg: {
operateType, // 2 拒绝
targetMsg: {
seq, // 通知序列号
type: notify.type,
groupCode: notify.group.groupCode,
postscript: reason
}
}
},
null
]
});
})
}
static async quitGroup(groupQQ: string) {
await callNTQQApi<GeneralCallResult>({
methodName: NTQQApiMethod.QUIT_GROUP,
args: [
{"groupCode": groupQQ},
{groupCode: groupQQ},
null
]
})
}
static async handleFriendRequest(sourceId: number, accept: boolean,) {
static async handleFriendRequest(sourceId: number, accept: boolean) {
const request: FriendRequest = friendRequests[sourceId]
if (!request) {
throw `sourceId ${sourceId}, 对应的好友请求不存在`
@@ -588,20 +590,20 @@ export class NTQQApi {
methodName: NTQQApiMethod.HANDLE_FRIEND_REQUEST,
args: [
{
"approvalInfo": {
"friendUid": request.friendUid,
"reqTime": request.reqTime,
approvalInfo: {
friendUid: request.friendUid,
reqTime: request.reqTime,
accept
}
}
]
})
delete friendRequests[sourceId];
return result;
delete friendRequests[sourceId]
return result
}
static kickMember(groupQQ: string, kickUids: string[], refuseForever: boolean = false, kickReason: string = "") {
return callNTQQApi<GeneralCallResult>(
static async kickMember(groupQQ: string, kickUids: string[], refuseForever: boolean = false, kickReason: string = '') {
return await callNTQQApi<GeneralCallResult>(
{
methodName: NTQQApiMethod.KICK_MEMBER,
args: [
@@ -609,30 +611,30 @@ export class NTQQApi {
groupCode: groupQQ,
kickUids,
refuseForever,
kickReason,
kickReason
}
]
}
)
}
static banMember(groupQQ: string, memList: { uid: string, timeStamp: number }[]) {
static async banMember(groupQQ: string, memList: Array<{ uid: string, timeStamp: number }>) {
// timeStamp为秒数, 0为解除禁言
return callNTQQApi<GeneralCallResult>(
return await callNTQQApi<GeneralCallResult>(
{
methodName: NTQQApiMethod.MUTE_MEMBER,
args: [
{
groupCode: groupQQ,
memList,
memList
}
]
}
)
}
static banGroup(groupQQ: string, shutUp: boolean) {
return callNTQQApi<GeneralCallResult>({
static async banGroup(groupQQ: string, shutUp: boolean) {
return await callNTQQApi<GeneralCallResult>({
methodName: NTQQApiMethod.MUTE_GROUP,
args: [
{
@@ -643,8 +645,8 @@ export class NTQQApi {
})
}
static setMemberCard(groupQQ: string, memberUid: string, cardName: string) {
return callNTQQApi<GeneralCallResult>({
static async setMemberCard(groupQQ: string, memberUid: string, cardName: string) {
return await callNTQQApi<GeneralCallResult>({
methodName: NTQQApiMethod.SET_MEMBER_CARD,
args: [
{
@@ -656,8 +658,8 @@ export class NTQQApi {
})
}
static setMemberRole(groupQQ: string, memberUid: string, role: GroupMemberRole) {
return callNTQQApi<GeneralCallResult>({
static async setMemberRole(groupQQ: string, memberUid: string, role: GroupMemberRole) {
return await callNTQQApi<GeneralCallResult>({
methodName: NTQQApiMethod.SET_MEMBER_ROLE,
args: [
{
@@ -669,8 +671,8 @@ export class NTQQApi {
})
}
static setGroupName(groupQQ: string, groupName: string) {
return callNTQQApi<GeneralCallResult>({
static async setGroupName(groupQQ: string, groupName: string) {
return await callNTQQApi<GeneralCallResult>({
methodName: NTQQApiMethod.SET_GROUP_NAME,
args: [
{
@@ -684,4 +686,4 @@ export class NTQQApi {
static publishGroupBulletin(groupQQ: string, title: string, content: string) {
}
}
}

View File

@@ -249,7 +249,7 @@ export interface VideoElement {
"thumbHeight": number,
"busiType": 0, // 未知
"subBusiType": 0, // 未知
"thumbPath": Map<number,any>,
"thumbPath": Map<number, any>,
"transferStatus": 0, // 未知
"progress": 0, // 下载进度?
"invalidState": 0, // 未知