mirror of
https://github.com/LLOneBot/LLOneBot.git
synced 2024-11-22 01:56:33 +00:00
866 lines
29 KiB
TypeScript
866 lines
29 KiB
TypeScript
import {ipcMain} from "electron";
|
||
import {hookApiCallbacks, ReceiveCmd, registerReceiveHook, removeReceiveHook} from "./hook";
|
||
import {log, sleep} from "../common/utils";
|
||
import {
|
||
ChatType,
|
||
ElementType,
|
||
Friend,
|
||
FriendRequest,
|
||
Group,
|
||
GroupMember,
|
||
GroupMemberRole,
|
||
GroupNotifies,
|
||
GroupNotify,
|
||
GroupRequestOperateTypes,
|
||
RawMessage,
|
||
SelfInfo,
|
||
SendMessageElement,
|
||
User,
|
||
CacheScanResult,
|
||
ChatCacheList, ChatCacheListItemBasic,
|
||
CacheFileList, CacheFileListItem, CacheFileType,
|
||
} from "./types";
|
||
import * as fs from "fs";
|
||
import {friendRequests, selfInfo, uidMaps} from "../common/data";
|
||
import {v4 as uuidv4} from "uuid"
|
||
import path from "path";
|
||
import {dbUtil} from "../common/db";
|
||
|
||
interface IPCReceiveEvent {
|
||
eventName: string
|
||
callbackId: string
|
||
}
|
||
|
||
export type IPCReceiveDetail = [
|
||
{
|
||
cmdName: NTQQApiMethod
|
||
payload: unknown
|
||
},
|
||
]
|
||
|
||
export enum NTQQApiClass {
|
||
NT_API = "ns-ntApi",
|
||
FS_API = "ns-FsApi",
|
||
OS_API = "ns-OsApi",
|
||
HOTUPDATE_API = "ns-HotUpdateApi",
|
||
BUSINESS_API = "ns-BusinessApi",
|
||
GLOBAL_DATA = "ns-GlobalDataApi"
|
||
}
|
||
|
||
export enum NTQQApiMethod {
|
||
SET_HEADER = "nodeIKernelProfileService/setHeader",
|
||
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",
|
||
FORWARD_MSG = "nodeIKernelMsgService/forwardMsgWithComment",
|
||
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",
|
||
SET_GROUP_TITLE = "nodeIKernelGroupService/modifyMemberSpecialTitle",
|
||
|
||
CACHE_SET_SILENCE = 'nodeIKernelStorageCleanService/setSilentScan',
|
||
CACHE_ADD_SCANNED_PATH = 'nodeIKernelStorageCleanService/addCacheScanedPaths',
|
||
CACHE_PATH_HOT_UPDATE = 'getHotUpdateCachePath',
|
||
CACHE_PATH_DESKTOP_TEMP = 'getDesktopTmpPath',
|
||
CACHE_PATH_SESSION = 'getCleanableAppSessionPathList',
|
||
CACHE_SCAN = 'nodeIKernelStorageCleanService/scanCache',
|
||
CACHE_CLEAR = 'nodeIKernelStorageCleanService/clearCacheDataByKeys',
|
||
|
||
CACHE_CHAT_GET = 'nodeIKernelStorageCleanService/getChatCacheInfo',
|
||
CACHE_FILE_GET = 'nodeIKernelStorageCleanService/getFileCacheInfo',
|
||
CACHE_CHAT_CLEAR = 'nodeIKernelStorageCleanService/clearChatCacheInfo',
|
||
}
|
||
|
||
enum NTQQApiChannel {
|
||
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?: ""
|
||
}
|
||
|
||
interface NTQQApiParams {
|
||
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,
|
||
}
|
||
|
||
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();
|
||
// log("callNTQQApi", channel, className, methodName, args, uuid)
|
||
return 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];
|
||
if (classNameIsRegister) {
|
||
eventName += "-register";
|
||
}
|
||
const apiArgs = [methodName, ...args]
|
||
if (!cbCmd) {
|
||
// QQ后端会返回结果,并且可以插根据uuid识别
|
||
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(payload)) {
|
||
removeReceiveHook(hookId);
|
||
success = true
|
||
resolve(payload);
|
||
}
|
||
} else {
|
||
removeReceiveHook(hookId);
|
||
success = true
|
||
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}`);
|
||
}
|
||
}
|
||
}
|
||
setTimeout(() => {
|
||
// log("ntqq api timeout", success, channel, className, methodName)
|
||
if (!success) {
|
||
log(`ntqq api timeout ${channel}, ${eventName}, ${methodName}`, apiArgs);
|
||
reject(`ntqq api timeout ${channel}, ${eventName}, ${methodName}, ${apiArgs}`)
|
||
}
|
||
}, _timeout)
|
||
|
||
ipcMain.emit(
|
||
channel,
|
||
{},
|
||
{type: 'request', callbackId: uuid, eventName},
|
||
apiArgs
|
||
)
|
||
})
|
||
}
|
||
|
||
|
||
export let sendMessagePool: Record<string, ((sendSuccessMsg: RawMessage) => void) | null> = {}// peerUid: callbackFunnc
|
||
|
||
interface GeneralCallResult {
|
||
result: number, // 0: success
|
||
errMsg: string
|
||
}
|
||
|
||
|
||
export class NTQQApi {
|
||
static async setHeader(path: string){
|
||
return await callNTQQApi<GeneralCallResult>({
|
||
methodName: NTQQApiMethod.SET_HEADER,
|
||
args: [path]
|
||
})
|
||
}
|
||
static async likeFriend(uid: string, count = 1) {
|
||
return await callNTQQApi<GeneralCallResult>({
|
||
methodName: NTQQApiMethod.LIKE_FRIEND,
|
||
args: [{
|
||
doLikeUserInfo: {
|
||
friendUid: uid,
|
||
sourceId: 71,
|
||
doLikeCount: count,
|
||
doLikeTollCount: 0
|
||
}
|
||
}, null]
|
||
})
|
||
}
|
||
|
||
static async getSelfInfo() {
|
||
return await callNTQQApi<SelfInfo>({
|
||
className: NTQQApiClass.GLOBAL_DATA,
|
||
methodName: NTQQApiMethod.SELF_INFO, timeoutSecond: 2
|
||
})
|
||
}
|
||
|
||
static async getUserInfo(uid: string) {
|
||
const result = await callNTQQApi<{ profiles: Map<string, User> }>({
|
||
methodName: NTQQApiMethod.USER_INFO,
|
||
args: [{force: true, uids: [uid]}, undefined],
|
||
cbCmd: ReceiveCmd.USER_INFO
|
||
})
|
||
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: {
|
||
categoryId: number,
|
||
categroyName: string,
|
||
categroyMbCount: number,
|
||
buddyList: Friend[]
|
||
}[]
|
||
}>(
|
||
{
|
||
methodName: NTQQApiMethod.FRIENDS,
|
||
args: [{force_update: forced}, undefined],
|
||
cbCmd: ReceiveCmd.FRIENDS
|
||
})
|
||
let _friends: Friend[] = [];
|
||
for (const fData of data.data) {
|
||
_friends.push(...fData.buddyList)
|
||
}
|
||
return _friends
|
||
}
|
||
|
||
static async getGroups(forced = false) {
|
||
let cbCmd = ReceiveCmd.GROUPS
|
||
if (process.platform != "win32") {
|
||
cbCmd = ReceiveCmd.GROUPS_UNIX
|
||
}
|
||
const result = await callNTQQApi<{
|
||
updateType: number,
|
||
groupList: Group[]
|
||
}>({methodName: NTQQApiMethod.GROUPS, args: [{force_update: forced}, undefined], cbCmd})
|
||
return result.groupList
|
||
}
|
||
|
||
static async getGroupMembers(groupQQ: string, num = 3000): Promise<GroupMember[]> {
|
||
const sceneId = await callNTQQApi({
|
||
methodName: NTQQApiMethod.GROUP_MEMBER_SCENE,
|
||
args: [{
|
||
groupCode: groupQQ,
|
||
scene: "groupMemberList_MainWindow"
|
||
}]
|
||
})
|
||
// log("get group member sceneId", sceneId);
|
||
try {
|
||
const result = await callNTQQApi<{
|
||
result: { infos: any }
|
||
}>({
|
||
methodName: NTQQApiMethod.GROUP_MEMBERS,
|
||
args: [{
|
||
sceneId: sceneId,
|
||
num: num
|
||
},
|
||
null
|
||
]
|
||
})
|
||
// log("members info", typeof result.result.infos, Object.keys(result.result.infos))
|
||
const values = result.result.infos.values()
|
||
|
||
const members: GroupMember[] = Array.from(values)
|
||
for (const member of members) {
|
||
uidMaps[member.uid] = member.uin;
|
||
}
|
||
// log(uidMaps);
|
||
// log("members info", values);
|
||
log(`get group ${groupQQ} members success`)
|
||
return members
|
||
} catch (e) {
|
||
log(`get group ${groupQQ} members failed`, e)
|
||
return []
|
||
}
|
||
}
|
||
|
||
static async getFileType(filePath: string) {
|
||
return await callNTQQApi<{ ext: string }>({
|
||
className: NTQQApiClass.FS_API, methodName: NTQQApiMethod.FILE_TYPE, args: [filePath]
|
||
})
|
||
}
|
||
|
||
static async getFileMd5(filePath: string) {
|
||
return await callNTQQApi<string>({
|
||
className: NTQQApiClass.FS_API,
|
||
methodName: NTQQApiMethod.FILE_MD5,
|
||
args: [filePath]
|
||
})
|
||
}
|
||
|
||
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 async getImageSize(filePath: string) {
|
||
return await callNTQQApi<{ width: number, height: number }>({
|
||
className: NTQQApiClass.FS_API, methodName: NTQQApiMethod.IMAGE_SIZE, args: [filePath]
|
||
})
|
||
}
|
||
|
||
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);
|
||
let ext = (await NTQQApi.getFileType(filePath))?.ext
|
||
if (ext) {
|
||
ext = "." + ext
|
||
} else {
|
||
ext = ""
|
||
}
|
||
let fileName = `${path.basename(filePath)}`;
|
||
if (fileName.indexOf(".") === -1) {
|
||
fileName += ext;
|
||
}
|
||
const mediaPath = await callNTQQApi<string>({
|
||
methodName: NTQQApiMethod.MEDIA_FILE_PATH,
|
||
args: [{
|
||
path_info: {
|
||
md5HexStr: md5,
|
||
fileName: fileName,
|
||
elementType: elementType,
|
||
elementSubType: 0,
|
||
thumbSize: 0,
|
||
needCreate: true,
|
||
downloadType: 1,
|
||
file_uuid: ""
|
||
}
|
||
}]
|
||
})
|
||
log("media path", mediaPath)
|
||
await NTQQApi.copyFile(filePath, mediaPath);
|
||
const fileSize = await NTQQApi.getFileSize(filePath);
|
||
return {
|
||
md5,
|
||
fileName,
|
||
path: mediaPath,
|
||
fileSize
|
||
}
|
||
}
|
||
|
||
static async downloadMedia(msgId: string, chatType: ChatType, peerUid: string, elementId: string, thumbPath: string, sourcePath: string) {
|
||
// 用于下载收到的消息中的图片等
|
||
if (fs.existsSync(sourcePath)) {
|
||
return sourcePath
|
||
}
|
||
const apiParams = [
|
||
{
|
||
getReq: {
|
||
msgId: msgId,
|
||
chatType: chatType,
|
||
peerUid: peerUid,
|
||
elementId: elementId,
|
||
thumbSize: 0,
|
||
downloadType: 1,
|
||
filePath: thumbPath,
|
||
},
|
||
},
|
||
undefined,
|
||
]
|
||
// log("需要下载media", sourcePath);
|
||
await callNTQQApi({
|
||
methodName: NTQQApiMethod.DOWNLOAD_MEDIA,
|
||
args: apiParams,
|
||
cbCmd: ReceiveCmd.MEDIA_DOWNLOAD_COMPLETE,
|
||
cmdCB: (payload: { notifyInfo: { filePath: string } }) => {
|
||
// log("media 下载完成判断", payload.notifyInfo.filePath, sourcePath);
|
||
return payload.notifyInfo.filePath == sourcePath;
|
||
}
|
||
})
|
||
return sourcePath
|
||
}
|
||
|
||
static async recallMsg(peer: Peer, msgIds: string[]) {
|
||
return await callNTQQApi({
|
||
methodName: NTQQApiMethod.RECALL_MSG,
|
||
args: [{
|
||
peer,
|
||
msgIds
|
||
}, null]
|
||
})
|
||
}
|
||
|
||
static async sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
|
||
const peerUid = peer.peerUid
|
||
|
||
// 等待上一个相同的peer发送完
|
||
let checkLastSendUsingTime = 0;
|
||
const waitLastSend = async () => {
|
||
if (checkLastSendUsingTime > timeout) {
|
||
throw ("发送超时")
|
||
}
|
||
let lastSending = sendMessagePool[peer.peerUid]
|
||
if (lastSending) {
|
||
// log("有正在发送的消息,等待中...")
|
||
await sleep(500);
|
||
checkLastSendUsingTime += 500;
|
||
return await waitLastSend();
|
||
} else {
|
||
return;
|
||
}
|
||
}
|
||
await waitLastSend();
|
||
|
||
let sentMessage: RawMessage = null;
|
||
sendMessagePool[peerUid] = async (rawMessage: RawMessage) => {
|
||
delete sendMessagePool[peerUid];
|
||
sentMessage = rawMessage;
|
||
}
|
||
|
||
let checkSendCompleteUsingTime = 0;
|
||
const checkSendComplete = async (): Promise<RawMessage> => {
|
||
if (sentMessage) {
|
||
if (waitComplete) {
|
||
if ((await dbUtil.getMsgByLongId(sentMessage.msgId)).sendStatus == 2) {
|
||
return sentMessage
|
||
}
|
||
}
|
||
else{
|
||
return sentMessage
|
||
}
|
||
// log(`给${peerUid}发送消息成功`)
|
||
}
|
||
checkSendCompleteUsingTime += 500
|
||
if (checkSendCompleteUsingTime > timeout) {
|
||
throw ('发送超时')
|
||
}
|
||
await sleep(500)
|
||
return await checkSendComplete()
|
||
}
|
||
|
||
callNTQQApi({
|
||
methodName: NTQQApiMethod.SEND_MSG,
|
||
args: [{
|
||
msgId: "0",
|
||
peer, msgElements,
|
||
msgAttributeInfos: new Map(),
|
||
}, null]
|
||
}).then()
|
||
return await checkSendComplete()
|
||
}
|
||
|
||
static async forwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]) {
|
||
return await callNTQQApi<GeneralCallResult>({
|
||
methodName: NTQQApiMethod.FORWARD_MSG,
|
||
args:[
|
||
{
|
||
msgIds: msgIds,
|
||
srcContact: srcPeer,
|
||
dstContacts: [
|
||
destPeer
|
||
],
|
||
commentElements: [],
|
||
msgAttributeInfos: new Map()
|
||
},
|
||
null,
|
||
]
|
||
})
|
||
|
||
}
|
||
static async multiForwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]) {
|
||
const msgInfos = msgIds.map(id => {
|
||
return {msgId: id, senderShowName: selfInfo.nick}
|
||
})
|
||
const apiArgs = [
|
||
{
|
||
msgInfos,
|
||
srcContact: srcPeer,
|
||
dstContact: destPeer,
|
||
commentElements: [],
|
||
msgAttributeInfos: new Map()
|
||
},
|
||
null,
|
||
]
|
||
return await new Promise<RawMessage>((resolve, reject) => {
|
||
let complete = false
|
||
setTimeout(() => {
|
||
if (!complete) {
|
||
reject("转发消息超时");
|
||
}
|
||
}, 5000)
|
||
registerReceiveHook(ReceiveCmd.SELF_SEND_MSG, async (payload: { msgRecord: RawMessage }) => {
|
||
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') {
|
||
return
|
||
}
|
||
if (msg.peerUid == destPeer.peerUid && msg.senderUid == selfInfo.uid) {
|
||
complete = true
|
||
await dbUtil.addMsg(msg)
|
||
resolve(msg)
|
||
log('转发消息成功:', payload)
|
||
}
|
||
})
|
||
callNTQQApi<GeneralCallResult>({
|
||
methodName: NTQQApiMethod.MULTI_FORWARD_MSG,
|
||
args: apiArgs
|
||
}).then(result => {
|
||
log("转发消息结果:", result, apiArgs)
|
||
if (result.result !== 0) {
|
||
complete = true;
|
||
reject("转发消息失败," + JSON.stringify(result));
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
static async getGroupNotifies() {
|
||
// 获取管理员变更
|
||
// 加群通知,退出通知,需要管理员权限
|
||
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
|
||
]
|
||
});
|
||
}
|
||
|
||
static async handleGroupRequest(seq: string, operateType: GroupRequestOperateTypes, reason?: string) {
|
||
const notify: GroupNotify = await dbUtil.getGroupNotify(seq)
|
||
if (!notify) {
|
||
throw `${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
|
||
}
|
||
}
|
||
},
|
||
null
|
||
]
|
||
});
|
||
}
|
||
|
||
static async quitGroup(groupQQ: string) {
|
||
await callNTQQApi<GeneralCallResult>({
|
||
methodName: NTQQApiMethod.QUIT_GROUP,
|
||
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;
|
||
}
|
||
|
||
static async kickMember(groupQQ: string, kickUids: string[], refuseForever: boolean = false, kickReason: string = '') {
|
||
return await callNTQQApi<GeneralCallResult>(
|
||
{
|
||
methodName: NTQQApiMethod.KICK_MEMBER,
|
||
args: [
|
||
{
|
||
groupCode: groupQQ,
|
||
kickUids,
|
||
refuseForever,
|
||
kickReason,
|
||
}
|
||
]
|
||
}
|
||
)
|
||
}
|
||
|
||
static async banMember(groupQQ: string, memList: Array<{ uid: string, timeStamp: number }>) {
|
||
// timeStamp为秒数, 0为解除禁言
|
||
return await callNTQQApi<GeneralCallResult>(
|
||
{
|
||
methodName: NTQQApiMethod.MUTE_MEMBER,
|
||
args: [
|
||
{
|
||
groupCode: groupQQ,
|
||
memList,
|
||
}
|
||
]
|
||
}
|
||
)
|
||
}
|
||
|
||
static async banGroup(groupQQ: string, shutUp: boolean) {
|
||
return await callNTQQApi<GeneralCallResult>({
|
||
methodName: NTQQApiMethod.MUTE_GROUP,
|
||
args: [
|
||
{
|
||
groupCode: groupQQ,
|
||
shutUp
|
||
}, null
|
||
]
|
||
})
|
||
}
|
||
|
||
static async setMemberCard(groupQQ: string, memberUid: string, cardName: string) {
|
||
return await callNTQQApi<GeneralCallResult>({
|
||
methodName: NTQQApiMethod.SET_MEMBER_CARD,
|
||
args: [
|
||
{
|
||
groupCode: groupQQ,
|
||
uid: memberUid,
|
||
cardName
|
||
}, null
|
||
]
|
||
})
|
||
}
|
||
|
||
static async setMemberRole(groupQQ: string, memberUid: string, role: GroupMemberRole) {
|
||
return await callNTQQApi<GeneralCallResult>({
|
||
methodName: NTQQApiMethod.SET_MEMBER_ROLE,
|
||
args: [
|
||
{
|
||
groupCode: groupQQ,
|
||
uid: memberUid,
|
||
role
|
||
}, null
|
||
]
|
||
})
|
||
}
|
||
|
||
static async setGroupName(groupQQ: string, groupName: string) {
|
||
return await callNTQQApi<GeneralCallResult>({
|
||
methodName: NTQQApiMethod.SET_GROUP_NAME,
|
||
args: [
|
||
{
|
||
groupCode: groupQQ,
|
||
groupName
|
||
}, null
|
||
]
|
||
})
|
||
}
|
||
|
||
static async call(className: NTQQApiClass, cmdName: string, args: any[],) {
|
||
return await callNTQQApi<GeneralCallResult>({
|
||
className,
|
||
methodName: cmdName,
|
||
args: [
|
||
...args,
|
||
]
|
||
})
|
||
}
|
||
|
||
static async setGroupTitle(groupQQ: string, uid: string, title: string) {
|
||
return await callNTQQApi<GeneralCallResult>({
|
||
methodName: NTQQApiMethod.SET_GROUP_TITLE,
|
||
args: [
|
||
{
|
||
groupCode: groupQQ,
|
||
uid,
|
||
title
|
||
}, null
|
||
]
|
||
})
|
||
}
|
||
|
||
static publishGroupBulletin(groupQQ: string, title: string, content: string) {
|
||
|
||
}
|
||
|
||
static async setCacheSilentScan(isSilent: boolean = true) {
|
||
return await callNTQQApi<GeneralCallResult>({
|
||
methodName: NTQQApiMethod.CACHE_SET_SILENCE,
|
||
args: [{
|
||
isSilent
|
||
}, null]
|
||
});
|
||
}
|
||
|
||
static addCacheScannedPaths(pathMap: object = {}) {
|
||
return callNTQQApi<GeneralCallResult>({
|
||
methodName: NTQQApiMethod.CACHE_ADD_SCANNED_PATH,
|
||
args: [{
|
||
pathMap: {...pathMap},
|
||
}, null]
|
||
});
|
||
}
|
||
|
||
static scanCache() {
|
||
callNTQQApi<GeneralCallResult>({
|
||
methodName: ReceiveCmd.CACHE_SCAN_FINISH,
|
||
classNameIsRegister: true,
|
||
}).then();
|
||
return callNTQQApi<CacheScanResult>({
|
||
methodName: NTQQApiMethod.CACHE_SCAN,
|
||
args: [null, null],
|
||
timeoutSecond: 300,
|
||
});
|
||
}
|
||
|
||
static getHotUpdateCachePath() {
|
||
return callNTQQApi<string>({
|
||
className: NTQQApiClass.HOTUPDATE_API,
|
||
methodName: NTQQApiMethod.CACHE_PATH_HOT_UPDATE
|
||
});
|
||
}
|
||
|
||
static getDesktopTmpPath() {
|
||
return callNTQQApi<string>({
|
||
className: NTQQApiClass.BUSINESS_API,
|
||
methodName: NTQQApiMethod.CACHE_PATH_DESKTOP_TEMP
|
||
});
|
||
}
|
||
|
||
static getCacheSessionPathList() {
|
||
return callNTQQApi<{
|
||
key: string,
|
||
value: string
|
||
}[]>({
|
||
className: NTQQApiClass.OS_API,
|
||
methodName: NTQQApiMethod.CACHE_PATH_SESSION,
|
||
});
|
||
}
|
||
|
||
static clearCache(cacheKeys: Array<string> = [ 'tmp', 'hotUpdate' ]) {
|
||
return callNTQQApi<any>({ // TODO: 目前还不知道真正的返回值是什么
|
||
methodName: NTQQApiMethod.CACHE_CLEAR,
|
||
args: [{
|
||
keys: cacheKeys
|
||
}, null]
|
||
});
|
||
}
|
||
|
||
static getChatCacheList(type: ChatType, pageSize: number = 1000, pageIndex: number = 0) {
|
||
return new Promise<ChatCacheList>((res, rej) => {
|
||
callNTQQApi<ChatCacheList>({
|
||
methodName: NTQQApiMethod.CACHE_CHAT_GET,
|
||
args: [{
|
||
chatType: type,
|
||
pageSize,
|
||
order: 1,
|
||
pageIndex
|
||
}, null]
|
||
}).then(list => res(list))
|
||
.catch(e => rej(e));
|
||
});
|
||
}
|
||
|
||
static getFileCacheInfo(fileType: CacheFileType, pageSize: number = 1000, lastRecord?: CacheFileListItem) {
|
||
const _lastRecord = lastRecord ? lastRecord : { fileType: fileType };
|
||
|
||
return callNTQQApi<CacheFileList>({
|
||
methodName: NTQQApiMethod.CACHE_FILE_GET,
|
||
args: [{
|
||
fileType: fileType,
|
||
restart: true,
|
||
pageSize: pageSize,
|
||
order: 1,
|
||
lastRecord: _lastRecord,
|
||
}, null]
|
||
})
|
||
}
|
||
|
||
static async clearChatCache(chats: ChatCacheListItemBasic[] = [], fileKeys: string[] = []) {
|
||
return await callNTQQApi<GeneralCallResult>({
|
||
methodName: NTQQApiMethod.CACHE_CHAT_CLEAR,
|
||
args: [{
|
||
chats,
|
||
fileKeys
|
||
}, null]
|
||
});
|
||
}
|
||
} |