mirror of
https://github.com/LLOneBot/LLOneBot.git
synced 2024-11-22 01:56:33 +00:00
Merge remote-tracking branch 'upstream/dev' into dev
This commit is contained in:
commit
cdb34ffe61
@ -3,7 +3,7 @@
|
|||||||
"type": "extension",
|
"type": "extension",
|
||||||
"name": "LLOneBot",
|
"name": "LLOneBot",
|
||||||
"slug": "LLOneBot",
|
"slug": "LLOneBot",
|
||||||
"description": "实现 OneBot 11 协议,帮助进行 QQ 机器人开发",
|
"description": "实现 OneBot 11 协议,用以 QQ 机器人开发",
|
||||||
"version": "3.27.4",
|
"version": "3.27.4",
|
||||||
"icon": "./icon.webp",
|
"icon": "./icon.webp",
|
||||||
"authors": [
|
"authors": [
|
||||||
|
231
src/common/utils/EventTask.ts
Normal file
231
src/common/utils/EventTask.ts
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
import { NodeIQQNTWrapperSession } from '@/ntqqapi/wrapper'
|
||||||
|
import { randomUUID } from 'node:crypto'
|
||||||
|
|
||||||
|
interface Internal_MapKey {
|
||||||
|
timeout: number
|
||||||
|
createtime: number
|
||||||
|
func: (...arg: any[]) => any
|
||||||
|
checker: ((...args: any[]) => boolean) | undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ListenerClassBase {
|
||||||
|
[key: string]: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ListenerIBase {
|
||||||
|
new(listener: any): ListenerClassBase
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NTEventWrapper {
|
||||||
|
private ListenerMap: { [key: string]: ListenerIBase } | undefined//ListenerName-Unique -> Listener构造函数
|
||||||
|
private WrapperSession: NodeIQQNTWrapperSession | undefined//WrapperSession
|
||||||
|
private ListenerManger: Map<string, ListenerClassBase> = new Map<string, ListenerClassBase>() //ListenerName-Unique -> Listener实例
|
||||||
|
private EventTask = new Map<string, Map<string, Map<string, Internal_MapKey>>>()//tasks ListenerMainName -> ListenerSubName-> uuid -> {timeout,createtime,func}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
createProxyDispatch(ListenerMainName: string) {
|
||||||
|
const current = this
|
||||||
|
return new Proxy({}, {
|
||||||
|
get(target: any, prop: any, receiver: any) {
|
||||||
|
// console.log('get', prop, typeof target[prop])
|
||||||
|
if (typeof target[prop] === 'undefined') {
|
||||||
|
// 如果方法不存在,返回一个函数,这个函数调用existentMethod
|
||||||
|
return (...args: any[]) => {
|
||||||
|
current.DispatcherListener.apply(current, [ListenerMainName, prop, ...args]).then()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果方法存在,正常返回
|
||||||
|
return Reflect.get(target, prop, receiver)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
init({ ListenerMap, WrapperSession }: { ListenerMap: { [key: string]: typeof ListenerClassBase }, WrapperSession: NodeIQQNTWrapperSession }) {
|
||||||
|
this.ListenerMap = ListenerMap
|
||||||
|
this.WrapperSession = WrapperSession
|
||||||
|
}
|
||||||
|
|
||||||
|
CreatEventFunction<T extends (...args: any) => any>(eventName: string): T | undefined {
|
||||||
|
const eventNameArr = eventName.split('/')
|
||||||
|
type eventType = {
|
||||||
|
[key: string]: () => { [key: string]: (...params: Parameters<T>) => Promise<ReturnType<T>> }
|
||||||
|
}
|
||||||
|
if (eventNameArr.length > 1) {
|
||||||
|
const serviceName = 'get' + eventNameArr[0].replace('NodeIKernel', '')
|
||||||
|
const eventName = eventNameArr[1]
|
||||||
|
//getNodeIKernelGroupListener,GroupService
|
||||||
|
//console.log('2', eventName)
|
||||||
|
const services = (this.WrapperSession as unknown as eventType)[serviceName]()
|
||||||
|
let event = services[eventName]
|
||||||
|
//重新绑定this
|
||||||
|
event = event.bind(services)
|
||||||
|
if (event) {
|
||||||
|
return event as T
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CreatListenerFunction<T>(listenerMainName: string, uniqueCode: string = ''): T {
|
||||||
|
const ListenerType = this.ListenerMap![listenerMainName]
|
||||||
|
let Listener = this.ListenerManger.get(listenerMainName + uniqueCode)
|
||||||
|
if (!Listener && ListenerType) {
|
||||||
|
Listener = new ListenerType(this.createProxyDispatch(listenerMainName))
|
||||||
|
const ServiceSubName = listenerMainName.match(/^NodeIKernel(.*?)Listener$/)![1]
|
||||||
|
const Service = 'NodeIKernel' + ServiceSubName + 'Service/addKernel' + ServiceSubName + 'Listener'
|
||||||
|
const addfunc = this.CreatEventFunction<(listener: T) => number>(Service)
|
||||||
|
addfunc!(Listener as T)
|
||||||
|
//console.log(addfunc!(Listener as T))
|
||||||
|
this.ListenerManger.set(listenerMainName + uniqueCode, Listener)
|
||||||
|
}
|
||||||
|
return Listener as T
|
||||||
|
}
|
||||||
|
|
||||||
|
//统一回调清理事件
|
||||||
|
async DispatcherListener(ListenerMainName: string, ListenerSubName: string, ...args: any[]) {
|
||||||
|
//console.log("[EventDispatcher]",ListenerMainName, ListenerSubName, ...args)
|
||||||
|
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.forEach((task, uuid) => {
|
||||||
|
//console.log(task.func, uuid, task.createtime, task.timeout)
|
||||||
|
if (task.createtime + task.timeout < Date.now()) {
|
||||||
|
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.delete(uuid)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (task.checker && task.checker(...args)) {
|
||||||
|
task.func(...args)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async CallNoListenerEvent<EventType extends (...args: any[]) => Promise<any> | any>(EventName = '', timeout: number = 3000, ...args: Parameters<EventType>) {
|
||||||
|
return new Promise<Awaited<ReturnType<EventType>>>(async (resolve, reject) => {
|
||||||
|
const EventFunc = this.CreatEventFunction<EventType>(EventName)
|
||||||
|
let complete = false
|
||||||
|
const Timeouter = setTimeout(() => {
|
||||||
|
if (!complete) {
|
||||||
|
reject(new Error('NTEvent EventName:' + EventName + ' timeout'))
|
||||||
|
}
|
||||||
|
}, timeout)
|
||||||
|
const retData = await EventFunc!(...args)
|
||||||
|
complete = true
|
||||||
|
resolve(retData)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async RegisterListen<ListenerType extends (...args: any[]) => void>(ListenerName = '', waitTimes = 1, timeout = 5000, checker: (...args: Parameters<ListenerType>) => boolean) {
|
||||||
|
return new Promise<Parameters<ListenerType>>((resolve, reject) => {
|
||||||
|
const ListenerNameList = ListenerName.split('/')
|
||||||
|
const ListenerMainName = ListenerNameList[0]
|
||||||
|
const ListenerSubName = ListenerNameList[1]
|
||||||
|
const id = randomUUID()
|
||||||
|
let complete = 0
|
||||||
|
let retData: Parameters<ListenerType> | undefined = undefined
|
||||||
|
const databack = () => {
|
||||||
|
if (complete == 0) {
|
||||||
|
reject(new Error(' ListenerName:' + ListenerName + ' timeout'))
|
||||||
|
} else {
|
||||||
|
resolve(retData!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const Timeouter = setTimeout(databack, timeout)
|
||||||
|
const eventCallbak = {
|
||||||
|
timeout: timeout,
|
||||||
|
createtime: Date.now(),
|
||||||
|
checker: checker,
|
||||||
|
func: (...args: Parameters<ListenerType>) => {
|
||||||
|
complete++
|
||||||
|
retData = args
|
||||||
|
if (complete >= waitTimes) {
|
||||||
|
clearTimeout(Timeouter)
|
||||||
|
databack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!this.EventTask.get(ListenerMainName)) {
|
||||||
|
this.EventTask.set(ListenerMainName, new Map())
|
||||||
|
}
|
||||||
|
if (!(this.EventTask.get(ListenerMainName)?.get(ListenerSubName))) {
|
||||||
|
this.EventTask.get(ListenerMainName)?.set(ListenerSubName, new Map())
|
||||||
|
}
|
||||||
|
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallbak)
|
||||||
|
this.CreatListenerFunction(ListenerMainName)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async CallNormalEvent<EventType extends (...args: any[]) => Promise<any>, ListenerType extends (...args: any[]) => void>
|
||||||
|
(EventName = '', ListenerName = '', waitTimes = 1, timeout: number = 3000, checker: (...args: Parameters<ListenerType>) => boolean, ...args: Parameters<EventType>) {
|
||||||
|
return new Promise<[EventRet: Awaited<ReturnType<EventType>>, ...Parameters<ListenerType>]>(async (resolve, reject) => {
|
||||||
|
const id = randomUUID()
|
||||||
|
let complete = 0
|
||||||
|
let retData: Parameters<ListenerType> | undefined = undefined
|
||||||
|
let retEvent: any = {}
|
||||||
|
const databack = () => {
|
||||||
|
if (complete == 0) {
|
||||||
|
reject(new Error('Timeout: NTEvent EventName:' + EventName + ' ListenerName:' + ListenerName + ' EventRet:\n' + JSON.stringify(retEvent, null, 4) + '\n'))
|
||||||
|
} else {
|
||||||
|
resolve([retEvent as Awaited<ReturnType<EventType>>, ...retData!])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ListenerNameList = ListenerName.split('/')
|
||||||
|
const ListenerMainName = ListenerNameList[0]
|
||||||
|
const ListenerSubName = ListenerNameList[1]
|
||||||
|
|
||||||
|
const Timeouter = setTimeout(databack, timeout)
|
||||||
|
|
||||||
|
const eventCallbak = {
|
||||||
|
timeout: timeout,
|
||||||
|
createtime: Date.now(),
|
||||||
|
checker: checker,
|
||||||
|
func: (...args: any[]) => {
|
||||||
|
complete++
|
||||||
|
//console.log('func', ...args)
|
||||||
|
retData = args as Parameters<ListenerType>
|
||||||
|
if (complete >= waitTimes) {
|
||||||
|
clearTimeout(Timeouter)
|
||||||
|
databack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!this.EventTask.get(ListenerMainName)) {
|
||||||
|
this.EventTask.set(ListenerMainName, new Map())
|
||||||
|
}
|
||||||
|
if (!(this.EventTask.get(ListenerMainName)?.get(ListenerSubName))) {
|
||||||
|
this.EventTask.get(ListenerMainName)?.set(ListenerSubName, new Map())
|
||||||
|
}
|
||||||
|
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallbak)
|
||||||
|
this.CreatListenerFunction(ListenerMainName)
|
||||||
|
const EventFunc = this.CreatEventFunction<EventType>(EventName)
|
||||||
|
retEvent = await EventFunc!(...(args as any[]))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const NTEventDispatch = new NTEventWrapper()
|
||||||
|
|
||||||
|
// 示例代码 快速创建事件
|
||||||
|
// let NTEvent = new NTEventWrapper()
|
||||||
|
// let TestEvent = NTEvent.CreatEventFunction<(force: boolean) => Promise<Number>>('NodeIKernelProfileLikeService/GetTest')
|
||||||
|
// if (TestEvent) {
|
||||||
|
// TestEvent(true)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 示例代码 快速创建监听Listener类
|
||||||
|
// let NTEvent = new NTEventWrapper()
|
||||||
|
// NTEvent.CreatListenerFunction<NodeIKernelMsgListener>('NodeIKernelMsgListener', 'core')
|
||||||
|
|
||||||
|
|
||||||
|
// 调用接口
|
||||||
|
//let NTEvent = new NTEventWrapper()
|
||||||
|
//let ret = await NTEvent.CallNormalEvent<(force: boolean) => Promise<Number>, (data1: string, data2: number) => void>('NodeIKernelProfileLikeService/GetTest', 'NodeIKernelMsgListener/onAddSendMsg', 1, 3000, true)
|
||||||
|
|
||||||
|
// 注册监听 解除监听
|
||||||
|
// NTEventDispatch.RigisterListener('NodeIKernelMsgListener/onAddSendMsg','core',cb)
|
||||||
|
// NTEventDispatch.UnRigisterListener('NodeIKernelMsgListener/onAddSendMsg','core')
|
||||||
|
|
||||||
|
// let GetTest = NTEventDispatch.CreatEvent('NodeIKernelProfileLikeService/GetTest','NodeIKernelMsgListener/onAddSendMsg',Mode)
|
||||||
|
// GetTest('test')
|
||||||
|
|
||||||
|
// always模式
|
||||||
|
// NTEventDispatch.CreatEvent('NodeIKernelProfileLikeService/GetTest','NodeIKernelMsgListener/onAddSendMsg',Mode,(...args:any[])=>{ console.log(args) })
|
@ -36,11 +36,8 @@ import {
|
|||||||
RawMessage,
|
RawMessage,
|
||||||
} from '../ntqqapi/types'
|
} from '../ntqqapi/types'
|
||||||
import { httpHeart, ob11HTTPServer } from '../onebot11/server/http'
|
import { httpHeart, ob11HTTPServer } from '../onebot11/server/http'
|
||||||
import { OB11FriendRecallNoticeEvent } from '../onebot11/event/notice/OB11FriendRecallNoticeEvent'
|
|
||||||
import { OB11GroupRecallNoticeEvent } from '../onebot11/event/notice/OB11GroupRecallNoticeEvent'
|
|
||||||
import { postOb11Event } from '../onebot11/server/post-ob11-event'
|
import { postOb11Event } from '../onebot11/server/post-ob11-event'
|
||||||
import { ob11ReverseWebsockets } from '../onebot11/server/ws/ReverseWebsocket'
|
import { ob11ReverseWebsockets } from '../onebot11/server/ws/ReverseWebsocket'
|
||||||
import { OB11GroupAdminNoticeEvent } from '../onebot11/event/notice/OB11GroupAdminNoticeEvent'
|
|
||||||
import { OB11GroupRequestEvent } from '../onebot11/event/request/OB11GroupRequest'
|
import { OB11GroupRequestEvent } from '../onebot11/event/request/OB11GroupRequest'
|
||||||
import { OB11FriendRequestEvent } from '../onebot11/event/request/OB11FriendRequest'
|
import { OB11FriendRequestEvent } from '../onebot11/event/request/OB11FriendRequest'
|
||||||
import * as path from 'node:path'
|
import * as path from 'node:path'
|
||||||
@ -48,16 +45,15 @@ import { dbUtil } from '../common/db'
|
|||||||
import { setConfig } from './setConfig'
|
import { setConfig } from './setConfig'
|
||||||
import { NTQQUserApi } from '../ntqqapi/api/user'
|
import { NTQQUserApi } from '../ntqqapi/api/user'
|
||||||
import { NTQQGroupApi } from '../ntqqapi/api/group'
|
import { NTQQGroupApi } from '../ntqqapi/api/group'
|
||||||
import { OB11FriendPokeEvent, OB11GroupPokeEvent } from '../onebot11/event/notice/OB11PokeEvent'
|
|
||||||
import { checkNewVersion, upgradeLLOneBot } from '../common/utils/upgrade'
|
import { checkNewVersion, upgradeLLOneBot } from '../common/utils/upgrade'
|
||||||
import { log } from '../common/utils/log'
|
import { log } from '../common/utils/log'
|
||||||
import { getConfigUtil } from '../common/config'
|
import { getConfigUtil } from '../common/config'
|
||||||
import { checkFfmpeg } from '../common/utils/video'
|
import { checkFfmpeg } from '../common/utils/video'
|
||||||
import { GroupDecreaseSubType, OB11GroupDecreaseEvent } from '../onebot11/event/notice/OB11GroupDecreaseEvent'
|
import { GroupDecreaseSubType, OB11GroupDecreaseEvent } from '../onebot11/event/notice/OB11GroupDecreaseEvent'
|
||||||
import '../ntqqapi/native/wrapper'
|
import '../ntqqapi/wrapper'
|
||||||
import { sentMessages } from '@/ntqqapi/api'
|
import { sentMessages } from '@/ntqqapi/api'
|
||||||
|
import { NTEventDispatch } from '../common/utils/EventTask'
|
||||||
let running = false
|
import { wrapperApi, wrapperConstructor } from '../ntqqapi/wrapper'
|
||||||
|
|
||||||
let mainWindow: BrowserWindow | null = null
|
let mainWindow: BrowserWindow | null = null
|
||||||
|
|
||||||
@ -442,6 +438,7 @@ function onLoad() {
|
|||||||
uidMaps[value] = key
|
uidMaps[value] = key
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
NTEventDispatch.init({ ListenerMap: wrapperConstructor, WrapperSession: wrapperApi.NodeIQQNTWrapperSession })
|
||||||
try {
|
try {
|
||||||
log('start get groups')
|
log('start get groups')
|
||||||
const _groups = await NTQQGroupApi.getGroups()
|
const _groups = await NTQQGroupApi.getGroups()
|
||||||
|
@ -11,22 +11,24 @@ import {
|
|||||||
IMAGE_HTTP_HOST,
|
IMAGE_HTTP_HOST,
|
||||||
IMAGE_HTTP_HOST_NT, PicElement,
|
IMAGE_HTTP_HOST_NT, PicElement,
|
||||||
} from '../types'
|
} from '../types'
|
||||||
import path from 'path'
|
import path from 'node:path'
|
||||||
import fs from 'fs'
|
import fs from 'node:fs'
|
||||||
import { ReceiveCmdS } from '../hook'
|
import { ReceiveCmdS } from '../hook'
|
||||||
import { log } from '@/common/utils'
|
import { log } from '@/common/utils'
|
||||||
import { rkeyManager } from '@/ntqqapi/api/rkey'
|
import { rkeyManager } from '@/ntqqapi/api/rkey'
|
||||||
import { wrapperApi } from '@/ntqqapi/native/wrapper'
|
import { wrapperApi } from '@/ntqqapi/wrapper'
|
||||||
import { Peer } from '@/ntqqapi/api/msg'
|
import { Peer } from '@/ntqqapi/types/msg'
|
||||||
|
|
||||||
export class NTQQFileApi {
|
export class NTQQFileApi {
|
||||||
static async getVideoUrl(peer: Peer, msgId: string, elementId: string): Promise<string> {
|
static async getVideoUrl(peer: Peer, msgId: string, elementId: string): Promise<string> {
|
||||||
return (await wrapperApi.NodeIQQNTWrapperSession.getRichMediaService().getVideoPlayUrlV2(peer,
|
const session = wrapperApi.NodeIQQNTWrapperSession
|
||||||
|
return (await session.getRichMediaService().getVideoPlayUrlV2(peer,
|
||||||
msgId,
|
msgId,
|
||||||
elementId,
|
elementId,
|
||||||
0,
|
0,
|
||||||
{ downSourceType: 1, triggerType: 1 })).urlResult?.domainUrl[0]?.url;
|
{ downSourceType: 1, triggerType: 1 })).urlResult?.domainUrl[0]?.url;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getFileType(filePath: string) {
|
static async getFileType(filePath: string) {
|
||||||
return await callNTQQApi<{ ext: string }>({
|
return await callNTQQApi<{ ext: string }>({
|
||||||
className: NTQQApiClass.FS_API,
|
className: NTQQApiClass.FS_API,
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import { Friend, FriendRequest } from '../types'
|
import { Friend, FriendRequest, FriendV2 } from '../types'
|
||||||
import { ReceiveCmdS } from '../hook'
|
import { ReceiveCmdS } from '../hook'
|
||||||
import { callNTQQApi, GeneralCallResult, NTQQApiMethod } from '../ntcall'
|
import { callNTQQApi, GeneralCallResult, NTQQApiMethod } from '../ntcall'
|
||||||
import { friendRequests } from '../../common/data'
|
import { friendRequests } from '../../common/data'
|
||||||
import { log } from '../../common/utils'
|
import { wrapperApi } from '@/ntqqapi/wrapper'
|
||||||
|
import { BuddyListReqType, NodeIKernelProfileService } from '../services'
|
||||||
|
import { NTEventDispatch } from '../../common/utils/EventTask'
|
||||||
|
|
||||||
export class NTQQFriendApi {
|
export class NTQQFriendApi {
|
||||||
static async getFriends(forced = false) {
|
static async getFriends(forced = false) {
|
||||||
@ -26,6 +28,7 @@ export class NTQQFriendApi {
|
|||||||
}
|
}
|
||||||
return _friends
|
return _friends
|
||||||
}
|
}
|
||||||
|
|
||||||
static async likeFriend(uid: string, count = 1) {
|
static async likeFriend(uid: string, count = 1) {
|
||||||
return await callNTQQApi<GeneralCallResult>({
|
return await callNTQQApi<GeneralCallResult>({
|
||||||
methodName: NTQQApiMethod.LIKE_FRIEND,
|
methodName: NTQQApiMethod.LIKE_FRIEND,
|
||||||
@ -42,6 +45,7 @@ export class NTQQFriendApi {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static async handleFriendRequest(flag: string, accept: boolean) {
|
static async handleFriendRequest(flag: string, accept: boolean) {
|
||||||
const request: FriendRequest = friendRequests[flag]
|
const request: FriendRequest = friendRequests[flag]
|
||||||
if (!request) {
|
if (!request) {
|
||||||
@ -62,4 +66,16 @@ export class NTQQFriendApi {
|
|||||||
delete friendRequests[flag]
|
delete friendRequests[flag]
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async getBuddyV2(refresh = false): Promise<FriendV2[]> {
|
||||||
|
const uids: string[] = []
|
||||||
|
const session = wrapperApi.NodeIQQNTWrapperSession
|
||||||
|
const buddyService = session.getBuddyService()
|
||||||
|
const buddyListV2 = refresh ? await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL) : await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL)
|
||||||
|
uids.push(...buddyListV2.data.flatMap(item => item.buddyUids))
|
||||||
|
const data = await NTEventDispatch.CallNoListenerEvent<NodeIKernelProfileService['getCoreAndBaseInfo']>(
|
||||||
|
'NodeIKernelProfileService/getCoreAndBaseInfo', 5000, 'nodeStore', uids
|
||||||
|
)
|
||||||
|
return Array.from(data.values())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,25 +5,26 @@ import { deleteGroup, uidMaps } from '../../common/data'
|
|||||||
import { dbUtil } from '../../common/db'
|
import { dbUtil } from '../../common/db'
|
||||||
import { log } from '../../common/utils/log'
|
import { log } from '../../common/utils/log'
|
||||||
import { NTQQWindowApi, NTQQWindows } from './window'
|
import { NTQQWindowApi, NTQQWindows } from './window'
|
||||||
import { wrapperApi } from '../native/wrapper'
|
import { wrapperApi } from '../wrapper'
|
||||||
|
|
||||||
export class NTQQGroupApi {
|
export class NTQQGroupApi {
|
||||||
|
static async activateMemberListChange() {
|
||||||
static async activateMemberListChange(){
|
|
||||||
return await callNTQQApi<GeneralCallResult>({
|
return await callNTQQApi<GeneralCallResult>({
|
||||||
methodName: NTQQApiMethod.ACTIVATE_MEMBER_LIST_CHANGE,
|
methodName: NTQQApiMethod.ACTIVATE_MEMBER_LIST_CHANGE,
|
||||||
classNameIsRegister: true,
|
classNameIsRegister: true,
|
||||||
args: [],
|
args: [],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
static async activateMemberInfoChange(){
|
|
||||||
|
static async activateMemberInfoChange() {
|
||||||
return await callNTQQApi<GeneralCallResult>({
|
return await callNTQQApi<GeneralCallResult>({
|
||||||
methodName: NTQQApiMethod.ACTIVATE_MEMBER_INFO_CHANGE,
|
methodName: NTQQApiMethod.ACTIVATE_MEMBER_INFO_CHANGE,
|
||||||
classNameIsRegister: true,
|
classNameIsRegister: true,
|
||||||
args: [],
|
args: [],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
static async getGroupAllInfo(groupCode: string, source: number=4){
|
|
||||||
|
static async getGroupAllInfo(groupCode: string, source: number = 4) {
|
||||||
return await callNTQQApi<GeneralCallResult & Group>({
|
return await callNTQQApi<GeneralCallResult & Group>({
|
||||||
methodName: NTQQApiMethod.GET_GROUP_ALL_INFO,
|
methodName: NTQQApiMethod.GET_GROUP_ALL_INFO,
|
||||||
args: [
|
args: [
|
||||||
@ -35,6 +36,7 @@ export class NTQQGroupApi {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getGroups(forced = false) {
|
static async getGroups(forced = false) {
|
||||||
// let cbCmd = ReceiveCmdS.GROUPS
|
// let cbCmd = ReceiveCmdS.GROUPS
|
||||||
// if (process.platform != 'win32') {
|
// if (process.platform != 'win32') {
|
||||||
@ -52,6 +54,7 @@ export class NTQQGroupApi {
|
|||||||
log('get groups result', result)
|
log('get groups result', result)
|
||||||
return result.groupList
|
return result.groupList
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getGroupMembers(groupQQ: string, num = 3000): Promise<GroupMember[]> {
|
static async getGroupMembers(groupQQ: string, num = 3000): Promise<GroupMember[]> {
|
||||||
const sceneId = await callNTQQApi({
|
const sceneId = await callNTQQApi({
|
||||||
methodName: NTQQApiMethod.GROUP_MEMBER_SCENE,
|
methodName: NTQQApiMethod.GROUP_MEMBER_SCENE,
|
||||||
@ -62,7 +65,7 @@ export class NTQQGroupApi {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
// log("get group member sceneId", sceneId);
|
// log("get group member sceneId", sceneId)
|
||||||
try {
|
try {
|
||||||
const result = await callNTQQApi<{
|
const result = await callNTQQApi<{
|
||||||
result: { infos: any }
|
result: { infos: any }
|
||||||
@ -83,8 +86,8 @@ export class NTQQGroupApi {
|
|||||||
for (const member of members) {
|
for (const member of members) {
|
||||||
uidMaps[member.uid] = member.uin
|
uidMaps[member.uid] = member.uin
|
||||||
}
|
}
|
||||||
// log(uidMaps);
|
// log(uidMaps)
|
||||||
// log("members info", values);
|
// log("members info", values)
|
||||||
log(`get group ${groupQQ} members success`)
|
log(`get group ${groupQQ} members success`)
|
||||||
return members
|
return members
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -92,7 +95,8 @@ export class NTQQGroupApi {
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static async getGroupMembersInfo(groupCode: string, uids: string[], forceUpdate: boolean=false) {
|
|
||||||
|
static async getGroupMembersInfo(groupCode: string, uids: string[], forceUpdate: boolean = false) {
|
||||||
return await callNTQQApi<GeneralCallResult>({
|
return await callNTQQApi<GeneralCallResult>({
|
||||||
methodName: NTQQApiMethod.GROUP_MEMBERS_INFO,
|
methodName: NTQQApiMethod.GROUP_MEMBERS_INFO,
|
||||||
args: [
|
args: [
|
||||||
@ -105,6 +109,7 @@ export class NTQQGroupApi {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getGroupNotifies() {
|
static async getGroupNotifies() {
|
||||||
// 获取管理员变更
|
// 获取管理员变更
|
||||||
// 加群通知,退出通知,需要管理员权限
|
// 加群通知,退出通知,需要管理员权限
|
||||||
@ -119,6 +124,7 @@ export class NTQQGroupApi {
|
|||||||
args: [{ doubt: false, startSeq: '', number: 14 }, null],
|
args: [{ doubt: false, startSeq: '', number: 14 }, null],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getGroupIgnoreNotifies() {
|
static async getGroupIgnoreNotifies() {
|
||||||
await NTQQGroupApi.getGroupNotifies()
|
await NTQQGroupApi.getGroupNotifies()
|
||||||
return await NTQQWindowApi.openWindow<GeneralCallResult & GroupNotifies>(
|
return await NTQQWindowApi.openWindow<GeneralCallResult & GroupNotifies>(
|
||||||
@ -127,12 +133,13 @@ export class NTQQGroupApi {
|
|||||||
ReceiveCmdS.GROUP_NOTIFY,
|
ReceiveCmdS.GROUP_NOTIFY,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
static async handleGroupRequest(seq: string, operateType: GroupRequestOperateTypes, reason?: string) {
|
static async handleGroupRequest(seq: string, operateType: GroupRequestOperateTypes, reason?: string) {
|
||||||
const notify: GroupNotify = await dbUtil.getGroupNotify(seq)
|
const notify: GroupNotify = await dbUtil.getGroupNotify(seq)
|
||||||
if (!notify) {
|
if (!notify) {
|
||||||
throw `${seq}对应的加群通知不存在`
|
throw `${seq}对应的加群通知不存在`
|
||||||
}
|
}
|
||||||
// delete groupNotifies[seq];
|
// delete groupNotifies[seq]
|
||||||
return await callNTQQApi<GeneralCallResult>({
|
return await callNTQQApi<GeneralCallResult>({
|
||||||
methodName: NTQQApiMethod.HANDLE_GROUP_REQUEST,
|
methodName: NTQQApiMethod.HANDLE_GROUP_REQUEST,
|
||||||
args: [
|
args: [
|
||||||
@ -152,6 +159,7 @@ export class NTQQGroupApi {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static async quitGroup(groupQQ: string) {
|
static async quitGroup(groupQQ: string) {
|
||||||
const result = await callNTQQApi<GeneralCallResult>({
|
const result = await callNTQQApi<GeneralCallResult>({
|
||||||
methodName: NTQQApiMethod.QUIT_GROUP,
|
methodName: NTQQApiMethod.QUIT_GROUP,
|
||||||
@ -162,6 +170,7 @@ export class NTQQGroupApi {
|
|||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
static async kickMember(
|
static async kickMember(
|
||||||
groupQQ: string,
|
groupQQ: string,
|
||||||
kickUids: string[],
|
kickUids: string[],
|
||||||
@ -180,7 +189,8 @@ export class NTQQGroupApi {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
static async banMember(groupQQ: string, memList: Array<{ uid: string; timeStamp: number }>) {
|
|
||||||
|
static async banMember(groupQQ: string, memList: Array<{ uid: string, timeStamp: number }>) {
|
||||||
// timeStamp为秒数, 0为解除禁言
|
// timeStamp为秒数, 0为解除禁言
|
||||||
return await callNTQQApi<GeneralCallResult>({
|
return await callNTQQApi<GeneralCallResult>({
|
||||||
methodName: NTQQApiMethod.MUTE_MEMBER,
|
methodName: NTQQApiMethod.MUTE_MEMBER,
|
||||||
@ -192,6 +202,7 @@ export class NTQQGroupApi {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static async banGroup(groupQQ: string, shutUp: boolean) {
|
static async banGroup(groupQQ: string, shutUp: boolean) {
|
||||||
return await callNTQQApi<GeneralCallResult>({
|
return await callNTQQApi<GeneralCallResult>({
|
||||||
methodName: NTQQApiMethod.MUTE_GROUP,
|
methodName: NTQQApiMethod.MUTE_GROUP,
|
||||||
@ -204,6 +215,7 @@ export class NTQQGroupApi {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static async setMemberCard(groupQQ: string, memberUid: string, cardName: string) {
|
static async setMemberCard(groupQQ: string, memberUid: string, cardName: string) {
|
||||||
NTQQGroupApi.activateMemberListChange().then().catch(log)
|
NTQQGroupApi.activateMemberListChange().then().catch(log)
|
||||||
const res = await callNTQQApi<GeneralCallResult>({
|
const res = await callNTQQApi<GeneralCallResult>({
|
||||||
@ -218,8 +230,9 @@ export class NTQQGroupApi {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
NTQQGroupApi.getGroupMembersInfo(groupQQ, [memberUid], true).then().catch(log)
|
NTQQGroupApi.getGroupMembersInfo(groupQQ, [memberUid], true).then().catch(log)
|
||||||
return res;
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
static async setMemberRole(groupQQ: string, memberUid: string, role: GroupMemberRole) {
|
static async setMemberRole(groupQQ: string, memberUid: string, role: GroupMemberRole) {
|
||||||
return await callNTQQApi<GeneralCallResult>({
|
return await callNTQQApi<GeneralCallResult>({
|
||||||
methodName: NTQQApiMethod.SET_MEMBER_ROLE,
|
methodName: NTQQApiMethod.SET_MEMBER_ROLE,
|
||||||
@ -233,6 +246,7 @@ export class NTQQGroupApi {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static async setGroupName(groupQQ: string, groupName: string) {
|
static async setGroupName(groupQQ: string, groupName: string) {
|
||||||
return await callNTQQApi<GeneralCallResult>({
|
return await callNTQQApi<GeneralCallResult>({
|
||||||
methodName: NTQQApiMethod.SET_GROUP_NAME,
|
methodName: NTQQApiMethod.SET_GROUP_NAME,
|
||||||
@ -282,29 +296,34 @@ export class NTQQGroupApi {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
static publishGroupBulletin(groupQQ: string, title: string, content: string) {}
|
|
||||||
|
static publishGroupBulletin(groupQQ: string, title: string, content: string) { }
|
||||||
|
|
||||||
static async removeGroupEssence(GroupCode: string, msgId: string) {
|
static async removeGroupEssence(GroupCode: string, msgId: string) {
|
||||||
|
const session = wrapperApi.NodeIQQNTWrapperSession
|
||||||
// 代码没测过
|
// 代码没测过
|
||||||
// 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom
|
// 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom
|
||||||
let MsgData = await wrapperApi.NodeIQQNTWrapperSession.getMsgService().getMsgsIncludeSelf({ chatType: 2, guildId: '', peerUid: GroupCode }, msgId, 1, false);
|
let MsgData = await session.getMsgService().getMsgsIncludeSelf({ chatType: 2, guildId: '', peerUid: GroupCode }, msgId, 1, false)
|
||||||
let param = {
|
let param = {
|
||||||
groupCode: GroupCode,
|
groupCode: GroupCode,
|
||||||
msgRandom: parseInt(MsgData.msgList[0].msgRandom),
|
msgRandom: parseInt(MsgData.msgList[0].msgRandom),
|
||||||
msgSeq: parseInt(MsgData.msgList[0].msgSeq)
|
msgSeq: parseInt(MsgData.msgList[0].msgSeq)
|
||||||
};
|
}
|
||||||
// GetMsgByShoretID(ShoretID); -> MsgService.getMsgs(Peer,MsgId,1,false); -> 组出参数
|
// GetMsgByShoretID(ShoretID) -> MsgService.getMsgs(Peer,MsgId,1,false) -> 组出参数
|
||||||
return wrapperApi.NodeIQQNTWrapperSession.getGroupService().removeGroupEssence(param);
|
return session.getGroupService().removeGroupEssence(param)
|
||||||
}
|
}
|
||||||
|
|
||||||
static async addGroupEssence(GroupCode: string, msgId: string) {
|
static async addGroupEssence(GroupCode: string, msgId: string) {
|
||||||
|
const session = wrapperApi.NodeIQQNTWrapperSession
|
||||||
// 代码没测过
|
// 代码没测过
|
||||||
// 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom
|
// 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom
|
||||||
let MsgData = await wrapperApi.NodeIQQNTWrapperSession.getMsgService().getMsgsIncludeSelf({ chatType: 2, guildId: '', peerUid: GroupCode }, msgId, 1, false);
|
let MsgData = await session.getMsgService().getMsgsIncludeSelf({ chatType: 2, guildId: '', peerUid: GroupCode }, msgId, 1, false)
|
||||||
let param = {
|
let param = {
|
||||||
groupCode: GroupCode,
|
groupCode: GroupCode,
|
||||||
msgRandom: parseInt(MsgData.msgList[0].msgRandom),
|
msgRandom: parseInt(MsgData.msgList[0].msgRandom),
|
||||||
msgSeq: parseInt(MsgData.msgList[0].msgSeq)
|
msgSeq: parseInt(MsgData.msgList[0].msgSeq)
|
||||||
};
|
}
|
||||||
// GetMsgByShoretID(ShoretID); -> MsgService.getMsgs(Peer,MsgId,1,false); -> 组出参数
|
// GetMsgByShoretID(ShoretID) -> MsgService.getMsgs(Peer,MsgId,1,false) -> 组出参数
|
||||||
return wrapperApi.NodeIQQNTWrapperSession.getGroupService().addGroupEssence(param);
|
return session.getGroupService().addGroupEssence(param)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import { ReceiveCmdS, registerReceiveHook } from '../hook'
|
|||||||
import { log } from '../../common/utils/log'
|
import { log } from '../../common/utils/log'
|
||||||
import { sleep } from '../../common/utils/helper'
|
import { sleep } from '../../common/utils/helper'
|
||||||
import { isQQ998 } from '../../common/utils'
|
import { isQQ998 } from '../../common/utils'
|
||||||
import { wrapperApi } from '@/ntqqapi/native/wrapper'
|
import { wrapperApi } from '@/ntqqapi/wrapper'
|
||||||
|
|
||||||
export let sendMessagePool: Record<string, ((sendSuccessMsg: RawMessage) => void) | null> = {} // peerUid: callbackFunc
|
export let sendMessagePool: Record<string, ((sendSuccessMsg: RawMessage) => void) | null> = {} // peerUid: callbackFunc
|
||||||
|
|
||||||
@ -289,6 +289,7 @@ export class NTQQMsgApi {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
static async getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, z: boolean) {
|
static async getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, z: boolean) {
|
||||||
return await wrapperApi.NodeIQQNTWrapperSession.getMsgService().getMsgsBySeqAndCount(peer, seq, count, desc, z);
|
const session = wrapperApi.NodeIQQNTWrapperSession
|
||||||
|
return await session.getMsgService().getMsgsBySeqAndCount(peer, seq, count, desc, z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,58 +2,63 @@
|
|||||||
|
|
||||||
import { log } from '@/common/utils'
|
import { log } from '@/common/utils'
|
||||||
|
|
||||||
interface ServerRkeyData{
|
interface ServerRkeyData {
|
||||||
group_rkey: string;
|
group_rkey: string
|
||||||
private_rkey: string;
|
private_rkey: string
|
||||||
expired_time: number;
|
expired_time: number
|
||||||
}
|
}
|
||||||
|
|
||||||
class RkeyManager {
|
class RkeyManager {
|
||||||
serverUrl: string = '';
|
serverUrl: string = ''
|
||||||
private rkeyData: ServerRkeyData = {
|
private rkeyData: ServerRkeyData = {
|
||||||
group_rkey: '',
|
group_rkey: '',
|
||||||
private_rkey: '',
|
private_rkey: '',
|
||||||
expired_time: 0
|
expired_time: 0
|
||||||
};
|
|
||||||
constructor(serverUrl: string) {
|
|
||||||
this.serverUrl = serverUrl;
|
|
||||||
}
|
}
|
||||||
async getRkey(){
|
|
||||||
|
constructor(serverUrl: string) {
|
||||||
|
this.serverUrl = serverUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRkey() {
|
||||||
if (this.isExpired()) {
|
if (this.isExpired()) {
|
||||||
try {
|
try {
|
||||||
await this.refreshRkey();
|
await this.refreshRkey()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('获取rkey失败', e);
|
log('获取rkey失败', e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this.rkeyData;
|
return this.rkeyData
|
||||||
}
|
}
|
||||||
|
|
||||||
isExpired(): boolean {
|
isExpired(): boolean {
|
||||||
const now = new Date().getTime() / 1000;
|
const now = new Date().getTime() / 1000
|
||||||
// console.log(`now: ${now}, expired_time: ${this.rkeyData.expired_time}`);
|
// console.log(`now: ${now}, expired_time: ${this.rkeyData.expired_time}`)
|
||||||
return now > this.rkeyData.expired_time;
|
return now > this.rkeyData.expired_time
|
||||||
}
|
}
|
||||||
|
|
||||||
async refreshRkey(): Promise<any> {
|
async refreshRkey(): Promise<any> {
|
||||||
//刷新rkey
|
//刷新rkey
|
||||||
this.rkeyData = await this.fetchServerRkey();
|
this.rkeyData = await this.fetchServerRkey()
|
||||||
}
|
}
|
||||||
async fetchServerRkey(){
|
|
||||||
|
async fetchServerRkey() {
|
||||||
return new Promise<ServerRkeyData>((resolve, reject) => {
|
return new Promise<ServerRkeyData>((resolve, reject) => {
|
||||||
fetch(this.serverUrl)
|
fetch(this.serverUrl)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
return reject(response.statusText); // 请求失败,返回错误信息
|
return reject(response.statusText) // 请求失败,返回错误信息
|
||||||
}
|
}
|
||||||
return response.json(); // 解析 JSON 格式的响应体
|
return response.json() // 解析 JSON 格式的响应体
|
||||||
})
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
resolve(data);
|
resolve(data)
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
reject(error);
|
reject(error)
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export const rkeyManager = new RkeyManager('http://napcat-sign.wumiao.wang:2082/rkey');
|
|
||||||
|
export const rkeyManager = new RkeyManager('http://napcat-sign.wumiao.wang:2082/rkey')
|
||||||
|
@ -2,13 +2,11 @@ import { callNTQQApi, GeneralCallResult, NTQQApiClass, NTQQApiMethod } from '../
|
|||||||
import { Group, SelfInfo, User } from '../types'
|
import { Group, SelfInfo, User } from '../types'
|
||||||
import { ReceiveCmdS } from '../hook'
|
import { ReceiveCmdS } from '../hook'
|
||||||
import { selfInfo, uidMaps } from '../../common/data'
|
import { selfInfo, uidMaps } from '../../common/data'
|
||||||
import { NTQQWindowApi, NTQQWindows } from './window'
|
|
||||||
import { cacheFunc, isQQ998, log, sleep } from '../../common/utils'
|
import { cacheFunc, isQQ998, log, sleep } from '../../common/utils'
|
||||||
import { wrapperApi } from '@/ntqqapi/native/wrapper'
|
import { wrapperApi } from '@/ntqqapi/wrapper'
|
||||||
import * as https from 'https'
|
|
||||||
import { RequestUtil } from '@/common/utils/request'
|
import { RequestUtil } from '@/common/utils/request'
|
||||||
|
|
||||||
let userInfoCache: Record<string, User> = {} // uid: User
|
const userInfoCache: Record<string, User> = {} // uid: User
|
||||||
|
|
||||||
export interface ClientKeyData extends GeneralCallResult {
|
export interface ClientKeyData extends GeneralCallResult {
|
||||||
url: string;
|
url: string;
|
||||||
@ -151,7 +149,8 @@ export class NTQQUserApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async getPSkey(domains: string[]): Promise<Map<string, string>> {
|
static async getPSkey(domains: string[]): Promise<Map<string, string>> {
|
||||||
const res = await wrapperApi.NodeIQQNTWrapperSession.getTipOffService().getPskey(domains, true)
|
const session = wrapperApi.NodeIQQNTWrapperSession
|
||||||
|
const res = await session.getTipOffService().getPskey(domains, true)
|
||||||
if (res.result !== 0) {
|
if (res.result !== 0) {
|
||||||
throw new Error(`获取Pskey失败: ${res.errMsg}`)
|
throw new Error(`获取Pskey失败: ${res.errMsg}`)
|
||||||
}
|
}
|
||||||
@ -159,7 +158,7 @@ export class NTQQUserApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async getClientKey(): Promise<ClientKeyData> {
|
static async getClientKey(): Promise<ClientKeyData> {
|
||||||
return await wrapperApi.NodeIQQNTWrapperSession.getTicketService().forceFetchClientKey('')
|
const session = wrapperApi.NodeIQQNTWrapperSession
|
||||||
|
return await session.getTicketService().forceFetchClientKey('')
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { WebGroupData, groups, selfInfo } from '@/common/data';
|
import { WebGroupData, groups, selfInfo } from '@/common/data'
|
||||||
import { log } from '@/common/utils/log';
|
import { log } from '@/common/utils/log'
|
||||||
import { NTQQUserApi } from './user';
|
import { NTQQUserApi } from './user'
|
||||||
import { RequestUtil } from '@/common/utils/request';
|
import { RequestUtil } from '@/common/utils/request'
|
||||||
|
|
||||||
export enum WebHonorType {
|
export enum WebHonorType {
|
||||||
ALL = 'all',
|
ALL = 'all',
|
||||||
TALKACTIVE = 'talkative',
|
TALKACTIVE = 'talkative',
|
||||||
@ -10,6 +11,7 @@ export enum WebHonorType {
|
|||||||
STORONGE_NEWBI = 'strong_newbie',
|
STORONGE_NEWBI = 'strong_newbie',
|
||||||
EMOTION = 'emotion'
|
EMOTION = 'emotion'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WebApiGroupMember {
|
export interface WebApiGroupMember {
|
||||||
uin: number
|
uin: number
|
||||||
role: number
|
role: number
|
||||||
@ -27,6 +29,7 @@ export interface WebApiGroupMember {
|
|||||||
qage: number
|
qage: number
|
||||||
rm: number
|
rm: number
|
||||||
}
|
}
|
||||||
|
|
||||||
interface WebApiGroupMemberRet {
|
interface WebApiGroupMemberRet {
|
||||||
ec: number
|
ec: number
|
||||||
errcode: number
|
errcode: number
|
||||||
@ -41,6 +44,7 @@ interface WebApiGroupMemberRet {
|
|||||||
search_count: number
|
search_count: number
|
||||||
extmode: number
|
extmode: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WebApiGroupNoticeFeed {
|
export interface WebApiGroupNoticeFeed {
|
||||||
u: number//发送者
|
u: number//发送者
|
||||||
fid: string//fid
|
fid: string//fid
|
||||||
@ -69,6 +73,7 @@ export interface WebApiGroupNoticeFeed {
|
|||||||
is_read: number
|
is_read: number
|
||||||
is_all_confirm: number
|
is_all_confirm: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WebApiGroupNoticeRet {
|
export interface WebApiGroupNoticeRet {
|
||||||
ec: number
|
ec: number
|
||||||
em: string
|
em: string
|
||||||
@ -89,6 +94,7 @@ export interface WebApiGroupNoticeRet {
|
|||||||
svrt: number
|
svrt: number
|
||||||
ad: number
|
ad: number
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GroupEssenceMsg {
|
interface GroupEssenceMsg {
|
||||||
group_code: string
|
group_code: string
|
||||||
msg_seq: number
|
msg_seq: number
|
||||||
@ -102,6 +108,7 @@ interface GroupEssenceMsg {
|
|||||||
msg_content: any[]
|
msg_content: any[]
|
||||||
can_be_removed: true
|
can_be_removed: true
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GroupEssenceMsgRet {
|
export interface GroupEssenceMsgRet {
|
||||||
retcode: number
|
retcode: number
|
||||||
retmsg: string
|
retmsg: string
|
||||||
@ -112,9 +119,10 @@ export interface GroupEssenceMsgRet {
|
|||||||
config_page_url: string
|
config_page_url: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WebApi {
|
export class WebApi {
|
||||||
static async getGroupEssenceMsg(GroupCode: string, page_start: string): Promise<GroupEssenceMsgRet> {
|
static async getGroupEssenceMsg(GroupCode: string, page_start: string): Promise<GroupEssenceMsgRet> {
|
||||||
const {cookies: CookieValue, bkn: Bkn} = (await NTQQUserApi.getCookies('qun.qq.com'))
|
const { cookies: CookieValue, bkn: Bkn } = (await NTQQUserApi.getCookies('qun.qq.com'))
|
||||||
const url = 'https://qun.qq.com/cgi-bin/group_digest/digest_list?bkn=' + Bkn + '&group_code=' + GroupCode + '&page_start=' + page_start + '&page_limit=20';
|
const url = 'https://qun.qq.com/cgi-bin/group_digest/digest_list?bkn=' + Bkn + '&group_code=' + GroupCode + '&page_start=' + page_start + '&page_limit=20';
|
||||||
let ret;
|
let ret;
|
||||||
try {
|
try {
|
||||||
@ -128,6 +136,7 @@ export class WebApi {
|
|||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getGroupMembers(GroupCode: string, cached: boolean = true): Promise<WebApiGroupMember[]> {
|
static async getGroupMembers(GroupCode: string, cached: boolean = true): Promise<WebApiGroupMember[]> {
|
||||||
log('webapi 获取群成员', GroupCode);
|
log('webapi 获取群成员', GroupCode);
|
||||||
let MemberData: Array<WebApiGroupMember> = new Array<WebApiGroupMember>();
|
let MemberData: Array<WebApiGroupMember> = new Array<WebApiGroupMember>();
|
||||||
@ -190,6 +199,7 @@ export class WebApi {
|
|||||||
// const res = await this.request(url);
|
// const res = await this.request(url);
|
||||||
// return await res.json();
|
// return await res.json();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
static async setGroupNotice(GroupCode: string, Content: string = '') {
|
static async setGroupNotice(GroupCode: string, Content: string = '') {
|
||||||
//https://web.qun.qq.com/cgi-bin/announce/add_qun_notice?bkn=${bkn}
|
//https://web.qun.qq.com/cgi-bin/announce/add_qun_notice?bkn=${bkn}
|
||||||
//qid=${群号}&bkn=${bkn}&text=${内容}&pinned=0&type=1&settings={"is_show_edit_card":1,"tip_window_type":1,"confirm_required":1}
|
//qid=${群号}&bkn=${bkn}&text=${内容}&pinned=0&type=1&settings={"is_show_edit_card":1,"tip_window_type":1,"confirm_required":1}
|
||||||
@ -213,6 +223,7 @@ export class WebApi {
|
|||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getGrouptNotice(GroupCode: string): Promise<undefined | WebApiGroupNoticeRet> {
|
static async getGrouptNotice(GroupCode: string): Promise<undefined | WebApiGroupNoticeRet> {
|
||||||
const _Pskey = (await NTQQUserApi.getPSkey(['qun.qq.com']))['qun.qq.com'];
|
const _Pskey = (await NTQQUserApi.getPSkey(['qun.qq.com']))['qun.qq.com'];
|
||||||
const _Skey = await NTQQUserApi.getSkey();
|
const _Skey = await NTQQUserApi.getSkey();
|
||||||
@ -236,6 +247,7 @@ export class WebApi {
|
|||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
static genBkn(sKey: string) {
|
static genBkn(sKey: string) {
|
||||||
sKey = sKey || '';
|
sKey = sKey || '';
|
||||||
let hash = 5381;
|
let hash = 5381;
|
||||||
@ -247,6 +259,7 @@ export class WebApi {
|
|||||||
|
|
||||||
return (hash & 0x7FFFFFFF).toString();
|
return (hash & 0x7FFFFFFF).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
//实现未缓存 考虑2h缓存
|
//实现未缓存 考虑2h缓存
|
||||||
static async getGroupHonorInfo(groupCode: string, getType: WebHonorType) {
|
static async getGroupHonorInfo(groupCode: string, getType: WebHonorType) {
|
||||||
async function getDataInternal(Internal_groupCode: string, Internal_type: number) {
|
async function getDataInternal(Internal_groupCode: string, Internal_type: number) {
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
let Process = require('process')
|
|
||||||
let os = require('os')
|
|
||||||
Process.dlopenOrig = Process.dlopen
|
|
||||||
|
|
||||||
export const wrapperApi: any = {}
|
|
||||||
|
|
||||||
Process.dlopen = function(module, filename, flags = os.constants.dlopen.RTLD_LAZY) {
|
|
||||||
let dlopenRet = this.dlopenOrig(module, filename, flags)
|
|
||||||
for (let export_name in module.exports) {
|
|
||||||
module.exports[export_name] = new Proxy(module.exports[export_name], {
|
|
||||||
construct: (target, args, _newTarget) => {
|
|
||||||
let ret = new target(...args)
|
|
||||||
if (export_name === 'NodeIQQNTWrapperSession') wrapperApi.NodeIQQNTWrapperSession = ret
|
|
||||||
return ret
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return dlopenRet
|
|
||||||
}
|
|
125
src/ntqqapi/services/NodeIKernelBuddyService.ts
Normal file
125
src/ntqqapi/services/NodeIKernelBuddyService.ts
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
import { GeneralCallResult } from './common'
|
||||||
|
|
||||||
|
export enum BuddyListReqType {
|
||||||
|
KNOMAL,
|
||||||
|
KLETTER
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NodeIKernelBuddyService {
|
||||||
|
// 26702 以上
|
||||||
|
getBuddyListV2(callFrom: string, reqType: BuddyListReqType): Promise<GeneralCallResult & {
|
||||||
|
data: Array<{
|
||||||
|
categoryId: number,
|
||||||
|
categorySortId: number,
|
||||||
|
categroyName: string,
|
||||||
|
categroyMbCount: number,
|
||||||
|
onlineCount: number,
|
||||||
|
buddyUids: Array<string>
|
||||||
|
}>
|
||||||
|
}>
|
||||||
|
|
||||||
|
//26702 以上
|
||||||
|
getBuddyListFromCache(callFrom: string): Promise<Array<
|
||||||
|
{
|
||||||
|
categoryId: number,//9999应该跳过 那是兜底数据吧
|
||||||
|
categorySortId: number,//排序方式
|
||||||
|
categroyName: string,//分类名
|
||||||
|
categroyMbCount: number,//不懂
|
||||||
|
onlineCount: number,//在线数目
|
||||||
|
buddyUids: Array<string>//Uids
|
||||||
|
}>>
|
||||||
|
|
||||||
|
addKernelBuddyListener(listener: any): number
|
||||||
|
|
||||||
|
getAllBuddyCount(): number
|
||||||
|
|
||||||
|
removeKernelBuddyListener(listener: unknown): void
|
||||||
|
|
||||||
|
getBuddyList(nocache: boolean): Promise<GeneralCallResult>
|
||||||
|
|
||||||
|
getBuddyNick(uid: number): string
|
||||||
|
|
||||||
|
getBuddyRemark(uid: number): string
|
||||||
|
|
||||||
|
setBuddyRemark(uid: number, remark: string): void
|
||||||
|
|
||||||
|
getAvatarUrl(uid: number): string
|
||||||
|
|
||||||
|
isBuddy(uid: string): boolean
|
||||||
|
|
||||||
|
getCategoryNameWithUid(uid: number): string
|
||||||
|
|
||||||
|
getTargetBuddySetting(uid: number): unknown
|
||||||
|
|
||||||
|
getTargetBuddySettingByType(uid: number, type: number): unknown
|
||||||
|
|
||||||
|
getBuddyReqUnreadCnt(): number
|
||||||
|
|
||||||
|
getBuddyReq(): unknown
|
||||||
|
|
||||||
|
delBuddyReq(uid: number): void
|
||||||
|
|
||||||
|
clearBuddyReqUnreadCnt(): void
|
||||||
|
|
||||||
|
reqToAddFriends(uid: number, msg: string): void
|
||||||
|
|
||||||
|
setSpacePermission(uid: number, permission: number): void
|
||||||
|
|
||||||
|
approvalFriendRequest(arg: {
|
||||||
|
friendUid: string
|
||||||
|
reqTime: string
|
||||||
|
accept: boolean
|
||||||
|
}): Promise<void>
|
||||||
|
|
||||||
|
delBuddy(uid: number): void
|
||||||
|
|
||||||
|
delBatchBuddy(uids: number[]): void
|
||||||
|
|
||||||
|
getSmartInfos(uid: number): unknown
|
||||||
|
|
||||||
|
setBuddyCategory(uid: number, category: number): void
|
||||||
|
|
||||||
|
setBatchBuddyCategory(uids: number[], category: number): void
|
||||||
|
|
||||||
|
addCategory(category: string): void
|
||||||
|
|
||||||
|
delCategory(category: string): void
|
||||||
|
|
||||||
|
renameCategory(oldCategory: string, newCategory: string): void
|
||||||
|
|
||||||
|
resortCategory(categorys: string[]): void
|
||||||
|
|
||||||
|
pullCategory(uid: number, category: string): void
|
||||||
|
|
||||||
|
setTop(uid: number, isTop: boolean): void
|
||||||
|
|
||||||
|
SetSpecialCare(uid: number, isSpecialCare: boolean): void
|
||||||
|
|
||||||
|
setMsgNotify(uid: number, isNotify: boolean): void
|
||||||
|
|
||||||
|
hasBuddyList(): boolean
|
||||||
|
|
||||||
|
setBlock(uid: number, isBlock: boolean): void
|
||||||
|
|
||||||
|
isBlocked(uid: number): boolean
|
||||||
|
|
||||||
|
modifyAddMeSetting(setting: unknown): void
|
||||||
|
|
||||||
|
getAddMeSetting(): unknown
|
||||||
|
|
||||||
|
getDoubtBuddyReq(): unknown
|
||||||
|
|
||||||
|
getDoubtBuddyUnreadNum(): number
|
||||||
|
|
||||||
|
approvalDoubtBuddyReq(uid: number, isAgree: boolean): void
|
||||||
|
|
||||||
|
delDoubtBuddyReq(uid: number): void
|
||||||
|
|
||||||
|
delAllDoubtBuddyReq(): void
|
||||||
|
|
||||||
|
reportDoubtBuddyReqUnread(): void
|
||||||
|
|
||||||
|
getBuddyRecommendContactArkJson(uid: string, phoneNumber: string): Promise<unknown>
|
||||||
|
|
||||||
|
isNull(): boolean
|
||||||
|
}
|
106
src/ntqqapi/services/NodeIKernelProfileService.ts
Normal file
106
src/ntqqapi/services/NodeIKernelProfileService.ts
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
import { AnyCnameRecord } from 'node:dns'
|
||||||
|
import { SimpleInfo } from '../types'
|
||||||
|
import { GeneralCallResult } from './common'
|
||||||
|
|
||||||
|
export enum UserDetailSource {
|
||||||
|
KDB,
|
||||||
|
KSERVER
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ProfileBizType {
|
||||||
|
KALL,
|
||||||
|
KBASEEXTEND,
|
||||||
|
KVAS,
|
||||||
|
KQZONE,
|
||||||
|
KOTHER
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NodeIKernelProfileService {
|
||||||
|
getUidByUin(callfrom: string, uin: Array<string>): Promise<Map<string,string>>//uin->uid
|
||||||
|
|
||||||
|
getUinByUid(callfrom: string, uid: Array<string>): Promise<Map<string,string>>
|
||||||
|
|
||||||
|
// {
|
||||||
|
// coreInfo: CoreInfo,
|
||||||
|
// baseInfo: BaseInfo,
|
||||||
|
// status: null,
|
||||||
|
// vasInfo: null,
|
||||||
|
// relationFlags: null,
|
||||||
|
// otherFlags: null,
|
||||||
|
// intimate: null
|
||||||
|
// }
|
||||||
|
getCoreAndBaseInfo(callfrom: string, uids: string[]): Promise<Map<string, SimpleInfo>>
|
||||||
|
|
||||||
|
fetchUserDetailInfo(trace: string, uids: string[], arg2: number, arg3: number[]): Promise<unknown>
|
||||||
|
|
||||||
|
addKernelProfileListener(listener: any): number
|
||||||
|
|
||||||
|
removeKernelProfileListener(listenerId: number): void
|
||||||
|
|
||||||
|
prepareRegionConfig(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getLocalStrangerRemark(): Promise<AnyCnameRecord>
|
||||||
|
|
||||||
|
enumCountryOptions(): Array<string>
|
||||||
|
|
||||||
|
enumProvinceOptions(Country: string): Array<string>
|
||||||
|
|
||||||
|
enumCityOptions(Country: string, Province: string): unknown
|
||||||
|
|
||||||
|
enumAreaOptions(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
//SimpleInfo
|
||||||
|
// this.uid = ""
|
||||||
|
// this.uid = str
|
||||||
|
// this.uin = j2
|
||||||
|
// this.isBuddy = z
|
||||||
|
// this.coreInfo = coreInfo
|
||||||
|
// this.baseInfo = baseInfo
|
||||||
|
// this.status = statusInfo
|
||||||
|
// this.vasInfo = vasInfo
|
||||||
|
// this.relationFlags = relationFlag
|
||||||
|
// this.otherFlags = otherFlag
|
||||||
|
// this.intimate = intimate
|
||||||
|
|
||||||
|
modifySelfProfile(...args: unknown[]): Promise<unknown>
|
||||||
|
|
||||||
|
modifyDesktopMiniProfile(param: any): Promise<GeneralCallResult>
|
||||||
|
|
||||||
|
setNickName(NickName: string): Promise<unknown>
|
||||||
|
|
||||||
|
setLongNick(longNick: string): Promise<unknown>
|
||||||
|
|
||||||
|
setBirthday(...args: unknown[]): Promise<unknown>
|
||||||
|
|
||||||
|
setGander(...args: unknown[]): Promise<unknown>
|
||||||
|
|
||||||
|
setHeader(arg: string): Promise<unknown>
|
||||||
|
|
||||||
|
setRecommendImgFlag(...args: unknown[]): Promise<unknown>
|
||||||
|
|
||||||
|
getUserSimpleInfo(force: boolean, uids: string[],): Promise<unknown>
|
||||||
|
|
||||||
|
getUserDetailInfo(uid: string): Promise<unknown>
|
||||||
|
|
||||||
|
getUserDetailInfoWithBizInfo(uid: string, Biz: any[]): Promise<GeneralCallResult>
|
||||||
|
|
||||||
|
getUserDetailInfoByUin(uin: string): Promise<any>
|
||||||
|
|
||||||
|
getZplanAvatarInfos(args: string[]): Promise<unknown>
|
||||||
|
|
||||||
|
getStatus(uid: string): Promise<unknown>
|
||||||
|
|
||||||
|
startStatusPolling(isForceReset: boolean): Promise<unknown>
|
||||||
|
|
||||||
|
getSelfStatus(): Promise<unknown>
|
||||||
|
|
||||||
|
setdisableEmojiShortCuts(...args: unknown[]): unknown
|
||||||
|
|
||||||
|
getProfileQzonePicInfo(uid: string, type: number, force: boolean): Promise<unknown>
|
||||||
|
|
||||||
|
//profileService.getCoreInfo("UserRemarkServiceImpl::getStrangerRemarkByUid", arrayList)
|
||||||
|
getCoreInfo(name: string, arg: any[]): unknown
|
||||||
|
|
||||||
|
//m429253e12.getOtherFlag("FriendListInfoCache_getKernelDataAndPutCache", new ArrayList<>())
|
||||||
|
isNull(): boolean
|
||||||
|
}
|
16
src/ntqqapi/services/common.ts
Normal file
16
src/ntqqapi/services/common.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
export enum GeneralCallResultStatus {
|
||||||
|
OK = 0
|
||||||
|
// ERROR = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GeneralCallResult {
|
||||||
|
result: GeneralCallResultStatus
|
||||||
|
errMsg: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface forceFetchClientKeyRetType extends GeneralCallResult {
|
||||||
|
url: string
|
||||||
|
keyIndex: string
|
||||||
|
clientKey: string
|
||||||
|
expireTime: string
|
||||||
|
}
|
2
src/ntqqapi/services/index.ts
Normal file
2
src/ntqqapi/services/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './NodeIKernelBuddyService'
|
||||||
|
export * from './NodeIKernelProfileService'
|
@ -1,5 +1,4 @@
|
|||||||
import { GroupMemberRole } from './group'
|
import { GroupMemberRole } from './group'
|
||||||
import exp from 'constants'
|
|
||||||
|
|
||||||
export enum ElementType {
|
export enum ElementType {
|
||||||
TEXT = 1,
|
TEXT = 1,
|
||||||
@ -417,7 +416,7 @@ export interface RawMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Peer {
|
export interface Peer {
|
||||||
chatType: ChatType;
|
chatType: ChatType
|
||||||
peerUid: string; // 如果是群聊uid为群号,私聊uid就是加密的字符串
|
peerUid: string // 如果是群聊uid为群号,私聊uid就是加密的字符串
|
||||||
guildId?: string;
|
guildId?: string
|
||||||
}
|
}
|
@ -77,8 +77,148 @@ export interface Friend extends User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface CategoryFriend {
|
export interface CategoryFriend {
|
||||||
categoryId: number;
|
categoryId: number
|
||||||
categroyName: string;
|
categroyName: string
|
||||||
categroyMbCount: number;
|
categroyMbCount: number
|
||||||
buddyList: User[]
|
buddyList: User[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CoreInfo {
|
||||||
|
uid: string
|
||||||
|
uin: string
|
||||||
|
nick: string
|
||||||
|
remark: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BaseInfo {
|
||||||
|
qid: string
|
||||||
|
longNick: string
|
||||||
|
birthday_year: number
|
||||||
|
birthday_month: number
|
||||||
|
birthday_day: number
|
||||||
|
age: number
|
||||||
|
sex: number
|
||||||
|
eMail: string
|
||||||
|
phoneNum: string
|
||||||
|
categoryId: number
|
||||||
|
richTime: number
|
||||||
|
richBuffer: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MusicInfo {
|
||||||
|
buf: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VideoBizInfo {
|
||||||
|
cid: string
|
||||||
|
tvUrl: string
|
||||||
|
synchType: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VideoInfo {
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ExtOnlineBusinessInfo {
|
||||||
|
buf: string
|
||||||
|
customStatus: any
|
||||||
|
videoBizInfo: VideoBizInfo
|
||||||
|
videoInfo: VideoInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ExtBuffer {
|
||||||
|
buf: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UserStatus {
|
||||||
|
uid: string
|
||||||
|
uin: string
|
||||||
|
status: number
|
||||||
|
extStatus: number
|
||||||
|
batteryStatus: number
|
||||||
|
termType: number
|
||||||
|
netType: number
|
||||||
|
iconType: number
|
||||||
|
customStatus: any
|
||||||
|
setTime: string
|
||||||
|
specialFlag: number
|
||||||
|
abiFlag: number
|
||||||
|
eNetworkType: number
|
||||||
|
showName: string
|
||||||
|
termDesc: string
|
||||||
|
musicInfo: MusicInfo
|
||||||
|
extOnlineBusinessInfo: ExtOnlineBusinessInfo
|
||||||
|
extBuffer: ExtBuffer
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PrivilegeIcon {
|
||||||
|
jumpUrl: string
|
||||||
|
openIconList: any[]
|
||||||
|
closeIconList: any[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VasInfo {
|
||||||
|
vipFlag: boolean
|
||||||
|
yearVipFlag: boolean
|
||||||
|
svipFlag: boolean
|
||||||
|
vipLevel: number
|
||||||
|
bigClub: boolean
|
||||||
|
bigClubLevel: number
|
||||||
|
nameplateVipType: number
|
||||||
|
grayNameplateFlag: number
|
||||||
|
superVipTemplateId: number
|
||||||
|
diyFontId: number
|
||||||
|
pendantId: number
|
||||||
|
pendantDiyId: number
|
||||||
|
faceId: number
|
||||||
|
vipFont: number
|
||||||
|
vipFontType: number
|
||||||
|
magicFont: number
|
||||||
|
fontEffect: number
|
||||||
|
newLoverDiamondFlag: number
|
||||||
|
extendNameplateId: number
|
||||||
|
diyNameplateIDs: any[]
|
||||||
|
vipStartFlag: number
|
||||||
|
vipDataFlag: number
|
||||||
|
gameNameplateId: string
|
||||||
|
gameLastLoginTime: string
|
||||||
|
gameRank: number
|
||||||
|
gameIconShowFlag: boolean
|
||||||
|
gameCardId: string
|
||||||
|
vipNameColorId: string
|
||||||
|
privilegeIcon: PrivilegeIcon
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SimpleInfo {
|
||||||
|
uid?: string
|
||||||
|
uin?: string
|
||||||
|
coreInfo: CoreInfo
|
||||||
|
baseInfo: BaseInfo
|
||||||
|
status: UserStatus | null
|
||||||
|
vasInfo: VasInfo | null
|
||||||
|
relationFlags: RelationFlags | null
|
||||||
|
otherFlags: any | null
|
||||||
|
intimate: any | null
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RelationFlags {
|
||||||
|
topTime: string
|
||||||
|
isBlock: boolean
|
||||||
|
isMsgDisturb: boolean
|
||||||
|
isSpecialCareOpen: boolean
|
||||||
|
isSpecialCareZone: boolean
|
||||||
|
ringId: string
|
||||||
|
isBlocked: boolean
|
||||||
|
recommendImgFlag: number
|
||||||
|
disableEmojiShortCuts: number
|
||||||
|
qidianMasterFlag: number
|
||||||
|
qidianCrewFlag: number
|
||||||
|
qidianCrewFlag2: number
|
||||||
|
isHideQQLevel: number
|
||||||
|
isHidePrivilegeIcon: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FriendV2 extends SimpleInfo {
|
||||||
|
categoryId?: number
|
||||||
|
categroyName?: string
|
||||||
}
|
}
|
68
src/ntqqapi/wrapper.ts
Normal file
68
src/ntqqapi/wrapper.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import { NodeIKernelBuddyService } from './services/NodeIKernelBuddyService'
|
||||||
|
import os from 'node:os'
|
||||||
|
const Process = require('node:process')
|
||||||
|
|
||||||
|
export interface NodeIQQNTWrapperSession {
|
||||||
|
[key: string]: any
|
||||||
|
getBuddyService(): NodeIKernelBuddyService
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WrapperApi {
|
||||||
|
NodeIQQNTWrapperSession?: NodeIQQNTWrapperSession
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WrapperConstructor {
|
||||||
|
[key: string]: any
|
||||||
|
NodeIKernelBuddyListener?: any
|
||||||
|
NodeIKernelGroupListener?: any
|
||||||
|
NodeQQNTWrapperUtil?: any
|
||||||
|
NodeIKernelMsgListener?: any
|
||||||
|
NodeIQQNTWrapperEngine?: any
|
||||||
|
NodeIGlobalAdapter?: any
|
||||||
|
NodeIDependsAdapter?: any
|
||||||
|
NodeIDispatcherAdapter?: any
|
||||||
|
NodeIKernelSessionListener?: any
|
||||||
|
NodeIKernelLoginService?: any
|
||||||
|
NodeIKernelLoginListener?: any
|
||||||
|
NodeIKernelProfileService?: any
|
||||||
|
NodeIKernelProfileListener?: any
|
||||||
|
}
|
||||||
|
|
||||||
|
export const wrapperApi: WrapperApi = {}
|
||||||
|
|
||||||
|
export const wrapperConstructor: WrapperConstructor = {}
|
||||||
|
|
||||||
|
const constructor = [
|
||||||
|
'NodeIKernelBuddyListener',
|
||||||
|
'NodeIKernelGroupListener',
|
||||||
|
'NodeQQNTWrapperUtil',
|
||||||
|
'NodeIKernelMsgListener',
|
||||||
|
'NodeIQQNTWrapperEngine',
|
||||||
|
'NodeIGlobalAdapter',
|
||||||
|
'NodeIDependsAdapter',
|
||||||
|
'NodeIDispatcherAdapter',
|
||||||
|
'NodeIKernelSessionListener',
|
||||||
|
'NodeIKernelLoginService',
|
||||||
|
'NodeIKernelLoginListener',
|
||||||
|
'NodeIKernelProfileService',
|
||||||
|
'NodeIKernelProfileListener',
|
||||||
|
]
|
||||||
|
|
||||||
|
Process.dlopenOrig = Process.dlopen
|
||||||
|
|
||||||
|
Process.dlopen = function (module, filename, flags = os.constants.dlopen.RTLD_LAZY) {
|
||||||
|
const dlopenRet = this.dlopenOrig(module, filename, flags)
|
||||||
|
for (let export_name in module.exports) {
|
||||||
|
module.exports[export_name] = new Proxy(module.exports[export_name], {
|
||||||
|
construct: (target, args, _newTarget) => {
|
||||||
|
const ret = new target(...args)
|
||||||
|
if (export_name === 'NodeIQQNTWrapperSession') wrapperApi.NodeIQQNTWrapperSession = ret
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (constructor.includes(export_name)) {
|
||||||
|
wrapperConstructor[export_name] = module.exports[export_name]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dlopenRet
|
||||||
|
}
|
@ -5,6 +5,7 @@ import BaseAction from '../BaseAction'
|
|||||||
import { ActionName } from '../types'
|
import { ActionName } from '../types'
|
||||||
import { NTQQFriendApi } from '@/ntqqapi/api'
|
import { NTQQFriendApi } from '@/ntqqapi/api'
|
||||||
import { CategoryFriend } from '@/ntqqapi/types'
|
import { CategoryFriend } from '@/ntqqapi/types'
|
||||||
|
import { qqPkgInfo } from '@/common/utils/QQBasicInfo'
|
||||||
|
|
||||||
interface Payload {
|
interface Payload {
|
||||||
no_cache: boolean | string
|
no_cache: boolean | string
|
||||||
@ -14,6 +15,9 @@ export class GetFriendList extends BaseAction<Payload, OB11User[]> {
|
|||||||
actionName = ActionName.GetFriendList
|
actionName = ActionName.GetFriendList
|
||||||
|
|
||||||
protected async _handle(payload: Payload) {
|
protected async _handle(payload: Payload) {
|
||||||
|
if (+qqPkgInfo.buildVersion >= 26702) {
|
||||||
|
return OB11Constructor.friendsV2(await NTQQFriendApi.getBuddyV2(payload?.no_cache === true || payload?.no_cache === 'true'))
|
||||||
|
}
|
||||||
if (friends.length === 0 || payload?.no_cache === true || payload?.no_cache === 'true') {
|
if (friends.length === 0 || payload?.no_cache === true || payload?.no_cache === 'true') {
|
||||||
const _friends = await NTQQFriendApi.getFriends(true)
|
const _friends = await NTQQFriendApi.getFriends(true)
|
||||||
// log('强制刷新好友列表,结果: ', _friends)
|
// log('强制刷新好友列表,结果: ', _friends)
|
||||||
|
@ -24,6 +24,7 @@ import {
|
|||||||
TipGroupElementType,
|
TipGroupElementType,
|
||||||
User,
|
User,
|
||||||
VideoElement,
|
VideoElement,
|
||||||
|
FriendV2
|
||||||
} from '../ntqqapi/types'
|
} from '../ntqqapi/types'
|
||||||
import { deleteGroup, getFriend, getGroupMember, selfInfo, tempGroupCodeMap, uidMaps } from '../common/data'
|
import { deleteGroup, getFriend, getGroupMember, selfInfo, tempGroupCodeMap, uidMaps } from '../common/data'
|
||||||
import { EventType } from './event/OB11BaseEvent'
|
import { EventType } from './event/OB11BaseEvent'
|
||||||
@ -50,8 +51,8 @@ import { OB11FriendAddNoticeEvent } from './event/notice/OB11FriendAddNoticeEven
|
|||||||
import { OB11FriendRecallNoticeEvent } from './event/notice/OB11FriendRecallNoticeEvent'
|
import { OB11FriendRecallNoticeEvent } from './event/notice/OB11FriendRecallNoticeEvent'
|
||||||
import { OB11GroupRecallNoticeEvent } from './event/notice/OB11GroupRecallNoticeEvent'
|
import { OB11GroupRecallNoticeEvent } from './event/notice/OB11GroupRecallNoticeEvent'
|
||||||
import { OB11FriendPokeEvent, OB11GroupPokeEvent } from './event/notice/OB11PokeEvent'
|
import { OB11FriendPokeEvent, OB11GroupPokeEvent } from './event/notice/OB11PokeEvent'
|
||||||
import { OB11BaseNoticeEvent } from './event/notice/OB11BaseNoticeEvent';
|
import { OB11BaseNoticeEvent } from './event/notice/OB11BaseNoticeEvent'
|
||||||
import { OB11GroupEssenceEvent } from './event/notice/OB11GroupEssenceEvent';
|
import { OB11GroupEssenceEvent } from './event/notice/OB11GroupEssenceEvent'
|
||||||
|
|
||||||
let lastRKeyUpdateTime = 0
|
let lastRKeyUpdateTime = 0
|
||||||
|
|
||||||
@ -259,9 +260,9 @@ export class OB11Constructor {
|
|||||||
|
|
||||||
// log("收到语音消息", msg)
|
// log("收到语音消息", msg)
|
||||||
// window.LLAPI.Ptt2Text(message.raw.msgId, message.peer, messages).then(text => {
|
// window.LLAPI.Ptt2Text(message.raw.msgId, message.peer, messages).then(text => {
|
||||||
// console.log("语音转文字结果", text);
|
// console.log("语音转文字结果", text)
|
||||||
// }).catch(err => {
|
// }).catch(err => {
|
||||||
// console.log("语音转文字失败", err);
|
// console.log("语音转文字失败", err)
|
||||||
// })
|
// })
|
||||||
}
|
}
|
||||||
else if (element.arkElement) {
|
else if (element.arkElement) {
|
||||||
@ -322,20 +323,20 @@ export class OB11Constructor {
|
|||||||
|
|
||||||
static async PrivateEvent(msg: RawMessage): Promise<OB11BaseNoticeEvent> {
|
static async PrivateEvent(msg: RawMessage): Promise<OB11BaseNoticeEvent> {
|
||||||
if (msg.chatType !== ChatType.friend) {
|
if (msg.chatType !== ChatType.friend) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
for (const element of msg.elements) {
|
for (const element of msg.elements) {
|
||||||
if (element.grayTipElement) {
|
if (element.grayTipElement) {
|
||||||
if (element.grayTipElement.subElementType == GrayTipElementSubType.MEMBER_NEW_TITLE) {
|
if (element.grayTipElement.subElementType == GrayTipElementSubType.MEMBER_NEW_TITLE) {
|
||||||
const json = JSON.parse(element.grayTipElement.jsonGrayTipElement.jsonStr);
|
const json = JSON.parse(element.grayTipElement.jsonGrayTipElement.jsonStr)
|
||||||
if (element.grayTipElement.jsonGrayTipElement.busiId == 1061) {
|
if (element.grayTipElement.jsonGrayTipElement.busiId == 1061) {
|
||||||
//判断业务类型
|
//判断业务类型
|
||||||
//Poke事件
|
//Poke事件
|
||||||
const pokedetail: any[] = json.items;
|
const pokedetail: any[] = json.items
|
||||||
//筛选item带有uid的元素
|
//筛选item带有uid的元素
|
||||||
const poke_uid = pokedetail.filter(item => item.uid);
|
const poke_uid = pokedetail.filter(item => item.uid)
|
||||||
if (poke_uid.length == 2) {
|
if (poke_uid.length == 2) {
|
||||||
return new OB11FriendPokeEvent(parseInt((uidMaps[poke_uid[0].uid])!), parseInt((uidMaps[poke_uid[1].uid])), pokedetail);
|
return new OB11FriendPokeEvent(parseInt((uidMaps[poke_uid[0].uid])!), parseInt((uidMaps[poke_uid[1].uid])), pokedetail)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//下面得改 上面也是错的grayTipElement.subElementType == GrayTipElementSubType.MEMBER_NEW_TITLE
|
//下面得改 上面也是错的grayTipElement.subElementType == GrayTipElementSubType.MEMBER_NEW_TITLE
|
||||||
@ -366,7 +367,7 @@ export class OB11Constructor {
|
|||||||
return event
|
return event
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// log("group msg", msg);
|
// log("group msg", msg)
|
||||||
for (let element of msg.elements) {
|
for (let element of msg.elements) {
|
||||||
const grayTipElement = element.grayTipElement
|
const grayTipElement = element.grayTipElement
|
||||||
const groupElement = grayTipElement?.groupElement
|
const groupElement = grayTipElement?.groupElement
|
||||||
@ -536,32 +537,32 @@ export class OB11Constructor {
|
|||||||
if (grayTipElement.jsonGrayTipElement.busiId == 1061) {
|
if (grayTipElement.jsonGrayTipElement.busiId == 1061) {
|
||||||
//判断业务类型
|
//判断业务类型
|
||||||
//Poke事件
|
//Poke事件
|
||||||
const pokedetail: any[] = json.items;
|
const pokedetail: any[] = json.items
|
||||||
//筛选item带有uid的元素
|
//筛选item带有uid的元素
|
||||||
const poke_uid = pokedetail.filter(item => item.uid);
|
const poke_uid = pokedetail.filter(item => item.uid)
|
||||||
if (poke_uid.length == 2) {
|
if (poke_uid.length == 2) {
|
||||||
return new OB11GroupPokeEvent(parseInt(msg.peerUid), parseInt((uidMaps[poke_uid[0].uid])!), parseInt((uidMaps[poke_uid[1].uid])), pokedetail);
|
return new OB11GroupPokeEvent(parseInt(msg.peerUid), parseInt((uidMaps[poke_uid[0].uid])!), parseInt((uidMaps[poke_uid[1].uid])), pokedetail)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (grayTipElement.jsonGrayTipElement.busiId == 2401) {
|
if (grayTipElement.jsonGrayTipElement.busiId == 2401) {
|
||||||
log('收到群精华消息', json)
|
log('收到群精华消息', json)
|
||||||
const searchParams = new URL(json.items[0].jp).searchParams;
|
const searchParams = new URL(json.items[0].jp).searchParams
|
||||||
const msgSeq = searchParams.get('msgSeq')!;
|
const msgSeq = searchParams.get('msgSeq')!
|
||||||
const Group = searchParams.get('groupCode');
|
const Group = searchParams.get('groupCode')
|
||||||
const Businessid = searchParams.get('businessid');
|
const Businessid = searchParams.get('businessid')
|
||||||
const Peer: Peer = {
|
const Peer: Peer = {
|
||||||
guildId: '',
|
guildId: '',
|
||||||
chatType: ChatType.group,
|
chatType: ChatType.group,
|
||||||
peerUid: Group!
|
peerUid: Group!
|
||||||
};
|
}
|
||||||
let msgList = (await NTQQMsgApi.getMsgsBySeqAndCount(Peer, msgSeq.toString(), 1, true, true)).msgList;
|
let msgList = (await NTQQMsgApi.getMsgsBySeqAndCount(Peer, msgSeq.toString(), 1, true, true)).msgList
|
||||||
const origMsg = await dbUtil.getMsgByLongId(msgList[0].msgId);
|
const origMsg = await dbUtil.getMsgByLongId(msgList[0].msgId)
|
||||||
const postMsg = await dbUtil.getMsgBySeqId(origMsg.msgSeq) ?? origMsg;
|
const postMsg = await dbUtil.getMsgBySeqId(origMsg.msgSeq) ?? origMsg
|
||||||
// 如果 senderUin 为 0,可能是 历史消息 或 自身消息
|
// 如果 senderUin 为 0,可能是 历史消息 或 自身消息
|
||||||
if (msgList[0].senderUin === '0') {
|
if (msgList[0].senderUin === '0') {
|
||||||
msgList[0].senderUin = postMsg?.senderUin ?? selfInfo.uin;
|
msgList[0].senderUin = postMsg?.senderUin ?? selfInfo.uin
|
||||||
}
|
}
|
||||||
return new OB11GroupEssenceEvent(parseInt(msg.peerUid), postMsg.msgShortId, parseInt(msgList[0].senderUin));
|
return new OB11GroupEssenceEvent(parseInt(msg.peerUid), postMsg.msgShortId, parseInt(msgList[0].senderUin))
|
||||||
// 获取MsgSeq+Peer可获取具体消息
|
// 获取MsgSeq+Peer可获取具体消息
|
||||||
}
|
}
|
||||||
if (grayTipElement.jsonGrayTipElement.busiId == 2407) {
|
if (grayTipElement.jsonGrayTipElement.busiId == 2407) {
|
||||||
@ -625,6 +626,25 @@ export class OB11Constructor {
|
|||||||
return friends.map(OB11Constructor.friend)
|
return friends.map(OB11Constructor.friend)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static friendsV2(friends: FriendV2[]): OB11User[] {
|
||||||
|
const data: OB11User[] = []
|
||||||
|
for (const friend of friends) {
|
||||||
|
const sexValue = this.sex(friend.baseInfo.sex!)
|
||||||
|
data.push({
|
||||||
|
...friend.baseInfo,
|
||||||
|
...friend.coreInfo,
|
||||||
|
user_id: parseInt(friend.coreInfo.uin),
|
||||||
|
nickname: friend.coreInfo.nick,
|
||||||
|
remark: friend.coreInfo.nick,
|
||||||
|
sex: sexValue,
|
||||||
|
level: 0,
|
||||||
|
categroyName: friend.categroyName,
|
||||||
|
categoryId: friend.categoryId
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
static groupMemberRole(role: number): OB11GroupMemberRole | undefined {
|
static groupMemberRole(role: number): OB11GroupMemberRole | undefined {
|
||||||
return {
|
return {
|
||||||
4: OB11GroupMemberRole.owner,
|
4: OB11GroupMemberRole.owner,
|
||||||
|
@ -11,6 +11,8 @@ export interface OB11User {
|
|||||||
age?: number
|
age?: number
|
||||||
qid?: string
|
qid?: string
|
||||||
login_days?: number
|
login_days?: number
|
||||||
|
categroyName?: string
|
||||||
|
categoryId?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum OB11UserSex {
|
export enum OB11UserSex {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user