@@ -1,8 +1,8 @@
import { BrowserWindow } from 'electron' ;
import { NTQQApiClass } from "./ntcall" ;
import { NTQQApiClass , NTQQApiMethod } from "./ntcall" ;
import { NTQQMsgApi , sendMessagePool } from "./api/msg"
import { ChatType , Group , GroupMember , GroupMemberRole , RawMessage , User } from "./types" ;
import { friends , getGroupMember , groups , selfInfo , tempGroupCodeMap , uidMaps } from "../common/data" ;
import { friends , getFriend , getGroupMember , groups , selfInfo , tempGroupCodeMap , uidMaps } from "../common/data" ;
import { OB11GroupDecreaseEvent } from "../onebot11/event/notice/OB11GroupDecreaseEvent" ;
import { v4 as uuidv4 } from "uuid"
import { postOB11Event } from "../onebot11/server/postOB11Event" ;
@@ -11,446 +11,503 @@ import fs from "fs";
import { dbUtil } from "../common/db" ;
import { NTQQGroupApi } from "./api/group" ;
import { log } from "../common/utils/log" ;
import { sleep } from "../common/utils/helper" ;
import { isNumeric , sleep} from "../common/utils/helper" ;
import { OB11Constructor } from "../onebot11/constructor" ;
export let hookApiCallbacks : Record < string , ( apiReturn : any ) = > void > = { }
export let ReceiveCmdS = {
RECENT_CONTACT : "nodeIKernelRecentContactListener/onRecentContactListChangedVer2" ,
UPDATE_MSG : "nodeIKernelMsgListener/onMsgInfoListUpdate" ,
UPDATE_ACTIVE_MSG : "nodeIKernelMsgListener/onActiveMsgInfoUpdate" ,
NEW_MSG : ` nodeIKernelMsgListener/onRecvMsg ` ,
NEW_ACTIVE_MSG : ` nodeIKernelMsgListener/onRecvActiveMsg ` ,
SELF_SEND_MSG : "nodeIKernelMsgListener/onAddSendMsg" ,
USER_INFO : "nodeIKernelProfileListener/onProfileSimpleChanged" ,
USER_DETAIL_INFO : "nodeIKernelProfileListener/onProfileDetailInfoChanged" ,
GROUPS : "nodeIKernelGroupListener/onGroupListUpdate" ,
GROUPS_STORE : "onGroupListUpdate" ,
GROUP_MEMBER_INFO_UPDATE : "nodeIKernelGroupListener/onMemberInfoChange" ,
FRIENDS : "onBuddyListChange" ,
MEDIA_DOWNLOAD_COMPLETE : "nodeIKernelMsgListener/onRichMediaDownloadComplete" ,
UNREAD_GROUP_NOTIFY : "nodeIKernelGroupListener/onGroupNotifiesUnreadCountUpdated" ,
GROUP_NOTIFY : "nodeIKernelGroupListener/onGroupSingleScreenNotifies" ,
FRIEND_REQUEST : "nodeIKernelBuddyListener/onBuddyReqChange" ,
SELF_STATUS : 'nodeIKernelProfileListener/onSelfStatusChanged' ,
CACHE_SCAN_FINISH : "nodeIKernelStorageCleanListener/onFinishScan" ,
MEDIA_UPLOAD_COMPLETE : "nodeIKernelMsgListener/onRichMediaUploadComplete" ,
SKEY_UPDATE : "onSkeyUpdate"
RECENT_CONTACT : "nodeIKernelRecentContactListener/onRecentContactListChangedVer2" ,
UPDATE_MSG : "nodeIKernelMsgListener/onMsgInfoListUpdate" ,
UPDATE_ACTIVE_MSG : "nodeIKernelMsgListener/onActiveMsgInfoUpdate" ,
NEW_MSG : ` nodeIKernelMsgListener/onRecvMsg ` ,
NEW_ACTIVE_MSG : ` nodeIKernelMsgListener/onRecvActiveMsg ` ,
SELF_SEND_MSG : "nodeIKernelMsgListener/onAddSendMsg" ,
USER_INFO : "nodeIKernelProfileListener/onProfileSimpleChanged" ,
USER_DETAIL_INFO : "nodeIKernelProfileListener/onProfileDetailInfoChanged" ,
GROUPS : "nodeIKernelGroupListener/onGroupListUpdate" ,
GROUPS_STORE : "onGroupListUpdate" ,
GROUP_MEMBER_INFO_UPDATE : "nodeIKernelGroupListener/onMemberInfoChange" ,
FRIENDS : "onBuddyListChange" ,
MEDIA_DOWNLOAD_COMPLETE : "nodeIKernelMsgListener/onRichMediaDownloadComplete" ,
UNREAD_GROUP_NOTIFY : "nodeIKernelGroupListener/onGroupNotifiesUnreadCountUpdated" ,
GROUP_NOTIFY : "nodeIKernelGroupListener/onGroupSingleScreenNotifies" ,
FRIEND_REQUEST : "nodeIKernelBuddyListener/onBuddyReqChange" ,
SELF_STATUS : 'nodeIKernelProfileListener/onSelfStatusChanged' ,
CACHE_SCAN_FINISH : "nodeIKernelStorageCleanListener/onFinishScan" ,
MEDIA_UPLOAD_COMPLETE : "nodeIKernelMsgListener/onRichMediaUploadComplete" ,
SKEY_UPDATE : "onSkeyUpdate"
}
export type ReceiveCmd = typeof ReceiveCmdS [ keyof typeof ReceiveCmdS ]
interface NTQQApiReturnData < PayloadType = unknown > extends Array < any > {
0 : {
"type" : "request" ,
"eventName" : NTQQApiClass ,
"callbackId" ? : string
} ,
1 :
{
cmdName : ReceiveCmd ,
cmdType : "event" ,
payload : PayloadType
} [ ]
0 : {
"type" : "request" ,
"eventName" : NTQQApiClass ,
"callbackId" ? : string
} ,
1 :
{
cmdName : ReceiveCmd ,
cmdType : "event" ,
payload : PayloadType
} [ ]
}
let receiveHooks : Array < {
method : ReceiveCmd [ ] ,
hookFunc : ( ( payload : any ) = > void | Promise < void > )
id : string
method : ReceiveCmd [ ] ,
hookFunc : ( ( payload : any ) = > void | Promise < void > )
id : string
} > = [ ]
export function hookNTQQApiReceive ( window : BrowserWindow ) {
const originalSend = window . webContents . send ;
const patchSend = ( channel : string , . . . args : NTQQApiReturnData ) = > {
// console.log("hookNTQQApiReceive", channel, args)
let isLogger = false
try {
isLogger = args [ 0 ] ? . eventName ? . startsWith ( "ns-LoggerApi" )
} catch ( e ) {
let callHooks : Array < {
method : NTQQApiMethod [ ] ,
hookFunc : ( ( callParams : unknown [ ] ) = > void | Promise < void > )
} > = [ ]
export function hookNTQQApiReceive ( window : BrowserWindow ) {
const originalSend = window . webContents . send ;
const patchSend = ( channel : string , . . . args : NTQQApiReturnData ) = > {
// console.log("hookNTQQApiReceive", channel, args)
let isLogger = false
try {
isLogger = args [ 0 ] ? . eventName ? . startsWith ( "ns-LoggerApi" )
} catch ( e ) {
}
if ( ! isLogger ) {
try {
HOOK_LOG && log ( ` received ntqq api message: ${ channel } ` , args )
} catch ( e ) {
log ( "hook log error" , e , args )
}
}
try {
if ( args ? . [ 1 ] instanceof Array ) {
for ( let receiveData of args ? . [ 1 ] ) {
const ntQQApiMethodName = receiveData . cmdName ;
// log(`received ntqq api message: ${channel} ${ntQQApiMethodName}`, JSON.stringify(receiveData))
for ( let hook of receiveHooks ) {
if ( hook . method . includes ( ntQQApiMethodName ) ) {
new Promise ( ( resolve , reject ) = > {
try {
let _ = hook . hookFunc ( receiveData . payload )
if ( hook . hookFunc . constructor . name === "AsyncFunction" ) {
( _ as Promise < void > ) . then ( )
}
} catch ( e ) {
log ( "hook error" , e , receiveData . payload )
}
} ) . then ( )
}
}
}
}
if ( args [ 0 ] ? . callbackId ) {
// log("hookApiCallback", hookApiCallbacks, args)
const callbackId = args [ 0 ] . callbackId ;
if ( hookApiCallbacks [ callbackId ] ) {
// log("callback found")
new Promise ( ( resolve , reject ) = > {
hookApiCallbacks [ callbackId ] ( args [ 1 ] ) ;
} ) . then ( )
delete hookApiCallbacks [ callbackId ] ;
}
}
} catch ( e ) {
log ( "hookNTQQApiReceive error" , e . stack . toString ( ) , args )
}
originalSend . call ( window . webContents , channel , . . . args ) ;
}
window . webContents . send = patchSend ;
if ( ! isLogger ) {
try {
HOOK_LOG && log ( ` received ntqq api message: ${ channel } ` , args )
} catch ( e ) {
log ( "hook log error" , e , args )
}
}
try {
if ( args ? . [ 1 ] instanceof Array ) {
for ( let receiveData of args ? . [ 1 ] ) {
const ntQQApiMethodName = receiveData . cmdName ;
// log(`received ntqq api message: ${channel} ${ntQQApiMethodName}`, JSON.stringify(receiveData))
for ( let hook of receiveHooks ) {
if ( hook . method . includes ( ntQQApiMethodName ) ) {
new Promise ( ( resolve , reject ) = > {
try {
let _ = hook . hookFunc ( receiveData . payload )
if ( hook . hookFunc . constructor . name === "AsyncFunction" ) {
( _ as Promise < void > ) . then ( )
}
} catch ( e ) {
log ( "hook error" , e , receiveData . payload )
}
} ) . then ( )
}
}
}
}
if ( args [ 0 ] ? . callbackId ) {
// log("hookApiCallback", hookApiCallbacks, args)
const callbackId = args [ 0 ] . callbackId ;
if ( hookApiCallbacks [ callbackId ] ) {
// log("callback found")
new Promise ( ( resolve , reject ) = > {
hookApiCallbacks [ callbackId ] ( args [ 1 ] ) ;
} ) . then ( )
delete hookApiCallbacks [ callbackId ] ;
}
}
} catch ( e ) {
log ( "hookNTQQApiReceive error" , e . stack . toString ( ) , args )
}
originalSend . call ( window . webContents , channel , . . . args ) ;
}
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" ] ;
// 监听调用NTQQApi
let 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 ) {
// console.log(thisArg, args);
let isLogger = false
try {
isLogger = args [ 3 ] [ 0 ] . eventName . startsWith ( "ns-LoggerApi" )
} catch ( e ) {
const proxyIpcMsg = new Proxy ( ipc_message_proxy , {
apply ( target , thisArg , args ) {
// console.log(thisArg, args);
let isLogger = false
try {
isLogger = args [ 3 ] [ 0 ] . eventName . startsWith ( "ns-LoggerApi" )
} catch ( e ) {
}
if ( ! isLogger ) {
try {
HOOK_LOG && log ( "call NTQQ api" , thisArg , args ) ;
} catch ( e ) {
}
if ( ! isLogger ) {
try {
HOOK_LOG && log ( "call NTQQ api" , thisArg , args ) ;
} catch ( e ) {
}
}
return target . apply ( thisArg , args ) ;
} ,
} ) ;
if ( webContents . _events [ "-ipc-message" ] ? . [ 0 ] ) {
webContents . _events [ "-ipc-message" ] [ 0 ] = proxyIpcMsg ;
} else {
webContents . _events [ "-ipc-message" ] = proxyIpcMsg ;
}
const ipc_invoke_proxy = webContents . _events [ "-ipc-invoke" ] ? . [ 0 ] || webContents . _events [ "-ipc-invoke" ] ;
const proxyIpcInvoke = new Proxy ( ipc_invoke_proxy , {
apply ( target , thisArg , args ) {
// console.log(args);
HOOK_LOG && log ( "call NTQQ invoke api" , thisArg , args )
args [ 0 ] [ "_replyChannel" ] [ "sendReply" ] = new Proxy ( args [ 0 ] [ "_replyChannel" ] [ "sendReply" ] , {
apply ( sendtarget , sendthisArg , sendargs ) {
sendtarget . apply ( sendthisArg , sendargs ) ;
}
} ) ;
let ret = target . apply ( thisArg , args ) ;
try {
HOOK_LOG && log ( "call NTQQ invoke api return" , ret )
} catch ( e ) {
}
return ret ;
}
} ) ;
if ( webContents . _events [ "-ipc-invoke" ] ? . [ 0 ] ) {
webContents . _events [ "-ipc-invoke" ] [ 0 ] = proxyIpcInvoke ;
} else {
webContents . _events [ "-ipc-invoke" ] = proxyIpcInvoke ;
try {
const _args : unknown [ ] = args [ 3 ] [ 1 ] ;
const cmdName : NTQQApiMethod = _args [ 0 ] as NTQQApiMethod ;
const callParams = _args . slice ( 1 ) ;
callHooks . forEach ( hook = > {
if ( hook . method . includes ( cmdName ) ) {
new Promise ( ( resolve , reject ) = > {
try {
let _ = hook . hookFunc ( callParams )
if ( hook . hookFunc . constructor . name === "AsyncFunction" ) {
( _ as Promise < void > ) . then ( )
}
} catch ( e ) {
log ( "hook call error" , e , _args )
}
} ) . then ( )
}
} )
} catch ( e ) {
}
}
return target . apply ( thisArg , args ) ;
} ,
} ) ;
if ( webContents . _events [ "-ipc-message" ] ? . [ 0 ] ) {
webContents . _events [ "-ipc-message" ] [ 0 ] = proxyIpcMsg ;
} else {
webContents . _events [ "-ipc-message" ] = proxyIpcMsg ;
}
const ipc_invoke_proxy = webContents . _events [ "-ipc-invoke" ] ? . [ 0 ] || webContents . _events [ "-ipc-invoke" ] ;
const proxyIpcInvoke = new Proxy ( ipc_invoke_proxy , {
apply ( target , thisArg , args ) {
// console.log(args);
HOOK_LOG && log ( "call NTQQ invoke api" , thisArg , args )
args [ 0 ] [ "_replyChannel" ] [ "sendReply" ] = new Proxy ( args [ 0 ] [ "_replyChannel" ] [ "sendReply" ] , {
apply ( sendtarget , sendthisArg , sendargs ) {
sendtarget . apply ( sendthisArg , sendargs ) ;
}
} ) ;
let ret = target . apply ( thisArg , args ) ;
try {
HOOK_LOG && log ( "call NTQQ invoke api return" , ret )
} catch ( e ) {
}
return ret ;
}
} ) ;
if ( webContents . _events [ "-ipc-invoke" ] ? . [ 0 ] ) {
webContents . _events [ "-ipc-invoke" ] [ 0 ] = proxyIpcInvoke ;
} else {
webContents . _events [ "-ipc-invoke" ] = proxyIpcInvoke ;
}
}
export function registerReceiveHook < PayloadType > ( method : ReceiveCmd | ReceiveCmd [ ] , hookFunc : ( payload : PayloadType ) = > void ) : string {
const id = uuidv4 ( )
if ( ! Array . isArray ( method ) ) {
method = [ method ]
}
receiveHooks . push ( {
method ,
hookFunc ,
id
} )
return id ;
const id = uuidv4 ( )
if ( ! Array . isArray ( method ) ) {
method = [ method ]
}
receiveHooks . push ( {
method ,
hookFunc ,
id
} )
return id ;
}
export function registerCallHook ( method : NTQQApiMethod | NTQQApiMethod [ ] , hookFunc : ( callParams : unknown [ ] ) = > void | Promise < void > ) : void {
if ( ! Array . isArray ( method ) ) {
method = [ method ]
}
callHooks . push ( {
method ,
hookFunc
} )
}
export function removeReceiveHook ( id : string ) {
const index = receiveHooks . findIndex ( h = > h . id === id )
receiveHooks . splice ( index , 1 ) ;
const index = receiveHooks . findIndex ( h = > h . id === id )
receiveHooks . splice ( index , 1 ) ;
}
let activatedGroups : string [ ] = [ ] ;
async function updateGroups ( _groups : Group [ ] , needUpdate : boolean = true ) {
for ( let group of _groups ) {
log ( "update group" , group )
// if (!activatedGroups.includes(group.groupCode)) {
NTQQMsgApi . activateChat ( { peerUid : group.groupCode , chatType : ChatType.group } ) . then ( ( r ) = > {
// activatedGroups.push(group.groupCode);
// log(`激活群聊天窗口${group.groupName}(${group.groupCode})`, r)
// if (r.result !== 0) {
// setTimeout(() => NTQQMsgApi.activateGroupChat(group.groupCode).then(r => log(`再次激活群聊天窗口${group.groupName}(${group.groupCode})`, r)), 500);
// }else {
// }
} ) . catch ( log )
// }
let existGroup = groups . find ( g = > g . groupCode == group . groupCode ) ;
if ( existGroup ) {
Object . assign ( existGroup , group ) ;
} else {
groups . push ( group ) ;
existGroup = group ;
}
if ( needUpdate ) {
const members = await NTQQGroupApi . getGroupMembers ( group . groupCode ) ;
if ( members ) {
existGroup . members = members ;
}
}
for ( let group of _groups ) {
log ( "update group" , group )
// if (!activatedGroups.includes(group.groupCode)) {
NTQQMsgApi . activateChat ( { peerUid : group.groupCode , chatType : ChatType.group } ) . then ( ( r ) = > {
// activatedGroups.push(group.groupCode);
// log(`激活群聊天窗口${group.groupName}(${group.groupCode})`, r)
// if (r.result !== 0) {
// setTimeout(() => NTQQMsgApi.activateGroupChat(group.groupCode).then(r => log(`再次激活群聊天窗口${group.groupName}(${group.groupCode})`, r)), 500);
// }else {
// }
} ) . catch ( log )
// }
let existGroup = groups . find ( g = > g . groupCode == group . groupCode ) ;
if ( existGroup ) {
Object . assign ( existGroup , group ) ;
} else {
groups . push ( group ) ;
existGroup = group ;
}
if ( needUpdate ) {
const members = await NTQQGroupApi . getGroupMembers ( group . groupCode ) ;
if ( members ) {
existGroup . members = members ;
}
}
}
}
async function processGroupEvent ( payload : { groupList : Group [ ] } ) {
try {
const newGroupList = payload . groupList ;
for ( const group of newGroupList ) {
let existGroup = groups . find ( g = > g . groupCode == group . groupCode ) ;
if ( existGroup ) {
if ( existGroup . memberCount > group . memberCount ) {
log ( ` 群( ${ group . groupCode } )成员数量减少 ${ existGroup . memberCount } -> ${ group . memberCount } ` ) ;
const oldMembers = existGroup . members ;
try {
const newGroupList = payload . groupList ;
for ( const group of newGroupList ) {
let existGroup = groups . find ( g = > g . groupCode == group . groupCode ) ;
if ( existGroup ) {
if ( existGroup . memberCount > group . memberCount ) {
log ( ` 群( ${ group . groupCode } )成员数量减少 ${ existGroup . memberCount } -> ${ group . memberCount } ` ) ;
const oldMembers = existGroup . members ;
await sleep ( 200 ) ; // 如果请求QQ API的速度过快, 通常无法正确拉取到最新的群信息, 因此这里人为引入一个延时
const newMembers = await NTQQGroupApi . getGroupMembers ( group . groupCode ) ;
await sleep ( 200 ) ; // 如果请求QQ API的速度过快, 通常无法正确拉取到最新的群信息, 因此这里人为引入一个延时
const newMembers = await NTQQGroupApi . 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 ) ;
}
// 判断bot是否是管理员, 如果是管理员不需要从这里得知有人退群, 这里的退群无法得知是主动退群还是被踢
let bot = await getGroupMember ( group . groupCode , selfInfo . uin )
if ( bot . role == GroupMemberRole . admin || bot . role == GroupMemberRole . owner ) {
continue
}
for ( const member of oldMembers ) {
if ( ! newMembersSet . has ( member . uin ) && member . uin != selfInfo . uin ) {
postOB11Event ( new OB11GroupDecreaseEvent ( parseInt ( group . groupCode ) , parseInt ( member . uin ) , parseInt ( member . uin ) , "leave" ) ) ;
break ;
}
}
}
for ( const member of newMembers ) {
newMembersSet . add ( member . uin ) ;
}
// 判断bot是否是管理员, 如果是管理员不需要从这里得知有人退群, 这里的退群无法得知是主动退群还是被踢
let bot = await getGroupMember ( group . groupCode , selfInfo . uin )
if ( bot . role == GroupMemberRole . admin || bot . role == GroupMemberRole . owner ) {
continue
}
for ( const member of oldMembers ) {
if ( ! newMembersSet . has ( member . uin ) && member . uin != selfInfo . uin ) {
postOB11Event ( new OB11GroupDecreaseEvent ( parseInt ( group . groupCode ) , parseInt ( member . uin ) , parseInt ( member . uin ) , "leave" ) ) ;
break ;
}
}
}
updateGroups ( newGroupList , false ) . then ( ) ;
} catch ( e ) {
updateGroups ( payload . groupList ) . then ( ) ;
log ( "更新群信息错误" , e . stack . toString ( ) ) ;
}
}
updateGroups ( newGroupList , false ) . then ( ) ;
} catch ( e ) {
updateGroups ( payload . groupList ) . then ( ) ;
log ( "更新群信息错误" , e . stack . toString ( ) ) ;
}
}
// 群列表变动
registerReceiveHook < { groupList : Group [ ] , updateType : number } > ( ReceiveCmdS . GROUPS , ( payload ) = > {
// updateType 3是群列表变动, 2是群成员变动
// log("群列表变动", payload.updateType, payload.groupList)
if ( payload . updateType != 2 ) {
updateGroups ( payload . groupList ) . then ( ) ;
} else {
if ( process . platform == "win32" ) {
processGroupEvent ( payload ) . then ( ) ;
}
// updateType 3是群列表变动, 2是群成员变动
// log("群列表变动", payload.updateType, payload.groupList)
if ( payload . updateType != 2 ) {
updateGroups ( payload . groupList ) . then ( ) ;
} else {
if ( process . platform == "win32" ) {
processGroupEvent ( payload ) . then ( ) ;
}
}
} )
registerReceiveHook < { groupList : Group [ ] , updateType : number } > ( ReceiveCmdS . GROUPS_STORE , ( payload ) = > {
// updateType 3是群列表变动, 2是群成员变动
// log("群列表变动", payload.updateType, payload.groupList)
if ( payload . updateType != 2 ) {
updateGroups ( payload . groupList ) . then ( ) ;
} else {
if ( process . platform != "win32" ) {
processGroupEvent ( payload ) . then ( ) ;
}
// updateType 3是群列表变动, 2是群成员变动
// log("群列表变动", payload.updateType, payload.groupList)
if ( payload . updateType != 2 ) {
updateGroups ( payload . groupList ) . then ( ) ;
} else {
if ( process . platform != "win32" ) {
processGroupEvent ( payload ) . then ( ) ;
}
}
} )
registerReceiveHook < {
groupCode : string ,
dataSource : number ,
members : Set < GroupMember >
groupCode : string ,
dataSource : number ,
members : Set < GroupMember >
} > ( ReceiveCmdS . GROUP_MEMBER_INFO_UPDATE , async ( payload ) = > {
const groupCode = payload . groupCode ;
const members = Array . from ( payload . members . values ( ) ) ;
// log("群成员信息变动", groupCode, members)
for ( const member of members ) {
const existMember = await getGroupMember ( groupCode , member . uin ) ;
if ( existMember ) {
Object . assign ( existMember , member ) ;
}
const groupCode = payload . groupCode ;
const members = Array . from ( payload . members . values ( ) ) ;
// log("群成员信息变动", groupCode, members)
for ( const member of members ) {
const existMember = await getGroupMember ( groupCode , member . uin ) ;
if ( existMember ) {
Object . assign ( existMember , member ) ;
}
// const existGroup = groups.find(g => g.groupCode == groupCode);
// if ( existGroup) {
// log("对比群成员", existGroup.members, members)
// for (const member of members) {
// const existMember = existGroup.members.find(m => m.uin == member.uin);
// if ( existMember) {
// log("对比群名片", existMember.cardName, member.cardName)
// if ( existMember.cardName != member.cardName) {
// postOB11Event(new OB11GroupCardEvent(parseInt(existGroup.groupCode), parseInt(member.uin), m ember.cardName, existM ember.cardName));
// }
// Object.assign(existMember, member);
// }
// }
// }
}
// const existGroup = groups.find(g => g.groupCode == groupCode);
// if (existGroup) {
// log("对比群成员", existGroup. members, members)
// for ( const member of members) {
// const existMember = existGroup.members.find(m => m.uin == member.uin);
// if (existMember) {
// log("对比群名片", existMember.cardName, member.cardName)
// if (existM ember.cardName != m ember.cardName) {
// postOB11Event(new OB11GroupCardEvent(parseInt(existGroup.groupCode), parseInt(member.uin), member.cardName, existMember.cardName));
// }
// Object.assign(existMember, member);
// }
// }
// }
} )
// 好友列表变动
registerReceiveHook < {
data : { categoryId : number , categroyName : string , categroyMbCount : number , buddyList : User [ ] } [ ]
data : { categoryId : number , categroyName : string , categroyMbCount : number , buddyList : User [ ] } [ ]
} > ( ReceiveCmdS . FRIENDS , payload = > {
for ( const fData of payload . data ) {
const _friends = fData . buddyList ;
for ( let friend of _friends ) {
NTQQMsgApi . activateChat ( { peerUid : friend.uid , chatType : ChatType.friend } ) . then ( )
let existFriend = friends . find ( f = > f . uin == friend . uin )
if ( ! existFriend ) {
friends . push ( friend )
} else {
Object . assign ( existFriend , friend )
}
}
for ( const fData of payload . data ) {
const _friends = fData . buddyList ;
for ( let friend of _friends ) {
NTQQMsgApi . activateChat ( { peerUid : friend.uid , chatType : ChatType.friend } ) . then ( )
let existFriend = friends . find ( f = > f . uin == friend . uin )
if ( ! existFriend ) {
friends . push ( friend )
} else {
Object . assign ( existFriend , friend )
}
}
}
} )
registerReceiveHook < { msgList : Array < RawMessage > } > ( [ ReceiveCmdS . NEW_MSG , ReceiveCmdS . NEW_ACTIVE_MSG ] , ( payload ) = > {
// 保存一下uid
for ( const message of payload . msgList ) {
const uid = message . senderUid ;
const uin = message . senderUin ;
if ( uid && uin ) {
if ( message . chatType === ChatType . temp ) {
dbUtil . getReceivedTempUinMap ( ) . then ( receivedTempUinMap = > {
if ( ! receivedTempUinMap [ uin ] ) {
receivedTempUinMap [ uin ] = uid ;
dbUtil . setReceivedTempUinMap ( receivedTempUinMap )
}
} )
}
uidMaps [ uid ] = uin ;
// 保存一下uid
for ( const message of payload . msgList ) {
const uid = message . senderUid ;
const uin = message . senderUin ;
if ( uid && uin ) {
if ( message . chatType === ChatType . temp ) {
dbUtil . getReceivedTempUinMap ( ) . then ( receivedTempUinMap = > {
if ( ! receivedTempUinMap [ uin ] ) {
receivedTempUinMap [ uin ] = uid ;
dbUtil . setReceivedTempUinMap ( receivedTempUinMap )
}
} )
}
uidMaps [ uid ] = uin ;
}
}
// 自动清理新消息文件
const { autoDeleteFile } = getConfigUtil ( ) . getConfig ( ) ;
if ( ! autoDeleteFile ) {
return
}
for ( const message of payload . msgList ) {
// log("收到新消息, push到历史记录", message.msgId)
// dbUtil.addMsg(message).then()
// 清理文件
for ( const msgElement of message . elements ) {
setTimeout ( ( ) = > {
const picPath = msgElement . picElement ? . sourcePath
const picThumbPath = [ . . . msgElement . picElement ? . thumbPath . values ( ) ]
const pttPath = msgElement . pttElement ? . filePath
const filePath = msgElement . fileElement ? . filePath
const videoPath = msgElement . videoElement ? . filePath
const videoThumbPath : string [ ] = [ . . . msgElement . videoElement ? . thumbPath . values ( ) ]
const pathList = [ picPath , . . . picThumbPath , pttPath , filePath , videoPath , . . . videoThumbPath ]
if ( msgElement . picElement ) {
pathList . push ( . . . Object . values ( msgElement . picElement . thumbPath ) )
}
}
// 自动清理新消息文件
const { autoDeleteFile } = getConfigUtil ( ) . getConfig ( ) ;
if ( ! autoDeleteFile ) {
return
}
for ( const message of payload . msgList ) {
// log("收到新消息, push到历史记录", message.msgId)
// dbUtil.addMsg(message).then()
// 清理文件
for ( const msgElement of message . elements ) {
setTimeout ( ( ) = > {
const picPath = msgElement . picElement ? . sourcePath
const picThumbPath = [ . . . msgElement . picElement ? . thumbPath . values ( ) ]
const pttPath = msgElement . pttElement ? . filePath
const filePath = msgElement . fileElement ? . filePath
const videoPath = msgElement . videoElement ? . filePath
const videoThumbPath : string [ ] = [ . . . msgElement . videoElement ? . thumbPath . values ( ) ]
const pathList = [ picPath , . . . picThumbPath , pttPath , filePath , videoPath , . . . videoThumbPath ]
if ( msgElement . picElement ) {
pathList . push ( . . . Object . values ( msgElement . picElement . thumbPath ) )
}
const aioOpGrayTipElement = msgElement . grayTipElement ? . aioOpGrayTipElement
if ( aioOpGrayTipElement ) {
tempGroupCodeMap [ aioOpGrayTipElement . peerUid ] = aioOpGrayTipElement . fromGrpCodeOfTmpChat ;
}
// log("需要清理的文件", pathList);
for ( const path of pathList ) {
if ( path ) {
fs . unlink ( picPath , ( ) = > {
log ( "删除文件成功" , path )
} ) ;
}
}
} , getConfigUtil ( ) . getConfig ( ) . autoDeleteFileSecond * 1000 )
const aioOpGrayTipElement = msgElement . grayTipElement ? . aioOpGrayTipElement
if ( aioOpGrayTipElement ) {
tempGroupCodeMap [ aioOpGrayTipElement . peerUid ] = aioOpGrayTipElement . fromGrpCodeOfTmpChat ;
}
// log("需要清理的文件", pathList);
for ( const path of pathList ) {
if ( path ) {
fs . unlink ( picPath , ( ) = > {
log ( "删除文件成功" , path )
} ) ;
}
}
} , getConfigUtil ( ) . getConfig ( ) . autoDeleteFileSecond * 1000 )
}
}
} )
registerReceiveHook < { msgRecord : RawMessage } > ( ReceiveCmdS . SELF_SEND_MSG , ( { msgRecord } ) = > {
const message = msgRecord ;
const peerUid = message . peerUid ;
// log("收到自己发送成功的消息", Object.keys(sendMessagePool), message);
// log("收到自己发送成功的消息", message.msgId, message.msgSeq);
dbUtil . addMsg ( message ) . then ( )
const sendCallback = sendMessagePool [ peerUid ]
if ( sendCallback ) {
try {
sendCallback ( message ) ;
} catch ( e ) {
log ( "receive self msg error" , e . stack )
}
const message = msgRecord ;
const peerUid = message . peerUid ;
// log("收到自己发送成功的消息", Object.keys(sendMessagePool), message);
// log("收到自己发送成功的消息", message.msgId, message.msgSeq);
dbUtil . addMsg ( message ) . then ( )
const sendCallback = sendMessagePool [ peerUid ]
if ( sendCallback ) {
try {
sendCallback ( message ) ;
} catch ( e ) {
log ( "receive self msg error" , e . stack )
}
}
} )
registerReceiveHook < { info : { status : number } } > ( ReceiveCmdS . SELF_STATUS , ( info ) = > {
selfInfo . online = info . info . status !== 20
selfInfo . online = info . info . status !== 20
} )
let activatedPeerUids : string [ ] = [ ]
registerReceiveHook < {
changedRecentContactLists : {
listType : number , sortedContactList : string [ ] ,
changedList : {
id : string , // peerUid
chatType : ChatType
} [ ]
changedRecentContactLists : {
listType : number , sortedContactList : string [ ] ,
changedList : {
id : string , // peerUid
chatType : ChatType
} [ ]
} [ ]
} > ( ReceiveCmdS . RECENT_CONTACT , async ( payload ) = > {
for ( const recentContact of payload . changedRecentContactLists ) {
for ( const changedContact of recentContact . changedList ) {
if ( activatedPeerUids . includes ( changedContact . id ) ) continue ;
activatedPeerUids . push ( changedContact . id )
const peer = { peerUid : changedContact.id , chatType : changedContact.chatType }
if ( changedContact . chatType === ChatType . temp ) {
log ( "收到临时会话消息" , peer )
NTQQMsgApi . activateChatAndGetHistory ( peer ) . then (
( ) = > {
NTQQMsgApi . getMsgHistory ( peer , "" , 20 ) . then ( ( { msgList } ) = > {
let lastTempMsg = msgList . pop ( )
log ( "激活窗口之前的第一条临时会话消息:" , lastTempMsg )
if ( ( Date . now ( ) / 1000 ) - parseInt ( lastTempMsg . msgTime ) < 5 ) {
OB11Constructor . message ( lastTempMsg ) . then ( r = > postOB11Event ( r ) )
}
} )
}
)
} else {
NTQQMsgApi . activateChat ( peer ) . then ( )
}
}
for ( const recentContact of payload . changedRecentContactLists ) {
for ( const changedContact of recentContact . changedList ) {
if ( activatedPeerUids . includes ( changedContact . id ) ) continue ;
activatedPeerUids . push ( changedContact . id )
const peer = { peerUid : changedContact.id , chatType : changedContact.chatType }
if ( changedContact . chatType === ChatType . temp ) {
log ( "收到临时会话消息" , peer )
NTQQMsgApi . activateChatAndGetHistory ( peer ) . then (
( ) = > {
NTQQMsgApi . getMsgHistory ( peer , "" , 20 ) . then ( ( { msgList } ) = > {
let lastTempMsg = msgList . pop ( )
log ( "激活窗口之前的第一条临时会话消息:" , lastTempMsg )
if ( ( Date . now ( ) / 1000 ) - parseInt ( lastTempMsg . msgTime ) < 5 ) {
OB11Constructor . message ( lastTempMsg ) . then ( r = > postOB11Event ( r ) )
}
} )
}
)
} else {
NTQQMsgApi . activateChat ( peer ) . then ( )
}
}
}
} )
registerCallHook ( NTQQApiMethod . DELETE_ACTIVE_CHAT , async ( payload ) = > {
const peerUid = payload [ 0 ] as string ;
log ( "激活的聊天窗口被删除,准备重新激活" , peerUid ) ;
let chatType = ChatType . friend ;
if ( isNumeric ( peerUid ) ) {
chatType = ChatType . group ;
}
else {
// 检查是否好友
if ( ! ( await getFriend ( peerUid ) ) ) {
chatType = ChatType . temp ;
}
}
const peer = { peerUid , chatType }
await sleep ( 1000 ) ;
NTQQMsgApi . activateChat ( peer ) . then ( ( r ) = > {
log ( "重新激活聊天窗口" , peer , { result : r.result , errMsg : r.errMsg } )
} ) ;
} )