diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..3bc0ef55 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true + +# Matches multiple files with brace expansion notation +# Set default charset +charset = utf-8 + +# 2 space indentation +[*.{cjs,mjs,js,jsx,ts,tsx,css,scss,sass,html,json}] +indent_style = space +indent_size = 2 + +# Unfortunately, EditorConfig doesn't support space configuration inside import braces directly. +# You'll need to rely on your linter/formatter like ESLint or Prettier for that. diff --git a/.env.development b/.env.development new file mode 100644 index 00000000..4642c3e8 --- /dev/null +++ b/.env.development @@ -0,0 +1 @@ +VITE_BUILD_TYPE = Development \ No newline at end of file diff --git a/.env.production b/.env.production new file mode 100644 index 00000000..458dab00 --- /dev/null +++ b/.env.production @@ -0,0 +1 @@ +VITE_BUILD_TYPE = Production \ No newline at end of file diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 00000000..1cc2dba3 --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,67 @@ +module.exports = { + 'env': { + 'es2021': true, + 'node': true + }, + 'ignorePatterns': ['src/core/'], + 'extends': [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended' + ], + 'overrides': [ + { + 'env': { + 'node': true + }, + 'files': [ + '.eslintrc.{js,cjs}' + ], + 'parserOptions': { + 'sourceType': 'script' + } + } + ], + 'parser': '@typescript-eslint/parser', + 'parserOptions': { + 'ecmaVersion': 'latest', + 'sourceType': 'module' + }, + 'plugins': [ + '@typescript-eslint', + 'import' + ], + 'settings': { + 'import/parsers': { + '@typescript-eslint/parser': ['.ts'] + }, + 'import/resolver': { + 'typescript': { + 'alwaysTryTypes': true + } + } + }, + 'rules': { + 'indent': [ + 'error', + 2 + ], + 'linebreak-style': [ + 'error', + 'unix' + ], + 'quotes': [ + 'error', + 'single' + ], + 'semi': [ + 'error', + 'always' + ], + 'no-unused-vars': 'off', + 'no-async-promise-executor': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-var-requires': 'off', + 'object-curly-spacing': ['error', 'always'], + } +}; diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..b4179835 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "npm" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "daily" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..dc74b99a --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,23 @@ +name: "publish" +on: + push: + tags: + - "v*" + +jobs: + build-and-publish: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: setup node + uses: actions/setup-node@v2 + with: + node-version: 18 + + - name: install dependenies + run: export ELECTRON_SKIP_BINARY_DOWNLOAD=1 && npm install + + - name: build + run: npm run build:prod diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..615fd51d --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +# Logs + +# Develop +node_modules/ +package-lock.json +out/ +dist/ +src/core.lib/common/ + +# Editor +.vscode/* +!.vscode/extensions.json +.idea/* + +# Build +*.db diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..10dc451f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "src/core"] + path = src/core + url = https://github.com/NapNeko/core.git + branch = master diff --git a/README.md b/README.md index 1386a779..c3affdeb 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,144 @@ ## 项目介绍 -NapCatQQ(瞌睡猫QQ,不准叫我NCQQ!),像睡着了一样在后台低占用运行的无头NTQQ +NapCatQQ(瞌睡猫QQ,不准叫我NCQQ!),像睡着了一样在后台低占用运行的无头(没有界面)的NTQQ -NapCat 是基于 官方NTQQ 实现的Bot框架 +目前测试在 Windows 上表现优秀,最低可达只占用内存 **20M**左右 -## 测试版本 -前往 Action 下载最新测试版 +由于 Linux 上的 QQ 图形依赖较多,会导致内存占用小高,大约 **100+M**,目前正在研究如何优化 -[跳转链接](https://github.com/NapNeko/NapCat.Build/actions) + +## 启动 + +NapCat 是基于 官方NTQQ 实现的Bot框架,因此先需要安装官方QQ + +*如果没有安装 QQ 请往后翻查看安装方法* + +修改 `config/onebot11.json`内容,并重名为 `onebot11_<你的QQ号>.json`,如`onebot11_1234567.json` + +json 配置内容参数解释: + +```json5 +{ + // 是否启用http服务,如果启用,可以通过http接口发送消息 + "enableHttp": false, + // http服务端口 + "httpPort": 3000, + // 是否启用正向websocket服务 + "enableWs": false, + // 正向websocket服务端口 + "wsPort": 3001, + // 是否启用反向websocket服务 + "enableWsReverse": false, + // 反向websocket对接的地址, 如["ws://127.0.0.1:8080/onebot/v11/ws"] + "wsReverseUrls": [], + // 是否启用http上报服务 + "enableHttpPost": false, + // http上报地址, 如["http://127.0.0.1:8080/onebot/v11/http"] + "httpPostUrls": [], + // http上报密钥,可为空 + "httpSecret": "", + // 消息上报格式,array为消息组,string为cq码字符串 + "messagePostFormat": "array", + // 是否上报自己发送的消息 + "reportSelfMessage": false, + // 是否开启调试模式,开启后上报消息会携带一个raw字段,为原始消息内容 + "debug": false, + // 调用get_file接口时如果获取不到url则使用base64字段返回文件内容 + "enableLocalFile2Url": true, + // ws心跳间隔,单位毫秒 + "heartInterval": 30000, + // access_token,可以为空 + "token": "" +} + +``` + +### Windows 启动 + +运行`powershell ./napcat.ps1`, 或者 `napcat.bat`,如果出现乱码,可以尝试运行`napcat_utf8.ps1` + +### Linux 启动 + +运行`napcat.sh` + +## 使用无需扫码快速登录 + +前提是你已经成功登录过QQ,可以加参数` -q <你的QQ>` 进行登录,如`napcat.sh -q 1234567` + +## 安装 + +### Linux安装 + +#### 安装 Linux QQ(22741),已经安装了的可以跳过 + +目前还在研究怎么精简安装,暂时只能安装官方QQ整体依赖 + +```bash +下载QQ的deb包 + +[deb x86版本](https://dldir1.qq.com/qqfile/qq/QQNT/Linux/QQ_3.2.7_240403_amd64_01.deb) +[deb arm版本](https://dldir1.qq.com/qqfile/qq/QQNT/Linux/QQ_3.2.7_240403_arm64_01.deb) + +[rpm x86版本](https://dldir1.qq.com/qqfile/qq/QQNT/Linux/QQ_3.2.7_240403_x86_64_01.rpm) +[rpm arm版本](https://dldir1.qq.com/qqfile/qq/QQNT/Linux/QQ_3.2.7_240403_aarch64_01.rpm) +``` + +```bash + +```bash +sudo apt install ./qq.deb +``` + +```bash +安装QQ的依赖 +sudo apt install libgbm1 libasound2 +``` + +### Windows 安装 + +#### 安装Windows QQ(22741),已经安装了的可以跳过 + +[Windows版本QQ下载](https://dldir1.qq.com/qqfile/qq/QQNT/Windows/QQ_9.9.9_240403_x64_01.exe) + +### 编译安装 NapCat + +**如果你是直接下载编译好的版本,可以跳过这一步** + +准备环境 [node18.18](https://nodejs.org/download/release/v18.18.2/) + +``` +export NODE_ENV=production +npm install +``` + +## 常见问题 + +### 二维码无法扫描 + +NapCat 会自动保存二维码到目录,可以手动打开图片扫描 + +如果没有条件访问本地目录,可以将二维码解析的 url 复制到二维码生成网站上生成二维码,然后手机QQ扫描 + +### 语音、视频发送失败 + +需要配置 ffmpeg,将 ffmpeg 目录加入环境变量,如果仍未生效,可以修改 napcat 启动脚本加入 FFMPEG_PATH 变量指定到 ffmpeg +程序的完整路径 + +如 Windows 上修改 napcat.ps1,在第一行加入 + +```powershell +$env:FFMPEG_PATH="d:\ffmpeg\bin\ffmpeg.exe" +``` + +### 出现 error code v2:-1 之类的提示 + +不用管,这是正常现象,是因为 QQ 本身的问题,不影响使用 + + + ## 声明 diff --git a/script/debug-gc.ps1 b/script/debug-gc.ps1 new file mode 100644 index 00000000..9fea136d --- /dev/null +++ b/script/debug-gc.ps1 @@ -0,0 +1,15 @@ +function Get-QQpath { + try { + $key = Get-ItemProperty -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ" + $uninstallString = $key.UninstallString + return [System.IO.Path]::GetDirectoryName($uninstallString) + "\QQ.exe" + } + catch { + throw "Error getting UninstallString: $_" + } +} +$params = $args -join " " +$QQpath = Get-QQpath +$Bootfile = Join-Path (Get-Location) "\dist\inject.cjs" +$env:ELECTRON_RUN_AS_NODE = 1 +Start-Process powershell -ArgumentList "-noexit", "-noprofile", "-command &{& '$QQpath' --expose-gc $Bootfile $params}" diff --git a/script/napcat-log.ps1 b/script/napcat-log.ps1 new file mode 100644 index 00000000..90ea28be --- /dev/null +++ b/script/napcat-log.ps1 @@ -0,0 +1,17 @@ +function Get-QQpath { + try { + $key = Get-ItemProperty -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ" + $uninstallString = $key.UninstallString + return [System.IO.Path]::GetDirectoryName($uninstallString) + "\QQ.exe" + } + catch { + return "D:\QQ.exe" + } +} +$params = $args -join " " +$QQpath = Get-QQpath +$Bootfile = Join-Path $PSScriptRoot "napcat.cjs" +$env:ELECTRON_RUN_AS_NODE = 1 +$argumentList = '-noexit', '-noprofile', "-command `"$QQpath`" `"$Bootfile`" $params" +Start-Process powershell -ArgumentList $argumentList -RedirectStandardOutput "log.txt" -RedirectStandardError "error.txt" +powershell Get-Content -Wait -Encoding UTF8 log.txt diff --git a/script/napcat-utf8.bat b/script/napcat-utf8.bat new file mode 100644 index 00000000..e1c5bdb3 --- /dev/null +++ b/script/napcat-utf8.bat @@ -0,0 +1,22 @@ +@echo off +setlocal enabledelayedexpansion +chcp 65001 +:loop_read +for /f "tokens=3" %%a in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ" /v "UninstallString"') do ( + set "RetString=%%a" + goto :napcat_boot +) + +goto :loop_read + +:napcat_boot +for %%a in ("!RetString!") do ( + set "pathWithoutUninstall=%%~dpa" + set "fileName=%%~na" + set "extension=%%~xa" +) + +set "QQPath=!pathWithoutUninstall!QQ.exe" +set ELECTRON_RUN_AS_NODE=1 +echo !QQPath! +!QQPath! ./napcat.cjs \ No newline at end of file diff --git a/script/napcat-utf8.ps1 b/script/napcat-utf8.ps1 new file mode 100644 index 00000000..72228b1c --- /dev/null +++ b/script/napcat-utf8.ps1 @@ -0,0 +1,15 @@ +function Get-QQpath { + try { + $key = Get-ItemProperty -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ" + $uninstallString = $key.UninstallString + return [System.IO.Path]::GetDirectoryName($uninstallString) + "\QQ.exe" + } + catch { + return "D:\QQ.exe" + } +} +$params = $args -join " " +$QQpath = Get-QQpath +$Bootfile = Join-Path $PSScriptRoot "napcat.cjs" +$env:ELECTRON_RUN_AS_NODE = 1 +Start-Process powershell -ArgumentList "-noexit", "-noprofile", "-command &{& chcp 65001;& '$QQpath' $Bootfile $params}" diff --git a/script/napcat.bat b/script/napcat.bat new file mode 100644 index 00000000..db48c2af --- /dev/null +++ b/script/napcat.bat @@ -0,0 +1,22 @@ +@echo off +setlocal enabledelayedexpansion + +:loop_read +for /f "tokens=3" %%a in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ" /v "UninstallString"') do ( + set "RetString=%%a" + goto :napcat_boot +) + +goto :loop_read + +:napcat_boot +for %%a in ("!RetString!") do ( + set "pathWithoutUninstall=%%~dpa" + set "fileName=%%~na" + set "extension=%%~xa" +) + +set "QQPath=!pathWithoutUninstall!QQ.exe" +set ELECTRON_RUN_AS_NODE=1 +echo !QQPath! +!QQPath! ./napcat.cjs \ No newline at end of file diff --git a/script/napcat.ps1 b/script/napcat.ps1 new file mode 100644 index 00000000..55abd42e --- /dev/null +++ b/script/napcat.ps1 @@ -0,0 +1,15 @@ +function Get-QQpath { + try { + $key = Get-ItemProperty -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ" + $uninstallString = $key.UninstallString + return [System.IO.Path]::GetDirectoryName($uninstallString) + "\QQ.exe" + } + catch { + return "D:\QQ.exe" + } +} +$params = $args -join " " +$QQpath = Get-QQpath +$Bootfile = Join-Path $PSScriptRoot "napcat.cjs" +$env:ELECTRON_RUN_AS_NODE = 1 +Start-Process powershell -ArgumentList "-noexit", "-noprofile", "-command &{& '$QQpath' $Bootfile $params}" diff --git a/script/napcat.sh b/script/napcat.sh new file mode 100644 index 00000000..70553086 --- /dev/null +++ b/script/napcat.sh @@ -0,0 +1,4 @@ +#!/bin/bash +SCRIPT_DIR=$(realpath $(dirname "${BASH_SOURCE[0]}")) +export ELECTRON_RUN_AS_NODE=1 +/opt/QQ/qq ${SCRIPT_DIR}/napcat.cjs $@ diff --git a/src/common/data.ts b/src/common/data.ts new file mode 100644 index 00000000..85f24feb --- /dev/null +++ b/src/common/data.ts @@ -0,0 +1,85 @@ +import { + type Friend, + type FriendRequest, + type Group, + type GroupMember, GroupNotify, + type SelfInfo +} from '@/core/qqnt/entities'; +import { isNumeric } from './utils/helper'; +import { log } from '@/common/utils/log'; + +export const selfInfo: SelfInfo = { + uid: '', + uin: '', + nick: '', + online: true +}; + +// groupCode -> Group +export const groups: Map = new Map(); + +// 群号 -> 群成员map(uid=>GroupMember) +export const groupMembers: Map> = new Map>(); + +// uid -> Friend +export const friends: Map = new Map(); + +export const friendRequests: Record = {}; // flag->FriendRequest +export const groupNotifies: Record = {}; // flag->GroupNotify + +export const napCatError = { + ffmpegError: '', + httpServerError: '', + wsServerError: '', + otherError: 'NapCat未能正常启动,请检查日志查看错误' +}; + +export async function getFriend(uinOrUid: string): Promise { + uinOrUid = uinOrUid.toString(); + if (isNumeric(uinOrUid)) { + const friendList = Array.from(friends.values()); + return friendList.find(friend => friend.uin === uinOrUid); + } else { + return friends.get(uinOrUid); + } +} + +export async function getGroup(qq: string): Promise { + const group = groups.get(qq.toString()); + return group; +} + +export async function getGroupMember(groupQQ: string | number, memberUinOrUid: string | number) { + groupQQ = groupQQ.toString(); + memberUinOrUid = memberUinOrUid.toString(); + const members = groupMembers.get(groupQQ); + if (!members) { + return null; + } + // log('getGroupMember', members); + if (isNumeric(memberUinOrUid)) { + return Array.from(members.values()).find(member => member.uin === memberUinOrUid); + } else { + return members.get(memberUinOrUid); + } +} + +export async function refreshGroupMembers(groupQQ: string) { + // const group = groups.find(group => group.groupCode === groupQQ) + // if (group) { + // group.members = await NTQQGroupApi.getGroupMembers(groupQQ) + // } +} + +export const uid2UinMap: Record = {}; // 一串加密的字符串(uid) -> qq号 + +export function getUidByUin(uin: string) { + for (const uid in uid2UinMap) { + if (uid2UinMap[uid] === uin) { + return uid; + } + } +} + +export const tempGroupCodeMap: Record = {}; // peerUid => 群号 + diff --git a/src/common/server/http.ts b/src/common/server/http.ts new file mode 100644 index 00000000..354d707e --- /dev/null +++ b/src/common/server/http.ts @@ -0,0 +1,113 @@ +import express, { Express, Request, Response } from 'express'; +import http from 'http'; +import { log } from '../utils/log'; +import { ob11Config } from '@/onebot11/config'; + +type RegisterHandler = (res: Response, payload: any) => Promise + +export abstract class HttpServerBase { + name: string = 'LLOneBot'; + private readonly expressAPP: Express; + private server: http.Server | null = null; + + constructor() { + this.expressAPP = express(); + this.expressAPP.use(express.urlencoded({ extended: true, limit: '5000mb' })); + this.expressAPP.use((req, res, next) => { + // 兼容处理没有带content-type的请求 + // log("req.headers['content-type']", req.headers['content-type']) + req.headers['content-type'] = 'application/json'; + const originalJson = express.json({ limit: '5000mb' }); + // 调用原始的express.json()处理器 + originalJson(req, res, (err) => { + if (err) { + log('Error parsing JSON:', err); + return res.status(400).send('Invalid JSON'); + } + next(); + }); + }); + } + + authorize(req: Request, res: Response, next: () => void) { + const serverToken = ob11Config.token; + let clientToken = ''; + const authHeader = req.get('authorization'); + if (authHeader) { + clientToken = authHeader.split('Bearer ').pop() || ''; + log('receive http header token', clientToken); + } else if (req.query.access_token) { + if (Array.isArray(req.query.access_token)) { + clientToken = req.query.access_token[0].toString(); + } else { + clientToken = req.query.access_token.toString(); + } + log('receive http url token', clientToken); + } + + if (serverToken && clientToken != serverToken) { + return res.status(403).send(JSON.stringify({ message: 'token verify failed!' })); + } + next(); + } + + start(port: number) { + try { + this.expressAPP.get('/', (req: Request, res: Response) => { + res.send(`${this.name}已启动`); + }); + this.listen(port); + } catch (e: any) { + log('HTTP服务启动失败', e.toString()); + // llonebotError.httpServerError = "HTTP服务启动失败, " + e.toString() + } + } + + stop() { + // llonebotError.httpServerError = "" + if (this.server) { + this.server.close(); + this.server = null; + } + } + + restart(port: number) { + this.stop(); + this.start(port); + } + + abstract handleFailed(res: Response, payload: any, err: any): void + + registerRouter(method: 'post' | 'get' | string, url: string, handler: RegisterHandler) { + if (!url.startsWith('/')) { + url = '/' + url; + } + + // @ts-expect-error wait fix + if (!this.expressAPP[method]) { + const err = `${this.name} register router failed,${method} not exist`; + log(err); + throw err; + } + // @ts-expect-error wait fix + this.expressAPP[method](url, this.authorize, async (req: Request, res: Response) => { + let payload = req.body; + if (method == 'get') { + payload = req.query; + } + log('收到http请求', url, payload); + try { + res.send(await handler(res, payload)); + } catch (e: any) { + this.handleFailed(res, payload, e.stack.toString()); + } + }); + } + + protected listen(port: number) { + this.server = this.expressAPP.listen(port, '0.0.0.0', () => { + const info = `${this.name} started 0.0.0.0:${port}`; + log(info); + }); + } +} diff --git a/src/common/server/websocket.ts b/src/common/server/websocket.ts new file mode 100644 index 00000000..977cd53b --- /dev/null +++ b/src/common/server/websocket.ts @@ -0,0 +1,99 @@ +import { WebSocket, WebSocketServer } from 'ws'; +import urlParse from 'url'; +import { IncomingMessage } from 'node:http'; +import { log } from '@/common/utils/log'; + +class WebsocketClientBase { + private wsClient: WebSocket | undefined; + + constructor() { + } + + send(msg: string) { + if (this.wsClient && this.wsClient.readyState == WebSocket.OPEN) { + this.wsClient.send(msg); + } + } + + onMessage(msg: string) { + + } +} + +export class WebsocketServerBase { + private ws: WebSocketServer | null = null; + public token: string = ''; + + constructor() { + } + + start(port: number) { + try { + this.ws = new WebSocketServer({ port }); + } catch (e: any) { + throw Error('ws服务启动失败, ' + e.toString()); + } + this.ws.on('connection', (wsClient, req) => { + const url: string = req.url!.split('?').shift() || '/'; + this.authorize(wsClient, req); + this.onConnect(wsClient, url, req); + wsClient.on('message', async (msg) => { + this.onMessage(wsClient, url, msg.toString()); + }); + }); + } + + stop() { + this.ws && this.ws.close((err) => { + log('ws server close failed!', err); + }); + this.ws = null; + } + + restart(port: number) { + this.stop(); + this.start(port); + } + + authorize(wsClient: WebSocket, req: IncomingMessage) { + const url = req.url!.split('?').shift(); + log('ws connect', url); + let clientToken: string = ''; + const authHeader = req.headers['authorization']; + if (authHeader) { + clientToken = authHeader.split('Bearer ').pop() || ''; + log('receive ws header token', clientToken); + } else { + const parsedUrl = urlParse.parse(req.url || '/', true); + const urlToken = parsedUrl.query.access_token; + if (urlToken) { + if (Array.isArray(urlToken)) { + clientToken = urlToken[0]; + } else { + clientToken = urlToken; + } + log('receive ws url token', clientToken); + } + } + if (this.token && clientToken != this.token) { + this.authorizeFailed(wsClient); + return wsClient.close(); + } + } + + authorizeFailed(wsClient: WebSocket) { + + } + + onConnect(wsClient: WebSocket, url: string, req: IncomingMessage) { + + } + + onMessage(wsClient: WebSocket, url: string, msg: string) { + + } + + sendHeart() { + + } +} diff --git a/src/common/utils/QQBasicInfo.ts b/src/common/utils/QQBasicInfo.ts new file mode 100644 index 00000000..5c980d7b --- /dev/null +++ b/src/common/utils/QQBasicInfo.ts @@ -0,0 +1,60 @@ +import path from 'node:path'; +import fs from 'node:fs'; +import os from 'node:os'; +import { systemPlatform } from '@/common/utils/system'; + +export const exePath = process.execPath; + +export const pkgInfoPath = path.join(path.dirname(exePath), 'resources', 'app', 'package.json'); +let configVersionInfoPath; + +if (os.platform() !== 'linux') { + configVersionInfoPath = path.join(path.dirname(exePath), 'resources', 'app', 'versions', 'config.json'); +} else { + const userPath = os.homedir(); + const appDataPath = path.resolve(userPath, './.config/QQ'); + configVersionInfoPath = path.resolve(appDataPath, './versions/config.json'); +} + +if (typeof configVersionInfoPath !== 'string') { + throw new Error('Something went wrong when load QQ info path'); +} + +export { configVersionInfoPath }; + +type QQPkgInfo = { + version: string; + buildVersion: string; + platform: string; + eleArch: string; +} +type QQVersionConfigInfo = { + baseVersion: string; + curVersion: string; + prevVersion: string; + onErrorVersions: Array; + buildId: string; +} + +let _qqVersionConfigInfo: QQVersionConfigInfo = { + 'baseVersion': '9.9.9-22578', + 'curVersion': '9.9.9-22578', + 'prevVersion': '', + 'onErrorVersions': [], + 'buildId': '22578' +}; + +if (fs.existsSync(configVersionInfoPath)) { + _qqVersionConfigInfo = JSON.parse(fs.readFileSync(configVersionInfoPath).toString()); +} + +export const qqVersionConfigInfo: QQVersionConfigInfo = _qqVersionConfigInfo; + +export const qqPkgInfo: QQPkgInfo = require(pkgInfoPath); + +let _appid: string = '537213335'; // 默认为 Windows 平台的 appid +if (systemPlatform === 'linux') { + _appid = '537213710'; +} +// todo: mac 平台的 appid +export const appid = _appid; diff --git a/src/common/utils/audio.ts b/src/common/utils/audio.ts new file mode 100644 index 00000000..d7602c5d --- /dev/null +++ b/src/common/utils/audio.ts @@ -0,0 +1,135 @@ +import fs from 'fs'; +import { encode, getDuration, getWavFileInfo, isWav } from 'silk-wasm'; +import fsPromise from 'fs/promises'; +import { log } from './log'; +import path from 'node:path'; +import { v4 as uuidv4 } from 'uuid'; +import { spawn } from 'node:child_process'; +import { getTempDir } from '@/common/utils/file'; + +let TEMP_DIR = './'; +setTimeout(() => { + TEMP_DIR = getTempDir(); +}, 100); +export async function encodeSilk(filePath: string) { + function getFileHeader(filePath: string) { + // 定义要读取的字节数 + const bytesToRead = 7; + try { + const buffer = fs.readFileSync(filePath, { + encoding: null, + flag: 'r', + }); + + const fileHeader = buffer.toString('hex', 0, bytesToRead); + return fileHeader; + } catch (err) { + console.error('读取文件错误:', err); + return; + } + } + + async function isWavFile(filePath: string) { + return isWav(fs.readFileSync(filePath)); + } + + async function guessDuration(pttPath: string) { + const pttFileInfo = await fsPromise.stat(pttPath); + let duration = pttFileInfo.size / 1024 / 3; // 3kb/s + duration = Math.floor(duration); + duration = Math.max(1, duration); + log('通过文件大小估算语音的时长:', duration); + return duration; + } + + // function verifyDuration(oriDuration: number, guessDuration: number) { + // // 单位都是秒 + // if (oriDuration - guessDuration > 10) { + // return guessDuration + // } + // oriDuration = Math.max(1, oriDuration) + // return oriDuration + // } + // async function getAudioSampleRate(filePath: string) { + // try { + // const mm = await import('music-metadata'); + // const metadata = await mm.parseFile(filePath); + // log(`${filePath}采样率`, metadata.format.sampleRate); + // return metadata.format.sampleRate; + // } catch (error) { + // log(`${filePath}采样率获取失败`, error.stack); + // // console.error(error); + // } + // } + + try { + const pttPath = path.join(TEMP_DIR, uuidv4()); + if (getFileHeader(filePath) !== '02232153494c4b') { + log(`语音文件${filePath}需要转换成silk`); + const _isWav = await isWavFile(filePath); + const pcmPath = pttPath + '.pcm'; + let sampleRate = 0; + const convert = () => { + return new Promise((resolve, reject) => { + // todo: 通过配置文件获取ffmpeg路径 + const ffmpegPath = process.env.FFMPEG_PATH || 'ffmpeg'; + const cp = spawn(ffmpegPath, ['-y', '-i', filePath, '-ar', '24000', '-ac', '1', '-f', 's16le', pcmPath]); + cp.on('error', err => { + log('FFmpeg处理转换出错: ', err.message); + return reject(err); + }); + cp.on('exit', (code, signal) => { + const EXIT_CODES = [0, 255]; + if (code == null || EXIT_CODES.includes(code)) { + sampleRate = 24000; + const data = fs.readFileSync(pcmPath); + fs.unlink(pcmPath, (err) => { + }); + return resolve(data); + } + log(`FFmpeg exit: code=${code ?? 'unknown'} sig=${signal ?? 'unknown'}`); + reject(Error('FFmpeg处理转换失败')); + }); + }); + }; + let input: Buffer; + if (!_isWav) { + input = await convert(); + } else { + input = fs.readFileSync(filePath); + const allowSampleRate = [8000, 12000, 16000, 24000, 32000, 44100, 48000]; + const { fmt } = getWavFileInfo(input); + // log(`wav文件信息`, fmt) + if (!allowSampleRate.includes(fmt.sampleRate)) { + input = await convert(); + } + } + const silk = await encode(input, sampleRate); + fs.writeFileSync(pttPath, silk.data); + log(`语音文件${filePath}转换成功!`, pttPath, '时长:', silk.duration); + return { + converted: true, + path: pttPath, + duration: silk.duration / 1000 + }; + } else { + const silk = fs.readFileSync(filePath); + let duration = 0; + try { + duration = getDuration(silk) / 1000; + } catch (e: any) { + log('获取语音文件时长失败, 使用文件大小推测时长', filePath, e.stack); + duration = await guessDuration(filePath); + } + + return { + converted: false, + path: filePath, + duration, + }; + } + } catch (error: any) { + log('convert silk failed', error.stack); + return {}; + } +} diff --git a/src/common/utils/db.ts b/src/common/utils/db.ts new file mode 100644 index 00000000..a1ec01df --- /dev/null +++ b/src/common/utils/db.ts @@ -0,0 +1,323 @@ +import { ElementType, FileElement, PicElement, PttElement, RawMessage, VideoElement } from '@/core/qqnt/entities'; + +import sqlite3 from 'sqlite3'; +import { log } from '@/common/utils/log'; + +type DBMsg = { + id: number, + longId: string, + seq: number, + peerUid: string, + msg: string +} + +type DBFile = { + name: string; // 文件名 + path: string; + url: string; + size: number; + uuid: string; + msgId: string; + elementId: string; + element: PicElement | VideoElement | FileElement | PttElement; + elementType: ElementType.PIC | ElementType.VIDEO | ElementType.FILE | ElementType.PTT; +} + + +class DBUtilBase { + protected db: sqlite3.Database | undefined; + + createConnection(dbPath: string) { + if (this.db) { + return; + } + this.db = new sqlite3.Database(dbPath, sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, (err) => { + if (err) { + log('Could not connect to database', err); + return; + } + this.createTable(); + }); + } + + protected createTable() { + throw new Error('Method not implemented.'); + } + + close() { + this.db?.close(); + } +} + +class DBUtil extends DBUtilBase { + private msgCache: Map = new Map(); + + constructor() { + super(); + const interval = 1000 * 60 * 10; // 10分钟清理一次缓存 + setInterval(() => { + log('清理消息缓存'); + this.msgCache.forEach((msg, key) => { + if ((Date.now() - parseInt(msg.msgTime) * 1000) > interval) { + this.msgCache.delete(key); + } + }); + }, interval); + } + + + protected createTable() { + // 消息记录 + const createTableSQL = ` + CREATE TABLE IF NOT EXISTS msgs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + long_id TEXT NOT NULL UNIQUE, + seq INTEGER NOT NULL, + peer_uid TEXT NOT NULL, + msg TEXT NOT NULL + )`; + this.db!.run(createTableSQL, function (err) { + if (err) { + log('Could not create table', err); + } + }); + + // 文件缓存 + const createFileTableSQL = ` + CREATE TABLE IF NOT EXISTS files ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + path TEXT NOT NULL, + url TEXT, + size INTEGER NOT NULL, + uuid TEXT, + elementType INTEGER, + element TEXT NOT NULL, + elementId TEXT NOT NULL, + msgId TEXT NOT NULL + )`; + this.db!.run(createFileTableSQL, function (err) { + if (err) { + log('Could not create table files', err); + } + }); + + // 接收到的临时会话消息uid + const createTempUinTableSQL = ` + CREATE TABLE IF NOT EXISTS temp_uins ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + uid TEXT, + uin TEXT + )`; + this.db!.run(createTempUinTableSQL, function (err) { + if (err) { + log('Could not create table temp_uins', err); + } + }); + } + + private async getMsg(query: string, params: any[]) { + const stmt = this.db!.prepare(query); + return new Promise((resolve, reject) => { + stmt.get(...params, (err: any, row: DBMsg) => { + // log("getMsg", row, err); + if (err) { + log('Could not get msg by short id', err); + resolve(null); + } + try { + const msg = JSON.parse(row.msg); + msg.id = row.id; + return resolve(msg); + } catch (e) { + return resolve(null); + } + }); + }); + } + + async getMsgByShortId(shortId: number): Promise { + const getStmt = 'SELECT * FROM msgs WHERE id = ?'; + return this.getMsg(getStmt, [shortId]); + } + + async getMsgByLongId(longId: string): Promise { + if (this.msgCache.has(longId)) { + return this.msgCache.get(longId)!; + } + return this.getMsg('SELECT * FROM msgs WHERE long_id = ?', [longId]); + } + + async getMsgBySeq(peerUid: string, seq: string): Promise { + const stmt = 'SELECT * FROM msgs WHERE peer_uid = ? AND seq = ?'; + return this.getMsg(stmt, [peerUid, seq]); + } + + async addMsg(msg: RawMessage, update = true): Promise { + log('正在记录消息到数据库', msg.msgId); + const existMsg = await this.getMsgByLongId(msg.msgId); + if (existMsg) { + // log('消息已存在,更新数据库', msg.msgId); + if (update) this.updateMsg(msg).then(); + return existMsg.id!; + } + const stmt = this.db!.prepare('INSERT INTO msgs (long_id, seq, peer_uid, msg) VALUES (?, ?, ?, ?)'); + + // const runAsync = promisify(stmt.run.bind(stmt)); + return new Promise((resolve, reject) => { + // eslint-disable-next-line @typescript-eslint/no-this-alias + const dbInstance = this; + stmt.run(msg.msgId, msg.msgSeq, msg.peerUid, JSON.stringify(msg), function (err: any) { + if (err) { + if (err.errno === 19) { + // log('消息已存在,更新数据库', msg.msgId); + dbInstance.getMsgByLongId(msg.msgId).then((msg: RawMessage | null) => { + if (msg) { + dbInstance.msgCache.set(msg.msgId, msg); + // log('获取消息短id成功', msg.id); + resolve(msg.id!); + } else { + log('db could not get msg by long id', err); + resolve(-1); + } + }); + } else { + log('db could not add msg', err); + resolve(-1); + } + } else { + // log("addMsg", this); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + msg.id = this.lastID; + dbInstance.msgCache.set(msg.msgId, msg); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // log('获取消息短id成功', this.lastID); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + resolve(this.lastID); + } + }); + }); + } + + async updateMsg(msg: RawMessage) { + const existMsg = this.msgCache.get(msg.msgId); + if (existMsg) { + Object.assign(existMsg, msg); + } + const stmt = this.db!.prepare('UPDATE msgs SET msg = ?, seq = ? WHERE long_id = ?'); + try { + stmt.run(JSON.stringify(msg), msg.msgSeq, msg.msgId); + } catch (e) { + log('updateMsg db error', e); + } + } + + async addFileCache(file: DBFile) { + const stmt = this.db!.prepare('INSERT INTO files (name, path, url, size, uuid, elementType ,element, elementId, msgId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)'); + return new Promise((resolve, reject) => { + stmt.run(file.name, file.path, file.url, file.size, file.uuid, + file.elementType, + JSON.stringify(file.element), + file.elementId, + file.msgId, + function (err: any) { + if (err) { + log('db could not add file', err); + reject(err); + } + resolve(null); + }); + }); + } + + private async getFileCache(query: string, params: any[]) { + const stmt = this.db!.prepare(query); + return new Promise((resolve, reject) => { + stmt.get(...params, (err: any, row: DBFile & { element: string }) => { + if (err) { + log('db could not get file cache', err); + reject(err); + } + if (row) { + row.element = JSON.parse(row.element); + } + resolve(row); + }); + }); + } + + async getFileCacheByName(name: string): Promise { + return this.getFileCache('SELECT * FROM files WHERE name = ?', [name]); + } + + async getFileCacheByUuid(uuid: string): Promise { + return this.getFileCache('SELECT * FROM files WHERE uuid = ?', [uuid]); + } + + // todo: 是否所有的文件都有uuid?语音消息有没有uuid? + async updateFileCache(file: DBFile) { + const stmt = this.db!.prepare('UPDATE files SET path = ?, url = ? WHERE uuid = ?'); + return new Promise((resolve, reject) => { + stmt.run(file.path, file.url, function (err: any) { + if (err) { + log('db could not update file cache', err); + reject(err); + } + resolve(null); + }); + }); + } + + // 被动收到的临时会话消息uin->uid + async getReceivedTempUinMap() { + const stmt = 'SELECT * FROM temp_uins'; + return new Promise>((resolve, reject) => { + this.db!.all(stmt, (err, rows: { uin: string, uid: string }[]) => { + if (err) { + log('db could not get temp uin map', err); + reject(err); + } + const map: Record = {}; + rows.forEach(row => { + map[row.uin] = row.uid; + }); + resolve(map); + }); + }); + } + + // 通过uin获取临时会话消息uid + async getUidByTempUin(uid: string) { + const stmt = 'SELECT * FROM temp_uins WHERE uin = ?'; + return new Promise((resolve, reject) => { + this.db!.get(stmt, [uid], (err, row: { uin: string, uid: string }) => { + if (err) { + log('db could not get temp uin map', err); + reject(err); + } + resolve(row?.uid); + }); + }); + } + + async addTempUin(uin: string, uid: string) { + const existUid = await this.getUidByTempUin(uin); + if (!existUid) { + const stmt = this.db!.prepare('INSERT INTO temp_uins (uin, uid) VALUES (?, ?)'); + return new Promise((resolve, reject) => { + stmt.run(uin, uid, function (err: any) { + if (err) { + log('db could not add temp uin', err); + reject(err); + } + resolve(null); + }); + }); + } + } +} + + +export const dbUtil = new DBUtil(); diff --git a/src/common/utils/file.ts b/src/common/utils/file.ts new file mode 100644 index 00000000..bc777a31 --- /dev/null +++ b/src/common/utils/file.ts @@ -0,0 +1,273 @@ +import fs from 'fs'; +import fsPromise from 'fs/promises'; +import crypto from 'crypto'; +import util from 'util'; +import path from 'node:path'; +import { log } from './log'; +import { dbUtil } from './db'; +import * as fileType from 'file-type'; +import { v4 as uuidv4 } from 'uuid'; +import { napCatCore } from '@/core'; +import os from 'node:os'; + +export const getNapCatDir = () => { + const p = path.join(napCatCore.wrapper.dataPath, 'NapCat'); + fs.mkdirSync(p, { recursive: true }); + return p; +}; +export const getTempDir = () => { + const p = path.join(getNapCatDir(), 'temp'); + // 创建临时目录 + if (!fs.existsSync(p)) { + fs.mkdirSync(p, { recursive: true }); + } + return p; +}; + + +export function isGIF(path: string) { + const buffer = Buffer.alloc(4); + const fd = fs.openSync(path, 'r'); + fs.readSync(fd, buffer, 0, 4, 0); + fs.closeSync(fd); + return buffer.toString() === 'GIF8'; +} + +// 定义一个异步函数来检查文件是否存在 +export function checkFileReceived(path: string, timeout: number = 3000): Promise { + return new Promise((resolve, reject) => { + const startTime = Date.now(); + + function check() { + if (fs.existsSync(path)) { + resolve(); + } else if (Date.now() - startTime > timeout) { + reject(new Error(`文件不存在: ${path}`)); + } else { + setTimeout(check, 100); + } + } + + check(); + }); +} + +export async function file2base64(path: string) { + const readFile = util.promisify(fs.readFile); + const result = { + err: '', + data: '' + }; + try { + // 读取文件内容 + // if (!fs.existsSync(path)){ + // path = path.replace("\\Ori\\", "\\Thumb\\"); + // } + try { + await checkFileReceived(path, 5000); + } catch (e: any) { + result.err = e.toString(); + return result; + } + const data = await readFile(path); + // 转换为Base64编码 + result.data = data.toString('base64'); + } catch (err: any) { + result.err = err.toString(); + } + return result; +} + + +export function calculateFileMD5(filePath: string): Promise { + return new Promise((resolve, reject) => { + // 创建一个流式读取器 + const stream = fs.createReadStream(filePath); + const hash = crypto.createHash('md5'); + + stream.on('data', (data: Buffer) => { + // 当读取到数据时,更新哈希对象的状态 + hash.update(data); + }); + + stream.on('end', () => { + // 文件读取完成,计算哈希 + const md5 = hash.digest('hex'); + resolve(md5); + }); + + stream.on('error', (err: Error) => { + // 处理可能的读取错误 + reject(err); + }); + }); +} + +export interface HttpDownloadOptions { + url: string; + headers?: Record | string; +} + +export async function httpDownload(options: string | HttpDownloadOptions): Promise { + const chunks: Buffer[] = []; + let url: string; + let headers: Record = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36' + }; + if (typeof options === 'string') { + url = options; + } else { + url = options.url; + if (options.headers) { + if (typeof options.headers === 'string') { + headers = JSON.parse(options.headers); + } else { + headers = options.headers; + } + } + } + const fetchRes = await fetch(url, headers); + if (!fetchRes.ok) throw new Error(`下载文件失败: ${fetchRes.statusText}`); + + const blob = await fetchRes.blob(); + const buffer = await blob.arrayBuffer(); + return Buffer.from(buffer); +} + +type Uri2LocalRes = { + success: boolean, + errMsg: string, + fileName: string, + ext: string, + path: string, + isLocal: boolean +} + +export async function uri2local(uri: string, fileName: string | null = null): Promise { + const res = { + success: false, + errMsg: '', + fileName: '', + ext: '', + path: '', + isLocal: false + }; + if (!fileName) { + fileName = uuidv4(); + } + let filePath = path.join(getTempDir(), fileName); + let url = null; + try { + url = new URL(uri); + } catch (e: any) { + res.errMsg = `uri ${uri} 解析失败,` + e.toString() + ` 可能${uri}不存在`; + return res; + } + + // log("uri protocol", url.protocol, uri); + if (url.protocol == 'base64:') { + // base64转成文件 + const base64Data = uri.split('base64://')[1]; + try { + const buffer = Buffer.from(base64Data, 'base64'); + fs.writeFileSync(filePath, buffer); + + } catch (e: any) { + res.errMsg = 'base64文件下载失败,' + e.toString(); + return res; + } + } else if (url.protocol == 'http:' || url.protocol == 'https:') { + // 下载文件 + let buffer: Buffer | null = null; + try { + buffer = await httpDownload(uri); + } catch (e: any) { + res.errMsg = `${url}下载失败,` + e.toString(); + return res; + } + try { + const pathInfo = path.parse(decodeURIComponent(url.pathname)); + if (pathInfo.name) { + fileName = pathInfo.name; + if (pathInfo.ext) { + fileName += pathInfo.ext; + // res.ext = pathInfo.ext + } + } + res.fileName = fileName; + filePath = path.join(getTempDir(), uuidv4() + fileName); + fs.writeFileSync(filePath, buffer); + } catch (e: any) { + res.errMsg = `${url}下载失败,` + e.toString(); + return res; + } + } else { + let pathname: string; + if (url.protocol === 'file:') { + // await fs.copyFile(url.pathname, filePath); + pathname = decodeURIComponent(url.pathname); + if (process.platform === 'win32') { + filePath = pathname.slice(1); + } else { + filePath = pathname; + } + } else { + const cache = await dbUtil.getFileCacheByName(uri); + if (cache) { + filePath = cache.path; + } else { + filePath = uri; + } + } + + res.isLocal = true; + } + // else{ + // res.errMsg = `不支持的file协议,` + url.protocol + // return res + // } + // if (isGIF(filePath) && !res.isLocal) { + // await fs.rename(filePath, filePath + ".gif"); + // filePath += ".gif"; + // } + if (!res.isLocal && !res.ext) { + try { + const ext: string | undefined = (await fileType.fileTypeFromFile(filePath))?.ext; + if (ext) { + log('获取文件类型', ext, filePath); + fs.renameSync(filePath, filePath + `.${ext}`); + filePath += `.${ext}`; + res.fileName += `.${ext}`; + res.ext = ext; + } + } catch (e) { + // log("获取文件类型失败", filePath,e.stack) + } + } + res.success = true; + res.path = filePath; + return res; +} + +export async function copyFolder(sourcePath: string, destPath: string) { + try { + const entries = await fsPromise.readdir(sourcePath, { withFileTypes: true }); + await fsPromise.mkdir(destPath, { recursive: true }); + for (const entry of entries) { + const srcPath = path.join(sourcePath, entry.name); + const dstPath = path.join(destPath, entry.name); + if (entry.isDirectory()) { + await copyFolder(srcPath, dstPath); + } else { + try { + await fsPromise.copyFile(srcPath, dstPath); + } catch (error) { + console.error(`无法复制文件 '${srcPath}' 到 '${dstPath}': ${error}`); + // 这里可以决定是否要继续复制其他文件 + } + } + } + } catch (error) { + console.error('复制文件夹时出错:', error); + } +} diff --git a/src/common/utils/helper.ts b/src/common/utils/helper.ts new file mode 100644 index 00000000..2142f6b6 --- /dev/null +++ b/src/common/utils/helper.ts @@ -0,0 +1,21 @@ +import crypto from 'node:crypto'; +import { resolve } from 'dns'; + +export function sleep(ms: number): Promise { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +export function getMd5(s: string) { + + const h = crypto.createHash('md5'); + h.update(s); + return h.digest('hex'); +} + +export function isNull(value: any) { + return value === undefined || value === null; +} + +export function isNumeric(str: string) { + return /^\d+$/.test(str); +} diff --git a/src/common/utils/log.ts b/src/common/utils/log.ts new file mode 100644 index 00000000..6e7ad391 --- /dev/null +++ b/src/common/utils/log.ts @@ -0,0 +1,4 @@ + +export function log(...args: any[]) { + console.log(...args); +} \ No newline at end of file diff --git a/src/common/utils/qqlevel.ts b/src/common/utils/qqlevel.ts new file mode 100644 index 00000000..9a2779ce --- /dev/null +++ b/src/common/utils/qqlevel.ts @@ -0,0 +1,7 @@ +// QQ等级换算 +import { QQLevel } from '../../ntqqapi/types'; + +export function calcQQLevel(level: QQLevel) { + const { crownNum, sunNum, moonNum, starNum } = level; + return crownNum * 64 + sunNum * 16 + moonNum * 4 + starNum; +} \ No newline at end of file diff --git a/src/common/utils/system.ts b/src/common/utils/system.ts new file mode 100644 index 00000000..71076d14 --- /dev/null +++ b/src/common/utils/system.ts @@ -0,0 +1,9 @@ +import os from 'node:os'; +import path from 'node:path'; + +export const systemPlatform = os.platform(); +export const systemVersion = os.release(); +export const hostname = os.hostname(); +const homeDir = os.homedir(); +export const downloadsPath = path.join(homeDir, 'Downloads'); +export const systemName = os.type(); \ No newline at end of file diff --git a/src/common/utils/umami.ts b/src/common/utils/umami.ts new file mode 100644 index 00000000..b42968ad --- /dev/null +++ b/src/common/utils/umami.ts @@ -0,0 +1,38 @@ +import { request } from "https"; +export function noifyLoginStatus() { + let req = request( + { + hostname: 'napcat.wumiao.wang', + path: '/api/send', + port: 443, + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'User-Agent': `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0` + } + }, + (res) => { + //let data = ''; + res.on('data', (chunk) => { + //data += chunk; + }); + res.on('end', () => { + //console.log('Response:', data); + }); + } + ); + let StatesData = { + type: "event", + payload: { + "website": "952bf82f-8f49-4456-aec5-e17db5f27f7e", + "hostname": "napcat.demo.cn", + "screen": "1920x1080", + "language": "zh-CN", + "title": "OneBot.Login", + "url": "/login/onebot11", + "referrer": "https://napcat.demo.cn/login?type=onebot11" + } + }; + req.write(JSON.stringify(StatesData)); + req.end(); +} \ No newline at end of file diff --git a/src/common/utils/version.ts b/src/common/utils/version.ts new file mode 100644 index 00000000..27788efd --- /dev/null +++ b/src/common/utils/version.ts @@ -0,0 +1,44 @@ +import { get as httpsGet } from "node:https"; +function requestMirror(url: string): Promise { + return new Promise((resolve, reject) => { + httpsGet(url, (response) => { + let data = ''; + response.on('data', (chunk) => { + data += chunk; + }); + + response.on('end', () => { + try { + const parsedData = JSON.parse(data); + const version = parsedData.version; + resolve(version); + } catch (error) { + // 解析失败或无法访问域名,跳过 + resolve(undefined); + } + }); + }).on('error', (error) => { + // 请求失败,跳过 + resolve(undefined); + }); + }); +} + +export async function checkVersion(): Promise { + return new Promise(async (resolve, reject) => { + const MirrorList = + [ + "https://fastly.jsdelivr.net/gh/NapNeko/NapCatQQ@main/package.json", + "https://gcore.jsdelivr.net/gh/NapNeko/NapCatQQ@main/package.json", + "https://cdn.jsdelivr.us/gh/NapNeko/NapCatQQ@main/package.json", + "https://jsd.cdn.zzko.cn/gh/NapNeko/NapCatQQ@main/package.json" + ]; + for (const url of MirrorList) { + const version = await requestMirror(url); + if (version) { + resolve(version); + } + } + reject("get verison error!"); + }); +} \ No newline at end of file diff --git a/src/common/utils/video.ts b/src/common/utils/video.ts new file mode 100644 index 00000000..ae639388 --- /dev/null +++ b/src/common/utils/video.ts @@ -0,0 +1,88 @@ +import { log } from './log'; +import ffmpeg from 'fluent-ffmpeg'; +import fs from 'fs'; + +const defaultVideoThumbB64 = '/9j/4AAQSkZJRgABAQAAAQABAAD//gAXR2VuZXJhdGVkIGJ5IFNuaXBhc3Rl/9sAhAAKBwcIBwYKCAgICwoKCw4YEA4NDQ4dFRYRGCMfJSQiHyIhJis3LyYpNCkhIjBBMTQ5Oz4+PiUuRElDPEg3PT47AQoLCw4NDhwQEBw7KCIoOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozv/wAARCAF/APADAREAAhEBAxEB/8QBogAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoLEAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4eLj5OXm5+jp6vHy8/T19vf4+foBAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKCxEAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDiAayNxwagBwNAC5oAM0xBmgBM0ANJoAjY0AQsaBkTGgCM0DEpAFAC0AFMBaACgAoEJTASgQlACUwCgQ4UAOFADhQA4UAOFADxQIkBqDQUGgBwagBQaBC5pgGaAELUAMLUARs1AETGgBhNAxhoASkAUALQIKYxaBBQAUwEoAQ0CEoASmAUAOoEKKAHCgBwoAeKAHigQ7NZmoZpgLmgBd1Ahd1ABupgNLUAMLUAMY0AMJoAYaAENACUCCgAoAWgAoAWgBKYCUAJQISgApgLQAooEOFACigB4oAeKBDxQAVmaiZpgGaAFzQAbqAE3UAIWpgNJoAYTQIaaAEoAQ0CEoASgBaACgBaACmAUAJQAlAgoAKYC0AKKBCigB4FADgKBDwKAHigBuazNRM0DEzTAM0AJmgAzQAhNAhpNACGmA2gQlACUCEoAKACgBaAFpgFACUAJQAUCCmAUALQIcBQA4CgB4FADgKBDhQA4UAMzWZqNzTGJQAZoATNABmgBKAEoEIaYCUCEoASgQlABQAtABQAtMBKACgAoEFABimAYoEKBQA4CgB4FADwKBDgKAFFADhQBCazNhKAEpgFACUAFACUAFAhDTAbQISgAoEJQAUALQAtMAoAKADFABigQYoAMUALimIUCgBwFAh4FADgKAHUALQAtAENZmwlACUwEoAKAEoAKACgQlMBpoEJQAUCCgBcUAFABTAXFAC4oAMUAGKBBigAxQIKYCigQ8UAOFADhQAtAC0ALQBDWZqJQMSgBKYBQAlABQISgBKYCGgQlAC0CCgBcUAFABTAUCkA7FMAxQAYoEJQAUCCmAooEOFADxQA4UAFAC0ALQBDWZqJQAlACUxhQAlABQIKAEoASmISgBcUCCgBaACgBcUAKBQAuKYC0CEoAQ0AJQISmAooEPFADhQA4UALQAtAC0AQ1maiUAFACUAJTAKAEoAKAEoAMUxBigAxQIWgAoAKAFAoAWgBaYBQIQ0ANNACUCCmIUUAOFADxQA4UALQAtABQBFWZqFACUAFACYpgFACUAFACUAFAgxTEFABQAUALQAooAWgAoAKYDTQIaaAEpiCgQ4UAOFAh4oGOFAC0ALSAKYEdZmglABQAUDDFACUwEoASgAoAKBBQIKYBQAUALQAtAC0AJQAhpgNJoENJoATNMQCgQ8UCHigB4oAWgYtABQAUAMrM0CgAoAKADFACUxiUAJQAlAgoAKYgoAKACgYtAC0AFAhDTAQmgBhNAhpNACZpiFBoEPFAEi0CHigB1ABQAUDEoAbWZoFABQAtABTAQ0ANNAxDQAlAhaAEpiCgAoGFAC0AFABmgBCaYhpNADCaBDSaBBmgABpiJFNAEimgB4NADqAFzQAlACE0AJWZoFAC0AFAC0wEIoAaaAG0AJQAUCCgApjCgAoAKADNABmgBpNMQ0mgBpNAhhNAgzQAoNADwaAHqaAJAaBDgaYC5oATNACZoAWszQKACgBaBDqYCGgBpoAYaBiUCCgBKYBQMKACgAoAM0AITQIaTQA0mmA0mgQ3NAhKAHCgBwNADwaAHg0AOBpiFzQAZoATNAD6zNAoAKAFoEOpgBoAaaAGGmAw0AJmgAzQMM0AGaADNABmgBM0AITQIaTQAhNMQw0AJQIKAFFADhQA4GgBwNADs0xC5oAM0CDNAEtZmoUCCgBaAHUwCgBppgRtQAw0ANzQAZoAM0AGaADNABmgBKAEoAQ0ANNMQhoEJQAlMBaQDgaAFBoAcDTAdmgQuaADNAgzQBPWZqFAgoAWgBaYC0CGmmBG1AyM0ANJoATNACZoAXNABmgAzQAUAJQAhoAQ0xDTQISmAUALQAUgHA0AKDTAdmgQuaBBQAtAFiszQKACgBaAFFMAoEIaYEbUDI2oAYaAEoASgAzQAuaACgAoAKAENMQ00AJTEFAhKACgAoAXNACg0AOBoAWgQtAC0AWazNAoAKACgBaYBQIQ0AMNMYw0AMIoAbQAlMAoAKACgAzSAKYhKAENACUxBQIKACgBKACgBaAHCgQ4UALQAUAWqzNAoAKACgApgFACGgQ00xjTQAwigBCKAG4pgJQAlABQAUCCgBKACgBKYgoEFABQISgAoAWgBRQA4UALQAUCLdZmoUAFABQAlMAoASgBDQA00wENACYoATFMBpFADSKAEoEJQAUAFABQAlMQtAgoASgQUAJQAUAKKAHCgBaBBQBbrM1CgAoAKACmAUAJQAlADaYBQAlACYpgIRQA0igBpFAhtABQAUAFMAoEFABQIKAEoASgQUALQAooAWgQUAW81mbC0CCgApgFACUAIaAEpgJQAUAFABQAhFMBpFADSKAGkUCExQAYoAMUAGKADFMQYoAMUCExSATFABQIKYBQAtABQIt5qDYM0ALmgQtIApgIaAENADaACmAlAC0ALQAUwGkUANIoAaRQAmKBBigAxQAYoAMUAGKBBigBMUAJigQmKAExTAKBC0AFAFnNQaig0AKDQAtAgoASgBDQAlMBKACgAFADhQAtMBCKAGkUAIRQAmKADFABigQmKADFACYoAXFABigQmKAExQAmKBCYpgJigAoAnzUGgZoAcDQAuaBC0AJQAhoASmAlABQAtADhQAtMAoATFACEUAJigAxQAYoATFAhMUAFABQAuKADFABigBpWgBCKBCYpgJigB+ag0DNADgaBDgaAFzQITNACUAJTAKACgBRQAopgOoAWgBKAEoAKACgAoASgBpoEJQAooAWgBaBhigBMUCEIoAQigBMUAJSLCgBQaBDgaQC5oEFACUwCgBKACmAtADhQA4UALQAUAJQAUAJQAUAJQAhoENoAWgBRQAooGLQAUAGKAGkUAIRQIZSKEoGKKBDhQAUCCgAoAKBBQAUwFoGKKAHCgBaACgAoASgAoASgBCaAEoEJmgAoAUGgBQaAHZoGFABQAUANoAjpDEoAWgBaAFoEFACUALQAUCCmAUAOFAxRQAtAC0AJQAUAJQAmaBDSaAEzQAmaYBmgBQaAHA0gFzQAuaBhmgAzQAlAEdIYUALQAtAgoAKAEoEFAC0AFMAoAUUDFFAC0ALQAUAJQAhoENNACE0wEoATNABmgBc0ALmgBc0gDNAC5oATNABmgBKRQlACigB1AgoASgQlABTAWgBKACgBaBi0ALQAZoAM0AFACGgQ00wENACUAJQAUCFzQMM0ALmgAzQAZoAM0AGaQC0igoAUUALQIWgBDQISmAUAFACUAFABQAuaBi5oAM0AGaBBmgBKAEpgIaAG0AJQAUCFoAM0DDNAC5oATNABmgAzQBJUlBQAooAWgQtACGmIaaACgAoASgBKACgBc0DCgQUAGaADNABTASgBDQAlACUAFAgoAKBhQAUAFABQAlAE1SUFAxRQIWgQtMBDQIQ0AJQAlAhKBiUAFABmgBc0AGaADNABTAKACgBKAEoASgQlABQAUAFAC0AFACUAFAE1SaBQAUCHCgQtMBKBCUAJQISgBDQA00DEzQAuaADNMBc0AGaADNABQAUAJQAlABQISgAoAKACgBaACgBKAEoAnqTQSgBRQIcKBC0xCUAJQISgBKAENADDQAmaYwzQAuaADNAC0AFABQAUAFAhKACgBKACgAoAWgAoELQAlAxKAJqk0EoAWgQooELTEFADaBCUABoENNMY00ANNAwzQAZoAXNAC0AFAC0CFoASgAoASgBKACgAoAWgQtABQAUANNAyWpNAoAKBCimIWgQUCEoASmIQ0ANNADTQMaaAEoGLmgAzQAtADhQIWgBaACgQhoASgYlACUALQIWgBaACgBKAENAyWpNBKYBQIcKBC0CEoEJTAKBCUANNADDQMQ0ANoGFAC5oAUGgBwNAhRQIWgBaAENACGgBtAwoAKAFzQIXNABmgAoAQ0DJKRoJQAtAhRQSLQIKYCUCCgBDQA00AMNAxpoGNoAM0AGaAFBoAcDQIcKBDqACgBDQAhoAQ0DEoAKADNAC5oEGaBhmgAoAkpGgUCCgQooELQIKYhKACgBKAGmgBpoGMNAxDQAlAwzQIUUAOFAhwoAcKBC0AJQAhoGNNACUAFABQAZoAXNABQAUAS0ixKACgQoNAhaYgoEFACUABoAaaAGmgYw0DENAxtABQAooEOFADhQIcKAFoASgBDQAhoGJQAUAFACUALQIKBi0CJDSLEoATNAhc0CHZpiCgQUAJQIKBjTQAhoGNNAxpoATFABigBQKAHCgBwoAWgAoAKACgBKAEoASgAoASgBaAAUAOoEONIoaTQAZoAUGmIUGgQtAgzQISgAoAQ0DGmgYlAxKACgAxQAtACigBRQAtAxaACgAoATFABigBCKAG0CEoAWgBRTAUUAf//Z'; + +export const defaultVideoThumb = Buffer.from(defaultVideoThumbB64, 'base64'); + +export async function getVideoInfo(filePath: string) { + const size = fs.statSync(filePath).size; + return new Promise<{ + width: number, + height: number, + time: number, + format: string, + size: number, + filePath: string + }>((resolve, reject) => { + // todo: 从配置文件中读取ffmpeg路径 + const ffmpegPath = './ffmpeg'; + ffmpegPath && ffmpeg.setFfmpegPath(ffmpegPath); + ffmpeg(filePath).ffprobe((err: any, metadata: any) => { + if (err) { + reject(err); + } else { + const videoStream = metadata.streams.find((s: { codec_type: string; }) => s.codec_type === 'video'); + if (videoStream) { + console.log(`视频尺寸: ${videoStream.width}x${videoStream.height}`); + } else { + console.log('未找到视频流信息。'); + } + resolve({ + width: videoStream.width, height: videoStream.height, + time: parseInt(videoStream.duration), + format: metadata.format.format_name, + size, + filePath + }); + } + }); + }); +} + +export async function encodeMp4(filePath: string) { + const videoInfo = await getVideoInfo(filePath); + log('视频信息', videoInfo); + if (videoInfo.format.indexOf('mp4') === -1) { + log('视频需要转换为MP4格式', filePath); + // 转成mp4 + const newPath: string = await new Promise((resolve, reject) => { + const newPath = filePath + '.mp4'; + ffmpeg(filePath) + .toFormat('mp4') + .on('error', (err) => { + reject(`转换视频格式失败: ${err.message}`); + }) + .on('end', () => { + log('视频转换为MP4格式完成'); + resolve(newPath); // 返回转换后的文件路径 + }) + .save(newPath); + }); + return await getVideoInfo(newPath); + } + return videoInfo; +} + +export function checkFfmpeg(newPath: string | null = null): Promise { + return new Promise((resolve, reject) => { + log('开始检查ffmpeg', newPath); + if (newPath) { + ffmpeg.setFfmpegPath(newPath); + } + try { + ffmpeg.getAvailableFormats((err: any, formats: any) => { + if (err) { + log('ffmpeg is not installed or not found in PATH:', err); + resolve(false); + } else { + log('ffmpeg is installed.'); + resolve(true); + } + }); + } catch (e) { + resolve(false); + } + }); +} \ No newline at end of file diff --git a/src/core.lib/package.json b/src/core.lib/package.json new file mode 100644 index 00000000..d7b4b825 --- /dev/null +++ b/src/core.lib/package.json @@ -0,0 +1,22 @@ +{ + "name": "@napneko/core", + "version": "1.0.0", + "description": "", + "type": "module", + "main": "./index.js", + "files": [ + "lib" + ], + "scripts": { + "lint": "eslint --fix ./src/**/*.ts", + "build:dev": "vite build --mode development", + "build:prod": "vite build --mode production", + "build": "npm run build:dev" + }, + "author": "NapNeko", + "license": "MIT", + "bugs": { + "url": "https://github.com/NapNeko/NapCatQQ/issues" + }, + "homepage": "https://github.com/NapNeko/NapCatQQ#readme" +} diff --git a/src/core.lib/src/index.d.ts b/src/core.lib/src/index.d.ts new file mode 100644 index 00000000..65c50248 --- /dev/null +++ b/src/core.lib/src/index.d.ts @@ -0,0 +1,27 @@ +/// +import { GlobalAdapter } from './qqnt/adapters'; +import { QRCodeLoginSucceedType } from './qqnt/services'; +import { NapCatCoreWrapper } from './wrapper'; +import { NapCatCoreLogin } from './login'; +import { NapCatCoreSession } from './session'; +import { NapCatCoreService } from './service'; +import { EventEmitter } from 'node:events'; +import * as log4js from '@log4js-node/log4js-api'; +export interface LoginSuccessCallback { + (): void | Promise; +} +export declare class NapCatCore extends EventEmitter { + readonly log: log4js.Logger; + readonly adapter: GlobalAdapter; + readonly wrapper: NapCatCoreWrapper; + readonly login: NapCatCoreLogin; + readonly session: NapCatCoreSession; + readonly service: NapCatCoreService; + private loginSuccessCbList; + constructor(); + initPostLogin(args: QRCodeLoginSucceedType): Promise; + private onLoginSuccess; + private onMessage; + addLoginSuccessCallback(cb: LoginSuccessCallback): void; +} +export declare const napCatCore: NapCatCore; diff --git a/src/core.lib/src/index.js b/src/core.lib/src/index.js new file mode 100644 index 00000000..a7f005b1 --- /dev/null +++ b/src/core.lib/src/index.js @@ -0,0 +1 @@ +const _0x583e98=_0x5504;(function(_0x76084b,_0x5db612){const _0x214fd2=_0x5504,_0x54e9b2=_0x76084b();while(!![]){try{const _0x2b0b0e=parseInt(_0x214fd2(0x194))/0x1+parseInt(_0x214fd2(0x189))/0x2*(-parseInt(_0x214fd2(0x167))/0x3)+parseInt(_0x214fd2(0x17d))/0x4+-parseInt(_0x214fd2(0x162))/0x5+-parseInt(_0x214fd2(0x18c))/0x6+parseInt(_0x214fd2(0x163))/0x7*(parseInt(_0x214fd2(0x181))/0x8)+parseInt(_0x214fd2(0x195))/0x9;if(_0x2b0b0e===_0x5db612)break;else _0x54e9b2['push'](_0x54e9b2['shift']());}catch(_0x1313eb){_0x54e9b2['push'](_0x54e9b2['shift']());}}}(_0x20cf,0xb4499));import{Wrapper}from'./qqnt';import{GlobalAdapter}from'./qqnt/adapters';function _0x20cf(){const _0x125d94=['登录失败','addLoginSuccessCallback','resolve','error','./NapCat/data','nRAgc','ifNsA','dataPathGlobal','jKEoJ','log','wrapper','getProfileLikeService','EFoSS','getMsgService','onLoginSuccess','loginSuccessCbList','getGroupService','4390056ULTZEd','init','IOFhk','system.login.error','47176mcFVNM','login','catch','getProfileService','uid','stringify','mkdirSync','JCepf','2paToiZ','adeIJ','V1_WIN_NQ_','7958490ewomMS','replace','adapter','NodeIGlobalAdapter','getLogger','debug','push','FpiVR','61660wehCPj','3107547eiNYnI','then','.db','session','gwSAN','split','QQNT\x20版本:','curVersion','1090075nkeLBQ','1169klANDD','dataPath','service','_GW_B','619107WwBQTx','onMessage','uin','emit','YTReJ'];_0x20cf=function(){return _0x125d94;};return _0x20cf();}import{NapCatCoreWrapper}from'./wrapper';import{NapCatCoreLogin}from'./login';import{NapCatCoreSession}from'./session';import{NapCatCoreService}from'./service';import{appid,qqVersionConfigInfo}from'@/common/utils/QQBasicInfo';import{dbUtil}from'@/common/utils/db';import{hostname,systemVersion}from'@/common/utils/system';import{selfInfo}from'@/common/data';import _0x263aa5 from'node:path';import _0x49a8bd from'node:fs';function _0x5504(_0x29a3fd,_0x441f9e){const _0x20cf22=_0x20cf();return _0x5504=function(_0x550454,_0xeef11e){_0x550454=_0x550454-0x15c;let _0x3e84d7=_0x20cf22[_0x550454];return _0x3e84d7;},_0x5504(_0x29a3fd,_0x441f9e);}import{EventEmitter}from'node:events';import*as _0x443792 from'@log4js-node/log4js-api';export class NapCatCore extends EventEmitter{['log'];[_0x583e98(0x18e)];[_0x583e98(0x176)];[_0x583e98(0x182)];[_0x583e98(0x15d)];[_0x583e98(0x165)];[_0x583e98(0x17b)]=[];constructor(){const _0x5d6b7e=_0x583e98,_0xdadbea={'FpiVR':'Core','RgOoc':_0x5d6b7e(0x160),'EFoSS':'Windows\x2010\x20Pro','gwSAN':'QQNT\x20数据目录:'},_0x1d6a96='2|3|7|6|9|1|0|4|10|8|5'[_0x5d6b7e(0x15f)]('|');let _0x55a35b=0x0;while(!![]){switch(_0x1d6a96[_0x55a35b++]){case'0':this['service']=new NapCatCoreService(this);continue;case'1':this[_0x5d6b7e(0x15d)]=new NapCatCoreSession();continue;case'2':super();continue;case'3':this[_0x5d6b7e(0x175)]=_0x443792[_0x5d6b7e(0x190)](_0xdadbea[_0x5d6b7e(0x193)]);continue;case'4':this[_0x5d6b7e(0x175)]['debug'](_0xdadbea['RgOoc'],qqVersionConfigInfo['curVersion']);continue;case'5':this[_0x5d6b7e(0x182)][_0x5d6b7e(0x17e)]({'machineId':'','appid':appid,'platVer':systemVersion,'commonPath':this[_0x5d6b7e(0x176)][_0x5d6b7e(0x173)],'clientVer':qqVersionConfigInfo[_0x5d6b7e(0x161)],'hostName':hostname});continue;case'6':this['wrapper']=new NapCatCoreWrapper();continue;case'7':this[_0x5d6b7e(0x18e)]=new GlobalAdapter();continue;case'8':this[_0x5d6b7e(0x176)][_0x5d6b7e(0x17e)]({'base_path_prefix':'','platform_type':0x3,'app_type':0x4,'app_version':qqVersionConfigInfo['curVersion'],'os_version':_0xdadbea[_0x5d6b7e(0x178)],'use_xlog':!![],'qua':_0x5d6b7e(0x18b)+qqVersionConfigInfo[_0x5d6b7e(0x161)][_0x5d6b7e(0x18d)]('-','_')+_0x5d6b7e(0x166),'global_path_config':{'desktopGlobalPath':this[_0x5d6b7e(0x176)][_0x5d6b7e(0x173)]},'thumb_config':{'maxSide':0x144,'minSide':0x30,'longLimit':0x6,'density':0x2}},new Wrapper[(_0x5d6b7e(0x18f))](this['adapter']));continue;case'9':this['login']=new NapCatCoreLogin(this);continue;case'10':this[_0x5d6b7e(0x175)][_0x5d6b7e(0x191)](_0xdadbea[_0x5d6b7e(0x15e)],this[_0x5d6b7e(0x176)][_0x5d6b7e(0x173)]);continue;}break;}}async['initPostLogin'](_0x48768b){const _0x5ea900=_0x583e98,_0x2e2f80={'nRAgc':_0x5ea900(0x16c),'JCepf':_0x5ea900(0x180)};this[_0x5ea900(0x15d)][_0x5ea900(0x17e)](_0x48768b[_0x5ea900(0x169)],_0x48768b[_0x5ea900(0x185)],this[_0x5ea900(0x176)][_0x5ea900(0x164)])[_0x5ea900(0x196)](()=>{const _0xaa6277=_0x5ea900;this[_0xaa6277(0x17a)](_0x48768b['uin'],_0x48768b[_0xaa6277(0x185)]);})['catch'](_0x12ba9b=>{const _0x38fe20=_0x5ea900;console[_0x38fe20(0x16f)](_0x2e2f80[_0x38fe20(0x171)],JSON[_0x38fe20(0x186)](_0x12ba9b)),this['emit'](_0x2e2f80[_0x38fe20(0x188)],{'code':'-1','message':_0x12ba9b});});}[_0x583e98(0x17a)](_0x2ba3cd,_0x4e28a9){const _0x2c64ac=_0x583e98,_0x3cebf8={'jKEoJ':function(_0x5557f7,_0x30ba6c){return _0x5557f7 instanceof _0x30ba6c;},'ifNsA':_0x2c64ac(0x170),'adeIJ':'本账号数据/缓存目录:','YTReJ':'system.online'},_0x3b72ff=_0x263aa5[_0x2c64ac(0x16e)](this[_0x2c64ac(0x176)][_0x2c64ac(0x164)],_0x3cebf8[_0x2c64ac(0x172)]);_0x49a8bd[_0x2c64ac(0x187)](_0x3b72ff,{'recursive':!![]}),this[_0x2c64ac(0x175)][_0x2c64ac(0x191)](_0x3cebf8[_0x2c64ac(0x18a)],_0x3b72ff),dbUtil['createConnection'](_0x263aa5[_0x2c64ac(0x16e)](_0x3b72ff,'./'+_0x2ba3cd+_0x2c64ac(0x15c))),selfInfo[_0x2c64ac(0x169)]=_0x2ba3cd,selfInfo[_0x2c64ac(0x185)]=_0x4e28a9,this[_0x2c64ac(0x165)][_0x2c64ac(0x17e)](this[_0x2c64ac(0x15d)]['wrapper'][_0x2c64ac(0x179)](),this[_0x2c64ac(0x15d)]['wrapper'][_0x2c64ac(0x17c)](),this[_0x2c64ac(0x15d)]['wrapper']['getBuddyService'](),this[_0x2c64ac(0x15d)][_0x2c64ac(0x176)][_0x2c64ac(0x184)](),this['session']['wrapper'][_0x2c64ac(0x177)]()),this[_0x2c64ac(0x17b)]['map'](_0x543732=>{const _0xb6cab4={'IOFhk':function(_0x5e2ff3,_0x15abff){const _0x4af82e=_0x5504;return _0x3cebf8[_0x4af82e(0x174)](_0x5e2ff3,_0x15abff);}};new Promise((_0x3042fd,_0x682ac5)=>{const _0x3c68a9=_0x5504,_0x4d0a3d=_0x543732();_0xb6cab4[_0x3c68a9(0x17f)](_0x4d0a3d,Promise)&&_0x4d0a3d[_0x3c68a9(0x196)](_0x3042fd)[_0x3c68a9(0x183)](_0x682ac5);})['then']();}),this[_0x2c64ac(0x16a)](_0x3cebf8[_0x2c64ac(0x16b)],{'uin':_0x2ba3cd,'uid':_0x4e28a9});}[_0x583e98(0x168)](){}[_0x583e98(0x16d)](_0xe01f7b){const _0xa250e9=_0x583e98;this[_0xa250e9(0x17b)][_0xa250e9(0x192)](_0xe01f7b);}}export const napCatCore=new NapCatCore(); \ No newline at end of file diff --git a/src/core.lib/src/login.d.ts b/src/core.lib/src/login.d.ts new file mode 100644 index 00000000..e4bae988 --- /dev/null +++ b/src/core.lib/src/login.d.ts @@ -0,0 +1,48 @@ +import { LoginListener } from './qqnt/listeners'; +import { LoginInitConfig, NodeIKernelLoginService } from './qqnt/services'; +import { NapCatCore } from '.'; +/** + * NapCat 登录相关核心类 + * + * **【注意】**:只有在调用 `init` 方法后才会被真正初始化! + */ +export declare class NapCatCoreLogin { + readonly core: NapCatCore; + readonly service: NodeIKernelLoginService; + readonly listener: LoginListener; + constructor(core: NapCatCore); + /** + * 初始化 `NodeIKernelLoginService` + * @param {LoginInitConfig} config `NodeIKernelLoginService` 初始化配置 + * @returns {void} + */ + init(config: LoginInitConfig): void; + /** + * 初始化监听器,用于向父级 `NapCatCore` 发送事件 + */ + private initListener; + /** + * 获取在此客户端上登录过的账号列表 + * @returns {Promise<{ result: number, LocalLoginInfoList: LoginListItem[] }>} + */ + private getLoginList; + /** + * 使用二维码方式登录账号,获取到的二维码链接可通过 `system.login.qrcode` 事件获取。 + */ + qrcode(): Promise; + /** + * 使用快速登录方式登录账号,欲登录的账号必须在此客户端上登录过 + * @param {string} uin 欲登录账户的 Uin + * @returns {Promise} + */ + quick(uin: string): Promise; + /** + * 使用账号密码方式登录,需要滑块验证会发送 `system.login.slider` 事件,登录错误会发送 `system.login.error` 事件。 + * @param {string} uin 登录账号 + * @param {string} password 登录密码 + * @param {string} [proofSig] 验证码返回的 ticket + * @param {string} [proofRand] 验证码返回的随机字符串值 + * @param {string} [proofSid] 验证码的 sid + */ + password(uin: string, password: string, proofSig?: string, proofRand?: string, proofSid?: string): Promise; +} diff --git a/src/core.lib/src/login.js b/src/core.lib/src/login.js new file mode 100644 index 00000000..61953e0c --- /dev/null +++ b/src/core.lib/src/login.js @@ -0,0 +1 @@ +const _0x2cc820=_0x531e;function _0x5009(){const _0x44b3b4=['brVcj','gGITh','error','2149542MpYJut','loginErrorInfo','quick','90296cvkzGA','system.login.qrcode','listener','175zRaItT','md5','proofWaterUrl','errMsg','1DMClof','init','xSRuJ','passwordLogin','876130ibJtrw','4875138MorUFh','system.login.error','initConfig','EJmLL','digest','140022013','\x20is\x20not\x20available','LocalLoginInfoList','NodeIKernelLoginService','onLoginFailed','core','609fHVqCl','aoMJJ','addKernelLoginListener','emit','system.login.slider','createHash','update','1030374sXqGDI','No\x20quick\x20login\x20accounts\x20available','onQRCodeSessionFailed','initListener','FpUza','password','NodeIKernelLoginListener','qrcodeUrl','result','Quick\x20login\x20for\x20','service','YMflm','getQRCodePicture','561orClrX','hex','3|1|2|4|0','140022008','44970RTRtHY','107304OUzjuH','getLoginList'];_0x5009=function(){return _0x44b3b4;};return _0x5009();}(function(_0x128f68,_0x3143ec){const _0x580d79=_0x531e,_0x1c79ab=_0x128f68();while(!![]){try{const _0x4de595=-parseInt(_0x580d79(0x1cc))/0x1*(-parseInt(_0x580d79(0x1d0))/0x2)+parseInt(_0x580d79(0x1c2))/0x3+-parseInt(_0x580d79(0x1bd))/0x4*(parseInt(_0x580d79(0x1c8))/0x5)+parseInt(_0x580d79(0x1ab))/0x6+parseInt(_0x580d79(0x1a4))/0x7*(parseInt(_0x580d79(0x1c5))/0x8)+-parseInt(_0x580d79(0x199))/0x9+parseInt(_0x580d79(0x1bc))/0xa*(-parseInt(_0x580d79(0x1b8))/0xb);if(_0x4de595===_0x3143ec)break;else _0x1c79ab['push'](_0x1c79ab['shift']());}catch(_0x2d04dd){_0x1c79ab['push'](_0x1c79ab['shift']());}}}(_0x5009,0x92142));import*as _0x4ae3c5 from'node:crypto';import{Wrapper as _0x2180db}from'./qqnt';import{LoginListener}from'./qqnt/listeners';import{sleep}from'@/common/utils/helper';function _0x531e(_0x134bb2,_0x34dd0b){const _0x5009b5=_0x5009();return _0x531e=function(_0x531e36,_0x40845c){_0x531e36=_0x531e36-0x199;let _0x5cb037=_0x5009b5[_0x531e36];return _0x5cb037;},_0x531e(_0x134bb2,_0x34dd0b);}export class NapCatCoreLogin{[_0x2cc820(0x1a3)];[_0x2cc820(0x1b5)];[_0x2cc820(0x1c7)];constructor(_0x149440){const _0x188e33=_0x2cc820,_0x471132={'nkjOS':_0x188e33(0x1ba)},_0x3f0b35=_0x471132['nkjOS']['split']('|');let _0x584ec3=0x0;while(!![]){switch(_0x3f0b35[_0x584ec3++]){case'0':this['listener']['onLoginFailed']=_0x1fc824=>{const _0x1796e1=_0x188e33;console['error'](_0x1796e1(0x1a2),_0x1fc824);};continue;case'1':this['service']=new _0x2180db[(_0x188e33(0x1a1))]();continue;case'2':this[_0x188e33(0x1c7)]=new LoginListener();continue;case'3':this[_0x188e33(0x1a3)]=_0x149440;continue;case'4':this[_0x188e33(0x1c7)][_0x188e33(0x1ad)]=_0x6bdb6d=>{const _0x1b4590=_0x188e33;console[_0x1b4590(0x1c1)](_0x1b4590(0x1ad),_0x6bdb6d);};continue;}break;}}[_0x2cc820(0x1cd)](_0x1f10c9){const _0x18d4aa=_0x2cc820;this[_0x18d4aa(0x1b5)][_0x18d4aa(0x19b)](_0x1f10c9),this[_0x18d4aa(0x1ae)](),this[_0x18d4aa(0x1b5)][_0x18d4aa(0x1a6)](new _0x2180db[(_0x18d4aa(0x1b1))](this['listener']));}[_0x2cc820(0x1ae)](){const _0xc52e05=_0x2cc820,_0x5a2c33={'wUPfO':_0xc52e05(0x1c6)};this['listener']['onQRCodeGetPicture']=_0xb8ac93=>{const _0x4ada9c=_0xc52e05;this[_0x4ada9c(0x1a3)][_0x4ada9c(0x1a7)](_0x5a2c33['wUPfO'],{'url':_0xb8ac93[_0x4ada9c(0x1b2)],'base64':_0xb8ac93['pngBase64QrcodeData']});},this[_0xc52e05(0x1c7)]['onQRCodeLoginSucceed']=_0x4c77fc=>{const _0x4e0d31=_0xc52e05;this[_0x4e0d31(0x1a3)]['initPostLogin'](_0x4c77fc);};}[_0x2cc820(0x1be)](){const _0x6742f1=_0x2cc820;return this[_0x6742f1(0x1b5)][_0x6742f1(0x1be)]();}async['qrcode'](){const _0x5f2f8e=_0x2cc820;this[_0x5f2f8e(0x1b5)][_0x5f2f8e(0x1b7)]();}async[_0x2cc820(0x1c4)](_0x2505c3){const _0x21a339=_0x2cc820,_0x2533f3={'EJmLL':function(_0x2a9098,_0x4e3e54){return _0x2a9098!==_0x4e3e54;},'xSRuJ':_0x21a339(0x1ac),'tZTNt':function(_0x33a6b8,_0x1d290a){return _0x33a6b8(_0x1d290a);},'aoMJJ':_0x21a339(0x19a)},_0x46f26b=await this[_0x21a339(0x1be)]();if(_0x2533f3[_0x21a339(0x19c)](_0x46f26b[_0x21a339(0x1b3)],0x0))throw new Error(_0x2533f3[_0x21a339(0x1ce)]);const _0x56a29f=_0x46f26b[_0x21a339(0x1a0)]['find'](_0x39941c=>_0x39941c['uin']===_0x2505c3);if(!_0x56a29f||!_0x56a29f?.['isQuickLogin'])throw new Error(_0x21a339(0x1b4)+_0x2505c3+_0x21a339(0x19f));await _0x2533f3['tZTNt'](sleep,0x3e8);const _0x5b0418=await this[_0x21a339(0x1b5)]['quickLoginWithUin'](_0x2505c3);if(!_0x5b0418[_0x21a339(0x1b3)])this[_0x21a339(0x1a3)][_0x21a339(0x1a7)](_0x2533f3[_0x21a339(0x1a5)],{'code':_0x5b0418[_0x21a339(0x1b3)],'message':_0x5b0418['loginErrorInfo'][_0x21a339(0x1cb)]});}async[_0x2cc820(0x1b0)](_0x30d135,_0x1440ac,_0x32ce36,_0x170ea4,_0x1df4ba){const _0x406608=_0x2cc820,_0x5abee1={'moToX':_0x406608(0x1c9),'gGITh':_0x406608(0x1b9),'BHwRm':function(_0x17c72c,_0xb277d1){return _0x17c72c&&_0xb277d1;},'brVcj':function(_0xd7cde1,_0x2c9c04){return _0xd7cde1||_0x2c9c04;},'FpUza':function(_0x3981e7,_0x2a368a){return _0x3981e7||_0x2a368a;},'IrjzA':function(_0x46da55,_0x3fa7f3){return _0x46da55(_0x3fa7f3);},'YMflm':_0x406608(0x1bb),'cSDjP':_0x406608(0x19a)},_0x42fa81=_0x4ae3c5[_0x406608(0x1a9)](_0x5abee1['moToX'])[_0x406608(0x1aa)](_0x1440ac)[_0x406608(0x19d)](_0x5abee1[_0x406608(0x1c0)]),_0x20590d={'uin':_0x30d135,'passwordMd5':_0x42fa81,'step':_0x5abee1['BHwRm'](_0x32ce36,_0x170ea4)&&_0x1df4ba?0x1:0x0,'newDeviceLoginSig':'','proofWaterSig':_0x5abee1[_0x406608(0x1bf)](_0x32ce36,''),'proofWaterRand':_0x5abee1[_0x406608(0x1af)](_0x170ea4,''),'proofWaterSid':_0x1df4ba||''};await this[_0x406608(0x1be)](),await _0x5abee1['IrjzA'](sleep,0x3e8);const _0x40dd55=await this[_0x406608(0x1b5)][_0x406608(0x1cf)](_0x20590d);switch(_0x40dd55[_0x406608(0x1b3)]){case'0':{break;}case _0x5abee1[_0x406608(0x1b6)]:{this['core'][_0x406608(0x1a7)](_0x406608(0x1a8),{'url':_0x40dd55[_0x406608(0x1c3)][_0x406608(0x1ca)]});break;}case'4':case _0x406608(0x19e):default:{this[_0x406608(0x1a3)][_0x406608(0x1a7)](_0x5abee1['cSDjP'],{'code':_0x40dd55['result'],'message':_0x40dd55[_0x406608(0x1c3)]['errMsg']});}}}} \ No newline at end of file diff --git a/src/core.lib/src/qqnt/adapters/NodeIDependsAdapter.d.ts b/src/core.lib/src/qqnt/adapters/NodeIDependsAdapter.d.ts new file mode 100644 index 00000000..4657d78d --- /dev/null +++ b/src/core.lib/src/qqnt/adapters/NodeIDependsAdapter.d.ts @@ -0,0 +1,14 @@ +interface IDependsAdapter { + onMSFStatusChange(args: unknown): void; + onMSFSsoError(args: unknown): void; + getGroupCode(args: unknown): void; +} +export interface NodeIDependsAdapter extends IDependsAdapter { + new (adapter: IDependsAdapter): NodeIDependsAdapter; +} +export declare class DependsAdapter implements IDependsAdapter { + onMSFStatusChange(args: unknown): void; + onMSFSsoError(args: unknown): void; + getGroupCode(args: unknown): void; +} +export {}; diff --git a/src/core.lib/src/qqnt/adapters/NodeIDependsAdapter.js b/src/core.lib/src/qqnt/adapters/NodeIDependsAdapter.js new file mode 100644 index 00000000..41b23c88 --- /dev/null +++ b/src/core.lib/src/qqnt/adapters/NodeIDependsAdapter.js @@ -0,0 +1 @@ +var _0x57b317=_0x36a8;function _0x36a8(_0x362896,_0x32c0b4){var _0xa26f0=_0xa26f();return _0x36a8=function(_0x36a8be,_0x3cc4a8){_0x36a8be=_0x36a8be-0x98;var _0x5c3910=_0xa26f0[_0x36a8be];return _0x5c3910;},_0x36a8(_0x362896,_0x32c0b4);}(function(_0x4bfc95,_0x27bdf2){var _0x2d33b2=_0x36a8,_0x2e43ac=_0x4bfc95();while(!![]){try{var _0x101bef=-parseInt(_0x2d33b2(0xa2))/0x1+-parseInt(_0x2d33b2(0xa0))/0x2+-parseInt(_0x2d33b2(0x9e))/0x3+parseInt(_0x2d33b2(0x9d))/0x4*(-parseInt(_0x2d33b2(0x9f))/0x5)+-parseInt(_0x2d33b2(0x98))/0x6+parseInt(_0x2d33b2(0xa1))/0x7+-parseInt(_0x2d33b2(0x99))/0x8*(-parseInt(_0x2d33b2(0x9b))/0x9);if(_0x101bef===_0x27bdf2)break;else _0x2e43ac['push'](_0x2e43ac['shift']());}catch(_0x2e66e0){_0x2e43ac['push'](_0x2e43ac['shift']());}}}(_0xa26f,0x390fc));export class DependsAdapter{[_0x57b317(0x9a)](_0x1a4f3d){}[_0x57b317(0x9c)](_0x160db6){}['getGroupCode'](_0x134d12){}}function _0xa26f(){var _0x1fb9a3=['1770958DwPkqM','174548cPvLOd','912234yRWXqs','88tYhZtg','onMSFStatusChange','728127LcGGeG','onMSFSsoError','4sPbEYq','892254AVBpCc','1155685djlRYh','108122wQMDgr'];_0xa26f=function(){return _0x1fb9a3;};return _0xa26f();} \ No newline at end of file diff --git a/src/core.lib/src/qqnt/adapters/NodeIDispatcherAdapter.d.ts b/src/core.lib/src/qqnt/adapters/NodeIDispatcherAdapter.d.ts new file mode 100644 index 00000000..51a6919e --- /dev/null +++ b/src/core.lib/src/qqnt/adapters/NodeIDispatcherAdapter.d.ts @@ -0,0 +1,14 @@ +interface IDispatcherAdapter { + dispatchRequest(arg: unknown): void; + dispatchCall(arg: unknown): void; + dispatchCallWithJson(arg: unknown): void; +} +export interface NodeIDispatcherAdapter extends IDispatcherAdapter { + new (adapter: IDispatcherAdapter): NodeIDispatcherAdapter; +} +export declare class DispatcherAdapter implements IDispatcherAdapter { + dispatchRequest(arg: unknown): void; + dispatchCall(arg: unknown): void; + dispatchCallWithJson(arg: unknown): void; +} +export {}; diff --git a/src/core.lib/src/qqnt/adapters/NodeIDispatcherAdapter.js b/src/core.lib/src/qqnt/adapters/NodeIDispatcherAdapter.js new file mode 100644 index 00000000..e886e78f --- /dev/null +++ b/src/core.lib/src/qqnt/adapters/NodeIDispatcherAdapter.js @@ -0,0 +1 @@ +function _0x4645(_0x29d00c,_0x944e8a){var _0x4a794b=_0x4a79();return _0x4645=function(_0x464531,_0x6a25e2){_0x464531=_0x464531-0xf2;var _0x468ff7=_0x4a794b[_0x464531];return _0x468ff7;},_0x4645(_0x29d00c,_0x944e8a);}function _0x4a79(){var _0x26cc01=['dispatchRequest','311920KeGlva','535480XzIKhH','2056210YksXki','192516eVLrcf','3265535aYTtGW','dispatchCallWithJson','81lllQjj','2970342zDVsGP','4WJlAhF','dispatchCall','108422nvfYww'];_0x4a79=function(){return _0x26cc01;};return _0x4a79();}var _0x569cde=_0x4645;(function(_0x2c0bf7,_0x545202){var _0x2d129d=_0x4645,_0x3a277a=_0x2c0bf7();while(!![]){try{var _0x51083b=parseInt(_0x2d129d(0xfb))/0x1+-parseInt(_0x2d129d(0xf9))/0x2+parseInt(_0x2d129d(0xf2))/0x3*(parseInt(_0x2d129d(0xf7))/0x4)+-parseInt(_0x2d129d(0xfd))/0x5+parseInt(_0x2d129d(0xf6))/0x6+parseInt(_0x2d129d(0xf3))/0x7+parseInt(_0x2d129d(0xfc))/0x8*(-parseInt(_0x2d129d(0xf5))/0x9);if(_0x51083b===_0x545202)break;else _0x3a277a['push'](_0x3a277a['shift']());}catch(_0x2c2a74){_0x3a277a['push'](_0x3a277a['shift']());}}}(_0x4a79,0x41dda));export class DispatcherAdapter{[_0x569cde(0xfa)](_0xde046){}[_0x569cde(0xf8)](_0x3b470d){}[_0x569cde(0xf4)](_0x199a33){}} \ No newline at end of file diff --git a/src/core.lib/src/qqnt/adapters/NodeIGlobalAdapter.d.ts b/src/core.lib/src/qqnt/adapters/NodeIGlobalAdapter.d.ts new file mode 100644 index 00000000..b44dcde0 --- /dev/null +++ b/src/core.lib/src/qqnt/adapters/NodeIGlobalAdapter.d.ts @@ -0,0 +1,24 @@ +interface IGlobalAdapter { + onLog(...args: unknown[]): void; + onGetSrvCalTime(...args: unknown[]): void; + onShowErrUITips(...args: unknown[]): void; + fixPicImgType(...args: unknown[]): void; + getAppSetting(...args: unknown[]): void; + onInstallFinished(...args: unknown[]): void; + onUpdateGeneralFlag(...args: unknown[]): void; + onGetOfflineMsg(...args: unknown[]): void; +} +export interface NodeIGlobalAdapter extends IGlobalAdapter { + new (adapter: IGlobalAdapter): NodeIGlobalAdapter; +} +export declare class GlobalAdapter implements IGlobalAdapter { + onLog(...args: unknown[]): void; + onGetSrvCalTime(...args: unknown[]): void; + onShowErrUITips(...args: unknown[]): void; + fixPicImgType(...args: unknown[]): void; + getAppSetting(...args: unknown[]): void; + onInstallFinished(...args: unknown[]): void; + onUpdateGeneralFlag(...args: unknown[]): void; + onGetOfflineMsg(...args: unknown[]): void; +} +export {}; diff --git a/src/core.lib/src/qqnt/adapters/NodeIGlobalAdapter.js b/src/core.lib/src/qqnt/adapters/NodeIGlobalAdapter.js new file mode 100644 index 00000000..deb6d3b4 --- /dev/null +++ b/src/core.lib/src/qqnt/adapters/NodeIGlobalAdapter.js @@ -0,0 +1 @@ +var _0x25a6e4=_0x19d4;(function(_0x17fa2a,_0x5a61f7){var _0x153e10=_0x19d4,_0x335668=_0x17fa2a();while(!![]){try{var _0xacf79e=-parseInt(_0x153e10(0x1ae))/0x1+parseInt(_0x153e10(0x1a2))/0x2*(-parseInt(_0x153e10(0x1a8))/0x3)+-parseInt(_0x153e10(0x19f))/0x4*(parseInt(_0x153e10(0x1a7))/0x5)+-parseInt(_0x153e10(0x1a5))/0x6+-parseInt(_0x153e10(0x1a9))/0x7*(parseInt(_0x153e10(0x1aa))/0x8)+-parseInt(_0x153e10(0x1a4))/0x9+parseInt(_0x153e10(0x1a1))/0xa;if(_0xacf79e===_0x5a61f7)break;else _0x335668['push'](_0x335668['shift']());}catch(_0x3a454c){_0x335668['push'](_0x335668['shift']());}}}(_0x2518,0x4e7b5));function _0x2518(){var _0x273672=['5ylrcJh','26799lvrnMh','2458862bUpwCR','8HhILZy','getAppSetting','onInstallFinished','onGetOfflineMsg','369889pZOrDs','804872ifFlmX','onShowErrUITips','21505450cWWtjO','50cWKjWB','onUpdateGeneralFlag','2306016LtyBae','2562972jZIHTW','fixPicImgType'];_0x2518=function(){return _0x273672;};return _0x2518();}function _0x19d4(_0x2acdec,_0x24fa31){var _0x251832=_0x2518();return _0x19d4=function(_0x19d485,_0x552415){_0x19d485=_0x19d485-0x19f;var _0x18198c=_0x251832[_0x19d485];return _0x18198c;},_0x19d4(_0x2acdec,_0x24fa31);}export class GlobalAdapter{['onLog'](..._0x11fd3b){}['onGetSrvCalTime'](..._0x93f2a8){}[_0x25a6e4(0x1a0)](..._0x537250){}[_0x25a6e4(0x1a6)](..._0x8bd0e2){}[_0x25a6e4(0x1ab)](..._0x40e232){}[_0x25a6e4(0x1ac)](..._0x479fcd){}[_0x25a6e4(0x1a3)](..._0x20cb52){}[_0x25a6e4(0x1ad)](..._0x381ed0){}} \ No newline at end of file diff --git a/src/core.lib/src/qqnt/adapters/index.d.ts b/src/core.lib/src/qqnt/adapters/index.d.ts new file mode 100644 index 00000000..2db6d288 --- /dev/null +++ b/src/core.lib/src/qqnt/adapters/index.d.ts @@ -0,0 +1,3 @@ +export * from './NodeIDependsAdapter'; +export * from './NodeIDispatcherAdapter'; +export * from './NodeIGlobalAdapter'; diff --git a/src/core.lib/src/qqnt/adapters/index.js b/src/core.lib/src/qqnt/adapters/index.js new file mode 100644 index 00000000..235daf92 --- /dev/null +++ b/src/core.lib/src/qqnt/adapters/index.js @@ -0,0 +1 @@ +(function(_0x3f0548,_0x4fbec7){var _0x30f47c=_0x5520,_0x23c841=_0x3f0548();while(!![]){try{var _0x6e452c=-parseInt(_0x30f47c(0xd0))/0x1*(-parseInt(_0x30f47c(0xd3))/0x2)+-parseInt(_0x30f47c(0xd5))/0x3*(-parseInt(_0x30f47c(0xd4))/0x4)+parseInt(_0x30f47c(0xd7))/0x5*(-parseInt(_0x30f47c(0xd1))/0x6)+-parseInt(_0x30f47c(0xcd))/0x7*(parseInt(_0x30f47c(0xcc))/0x8)+parseInt(_0x30f47c(0xd6))/0x9*(-parseInt(_0x30f47c(0xd2))/0xa)+parseInt(_0x30f47c(0xcf))/0xb+parseInt(_0x30f47c(0xce))/0xc;if(_0x6e452c===_0x4fbec7)break;else _0x23c841['push'](_0x23c841['shift']());}catch(_0x49d4c9){_0x23c841['push'](_0x23c841['shift']());}}}(_0x490d,0x33833));export*from'./NodeIDependsAdapter';export*from'./NodeIDispatcherAdapter';export*from'./NodeIGlobalAdapter';function _0x5520(_0x6df29c,_0x34b267){var _0x490de6=_0x490d();return _0x5520=function(_0x552034,_0x30d8c9){_0x552034=_0x552034-0xcc;var _0x1349c1=_0x490de6[_0x552034];return _0x1349c1;},_0x5520(_0x6df29c,_0x34b267);}function _0x490d(){var _0x14daaf=['246HEKUvN','7016JTzFAQ','51ToMDrp','598194CIeOFq','17745KHyvbm','6376SvVkGK','3647qlxjSN','9452604ZWfenL','1399618PDbghS','2082QsnFYw','522UnokdV','40fvQpoj'];_0x490d=function(){return _0x14daaf;};return _0x490d();} \ No newline at end of file diff --git a/src/core.lib/src/qqnt/apis/file.d.ts b/src/core.lib/src/qqnt/apis/file.d.ts new file mode 100644 index 00000000..6d607572 --- /dev/null +++ b/src/core.lib/src/qqnt/apis/file.d.ts @@ -0,0 +1,17 @@ +import { ChatType, ElementType } from '@/core/qqnt/entities'; +import * as fileType from 'file-type'; +import { ISizeCalculationResult } from 'image-size/dist/types/interface'; +export declare class NTQQFileApi { + static getFileType(filePath: string): Promise; + static copyFile(filePath: string, destPath: string): Promise; + static getFileSize(filePath: string): Promise; + static uploadFile(filePath: string, elementType?: ElementType, elementSubType?: number): Promise<{ + md5: string; + fileName: string; + path: string; + fileSize: number; + ext: string; + }>; + static downloadMedia(msgId: string, chatType: ChatType, peerUid: string, elementId: string, thumbPath: string, sourcePath: string, timeout?: number): Promise; + static getImageSize(filePath: string): Promise; +} diff --git a/src/core.lib/src/qqnt/apis/file.js b/src/core.lib/src/qqnt/apis/file.js new file mode 100644 index 00000000..18ae4948 --- /dev/null +++ b/src/core.lib/src/qqnt/apis/file.js @@ -0,0 +1 @@ +function _0x3cdf(){const _0x23561d=['25036SzCvuo','getFileType','service','removeKernelMsgListener','下载超时','1144215VNxxyu','downloadMedia','basename','7jzybpD','kkPxs','filePath','getImageSize','kernelService','getFileSize','3148158NjznOp','msg','defaultFileDownloadPath','1008493ZsAyKt','190vGvvwJ','indexOf','wrapper','801qjqwfL','ext','IrTcj','3408rGfltg','uKkSo','msgId','downloadRichMedia','uploadFile','util','35230fzvyYc','1565960JZDcFH','qRxUy','79475GecnLI','PIC','copyFile','2hTfBpN','getRichMediaFilePathForGuild','NELej','lOIcS','fileTypeFromFile'];_0x3cdf=function(){return _0x23561d;};return _0x3cdf();}const _0x59daf3=_0x5f04;(function(_0xb328e5,_0x164c38){const _0x211b30=_0x5f04,_0x4e8677=_0xb328e5();while(!![]){try{const _0x54093f=parseInt(_0x211b30(0xdd))/0x1+-parseInt(_0x211b30(0xf0))/0x2*(-parseInt(_0x211b30(0xd1))/0x3)+parseInt(_0x211b30(0xf5))/0x4*(parseInt(_0x211b30(0xde))/0x5)+-parseInt(_0x211b30(0xda))/0x6*(-parseInt(_0x211b30(0xd4))/0x7)+parseInt(_0x211b30(0xeb))/0x8+-parseInt(_0x211b30(0xe1))/0x9*(-parseInt(_0x211b30(0xea))/0xa)+parseInt(_0x211b30(0xed))/0xb*(-parseInt(_0x211b30(0xe4))/0xc);if(_0x54093f===_0x164c38)break;else _0x4e8677['push'](_0x4e8677['shift']());}catch(_0x2a56a9){_0x4e8677['push'](_0x4e8677['shift']());}}}(_0x3cdf,0x94e21));import{ElementType}from'@/core/qqnt/entities';import _0x232d54 from'path';import _0x18122d from'fs';import{napCatCore}from'@/core';import{calculateFileMD5}from'@/common/utils/file';import*as _0x3a7f86 from'file-type';import{MsgListener}from'@/core/qqnt/listeners';import _0x25df7f from'image-size';function _0x5f04(_0x1a8fa9,_0x57c4b1){const _0x3cdf7d=_0x3cdf();return _0x5f04=function(_0x5f0451,_0x234a2e){_0x5f0451=_0x5f0451-0xce;let _0x52d7d3=_0x3cdf7d[_0x5f0451];return _0x52d7d3;},_0x5f04(_0x1a8fa9,_0x57c4b1);}import{sessionConfig}from'@/core/qqnt/sessionConfig';export class NTQQFileApi{static async['getFileType'](_0x30d2b3){const _0x5cbf7a=_0x5f04;return _0x3a7f86[_0x5cbf7a(0xf4)](_0x30d2b3);}static async[_0x59daf3(0xef)](_0x2c8c3c,_0x4397cc){const _0x38ec26=_0x59daf3;await napCatCore['wrapper'][_0x38ec26(0xe9)][_0x38ec26(0xef)](_0x2c8c3c,_0x4397cc);}static async[_0x59daf3(0xd9)](_0x2d767e){const _0x13ec4f=_0x59daf3;return await napCatCore[_0x13ec4f(0xe0)][_0x13ec4f(0xe9)][_0x13ec4f(0xd9)](_0x2d767e);}static async[_0x59daf3(0xe8)](_0x3ef3f4,_0x456d7a=ElementType[_0x59daf3(0xee)],_0x5482fe=0x0){const _0x472066=_0x59daf3,_0x5b44dc={'OnRww':function(_0x2898aa,_0x31efff){return _0x2898aa(_0x31efff);}},_0x3589e8=await _0x5b44dc['OnRww'](calculateFileMD5,_0x3ef3f4);let _0x3d0fe5=(await NTQQFileApi[_0x472066(0xf6)](_0x3ef3f4))?.[_0x472066(0xe2)]||'';_0x3d0fe5&&(_0x3d0fe5='.'+_0x3d0fe5);let _0x10fce9=''+_0x232d54[_0x472066(0xd3)](_0x3ef3f4);_0x10fce9[_0x472066(0xdf)]('.')===-0x1&&(_0x10fce9+=_0x3d0fe5);const _0x4b4307=napCatCore[_0x472066(0xce)]['msg'][_0x472066(0xd8)][_0x472066(0xf1)]({'md5HexStr':_0x3589e8,'fileName':_0x10fce9,'elementType':_0x456d7a,'elementSubType':_0x5482fe,'thumbSize':0x0,'needCreate':!![],'downloadType':0x1,'file_uuid':''});await NTQQFileApi[_0x472066(0xef)](_0x3ef3f4,_0x4b4307);const _0x33d17a=await NTQQFileApi[_0x472066(0xd9)](_0x3ef3f4);return{'md5':_0x3589e8,'fileName':_0x10fce9,'path':_0x4b4307,'fileSize':_0x33d17a,'ext':_0x3d0fe5};}static async[_0x59daf3(0xd2)](_0xc775ee,_0x420c4d,_0x28a611,_0x185f91,_0x3b67d8,_0x3b6178,_0x4e173d=0x3e8*0x3c*0x2){const _0x47f9ea=_0x59daf3,_0x3ade49={'lOIcS':function(_0x410e06,_0x550161){return _0x410e06===_0x550161;},'uKkSo':function(_0x503437,_0x16da29){return _0x503437(_0x16da29);},'kkPxs':function(_0x185744,_0x580483){return _0x185744(_0x580483);},'IrTcj':_0x47f9ea(0xd0)};if(_0x3b6178&&_0x18122d['existsSync'](_0x3b6178))return _0x3b6178;const _0x266d71=new MsgListener();return new Promise((_0x187dd9,_0x210012)=>{const _0x5c2ed6=_0x47f9ea;let _0xc9c7bb=![];_0x266d71['onRichMediaDownloadComplete']=_0x138729=>{const _0x5e21ca=_0x5f04;if(_0x3ade49[_0x5e21ca(0xf3)](_0x138729[_0x5e21ca(0xe6)],_0xc775ee)){_0xc9c7bb=!![];let _0x404745=_0x138729[_0x5e21ca(0xd6)];if(_0x404745['startsWith']('\x5c')){const _0x37807b=sessionConfig?.[_0x5e21ca(0xdc)];_0x404745=_0x232d54['join'](_0x37807b,_0x404745);}_0x3ade49[_0x5e21ca(0xe5)](_0x187dd9,_0x404745),napCatCore['service'][_0x5e21ca(0xdb)]['kernelService']?.[_0x5e21ca(0xcf)](_0x35b8da);}};const _0x35b8da=napCatCore[_0x5c2ed6(0xce)]['msg']['addMsgListener'](_0x266d71);setTimeout(()=>{const _0x361c18=_0x5c2ed6;!_0xc9c7bb&&(_0x3ade49[_0x361c18(0xd5)](_0x210012,new Error(_0x3ade49[_0x361c18(0xe3)])),napCatCore[_0x361c18(0xce)][_0x361c18(0xdb)][_0x361c18(0xd8)]?.[_0x361c18(0xcf)](_0x35b8da));},_0x4e173d),napCatCore[_0x5c2ed6(0xce)]['msg'][_0x5c2ed6(0xd8)]?.[_0x5c2ed6(0xe7)]({'fileModelId':'0','downloadSourceType':0x0,'triggerType':0x1,'msgId':_0xc775ee,'chatType':_0x420c4d,'peerUid':_0x28a611,'elementId':_0x185f91,'thumbSize':0x0,'downloadType':0x1,'filePath':_0x3b67d8});});}static async[_0x59daf3(0xd7)](_0x19cb6a){const _0x459677={'NELej':function(_0x2865f8,_0x5679b0){return _0x2865f8(_0x5679b0);},'qRxUy':function(_0x2cf716,_0x867234,_0x57a85d){return _0x2cf716(_0x867234,_0x57a85d);}};return new Promise((_0x2e131f,_0x3c53f5)=>{const _0x11c006=_0x5f04;_0x459677[_0x11c006(0xec)](_0x25df7f,_0x19cb6a,(_0x2edc41,_0x1be064)=>{const _0x24d739=_0x11c006;_0x2edc41?_0x459677[_0x24d739(0xf2)](_0x3c53f5,_0x2edc41):_0x459677[_0x24d739(0xf2)](_0x2e131f,_0x1be064);});});}} \ No newline at end of file diff --git a/src/core.lib/src/qqnt/apis/friend.d.ts b/src/core.lib/src/qqnt/apis/friend.d.ts new file mode 100644 index 00000000..2b6e6f26 --- /dev/null +++ b/src/core.lib/src/qqnt/apis/friend.d.ts @@ -0,0 +1,5 @@ +import { FriendRequest } from '@/core/qqnt/entities'; +export declare class NTQQFriendApi { + static getFriends(forced?: boolean): Promise; + static handleFriendRequest(request: FriendRequest, accept: boolean): Promise; +} diff --git a/src/core.lib/src/qqnt/apis/friend.js b/src/core.lib/src/qqnt/apis/friend.js new file mode 100644 index 00000000..c8fe1ce0 --- /dev/null +++ b/src/core.lib/src/qqnt/apis/friend.js @@ -0,0 +1 @@ +function _0x136f(){var _0x487389=['buddy','reqTime','968708hLjUkA','approvalFriendRequest','getFriends','69114EccZVi','198608lLINWk','4380687kTlPFA','2988805qbOqnA','4638628mkIttd','friendUid','2XjXKaA','kernelService','handleFriendRequest','598971OjXYSX','343kfsSKf'];_0x136f=function(){return _0x487389;};return _0x136f();}var _0x1641d3=_0x5d32;function _0x5d32(_0x1b1354,_0x5a83c8){var _0x136ff0=_0x136f();return _0x5d32=function(_0x5d32ee,_0x10806c){_0x5d32ee=_0x5d32ee-0x1c9;var _0x410c9d=_0x136ff0[_0x5d32ee];return _0x410c9d;},_0x5d32(_0x1b1354,_0x5a83c8);}(function(_0x2c89ca,_0xc3cd97){var _0x19bb7f=_0x5d32,_0x4d1a50=_0x2c89ca();while(!![]){try{var _0x37ca2f=-parseInt(_0x19bb7f(0x1d8))/0x1*(-parseInt(_0x19bb7f(0x1cf))/0x2)+-parseInt(_0x19bb7f(0x1cb))/0x3+-parseInt(_0x19bb7f(0x1d6))/0x4+-parseInt(_0x19bb7f(0x1d5))/0x5+-parseInt(_0x19bb7f(0x1d2))/0x6+-parseInt(_0x19bb7f(0x1cc))/0x7*(-parseInt(_0x19bb7f(0x1d3))/0x8)+parseInt(_0x19bb7f(0x1d4))/0x9;if(_0x37ca2f===_0xc3cd97)break;else _0x4d1a50['push'](_0x4d1a50['shift']());}catch(_0x138c78){_0x4d1a50['push'](_0x4d1a50['shift']());}}}(_0x136f,0xabb63));import{napCatCore}from'@/core';export class NTQQFriendApi{static async[_0x1641d3(0x1d1)](_0x416ae3=![]){}static async[_0x1641d3(0x1ca)](_0x11ef3f,_0x21193e){var _0x57156a=_0x1641d3;napCatCore['service'][_0x57156a(0x1cd)][_0x57156a(0x1c9)]?.[_0x57156a(0x1d0)]({'friendUid':_0x11ef3f[_0x57156a(0x1d7)],'reqTime':_0x11ef3f[_0x57156a(0x1ce)],'accept':_0x21193e});}} \ No newline at end of file diff --git a/src/core.lib/src/qqnt/apis/group.d.ts b/src/core.lib/src/qqnt/apis/group.d.ts new file mode 100644 index 00000000..42b2b4e8 --- /dev/null +++ b/src/core.lib/src/qqnt/apis/group.d.ts @@ -0,0 +1,20 @@ +import { GroupMember, GroupRequestOperateTypes, GroupMemberRole, GroupNotify } from '../entities'; +export declare class NTQQGroupApi { + static getGroups(forced?: boolean): Promise; + static getGroupMembers(groupQQ: string, num?: number): Promise; + static getGroupNotifies(): Promise; + static getGroupIgnoreNotifies(): Promise; + static handleGroupRequest(notify: GroupNotify, operateType: GroupRequestOperateTypes, reason?: string): Promise; + static quitGroup(groupQQ: string): Promise; + static kickMember(groupQQ: string, kickUids: string[], refuseForever?: boolean, kickReason?: string): Promise; + static banMember(groupQQ: string, memList: Array<{ + uid: string; + timeStamp: number; + }>): Promise; + static banGroup(groupQQ: string, shutUp: boolean): Promise; + static setMemberCard(groupQQ: string, memberUid: string, cardName: string): Promise; + static setMemberRole(groupQQ: string, memberUid: string, role: GroupMemberRole): Promise; + static setGroupName(groupQQ: string, groupName: string): Promise; + static setGroupTitle(groupQQ: string, uid: string, title: string): Promise; + static publishGroupBulletin(groupQQ: string, title: string, content: string): void; +} diff --git a/src/core.lib/src/qqnt/apis/group.js b/src/core.lib/src/qqnt/apis/group.js new file mode 100644 index 00000000..0e338a7a --- /dev/null +++ b/src/core.lib/src/qqnt/apis/group.js @@ -0,0 +1 @@ +function _0x2e16(_0x1fe738,_0x24e634){var _0x176ed5=_0x176e();return _0x2e16=function(_0x2e16b5,_0x1efc2a){_0x2e16b5=_0x2e16b5-0xd8;var _0x966900=_0x176ed5[_0x2e16b5];return _0x966900;},_0x2e16(_0x1fe738,_0x24e634);}function _0x176e(){var _0x3c3558=['110BRfNSO','publishGroupBulletin','setMemberRole','setGroupShutUp','setGroupName','setMemberCard','getGroupMembers','24XrbdEg','8MALKOK','groupCode','79758ZtgTwZ','6rFdEQw','3625821rZFgFC','783936QZfBKE','getGroupNotifies','kickMember','kernelService','387321sYhpce','banGroup','2804400pQTOdP','quitGroup','303455eSqRtV','modifyMemberRole','group','service','type','getGroupIgnoreNotifies','handleGroupRequest','getGroups','95346qOipUk','setGroupTitle'];_0x176e=function(){return _0x3c3558;};return _0x176e();}var _0x49231b=_0x2e16;(function(_0x38b36f,_0x2862d4){var _0x806a51=_0x2e16,_0x478a07=_0x38b36f();while(!![]){try{var _0x539c5b=-parseInt(_0x806a51(0xe3))/0x1*(-parseInt(_0x806a51(0xf0))/0x2)+parseInt(_0x806a51(0xf2))/0x3+parseInt(_0x806a51(0xed))/0x4*(parseInt(_0x806a51(0xdb))/0x5)+-parseInt(_0x806a51(0xd9))/0x6+parseInt(_0x806a51(0xef))/0x7*(parseInt(_0x806a51(0xec))/0x8)+parseInt(_0x806a51(0xf1))/0x9+-parseInt(_0x806a51(0xe5))/0xa*(parseInt(_0x806a51(0xf6))/0xb);if(_0x539c5b===_0x2862d4)break;else _0x478a07['push'](_0x478a07['shift']());}catch(_0x9a9237){_0x478a07['push'](_0x478a07['shift']());}}}(_0x176e,0x3d4b6));import{napCatCore}from'@/core';export class NTQQGroupApi{static async[_0x49231b(0xe2)](_0xc23cc8=![]){}static async[_0x49231b(0xeb)](_0x517356,_0x581b3a=0xbb8){}static async[_0x49231b(0xf3)](){}static async[_0x49231b(0xe0)](){}static async[_0x49231b(0xe1)](_0x59e3a1,_0x2b8a38,_0x2426b9){var _0x48ad61=_0x49231b,_0x1e46a9={'ilRex':function(_0x364404,_0x3301a1){return _0x364404||_0x3301a1;}};return napCatCore['service'][_0x48ad61(0xdd)][_0x48ad61(0xf5)]?.['operateSysNotify'](![],{'operateType':_0x2b8a38,'targetMsg':{'seq':_0x59e3a1['seq'],'type':_0x59e3a1[_0x48ad61(0xdf)],'groupCode':_0x59e3a1[_0x48ad61(0xdd)][_0x48ad61(0xee)],'postscript':_0x1e46a9['ilRex'](_0x2426b9,'')}});}static async[_0x49231b(0xda)](_0x4c7963){var _0xd951c6=_0x49231b;return napCatCore[_0xd951c6(0xde)][_0xd951c6(0xdd)][_0xd951c6(0xf5)]?.[_0xd951c6(0xda)](_0x4c7963);}static async['kickMember'](_0x2ad7f0,_0x40077a,_0x27b012=![],_0x18bff2=''){var _0x29848f=_0x49231b;return napCatCore[_0x29848f(0xde)]['group'][_0x29848f(0xf5)]?.[_0x29848f(0xf4)](_0x2ad7f0,_0x40077a,_0x27b012,_0x18bff2);}static async['banMember'](_0x3199e0,_0x353d73){var _0x332877=_0x49231b;return napCatCore[_0x332877(0xde)][_0x332877(0xdd)][_0x332877(0xf5)]?.['setMemberShutUp'](_0x3199e0,_0x353d73);}static async[_0x49231b(0xd8)](_0x4f3b07,_0xb8aea4){var _0x3cd20c=_0x49231b;return napCatCore[_0x3cd20c(0xde)][_0x3cd20c(0xdd)][_0x3cd20c(0xf5)]?.[_0x3cd20c(0xe8)](_0x4f3b07,_0xb8aea4);}static async[_0x49231b(0xea)](_0x59c404,_0x3164c1,_0x3641bd){var _0x3d1f4b=_0x49231b;return napCatCore['service'][_0x3d1f4b(0xdd)][_0x3d1f4b(0xf5)]?.['modifyMemberCardName'](_0x59c404,_0x3164c1,_0x3641bd);}static async[_0x49231b(0xe7)](_0x222e29,_0x379e55,_0x431acd){var _0x4babe7=_0x49231b;return napCatCore[_0x4babe7(0xde)][_0x4babe7(0xdd)]['kernelService']?.[_0x4babe7(0xdc)](_0x222e29,_0x379e55,_0x431acd);}static async[_0x49231b(0xe9)](_0x2f1dc9,_0x29d198){var _0xe8c9a1=_0x49231b;return napCatCore[_0xe8c9a1(0xde)]['group'][_0xe8c9a1(0xf5)]?.['modifyGroupName'](_0x2f1dc9,_0x29d198,![]);}static async[_0x49231b(0xe4)](_0x15f265,_0x26d3f9,_0x146c6d){}static[_0x49231b(0xe6)](_0x5da3aa,_0x11eaab,_0x2124ec){}} \ No newline at end of file diff --git a/src/core.lib/src/qqnt/apis/index.d.ts b/src/core.lib/src/qqnt/apis/index.d.ts new file mode 100644 index 00000000..2006bbf4 --- /dev/null +++ b/src/core.lib/src/qqnt/apis/index.d.ts @@ -0,0 +1,7 @@ +export * from './file'; +export * from './friend'; +export * from './group'; +export * from './msg'; +export * from './user'; +export * from './webapi'; +export * from './window'; diff --git a/src/core.lib/src/qqnt/apis/index.js b/src/core.lib/src/qqnt/apis/index.js new file mode 100644 index 00000000..be106119 --- /dev/null +++ b/src/core.lib/src/qqnt/apis/index.js @@ -0,0 +1 @@ +function _0x55af(_0x3322b9,_0x4251af){var _0x4f1440=_0x4f14();return _0x55af=function(_0x55af60,_0xf92f9e){_0x55af60=_0x55af60-0x1a4;var _0x24d4ba=_0x4f1440[_0x55af60];return _0x24d4ba;},_0x55af(_0x3322b9,_0x4251af);}(function(_0x4482eb,_0x8e60a){var _0x194bce=_0x55af,_0x252dd6=_0x4482eb();while(!![]){try{var _0x4eb392=parseInt(_0x194bce(0x1ad))/0x1+parseInt(_0x194bce(0x1ac))/0x2*(parseInt(_0x194bce(0x1a8))/0x3)+-parseInt(_0x194bce(0x1a7))/0x4+-parseInt(_0x194bce(0x1a4))/0x5*(parseInt(_0x194bce(0x1aa))/0x6)+-parseInt(_0x194bce(0x1a6))/0x7+-parseInt(_0x194bce(0x1a5))/0x8*(-parseInt(_0x194bce(0x1ab))/0x9)+parseInt(_0x194bce(0x1a9))/0xa;if(_0x4eb392===_0x8e60a)break;else _0x252dd6['push'](_0x252dd6['shift']());}catch(_0x4ba48e){_0x252dd6['push'](_0x252dd6['shift']());}}}(_0x4f14,0xc57d0));export*from'./file';export*from'./friend';function _0x4f14(){var _0x340e14=['5482564mnDlZV','33JSzSaI','8898180tkZBEn','78aZQHzF','117DdOuYC','215362jwkVMI','1180535QjSBVq','404065odSirS','763304xkSfNs','8855637vsSKnT'];_0x4f14=function(){return _0x340e14;};return _0x4f14();}export*from'./group';export*from'./msg';export*from'./user';export*from'./webapi';export*from'./window'; \ No newline at end of file diff --git a/src/core.lib/src/qqnt/apis/msg.d.ts b/src/core.lib/src/qqnt/apis/msg.d.ts new file mode 100644 index 00000000..aad198a7 --- /dev/null +++ b/src/core.lib/src/qqnt/apis/msg.d.ts @@ -0,0 +1,19 @@ +import { Peer, RawMessage, SendMessageElement } from '@/core/qqnt/entities'; +import { NapCatCore } from '@/core'; +import { GeneralCallResult } from '@/core/qqnt/services/common'; +export declare class NTQQMsgApi { + static napCatCore: NapCatCore | null; + static getMultiMsg(peer: Peer, rootMsgId: string, parentMsgId: string): Promise; + static activateChat(peer: Peer): Promise; + static activateChatAndGetHistory(peer: Peer): Promise; + static getMsgHistory(peer: Peer, msgId: string, count: number): Promise; + static fetchRecentContact(): Promise; + static recallMsg(peer: Peer, msgIds: string[]): Promise; + static sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete?: boolean, timeout?: number): Promise; + static forwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]): Promise; + static multiForwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]): Promise; +} diff --git a/src/core.lib/src/qqnt/apis/msg.js b/src/core.lib/src/qqnt/apis/msg.js new file mode 100644 index 00000000..d4860272 --- /dev/null +++ b/src/core.lib/src/qqnt/apis/msg.js @@ -0,0 +1 @@ +const _0x5e8147=_0x288b;(function(_0x3519ce,_0x271c85){const _0xc699ce=_0x288b,_0x3d8db4=_0x3519ce();while(!![]){try{const _0x224033=parseInt(_0xc699ce(0x19a))/0x1*(-parseInt(_0xc699ce(0x17f))/0x2)+-parseInt(_0xc699ce(0x169))/0x3*(-parseInt(_0xc699ce(0x180))/0x4)+-parseInt(_0xc699ce(0x17d))/0x5*(parseInt(_0xc699ce(0x171))/0x6)+parseInt(_0xc699ce(0x173))/0x7*(-parseInt(_0xc699ce(0x188))/0x8)+parseInt(_0xc699ce(0x190))/0x9*(-parseInt(_0xc699ce(0x17a))/0xa)+-parseInt(_0xc699ce(0x197))/0xb*(-parseInt(_0xc699ce(0x18c))/0xc)+parseInt(_0xc699ce(0x166))/0xd;if(_0x224033===_0x271c85)break;else _0x3d8db4['push'](_0x3d8db4['shift']());}catch(_0x4685d5){_0x3d8db4['push'](_0x3d8db4['shift']());}}}(_0x42fa,0x948e1));function _0x42fa(){const _0x46e0fb=['getMultiMsg','27GYPDyh','uid','addMsgListener','evJaD','rNEeo','kernelService','msg','2422838hoJjjg','activateChat','BKUwd','7661UlrujC','onAddSendMsg','36843534fGoAFv','ayGEH','DEFQV','1079487FbSWld','发送超时','GPLIz','senderUid','forEach','multiForwardMsg','removeKernelMsgListener','addLoginSuccessCallback','564ZiJYaM','arkElement','130473AqFxDy','peerUid','jsTJZ','getMsgHistory','app','KbeYc','napCatCore','978430UdmvRV','nick','catch','46305VQpBqF','chatType','268NhpVoH','4VxiqZg','转发消息超时','sendMsg','service','ErvQm','find','then','recallMsg','264kOIRrl','onMsgInfoListUpdate','bytesData','YMbBa','12PzzaGj','msgId','Rtfrq'];_0x42fa=function(){return _0x46e0fb;};return _0x42fa();}import{selfInfo}from'@/common/data';import{log}from'@/common/utils/log';import{sleep}from'@/common/utils/helper';import{napCatCore}from'@/core';import{MsgListener}from'@/core/qqnt/listeners';function _0x288b(_0x5c93d8,_0x2ae069){const _0x42fa81=_0x42fa();return _0x288b=function(_0x288b8f,_0x57af17){_0x288b8f=_0x288b8f-0x165;let _0x4971ef=_0x42fa81[_0x288b8f];return _0x4971ef;},_0x288b(_0x5c93d8,_0x2ae069);}import{randomUUID}from'crypto';const sendMessagePool={},sendSuccessCBMap={},msgListener=new MsgListener();msgListener[_0x5e8147(0x165)]=_0x163bf9=>{const _0xc055e8=_0x5e8147,_0x5ab842={'BKUwd':function(_0x4a79eb,_0x2f1aa2){return _0x4a79eb instanceof _0x2f1aa2;}};if(sendMessagePool[_0x163bf9[_0xc055e8(0x174)]]){const _0x20646d=sendMessagePool[_0x163bf9[_0xc055e8(0x174)]]?.(_0x163bf9);_0x5ab842[_0xc055e8(0x199)](_0x20646d,Promise)&&_0x20646d[_0xc055e8(0x186)]()[_0xc055e8(0x186)](log);}},msgListener[_0x5e8147(0x189)]=_0x34c909=>{const _0x328044=_0x5e8147,_0x29b8c1={'cuQZo':function(_0x29bc15,_0x1be519){return _0x29bc15(_0x1be519);}};_0x34c909[_0x328044(0x16d)](_0x3d7c15=>{const _0x191a4b=_0x328044,_0x480c0c={'GPLIz':function(_0x38555c,_0x144d40){return _0x38555c instanceof _0x144d40;},'Rtfrq':function(_0x4f619d,_0x577029){return _0x29b8c1['cuQZo'](_0x4f619d,_0x577029);}};new Promise((_0x2080f9,_0x568e80)=>{const _0x18a595=_0x288b;for(const _0x5a3902 in sendSuccessCBMap){const _0x4888bc=sendSuccessCBMap[_0x5a3902],_0x5ace06=_0x4888bc(_0x3d7c15),_0x1c4173=_0x62b273=>{_0x62b273&&delete sendSuccessCBMap[_0x5a3902];};_0x480c0c[_0x18a595(0x16b)](_0x5ace06,Promise)?_0x5ace06[_0x18a595(0x186)](_0x1c4173):_0x480c0c[_0x18a595(0x18e)](_0x1c4173,_0x5ace06);}})[_0x191a4b(0x186)]()[_0x191a4b(0x17c)](log);});},setTimeout(()=>{const _0x413706=_0x5e8147;napCatCore[_0x413706(0x170)](()=>{const _0x351c2b=_0x413706;napCatCore[_0x351c2b(0x183)][_0x351c2b(0x196)]['addMsgListener'](msgListener);});},0x64);export class NTQQMsgApi{static [_0x5e8147(0x179)]=null;static async[_0x5e8147(0x18f)](_0x384564,_0x1b759e,_0x36b86c){const _0x566b50=_0x5e8147;return napCatCore[_0x566b50(0x183)][_0x566b50(0x196)]['kernelService']?.[_0x566b50(0x18f)](_0x384564,_0x1b759e,_0x36b86c);}static async[_0x5e8147(0x198)](_0x5037c3){}static async['activateChatAndGetHistory'](_0x5b6dff){}static async[_0x5e8147(0x176)](_0x1f492a,_0x25dee3,_0x3208aa){const _0x59cbb0=_0x5e8147;return napCatCore[_0x59cbb0(0x183)][_0x59cbb0(0x196)]['kernelService']['getMsgsIncludeSelf'](_0x1f492a,_0x25dee3,_0x3208aa,!![]);}static async['fetchRecentContact'](){}static async[_0x5e8147(0x187)](_0x321dbb,_0x5dcad3){const _0x263bbc=_0x5e8147;await napCatCore[_0x263bbc(0x183)][_0x263bbc(0x196)][_0x263bbc(0x195)]?.[_0x263bbc(0x187)]({'chatType':_0x321dbb[_0x263bbc(0x17e)],'peerUid':_0x321dbb[_0x263bbc(0x174)]},_0x5dcad3);}static async[_0x5e8147(0x182)](_0x585cd0,_0x47a650,_0xad3d31=!![],_0x2f635a=0x2710){const _0x3c119c=_0x5e8147,_0x4c71c8={'KbeYc':function(_0x27ce30,_0x4cd808){return _0x27ce30(_0x4cd808);},'meKOv':function(_0x43fba4){return _0x43fba4();},'ayGEH':function(_0x3de136,_0x505ea6){return _0x3de136===_0x505ea6;},'YMbBa':function(_0x325cea,_0x2d3d78){return _0x325cea(_0x2d3d78);},'jsTJZ':function(_0x521d2f,_0x29f3c9){return _0x521d2f(_0x29f3c9);}},_0x8c5762=_0x585cd0[_0x3c119c(0x174)];let _0x5a07ab=0x0;const _0x1ea311=async()=>{const _0x2e268e=_0x3c119c;if(_0x5a07ab>_0x2f635a)throw _0x2e268e(0x16a);const _0x5ad52b=sendMessagePool[_0x585cd0['peerUid']];if(_0x5ad52b)return await _0x4c71c8[_0x2e268e(0x178)](sleep,0x1f4),_0x5a07ab+=0x1f4,await _0x4c71c8['meKOv'](_0x1ea311);else return;};return await _0x1ea311(),new Promise((_0x2fbc98,_0x2063df)=>{const _0x444399=_0x3c119c,_0x1aa9ee={'rNEeo':function(_0x2342b8,_0x2b57e7){const _0x6c5f6a=_0x288b;return _0x4c71c8[_0x6c5f6a(0x175)](_0x2342b8,_0x2b57e7);}};let _0x3c7a76=![],_0x136d58=null;const _0x39d60a=_0x4c71c8['meKOv'](randomUUID);sendSuccessCBMap[_0x39d60a]=_0x10d2a1=>{const _0x169c23=_0x288b;if(_0x4c71c8['ayGEH'](_0x10d2a1[_0x169c23(0x18d)],_0x136d58?.['msgId'])){if(_0x4c71c8[_0x169c23(0x167)](_0x10d2a1['sendStatus'],0x2))return delete sendSuccessCBMap[_0x39d60a],_0x3c7a76=!![],_0x4c71c8[_0x169c23(0x18b)](_0x2fbc98,_0x10d2a1),!![];return![];}return![];},sendMessagePool[_0x8c5762]=async _0x31045f=>{delete sendMessagePool[_0x8c5762],_0x136d58=_0x31045f;},setTimeout(()=>{const _0x3b0e9d=_0x288b;if(_0x3c7a76)return;delete sendMessagePool[_0x8c5762],delete sendSuccessCBMap[_0x39d60a],_0x1aa9ee[_0x3b0e9d(0x194)](_0x2063df,_0x3b0e9d(0x16a));},_0x2f635a);const _0x24de7f=napCatCore[_0x444399(0x183)][_0x444399(0x196)]['kernelService']?.[_0x444399(0x182)]('0',_0x585cd0,_0x47a650,new Map());});}static async['forwardMsg'](_0x2fdbb2,_0x570a1c,_0x55a22c){}static async[_0x5e8147(0x16e)](_0x29234f,_0x1764fb,_0xe14a9){const _0x5db988={'ErvQm':function(_0x55473e,_0x1b8f3d){return _0x55473e!=_0x1b8f3d;},'DEFQV':function(_0x4db009,_0x4f2f1c){return _0x4db009==_0x4f2f1c;},'evJaD':function(_0x19261a,_0x418512,_0x119012){return _0x19261a(_0x418512,_0x119012);}},_0x3c529f=_0xe14a9['map'](_0x3cfd21=>{const _0x219502=_0x288b;return{'msgId':_0x3cfd21,'senderShowName':selfInfo[_0x219502(0x17b)]};});return new Promise((_0x15edbd,_0x1c064e)=>{const _0x53ab17=_0x288b;let _0x16afc0=![];const _0x356ee9=new MsgListener(),_0x522494=_0x47fa24=>{const _0x2e47a1=_0x288b,_0x1e877d=_0x47fa24['elements'][_0x2e47a1(0x185)](_0x5c6920=>_0x5c6920[_0x2e47a1(0x172)]);if(!_0x1e877d)return;const _0x12649c=JSON['parse'](_0x1e877d[_0x2e47a1(0x172)][_0x2e47a1(0x18a)]);if(_0x5db988[_0x2e47a1(0x184)](_0x12649c[_0x2e47a1(0x177)],'com.tencent.multimsg'))return;_0x47fa24[_0x2e47a1(0x174)]==_0x1764fb['peerUid']&&_0x5db988[_0x2e47a1(0x168)](_0x47fa24[_0x2e47a1(0x16c)],selfInfo[_0x2e47a1(0x191)])&&(_0x16afc0=!![]);};_0x356ee9[_0x53ab17(0x165)]=_0x522494;const _0xe5598d=napCatCore[_0x53ab17(0x183)][_0x53ab17(0x196)][_0x53ab17(0x192)](_0x356ee9);_0x5db988[_0x53ab17(0x193)](setTimeout,()=>{const _0x5040b4=_0x53ab17;!_0x16afc0&&(napCatCore[_0x5040b4(0x183)][_0x5040b4(0x196)][_0x5040b4(0x195)]?.[_0x5040b4(0x16f)](_0xe5598d),_0x1c064e(_0x5040b4(0x181)));},0x1388),napCatCore[_0x53ab17(0x183)][_0x53ab17(0x196)][_0x53ab17(0x195)]?.['multiForwardMsgWithComment'](_0x3c529f,_0x29234f,_0x1764fb,[],new Map());});}} \ No newline at end of file diff --git a/src/core.lib/src/qqnt/apis/user.d.ts b/src/core.lib/src/qqnt/apis/user.d.ts new file mode 100644 index 00000000..408ec9ff --- /dev/null +++ b/src/core.lib/src/qqnt/apis/user.d.ts @@ -0,0 +1,19 @@ +import { User } from '@/core/qqnt/entities'; +export declare class NTQQUserApi { + static like(uid: string, count?: number): Promise<{ + result: number; + errMsg: string; + succCounts: number; + }>; + static setQQAvatar(filePath: string): Promise<{ + result: number; + errMsg: string; + }>; + static getSelfInfo(): Promise; + static getUserInfo(uid: string): Promise; + static getUserDetailInfo(uid: string): Promise; + static getPSkey(): Promise; + static getSkey(groupName: string, groupCode: string): Promise; +} diff --git a/src/core.lib/src/qqnt/apis/user.js b/src/core.lib/src/qqnt/apis/user.js new file mode 100644 index 00000000..c3da2d71 --- /dev/null +++ b/src/core.lib/src/qqnt/apis/user.js @@ -0,0 +1 @@ +const _0x2fcf14=_0x51c8;(function(_0x4b2074,_0x262595){const _0x5f10c8=_0x51c8,_0x241f2a=_0x4b2074();while(!![]){try{const _0xcee58d=-parseInt(_0x5f10c8(0x1e2))/0x1+parseInt(_0x5f10c8(0x1ed))/0x2*(-parseInt(_0x5f10c8(0x1f6))/0x3)+parseInt(_0x5f10c8(0x1dd))/0x4*(-parseInt(_0x5f10c8(0x1da))/0x5)+-parseInt(_0x5f10c8(0x1f3))/0x6*(parseInt(_0x5f10c8(0x1e4))/0x7)+parseInt(_0x5f10c8(0x1e6))/0x8+parseInt(_0x5f10c8(0x1f2))/0x9*(-parseInt(_0x5f10c8(0x1de))/0xa)+parseInt(_0x5f10c8(0x1e9))/0xb*(parseInt(_0x5f10c8(0x1f8))/0xc);if(_0xcee58d===_0x262595)break;else _0x241f2a['push'](_0x241f2a['shift']());}catch(_0x365546){_0x241f2a['push'](_0x241f2a['shift']());}}}(_0x360d,0xcc3b8));function _0x51c8(_0x5155d8,_0x18859a){const _0x360d3f=_0x360d();return _0x51c8=function(_0x51c87e,_0x3b9dd2){_0x51c87e=_0x51c87e-0x1d6;let _0x2df455=_0x360d3f[_0x51c87e];return _0x2df455;},_0x51c8(_0x5155d8,_0x18859a);}import{napCatCore}from'@/core';import{ProfileListener}from'@/core/qqnt/listeners';import{randomUUID}from'crypto';const userInfoCache={},profileListener=new ProfileListener(),userDetailHandlers=new Map();function _0x360d(){const _0x1414b4=['service','getUserInfo','setHeader','1717745WdLtmA','then','forEach','4ZCzEjf','2105260tMnSQF','addProfileListener','uid','setBuddyProfileLike','631300wTXgrZ','set','126cFpJhN','numBP','1581472kNEuDG','profileLike','profile','461087WoGnak','sGOSk','onProfileDetailInfoChanged','result','2122txYGyQ','getUserDetailInfoWithBizInfo','sSbeu','setQQAvatar','getPSkey','54vjcoXS','196338fFqHqx','addLoginSuccessCallback','getSkey','393GwEKLv','getUserDetailInfo\x20timeout','1032hpzqUQ','kernelService'];_0x360d=function(){return _0x1414b4;};return _0x360d();}profileListener[_0x2fcf14(0x1eb)]=_0x4f43df=>{const _0x131fd3=_0x2fcf14;userInfoCache[_0x4f43df[_0x131fd3(0x1e0)]]=_0x4f43df,userDetailHandlers[_0x131fd3(0x1dc)](_0xc9895d=>_0xc9895d(_0x4f43df));},setTimeout(()=>{const _0x4993c6=_0x2fcf14;napCatCore[_0x4993c6(0x1f4)](()=>{const _0x1059b2=_0x4993c6;napCatCore[_0x1059b2(0x1d7)][_0x1059b2(0x1e8)][_0x1059b2(0x1df)](profileListener);});},0x64);export class NTQQUserApi{static async['like'](_0x3883a5,_0x4ac913=0x1){const _0x36aee2=_0x2fcf14;return napCatCore[_0x36aee2(0x1d7)][_0x36aee2(0x1e7)]['kernelService'][_0x36aee2(0x1e1)]({'friendUid':_0x3883a5,'sourceId':0x47,'doLikeCount':_0x4ac913,'doLikeTollCount':0x0});}static async[_0x2fcf14(0x1f0)](_0x59a957){const _0x336e7a=_0x2fcf14,_0x42da54=napCatCore[_0x336e7a(0x1d7)][_0x336e7a(0x1e8)][_0x336e7a(0x1d6)]?.[_0x336e7a(0x1d9)](_0x59a957);return{'result':_0x42da54?.[_0x336e7a(0x1ec)],'errMsg':_0x42da54?.['errMsg']};}static async['getSelfInfo'](){}static async[_0x2fcf14(0x1d8)](_0x37b088){}static async['getUserDetailInfo'](_0x5706fe){const _0x3646bb=_0x2fcf14,_0x31742b={'sGOSk':function(_0x300d49,_0x290712){return _0x300d49(_0x290712);},'OaVYQ':_0x3646bb(0x1f7),'sSbeu':function(_0x1be533,_0x2a30c2){return _0x1be533===_0x2a30c2;},'WLFVD':function(_0x55c6fe){return _0x55c6fe();},'numBP':function(_0x5e29f7,_0x47a6eb,_0x570b10){return _0x5e29f7(_0x47a6eb,_0x570b10);}},_0x579a72=napCatCore[_0x3646bb(0x1d7)]['profile'][_0x3646bb(0x1d6)];return new Promise((_0x1fb245,_0x2b7600)=>{const _0x15c507=_0x3646bb,_0x4bc433=_0x31742b['WLFVD'](randomUUID);let _0x1196ff=![];_0x31742b[_0x15c507(0x1e5)](setTimeout,()=>{const _0x32d6a2=_0x15c507;!_0x1196ff&&_0x31742b[_0x32d6a2(0x1ea)](_0x2b7600,_0x31742b['OaVYQ']);},0x1388),userDetailHandlers[_0x15c507(0x1e3)](_0x4bc433,_0x11b418=>{const _0x57c2a7=_0x15c507;_0x31742b[_0x57c2a7(0x1ef)](_0x11b418['uid'],_0x5706fe)&&(_0x1196ff=!![],userDetailHandlers['delete'](_0x4bc433),_0x1fb245(_0x11b418));}),_0x579a72[_0x15c507(0x1ee)](_0x5706fe,[0x0])[_0x15c507(0x1db)](_0x29bd1e=>{});});}static async[_0x2fcf14(0x1f1)](){}static async[_0x2fcf14(0x1f5)](_0x51814e,_0x1eb586){}} \ No newline at end of file diff --git a/src/core.lib/src/qqnt/apis/webapi.d.ts b/src/core.lib/src/qqnt/apis/webapi.d.ts new file mode 100644 index 00000000..10d6b7e7 --- /dev/null +++ b/src/core.lib/src/qqnt/apis/webapi.d.ts @@ -0,0 +1,13 @@ +export declare class WebApi { + private static bkn; + private static skey; + private static pskey; + private static cookie; + private defaultHeaders; + constructor(); + addGroupDigest(groupCode: string, msgSeq: string): Promise; + getGroupDigest(groupCode: string): Promise; + private genBkn; + private init; + private request; +} diff --git a/src/core.lib/src/qqnt/apis/webapi.js b/src/core.lib/src/qqnt/apis/webapi.js new file mode 100644 index 00000000..73730368 --- /dev/null +++ b/src/core.lib/src/qqnt/apis/webapi.js @@ -0,0 +1 @@ +function _0x259a(_0x1b9711,_0x27a337){const _0x5d7d26=_0x5d7d();return _0x259a=function(_0x259aed,_0x51a275){_0x259aed=_0x259aed-0x1a6;let _0x49c585=_0x5d7d26[_0x259aed];return _0x49c585;},_0x259a(_0x1b9711,_0x27a337);}const _0x1d44f9=_0x259a;function _0x5d7d(){const _0x39f97c=['qrGuG','&msg_seq=','https://qun.qq.com/cgi-bin/group_digest/digest_list?random=665&X-CROSS-ORIGIN=fetch&group_code=','HRZJE','28nprdIM','16737147XokBSw','3162156lIVlJc','&msg_random=444021292','218354wIQpum','getGroupDigest','genBkn','pskey','RAglJ','nAOaX','json','headers','request','addGroupDigest','init','charCodeAt','2566616EeBMzW','SUnoY','include','GET','cookie','toString','Htqvv','bkn','defaultHeaders','4EdNICD','2641620XwewlF','4633585gGPEBp','lOhDm','615640HQEWdu','&bkn='];_0x5d7d=function(){return _0x39f97c;};return _0x5d7d();}(function(_0x29dbc2,_0x1f61fd){const _0x45bbf4=_0x259a,_0x58236a=_0x29dbc2();while(!![]){try{const _0x5d557f=parseInt(_0x45bbf4(0x1b7))/0x1+-parseInt(_0x45bbf4(0x1c3))/0x2+parseInt(_0x45bbf4(0x1b5))/0x3*(-parseInt(_0x45bbf4(0x1a9))/0x4)+parseInt(_0x45bbf4(0x1ab))/0x5+parseInt(_0x45bbf4(0x1aa))/0x6+-parseInt(_0x45bbf4(0x1b3))/0x7*(parseInt(_0x45bbf4(0x1ad))/0x8)+parseInt(_0x45bbf4(0x1b4))/0x9;if(_0x5d557f===_0x1f61fd)break;else _0x58236a['push'](_0x58236a['shift']());}catch(_0x4f27f8){_0x58236a['push'](_0x58236a['shift']());}}}(_0x5d7d,0xc3464));import{log}from'@/common/utils/log';export class WebApi{static [_0x1d44f9(0x1a7)];static ['skey'];static [_0x1d44f9(0x1ba)];static [_0x1d44f9(0x1c7)];[_0x1d44f9(0x1a8)]={'User-Agent':'QQ/8.9.28.635\x20CFNetwork/1312\x20Darwin/21.0.0'};constructor(){}async[_0x1d44f9(0x1c0)](_0x19bac9,_0x34b30e){const _0x5458ef=_0x1d44f9,_0x40814e='https://qun.qq.com/cgi-bin/group_digest/cancel_digest?random=665&X-CROSS-ORIGIN=fetch&group_code='+_0x19bac9+_0x5458ef(0x1b0)+_0x34b30e+_0x5458ef(0x1b6),_0x285b21=await this['request'](_0x40814e);return await _0x285b21[_0x5458ef(0x1bd)]();}async[_0x1d44f9(0x1b8)](_0x5f6465){const _0x2330c7=_0x1d44f9,_0x3e440a={'Htqvv':function(_0x1dee82,_0x3d4f6d){return _0x1dee82(_0x3d4f6d);}},_0x3af767=_0x2330c7(0x1b1)+_0x5f6465+'&page_start=0&page_limit=20',_0x5f000b=await this[_0x2330c7(0x1bf)](_0x3af767);return _0x3e440a[_0x2330c7(0x1a6)](log,_0x5f000b[_0x2330c7(0x1be)]),await _0x5f000b[_0x2330c7(0x1bd)]();}[_0x1d44f9(0x1b9)](_0x1d0bf6){const _0x59e03c=_0x1d44f9,_0x2cf436={'SUTmQ':function(_0x177bec,_0xdcbe98){return _0x177bec<_0xdcbe98;},'RAglJ':function(_0x4c0694,_0x4b9e5d){return _0x4c0694+_0x4b9e5d;},'SUnoY':function(_0x370d8c,_0x3d141c){return _0x370d8c<<_0x3d141c;},'qrGuG':function(_0x31baff,_0x5bddcc){return _0x31baff&_0x5bddcc;}};_0x1d0bf6=_0x1d0bf6||'';let _0x2c07e3=0x1505;for(let _0x21d4d1=0x0;_0x2cf436['SUTmQ'](_0x21d4d1,_0x1d0bf6['length']);_0x21d4d1++){const _0xd49f72=_0x1d0bf6[_0x59e03c(0x1c2)](_0x21d4d1);_0x2c07e3=_0x2cf436[_0x59e03c(0x1bb)](_0x2c07e3+_0x2cf436[_0x59e03c(0x1c4)](_0x2c07e3,0x5),_0xd49f72);}return _0x2cf436[_0x59e03c(0x1af)](_0x2c07e3,0x7fffffff)[_0x59e03c(0x1c8)]();}async[_0x1d44f9(0x1c1)](){if(!WebApi['bkn']){}}async['request'](_0x50aa56,_0x5b0a36=_0x1d44f9(0x1c6),_0x62f02a={}){const _0x4194c5=_0x1d44f9,_0x5c7129={'wOKDy':_0x4194c5(0x1ae),'nAOaX':_0x4194c5(0x1c5),'HRZJE':function(_0x364283,_0x5786da,_0xfdddda,_0x192eb4){return _0x364283(_0x5786da,_0xfdddda,_0x192eb4);},'lOhDm':function(_0x16e2f3,_0x1a8c32,_0x35dda0){return _0x16e2f3(_0x1a8c32,_0x35dda0);}};await this['init'](),_0x50aa56+=_0x5c7129['wOKDy']+WebApi['bkn'];const _0x4dc4c2={...this['defaultHeaders'],..._0x62f02a,'Cookie':WebApi[_0x4194c5(0x1c7)],'credentials':_0x5c7129[_0x4194c5(0x1bc)]};_0x5c7129[_0x4194c5(0x1b2)](log,'request',_0x50aa56,_0x4dc4c2);const _0x138d74={'method':_0x5b0a36,'headers':_0x4dc4c2};return _0x5c7129[_0x4194c5(0x1ac)](fetch,_0x50aa56,_0x138d74);}} \ No newline at end of file diff --git a/src/core.lib/src/qqnt/apis/window.d.ts b/src/core.lib/src/qqnt/apis/window.d.ts new file mode 100644 index 00000000..29674b46 --- /dev/null +++ b/src/core.lib/src/qqnt/apis/window.d.ts @@ -0,0 +1,11 @@ +export interface NTQQWindow { + windowName: string; + windowUrlHash: string; +} +export declare class NTQQWindows { + static GroupHomeWorkWindow: NTQQWindow; + static GroupNotifyFilterWindow: NTQQWindow; + static GroupEssenceWindow: NTQQWindow; +} +export declare class NTQQWindowApi { +} diff --git a/src/core.lib/src/qqnt/apis/window.js b/src/core.lib/src/qqnt/apis/window.js new file mode 100644 index 00000000..76cd2303 --- /dev/null +++ b/src/core.lib/src/qqnt/apis/window.js @@ -0,0 +1 @@ +var _0x5811b1=_0x1b27;(function(_0x2c452c,_0x325f2e){var _0x571cbe=_0x1b27,_0x41c785=_0x2c452c();while(!![]){try{var _0x27a39f=-parseInt(_0x571cbe(0x10a))/0x1*(parseInt(_0x571cbe(0xff))/0x2)+parseInt(_0x571cbe(0x109))/0x3+-parseInt(_0x571cbe(0x104))/0x4*(parseInt(_0x571cbe(0xfd))/0x5)+-parseInt(_0x571cbe(0xfe))/0x6+parseInt(_0x571cbe(0xfb))/0x7*(-parseInt(_0x571cbe(0x103))/0x8)+-parseInt(_0x571cbe(0xfc))/0x9+-parseInt(_0x571cbe(0x100))/0xa*(-parseInt(_0x571cbe(0x106))/0xb);if(_0x27a39f===_0x325f2e)break;else _0x41c785['push'](_0x41c785['shift']());}catch(_0x23c487){_0x41c785['push'](_0x41c785['shift']());}}}(_0x5c44,0xae894));function _0x1b27(_0x1557f4,_0x3d2e9e){var _0x5c44cb=_0x5c44();return _0x1b27=function(_0x1b2736,_0x54d018){_0x1b2736=_0x1b2736-0xfb;var _0x47d46d=_0x5c44cb[_0x1b2736];return _0x47d46d;},_0x1b27(_0x1557f4,_0x3d2e9e);}export class NTQQWindows{static ['GroupHomeWorkWindow']={'windowName':_0x5811b1(0x101),'windowUrlHash':_0x5811b1(0x107)};static [_0x5811b1(0x105)]={'windowName':_0x5811b1(0x105),'windowUrlHash':'#/group-notify-filter'};static [_0x5811b1(0x102)]={'windowName':_0x5811b1(0x102),'windowUrlHash':_0x5811b1(0x108)};}export class NTQQWindowApi{}function _0x5c44(){var _0x48df20=['58840qvqEfd','GroupHomeWorkWindow','GroupEssenceWindow','518944YSwNAE','128xftkxA','GroupNotifyFilterWindow','4279Agnxeo','#/group-home-work','#/group-essence','1891380ABbPkG','1367oewWPE','84fzDtKk','7141716XHlRNS','30315VziGyZ','2466840rrUofs','40XWkrdP'];_0x5c44=function(){return _0x48df20;};return _0x5c44();} \ No newline at end of file diff --git a/src/core.lib/src/qqnt/entities/cache.d.ts b/src/core.lib/src/qqnt/entities/cache.d.ts new file mode 100644 index 00000000..c48cb2b1 --- /dev/null +++ b/src/core.lib/src/qqnt/entities/cache.d.ts @@ -0,0 +1,58 @@ +import { ChatType } from './msg'; +export interface CacheScanResult { + result: number; + size: [ + string, + string, + string, + string, + string, + string, + string, + string, + string + ]; +} +export interface ChatCacheList { + pageCount: number; + infos: ChatCacheListItem[]; +} +export interface ChatCacheListItem { + chatType: ChatType; + basicChatCacheInfo: ChatCacheListItemBasic; + guildChatCacheInfo: unknown[]; +} +export interface ChatCacheListItemBasic { + chatSize: string; + chatTime: string; + uid: string; + uin: string; + remarkName: string; + nickName: string; + chatType?: ChatType; + isChecked?: boolean; +} +export declare enum CacheFileType { + IMAGE = 0, + VIDEO = 1, + AUDIO = 2, + DOCUMENT = 3, + OTHER = 4 +} +export interface CacheFileList { + infos: CacheFileListItem[]; +} +export interface CacheFileListItem { + fileSize: string; + fileTime: string; + fileKey: string; + elementId: string; + elementIdStr: string; + fileType: CacheFileType; + path: string; + fileName: string; + senderId: string; + previewPath: string; + senderName: string; + isChecked?: boolean; +} diff --git a/src/core.lib/src/qqnt/entities/cache.js b/src/core.lib/src/qqnt/entities/cache.js new file mode 100644 index 00000000..230a996c --- /dev/null +++ b/src/core.lib/src/qqnt/entities/cache.js @@ -0,0 +1 @@ +(function(_0x4f558f,_0x3d5d0a){var _0x53741d=_0x4e77,_0x1e567c=_0x4f558f();while(!![]){try{var _0x24be65=parseInt(_0x53741d(0x1c9))/0x1+-parseInt(_0x53741d(0x1c8))/0x2+-parseInt(_0x53741d(0x1cb))/0x3*(parseInt(_0x53741d(0x1c2))/0x4)+parseInt(_0x53741d(0x1d0))/0x5+parseInt(_0x53741d(0x1c1))/0x6+-parseInt(_0x53741d(0x1c4))/0x7*(parseInt(_0x53741d(0x1cf))/0x8)+-parseInt(_0x53741d(0x1c0))/0x9;if(_0x24be65===_0x3d5d0a)break;else _0x1e567c['push'](_0x1e567c['shift']());}catch(_0x47dbc8){_0x1e567c['push'](_0x1e567c['shift']());}}}(_0x4471,0xc801e));export var CacheFileType;function _0x4e77(_0xc9c32d,_0x11bf9c){var _0x44713f=_0x4471();return _0x4e77=function(_0x4e772f,_0x10fabe){_0x4e772f=_0x4e772f-0x1bf;var _0x2b02e5=_0x44713f[_0x4e772f];return _0x2b02e5;},_0x4e77(_0xc9c32d,_0x11bf9c);}function _0x4471(){var _0x5ada04=['1537921rkwNyv','3|1|4|2|0','12hWfcjq','pSJjv','cBhUo','split','4562672iQfBMK','1628855djlRgU','DOCUMENT','uDtes','KgoRy','1197702ZPFDWj','1046046YXSIfz','251824jeIdER','OTHER','7wcFfgX','osuEc','VIDEO','IMAGE','527134AHvlPR'];_0x4471=function(){return _0x5ada04;};return _0x4471();}(function(_0xd3ea3a){var _0x1afd11=_0x4e77,_0x977432={'YGtuD':_0x1afd11(0x1ca),'cBhUo':_0x1afd11(0x1c3),'KgoRy':_0x1afd11(0x1c6),'uDtes':_0x1afd11(0x1d1),'osuEc':_0x1afd11(0x1c7),'pSJjv':'AUDIO'},_0x46fd8e=_0x977432['YGtuD'][_0x1afd11(0x1ce)]('|'),_0x1ff8cd=0x0;while(!![]){switch(_0x46fd8e[_0x1ff8cd++]){case'0':_0xd3ea3a[_0xd3ea3a[_0x977432['cBhUo']]=0x4]=_0x977432[_0x1afd11(0x1cd)];continue;case'1':_0xd3ea3a[_0xd3ea3a[_0x977432['KgoRy']]=0x1]=_0x977432[_0x1afd11(0x1bf)];continue;case'2':_0xd3ea3a[_0xd3ea3a[_0x977432[_0x1afd11(0x1d2)]]=0x3]=_0x977432[_0x1afd11(0x1d2)];continue;case'3':_0xd3ea3a[_0xd3ea3a[_0x977432[_0x1afd11(0x1c5)]]=0x0]=_0x1afd11(0x1c7);continue;case'4':_0xd3ea3a[_0xd3ea3a[_0x977432[_0x1afd11(0x1cc)]]=0x2]=_0x977432[_0x1afd11(0x1cc)];continue;}break;}}(CacheFileType||(CacheFileType={}))); \ No newline at end of file diff --git a/src/core.lib/src/qqnt/entities/constructor.d.ts b/src/core.lib/src/qqnt/entities/constructor.d.ts new file mode 100644 index 00000000..f3e2c1a6 --- /dev/null +++ b/src/core.lib/src/qqnt/entities/constructor.d.ts @@ -0,0 +1,12 @@ +import { AtType, SendArkElement, SendFaceElement, SendFileElement, SendPicElement, SendPttElement, SendReplyElement, SendTextElement, SendVideoElement } from '../entities'; +export declare class SendMsgElementConstructor { + static text(content: string): SendTextElement; + static at(atUid: string, atNtUid: string, atType: AtType, atName: string): SendTextElement; + static reply(msgSeq: string, msgId: string, senderUin: string, senderUinStr: string): SendReplyElement; + static pic(picPath: string, summary?: string, subType?: 0 | 1): Promise; + static file(filePath: string, fileName?: string): Promise; + static video(filePath: string, fileName?: string, diyThumbPath?: string): Promise; + static ptt(pttPath: string): Promise; + static face(faceId: number): SendFaceElement; + static ark(data: any): SendArkElement; +} diff --git a/src/core.lib/src/qqnt/entities/constructor.js b/src/core.lib/src/qqnt/entities/constructor.js new file mode 100644 index 00000000..27c3af7d --- /dev/null +++ b/src/core.lib/src/qqnt/entities/constructor.js @@ -0,0 +1 @@ +function _0x2cd0(_0x2f8175,_0x44a7f8){const _0xd4fdae=_0xd4fd();return _0x2cd0=function(_0x2cd0ed,_0x4c835e){_0x2cd0ed=_0x2cd0ed-0x9f;let _0x406e62=_0xd4fdae[_0x2cd0ed];return _0x406e62;},_0x2cd0(_0x2f8175,_0x44a7f8);}const _0x421d43=_0x2cd0;(function(_0x53b794,_0x5b7bf5){const _0x2deb93=_0x2cd0,_0x205025=_0x53b794();while(!![]){try{const _0x2fec93=parseInt(_0x2deb93(0xc2))/0x1+parseInt(_0x2deb93(0xa6))/0x2+parseInt(_0x2deb93(0xc7))/0x3+-parseInt(_0x2deb93(0xa7))/0x4*(parseInt(_0x2deb93(0xdc))/0x5)+parseInt(_0x2deb93(0xb5))/0x6*(parseInt(_0x2deb93(0x9f))/0x7)+-parseInt(_0x2deb93(0xac))/0x8+-parseInt(_0x2deb93(0xb4))/0x9*(parseInt(_0x2deb93(0xbd))/0xa);if(_0x2fec93===_0x5b7bf5)break;else _0x205025['push'](_0x205025['shift']());}catch(_0x1d377b){_0x205025['push'](_0x205025['shift']());}}}(_0xd4fd,0x8f469));import{AtType,ElementType,PicType}from'../entities';import{promises as _0xa51557}from'node:fs';import _0x320dc2 from'fluent-ffmpeg';import{NTQQFileApi}from'@/core/qqnt/apis/file';import{calculateFileMD5,isGIF}from'@/common/utils/file';function _0xd4fd(){const _0x155e03=['sYAfQ','unlink','replace','pic','ZIHAj','35271UeTqsA','1091754KETcTG','TFNbS','face','ARK','end','_0.png','writeFile','join','2110tMpJgN','cxQGC','getImageSize','获取视频封面失败,使用默认封面','video','603243TiHQOa','图片信息','copyFile','height','zyyCI','204750eTdDjl','CXOkx','error','EZcpE','tpORS','time','QihSJ','MarHA','catch','Eiihj','toString','BfBEM','文件异常,大小为0','width','Ori','mp4','dirname','FILE','uploadFile','stat','VIDEO','2335RxtXPf','PTT','TEXT','NxXLv','PIC','NGkse','28ovPyGz','DqfaC','screenshots','reply','TMRIU','sep','then','1796672pskyPv','3932nUbtSO','IANyf','doTnQ','boFBY','ark','3398704rEShgk','获取视频信息失败','kiQcj'];_0xd4fd=function(){return _0x155e03;};return _0xd4fd();}import{log}from'@/common/utils/log';import{defaultVideoThumb,getVideoInfo}from'@/common/utils/video';import{encodeSilk}from'@/common/utils/audio';export class SendMsgElementConstructor{static['text'](_0x21d01e){const _0x49dbe2=_0x2cd0;return{'elementType':ElementType[_0x49dbe2(0xde)],'elementId':'','textElement':{'content':_0x21d01e,'atType':AtType['notAt'],'atUid':'','atTinyId':'','atNtUid':''}};}static['at'](_0x5524e9,_0x47d7e1,_0x34c6f2,_0x66708){const _0x199ad7=_0x2cd0;return{'elementType':ElementType[_0x199ad7(0xde)],'elementId':'','textElement':{'content':'@'+_0x66708,'atType':_0x34c6f2,'atUid':_0x5524e9,'atTinyId':'','atNtUid':_0x47d7e1}};}static[_0x421d43(0xa2)](_0x9d4eea,_0x471b3a,_0x2ed892,_0x772520){return{'elementType':ElementType['REPLY'],'elementId':'','replyElement':{'replayMsgSeq':_0x9d4eea,'replayMsgId':_0x471b3a,'senderUin':_0x2ed892,'senderUinStr':_0x772520}};}static async[_0x421d43(0xb2)](_0x375e61,_0x33f039='',_0x2e33bf=0x0){const _0x3eb004=_0x421d43,_0x29407f={'DqfaC':function(_0x4549b7,_0x1a74a0){return _0x4549b7===_0x1a74a0;},'wjfIJ':_0x3eb004(0xd3),'Eiihj':function(_0x14ad0a,_0x15b5c0){return _0x14ad0a(_0x15b5c0);},'TMRIU':function(_0xedbd6b,_0x5b95b5,_0x73fe14){return _0xedbd6b(_0x5b95b5,_0x73fe14);},'boFBY':_0x3eb004(0xc3)},{md5:_0x10810d,fileName:_0x4aaa90,path:_0x5c10f0,fileSize:_0x288ed4}=await NTQQFileApi['uploadFile'](_0x375e61,ElementType[_0x3eb004(0xe0)],_0x2e33bf);if(_0x29407f[_0x3eb004(0xa0)](_0x288ed4,0x0))throw _0x29407f['wjfIJ'];const _0x549d3e=await NTQQFileApi[_0x3eb004(0xbf)](_0x375e61),_0x38d626={'md5HexStr':_0x10810d,'fileSize':_0x288ed4[_0x3eb004(0xd1)](),'picWidth':_0x549d3e?.[_0x3eb004(0xd4)],'picHeight':_0x549d3e?.[_0x3eb004(0xc5)],'fileName':_0x4aaa90,'sourcePath':_0x5c10f0,'original':!![],'picType':_0x29407f[_0x3eb004(0xd0)](isGIF,_0x375e61)?PicType['gif']:PicType['jpg'],'picSubType':_0x2e33bf,'fileUuid':'','fileSubId':'','thumbFileSize':0x0,'summary':_0x33f039};return _0x29407f[_0x3eb004(0xa3)](log,_0x29407f[_0x3eb004(0xaa)],_0x38d626),{'elementType':ElementType['PIC'],'elementId':'','picElement':_0x38d626};}static async['file'](_0x220742,_0x3007b4=''){const _0x35bce7=_0x421d43,_0x41d2ae={'FyiEg':function(_0x3c9c5c,_0x19bc04){return _0x3c9c5c===_0x19bc04;},'PrCsd':_0x35bce7(0xd3),'zyyCI':function(_0xed2712,_0x36b64b){return _0xed2712||_0x36b64b;}},{md5:_0x4de466,fileName:_0x22e274,path:_0xbe0256,fileSize:_0x5bccae}=await NTQQFileApi[_0x35bce7(0xd9)](_0x220742,ElementType['FILE']);if(_0x41d2ae['FyiEg'](_0x5bccae,0x0))throw _0x41d2ae['PrCsd'];const _0x418e14={'elementType':ElementType[_0x35bce7(0xd8)],'elementId':'','fileElement':{'fileName':_0x41d2ae[_0x35bce7(0xc6)](_0x3007b4,_0x22e274),'filePath':_0xbe0256,'fileSize':_0x5bccae[_0x35bce7(0xd1)]()}};return _0x418e14;}static async[_0x421d43(0xc1)](_0x51a440,_0x2b26cf='',_0x4fe90d=''){const _0x1db88a=_0x421d43,_0x210b6d={'cxQGC':function(_0x67a95e,_0x2d2d0b,_0xf8e89e){return _0x67a95e(_0x2d2d0b,_0xf8e89e);},'doTnQ':_0x1db88a(0xc0),'tpORS':function(_0x4a03bf,_0x7f4c8a){return _0x4a03bf(_0x7f4c8a);},'CXOkx':_0x1db88a(0xc9),'TFNbS':function(_0x236f6e,_0x2f661b){return _0x236f6e+_0x2f661b;},'PAXcs':_0x1db88a(0xb9),'IANyf':function(_0x51f3af,_0x27b88a){return _0x51f3af===_0x27b88a;},'sYAfQ':_0x1db88a(0xd3),'EZcpE':'path','TLyAW':_0x1db88a(0xd6),'NGkse':'视频信息','ktvcW':function(_0x3d4c60,_0x476989,_0x15a148){return _0x3d4c60(_0x476989,_0x15a148);},'MarHA':_0x1db88a(0xad),'ZIHAj':function(_0x494e14,_0x4d90e5){return _0x494e14||_0x4d90e5;},'kiQcj':function(_0x337f6c,_0x25b067){return _0x337f6c+_0x25b067;}},{fileName:_0x4f375f,path:_0x9e759a,fileSize:_0x1ea816,md5:_0x3eb7ce}=await NTQQFileApi[_0x1db88a(0xd9)](_0x51a440,ElementType[_0x1db88a(0xdb)]);if(_0x210b6d[_0x1db88a(0xa8)](_0x1ea816,0x0))throw _0x210b6d[_0x1db88a(0xaf)];const _0x3fecc0=_0x210b6d['tpORS'](require,_0x210b6d[_0x1db88a(0xca)]);let _0x46d0d5=_0x9e759a[_0x1db88a(0xb1)](_0x3fecc0[_0x1db88a(0xa4)]+_0x1db88a(0xd5)+_0x3fecc0['sep'],_0x3fecc0[_0x1db88a(0xa4)]+'Thumb'+_0x3fecc0[_0x1db88a(0xa4)]);_0x46d0d5=_0x3fecc0[_0x1db88a(0xd7)](_0x46d0d5);let _0x4d928e={'width':0x780,'height':0x438,'time':0xf,'format':_0x210b6d['TLyAW'],'size':_0x1ea816,'filePath':_0x51a440};try{_0x4d928e=await _0x210b6d[_0x1db88a(0xcb)](getVideoInfo,_0x9e759a),log(_0x210b6d[_0x1db88a(0xe1)],_0x4d928e);}catch(_0x14b069){_0x210b6d['ktvcW'](log,_0x210b6d[_0x1db88a(0xce)],_0x14b069);}const _0x5b6c5d=new Promise((_0x586dc1,_0x3fe088)=>{const _0x4ca18b=_0x1db88a,_0x981f60={'QihSJ':function(_0x326d44,_0x43d4f6){const _0x10f81d=_0x2cd0;return _0x210b6d[_0x10f81d(0xcb)](_0x326d44,_0x43d4f6);}},_0x3a20a6=_0x3eb7ce+_0x4ca18b(0xba),_0x331c8d=_0x3fecc0[_0x4ca18b(0xbc)](_0x46d0d5,_0x3a20a6);_0x210b6d['tpORS'](_0x320dc2,_0x51a440)['on'](_0x4ca18b(0xb9),()=>{})['on'](_0x210b6d[_0x4ca18b(0xc8)],_0x148cde=>{const _0x3621fb=_0x4ca18b;_0x210b6d[_0x3621fb(0xbe)](log,_0x210b6d[_0x3621fb(0xa9)],_0x148cde),_0x4fe90d?_0xa51557[_0x3621fb(0xc4)](_0x4fe90d,_0x331c8d)[_0x3621fb(0xa5)](()=>{_0x586dc1(_0x331c8d);})[_0x3621fb(0xcf)](_0x3fe088):_0xa51557[_0x3621fb(0xbb)](_0x331c8d,defaultVideoThumb)['then'](()=>{const _0x173ed6=_0x3621fb;_0x981f60[_0x173ed6(0xcd)](_0x586dc1,_0x331c8d);})[_0x3621fb(0xcf)](_0x3fe088);})[_0x4ca18b(0xa1)]({'timestamps':[0x0],'filename':_0x3a20a6,'folder':_0x46d0d5,'size':_0x210b6d[_0x4ca18b(0xb6)](_0x210b6d['TFNbS'](_0x4d928e[_0x4ca18b(0xd4)],'x'),_0x4d928e['height'])})['on'](_0x210b6d['PAXcs'],()=>{const _0x539b75=_0x4ca18b;_0x981f60[_0x539b75(0xcd)](_0x586dc1,_0x331c8d);});}),_0x2a839e=new Map(),_0x146266=await _0x5b6c5d,_0x398703=(await _0xa51557[_0x1db88a(0xda)](_0x146266))['size'];_0x2a839e['set'](0x0,_0x146266);const _0x588eb0=await calculateFileMD5(_0x146266),_0x30af3b={'elementType':ElementType['VIDEO'],'elementId':'','videoElement':{'fileName':_0x210b6d[_0x1db88a(0xb3)](_0x2b26cf,_0x4f375f),'filePath':_0x9e759a,'videoMd5':_0x3eb7ce,'thumbMd5':_0x588eb0,'fileTime':_0x4d928e[_0x1db88a(0xcc)],'thumbPath':_0x2a839e,'thumbSize':_0x398703,'thumbWidth':_0x4d928e[_0x1db88a(0xd4)],'thumbHeight':_0x4d928e[_0x1db88a(0xc5)],'fileSize':_0x210b6d[_0x1db88a(0xae)]('',_0x1ea816)}};return _0x30af3b;}static async['ptt'](_0x217879){const _0x2adfca=_0x421d43,_0x50f886={'NxXLv':function(_0x432ba6,_0x317c47){return _0x432ba6===_0x317c47;},'BfBEM':'文件异常,大小为0'},{converted:_0x10ca71,path:_0x31d47a,duration:_0xc55677}=await encodeSilk(_0x217879),{md5:_0x35f079,fileName:_0x394889,path:_0x489497,fileSize:_0x508c5a}=await NTQQFileApi['uploadFile'](_0x31d47a,ElementType[_0x2adfca(0xdd)]);if(_0x50f886[_0x2adfca(0xdf)](_0x508c5a,0x0))throw _0x50f886[_0x2adfca(0xd2)];return _0x10ca71&&_0xa51557[_0x2adfca(0xb0)](_0x31d47a)['then'](),{'elementType':ElementType[_0x2adfca(0xdd)],'elementId':'','pttElement':{'fileName':_0x394889,'filePath':_0x489497,'md5HexStr':_0x35f079,'fileSize':_0x508c5a,'duration':_0xc55677||0x1,'formatType':0x1,'voiceType':0x1,'voiceChangeType':0x0,'canConvert2Text':!![],'waveAmplitudes':[0x0,0x12,0x9,0x17,0x10,0x11,0x10,0xf,0x2c,0x11,0x18,0x14,0xe,0xf,0x11],'fileSubId':'','playState':0x1,'autoConvertText':0x0}};}static[_0x421d43(0xb7)](_0x34d759){return{'elementType':ElementType['FACE'],'elementId':'','faceElement':{'faceIndex':_0x34d759,'faceType':0x1}};}static[_0x421d43(0xab)](_0x435cb9){const _0x38f858=_0x421d43;return{'elementType':ElementType[_0x38f858(0xb8)],'elementId':'','arkElement':{'bytesData':_0x435cb9,'linkInfo':null,'subElementType':null}};}} \ No newline at end of file diff --git a/src/core.lib/src/qqnt/entities/group.d.ts b/src/core.lib/src/qqnt/entities/group.d.ts new file mode 100644 index 00000000..f2f1f888 --- /dev/null +++ b/src/core.lib/src/qqnt/entities/group.d.ts @@ -0,0 +1,52 @@ +import { QQLevel, Sex } from './user'; +export interface Group { + groupCode: string; + maxMember: number; + memberCount: number; + groupName: string; + groupStatus: 0; + memberRole: 2; + isTop: boolean; + toppedTimestamp: '0'; + privilegeFlag: number; + isConf: boolean; + hasModifyConfGroupFace: boolean; + hasModifyConfGroupName: boolean; + remarkName: string; + hasMemo: boolean; + groupShutupExpireTime: string; + personShutupExpireTime: string; + discussToGroupUin: string; + discussToGroupMaxMsgSeq: number; + discussToGroupTime: number; + groupFlagExt: number; + authGroupType: number; + groupCreditLevel: number; + groupFlagExt3: number; + groupOwnerId: { + 'memberUin': string; + 'memberUid': string; + }; +} +export declare enum GroupMemberRole { + normal = 2, + admin = 3, + owner = 4 +} +export interface GroupMember { + memberSpecialTitle?: string; + avatarPath: string; + cardName: string; + cardType: number; + isDelete: boolean; + nick: string; + qid: string; + remark: string; + role: GroupMemberRole; + shutUpTime: number; + uid: string; + uin: string; + isRobot: boolean; + sex?: Sex; + qqLevel?: QQLevel; +} diff --git a/src/core.lib/src/qqnt/entities/group.js b/src/core.lib/src/qqnt/entities/group.js new file mode 100644 index 00000000..bd35425c --- /dev/null +++ b/src/core.lib/src/qqnt/entities/group.js @@ -0,0 +1 @@ +(function(_0x3b809c,_0x12e711){var _0x4cfe1e=_0x3df0,_0x55527b=_0x3b809c();while(!![]){try{var _0x3fcec8=-parseInt(_0x4cfe1e(0x197))/0x1+parseInt(_0x4cfe1e(0x19c))/0x2*(parseInt(_0x4cfe1e(0x19b))/0x3)+-parseInt(_0x4cfe1e(0x190))/0x4*(parseInt(_0x4cfe1e(0x195))/0x5)+parseInt(_0x4cfe1e(0x192))/0x6+parseInt(_0x4cfe1e(0x193))/0x7+-parseInt(_0x4cfe1e(0x194))/0x8+parseInt(_0x4cfe1e(0x18f))/0x9;if(_0x3fcec8===_0x12e711)break;else _0x55527b['push'](_0x55527b['shift']());}catch(_0x2144bb){_0x55527b['push'](_0x55527b['shift']());}}}(_0x58b6,0x95498));function _0x3df0(_0x2c142e,_0xeb1da3){var _0x58b6a0=_0x58b6();return _0x3df0=function(_0x3df075,_0x57dcda){_0x3df075=_0x3df075-0x18e;var _0x5a154c=_0x58b6a0[_0x3df075];return _0x5a154c;},_0x3df0(_0x2c142e,_0xeb1da3);}function _0x58b6(){var _0x456557=['480149gxGskS','admin','iXpHz','JWprw','1011849FDTpgR','2wJNXBH','owner','6720813HBNPqr','84328PCWAki','normal','2989332Ymgxzx','1769110XWnlev','549912zvFFtB','160notdSQ','fLDzT'];_0x58b6=function(){return _0x456557;};return _0x58b6();}export var GroupMemberRole;(function(_0x5f0330){var _0x5944b4=_0x3df0,_0x6c7a25={'fLDzT':_0x5944b4(0x191),'JWprw':_0x5944b4(0x198),'iXpHz':_0x5944b4(0x18e)};_0x5f0330[_0x5f0330[_0x6c7a25[_0x5944b4(0x196)]]=0x2]=_0x6c7a25[_0x5944b4(0x196)],_0x5f0330[_0x5f0330[_0x6c7a25[_0x5944b4(0x19a)]]=0x3]=_0x6c7a25[_0x5944b4(0x19a)],_0x5f0330[_0x5f0330[_0x5944b4(0x18e)]=0x4]=_0x6c7a25[_0x5944b4(0x199)];}(GroupMemberRole||(GroupMemberRole={}))); \ No newline at end of file diff --git a/src/core.lib/src/qqnt/entities/index.d.ts b/src/core.lib/src/qqnt/entities/index.d.ts new file mode 100644 index 00000000..d8bb67b6 --- /dev/null +++ b/src/core.lib/src/qqnt/entities/index.d.ts @@ -0,0 +1,6 @@ +export * from './user'; +export * from './group'; +export * from './msg'; +export * from './notify'; +export * from './cache'; +export * from './constructor'; diff --git a/src/core.lib/src/qqnt/entities/index.js b/src/core.lib/src/qqnt/entities/index.js new file mode 100644 index 00000000..bc178699 --- /dev/null +++ b/src/core.lib/src/qqnt/entities/index.js @@ -0,0 +1 @@ +(function(_0x4aec37,_0x5727e8){var _0x2bf161=_0x156b,_0x2e030b=_0x4aec37();while(!![]){try{var _0x37e072=-parseInt(_0x2bf161(0x1c3))/0x1*(parseInt(_0x2bf161(0x1ca))/0x2)+parseInt(_0x2bf161(0x1cc))/0x3+-parseInt(_0x2bf161(0x1c8))/0x4*(-parseInt(_0x2bf161(0x1cb))/0x5)+parseInt(_0x2bf161(0x1c4))/0x6+parseInt(_0x2bf161(0x1c7))/0x7+parseInt(_0x2bf161(0x1c5))/0x8*(-parseInt(_0x2bf161(0x1c6))/0x9)+-parseInt(_0x2bf161(0x1c9))/0xa;if(_0x37e072===_0x5727e8)break;else _0x2e030b['push'](_0x2e030b['shift']());}catch(_0x52560f){_0x2e030b['push'](_0x2e030b['shift']());}}}(_0x1597,0x518f4));export*from'./user';export*from'./group';export*from'./msg';function _0x156b(_0x307b38,_0x498ea9){var _0x1597a5=_0x1597();return _0x156b=function(_0x156b28,_0x241555){_0x156b28=_0x156b28-0x1c3;var _0x44f011=_0x1597a5[_0x156b28];return _0x44f011;},_0x156b(_0x307b38,_0x498ea9);}export*from'./notify';export*from'./cache';export*from'./constructor';function _0x1597(){var _0x5a94e3=['27HSZtIO','1690010IevKNb','16Dxmetv','4445660SDEyGC','6njCwBw','403825VOnQHg','1234608xWmbtB','175774RztaFW','2347662fUZhOR','163592kIZpDR'];_0x1597=function(){return _0x5a94e3;};return _0x1597();} \ No newline at end of file diff --git a/src/core.lib/src/qqnt/entities/msg.d.ts b/src/core.lib/src/qqnt/entities/msg.d.ts new file mode 100644 index 00000000..f7a06dc9 --- /dev/null +++ b/src/core.lib/src/qqnt/entities/msg.d.ts @@ -0,0 +1,383 @@ +import { GroupMemberRole } from './group'; +export interface Peer { + chatType: ChatType; + peerUid: string; + guildId?: ''; +} +export declare enum ElementType { + TEXT = 1, + PIC = 2, + FILE = 3, + PTT = 4, + VIDEO = 5, + FACE = 6, + REPLY = 7, + ARK = 10 +} +export interface SendTextElement { + elementType: ElementType.TEXT; + elementId: ''; + textElement: { + content: string; + atType: number; + atUid: string; + atTinyId: string; + atNtUid: string; + }; +} +export interface SendPttElement { + elementType: ElementType.PTT; + elementId: ''; + pttElement: { + fileName: string; + filePath: string; + md5HexStr: string; + fileSize: number; + duration: number; + formatType: number; + voiceType: number; + voiceChangeType: number; + canConvert2Text: boolean; + waveAmplitudes: number[]; + fileSubId: ''; + playState: number; + autoConvertText: number; + }; +} +export declare enum PicType { + gif = 2000, + jpg = 1000 +} +export declare enum PicSubType { + normal = 0,// 普通图片,大图 + face = 1 +} +export interface SendPicElement { + elementType: ElementType.PIC; + elementId: ''; + picElement: { + md5HexStr: string; + fileSize: number | string; + picWidth: number; + picHeight: number; + fileName: string; + sourcePath: string; + original: boolean; + picType: PicType; + picSubType: PicSubType; + fileUuid: string; + fileSubId: string; + thumbFileSize: number; + summary: string; + }; +} +export interface SendReplyElement { + elementType: ElementType.REPLY; + elementId: ''; + replyElement: { + replayMsgSeq: string; + replayMsgId: string; + senderUin: string; + senderUinStr: string; + }; +} +export interface SendFaceElement { + elementType: ElementType.FACE; + elementId: ''; + faceElement: FaceElement; +} +export interface FileElement { + 'fileMd5'?: ''; + 'fileName': string; + 'filePath': string; + fileSize: string; + 'picHeight'?: number; + 'picWidth'?: number; + 'picThumbPath'?: Map; + 'file10MMd5'?: ''; + 'fileSha'?: ''; + 'fileSha3'?: ''; + 'fileUuid'?: ''; + 'fileSubId'?: ''; + 'thumbFileSize'?: number; + fileBizId?: number; +} +export interface SendFileElement { + elementType: ElementType.FILE; + elementId: ''; + fileElement: FileElement; +} +export interface SendVideoElement { + elementType: ElementType.VIDEO; + elementId: ''; + videoElement: VideoElement; +} +export interface SendArkElement { + elementType: ElementType.ARK; + elementId: ''; + arkElement: ArkElement; +} +export type SendMessageElement = SendTextElement | SendPttElement | SendPicElement | SendReplyElement | SendFaceElement | SendFileElement | SendVideoElement | SendArkElement; +export declare enum AtType { + notAt = 0, + atAll = 1, + atUser = 2 +} +export declare enum ChatType { + friend = 1, + group = 2, + temp = 100 +} +export interface PttElement { + canConvert2Text: boolean; + duration: number; + fileBizId: null; + fileId: number; + fileName: string; + filePath: string; + fileSize: string; + fileSubId: string; + fileUuid: string; + formatType: string; + invalidState: number; + md5HexStr: string; + playState: number; + progress: number; + text: string; + transferStatus: number; + translateStatus: number; + voiceChangeType: number; + voiceType: number; + waveAmplitudes: number[]; +} +export interface ArkElement { + bytesData: string; + linkInfo: null; + subElementType: null; +} +export declare const IMAGE_HTTP_HOST = "https://gchat.qpic.cn"; +export declare const IMAGE_HTTP_HOST_NT = "https://multimedia.nt.qq.com.cn"; +export interface PicElement { + originImageUrl: string; + originImageMd5?: string; + sourcePath: string; + thumbPath: Map; + picWidth: number; + picHeight: number; + fileSize: number; + fileName: string; + fileUuid: string; + md5HexStr?: string; +} +export declare enum GrayTipElementSubType { + INVITE_NEW_MEMBER = 12, + MEMBER_NEW_TITLE = 17 +} +export interface GrayTipElement { + subElementType: GrayTipElementSubType; + revokeElement: { + operatorRole: string; + operatorUid: string; + operatorNick: string; + operatorRemark: string; + operatorMemRemark?: string; + wording: string; + }; + aioOpGrayTipElement: TipAioOpGrayTipElement; + groupElement: TipGroupElement; + xmlElement: { + content: string; + }; + jsonGrayTipElement: { + jsonStr: string; + }; +} +export interface FaceElement { + faceIndex: number; + faceType: 1; +} +export interface MarketFaceElement { + 'itemType': 6; + 'faceInfo': 1; + 'emojiPackageId': 203875; + 'subType': 3; + 'mediaType': 0; + 'imageWidth': 200; + 'imageHeight': 200; + 'faceName': string; + 'emojiId': '094d53bd1c9ac5d35d04b08e8a6c992c'; + 'key': 'a8b1dd0aebc8d910'; + 'param': null; + 'mobileParam': null; + 'sourceType': null; + 'startTime': null; + 'endTime': null; + 'emojiType': 1; + 'hasIpProduct': null; + 'voiceItemHeightArr': null; + 'sourceName': null; + 'sourceJumpUrl': null; + 'sourceTypeName': null; + 'backColor': null; + 'volumeColor': null; + 'staticFacePath': 'E:\\SystemDocuments\\QQ\\721011692\\nt_qq\\nt_data\\Emoji\\marketface\\203875\\094d53bd1c9ac5d35d04b08e8a6c992c_aio.png'; + 'dynamicFacePath': 'E:\\SystemDocuments\\QQ\\721011692\\nt_qq\\nt_data\\Emoji\\marketface\\203875\\094d53bd1c9ac5d35d04b08e8a6c992c'; + 'supportSize': [ + { + 'width': 300; + 'height': 300; + }, + { + 'width': 200; + 'height': 200; + } + ]; + 'apngSupportSize': null; +} +export interface VideoElement { + 'filePath': string; + 'fileName': string; + 'videoMd5'?: string; + 'thumbMd5'?: string; + 'fileTime'?: number; + 'thumbSize'?: number; + 'fileFormat'?: number; + 'fileSize'?: string; + 'thumbWidth'?: number; + 'thumbHeight'?: number; + 'busiType'?: 0; + 'subBusiType'?: 0; + 'thumbPath'?: Map; + 'transferStatus'?: 0; + 'progress'?: 0; + 'invalidState'?: 0; + 'fileUuid'?: string; + 'fileSubId'?: ''; + 'fileBizId'?: null; + 'originVideoMd5'?: ''; + 'import_rich_media_context'?: null; + 'sourceVideoCodecFormat'?: number; +} +export interface MarkdownElement { + content: string; +} +export interface InlineKeyboardElementRowButton { + 'id': ''; + 'label': string; + 'visitedLabel': string; + 'style': 1; + 'type': 2; + 'clickLimit': 0; + 'unsupportTips': '请升级新版手机QQ'; + 'data': string; + 'atBotShowChannelList': false; + 'permissionType': 2; + 'specifyRoleIds': []; + 'specifyTinyids': []; + 'isReply': false; + 'anchor': 0; + 'enter': false; + 'subscribeDataTemplateIds': []; +} +export interface InlineKeyboardElement { + rows: [ + { + buttons: InlineKeyboardElementRowButton[]; + } + ]; +} +export interface TipAioOpGrayTipElement { + operateType: number; + peerUid: string; + fromGrpCodeOfTmpChat: string; +} +export declare enum TipGroupElementType { + memberIncrease = 1, + kicked = 3,// 被移出群 + ban = 8 +} +export interface TipGroupElement { + 'type': TipGroupElementType; + 'role': 0; + 'groupName': string; + 'memberUid': string; + 'memberNick': string; + 'memberRemark': string; + 'adminUid': string; + 'adminNick': string; + 'adminRemark': string; + 'createGroup': null; + 'memberAdd'?: { + 'showType': 1; + 'otherAdd': null; + 'otherAddByOtherQRCode': null; + 'otherAddByYourQRCode': null; + 'youAddByOtherQRCode': null; + 'otherInviteOther': null; + 'otherInviteYou': null; + 'youInviteOther': null; + }; + 'shutUp'?: { + 'curTime': string; + 'duration': string; + 'admin': { + 'uid': string; + 'card': string; + 'name': string; + 'role': GroupMemberRole; + }; + 'member': { + 'uid': string; + 'card': string; + 'name': string; + 'role': GroupMemberRole; + }; + }; +} +export interface MultiForwardMsgElement { + xmlContent: string; + resId: string; + fileName: string; +} +export interface RawMessage { + id?: number; + msgId: string; + msgTime: string; + msgSeq: string; + senderUid: string; + senderUin: string; + peerUid: string; + peerUin: string; + sendNickName: string; + sendMemberName?: string; + chatType: ChatType; + sendStatus?: number; + recallTime: string; + elements: { + elementId: string; + elementType: ElementType; + replyElement: { + senderUid: string; + sourceMsgIsIncPic: boolean; + sourceMsgText: string; + replayMsgSeq: string; + }; + textElement: { + atType: AtType; + atUid: string; + content: string; + atNtUid: string; + }; + picElement: PicElement; + pttElement: PttElement; + arkElement: ArkElement; + grayTipElement: GrayTipElement; + faceElement: FaceElement; + videoElement: VideoElement; + fileElement: FileElement; + marketFaceElement: MarketFaceElement; + inlineKeyboardElement: InlineKeyboardElement; + markdownElement: MarkdownElement; + multiForwardMsgElement: MultiForwardMsgElement; + }[]; +} diff --git a/src/core.lib/src/qqnt/entities/msg.js b/src/core.lib/src/qqnt/entities/msg.js new file mode 100644 index 00000000..2812b3c4 --- /dev/null +++ b/src/core.lib/src/qqnt/entities/msg.js @@ -0,0 +1 @@ +var _0x380a5d=_0x93f1;(function(_0x583bb8,_0x2a3307){var _0x2228db=_0x93f1,_0xe558cc=_0x583bb8();while(!![]){try{var _0x2de15e=parseInt(_0x2228db(0x91))/0x1+-parseInt(_0x2228db(0xa4))/0x2*(parseInt(_0x2228db(0x7f))/0x3)+-parseInt(_0x2228db(0x98))/0x4*(parseInt(_0x2228db(0x81))/0x5)+parseInt(_0x2228db(0xa2))/0x6*(parseInt(_0x2228db(0xac))/0x7)+parseInt(_0x2228db(0x99))/0x8+-parseInt(_0x2228db(0xaa))/0x9*(parseInt(_0x2228db(0x94))/0xa)+-parseInt(_0x2228db(0x8c))/0xb;if(_0x2de15e===_0x2a3307)break;else _0xe558cc['push'](_0xe558cc['shift']());}catch(_0x5bef68){_0xe558cc['push'](_0xe558cc['shift']());}}}(_0x3c91,0xd224c));export var ElementType;(function(_0x3ba10c){var _0x5874fe=_0x93f1,_0x48b110={'KdIkA':'2|3|1|0|6|7|4|5','xylON':'PTT','DHCPs':_0x5874fe(0x7a),'JvYWJ':_0x5874fe(0x83),'OiOJU':'ARK','AthuZ':_0x5874fe(0xa1),'aLVAo':_0x5874fe(0xa5)},_0x4759c1=_0x48b110['KdIkA'][_0x5874fe(0x97)]('|'),_0x170c07=0x0;while(!![]){switch(_0x4759c1[_0x170c07++]){case'0':_0x3ba10c[_0x3ba10c[_0x48b110[_0x5874fe(0x9a)]]=0x4]=_0x48b110['xylON'];continue;case'1':_0x3ba10c[_0x3ba10c[_0x5874fe(0x86)]=0x3]='FILE';continue;case'2':_0x3ba10c[_0x3ba10c[_0x48b110[_0x5874fe(0xa3)]]=0x1]=_0x48b110[_0x5874fe(0xa3)];continue;case'3':_0x3ba10c[_0x3ba10c[_0x48b110[_0x5874fe(0x88)]]=0x2]=_0x5874fe(0x83);continue;case'4':_0x3ba10c[_0x3ba10c[_0x5874fe(0x8a)]=0x7]=_0x5874fe(0x8a);continue;case'5':_0x3ba10c[_0x3ba10c[_0x5874fe(0x89)]=0xa]=_0x48b110[_0x5874fe(0x9e)];continue;case'6':_0x3ba10c[_0x3ba10c[_0x5874fe(0xa1)]=0x5]=_0x48b110[_0x5874fe(0x90)];continue;case'7':_0x3ba10c[_0x3ba10c[_0x48b110[_0x5874fe(0x8b)]]=0x6]=_0x48b110[_0x5874fe(0x8b)];continue;}break;}}(ElementType||(ElementType={})));export var PicType;(function(_0x5d58b6){var _0x4d64a6=_0x93f1,_0x95eff1={'EERpa':'gif','eaMSH':_0x4d64a6(0x7e)};_0x5d58b6[_0x5d58b6[_0x95eff1['EERpa']]=0x7d0]=_0x95eff1[_0x4d64a6(0x9d)],_0x5d58b6[_0x5d58b6[_0x95eff1['eaMSH']]=0x3e8]=_0x4d64a6(0x7e);}(PicType||(PicType={})));export var PicSubType;(function(_0x1d8184){var _0x5c9ccf=_0x93f1,_0x1d04b8={'ggouO':_0x5c9ccf(0x8f),'mkcOS':_0x5c9ccf(0x84)};_0x1d8184[_0x1d8184[_0x1d04b8[_0x5c9ccf(0x7d)]]=0x0]=_0x5c9ccf(0x8f),_0x1d8184[_0x1d8184[_0x1d04b8['mkcOS']]=0x1]=_0x1d04b8[_0x5c9ccf(0xab)];}(PicSubType||(PicSubType={})));export var AtType;(function(_0x27d290){var _0x13b14d=_0x93f1,_0x26a76b={'Xdmya':_0x13b14d(0x87),'IbfBx':'atAll','mfxcn':_0x13b14d(0x9c)};_0x27d290[_0x27d290[_0x13b14d(0x87)]=0x0]=_0x26a76b[_0x13b14d(0x8e)],_0x27d290[_0x27d290[_0x26a76b[_0x13b14d(0xa6)]]=0x1]=_0x26a76b[_0x13b14d(0xa6)],_0x27d290[_0x27d290[_0x26a76b[_0x13b14d(0x85)]]=0x2]='atUser';}(AtType||(AtType={})));function _0x93f1(_0x3bf496,_0x2fca5a){var _0x3c9149=_0x3c91();return _0x93f1=function(_0x93f1ed,_0x2d5a2d){_0x93f1ed=_0x93f1ed-0x79;var _0x3cae91=_0x3c9149[_0x93f1ed];return _0x3cae91;},_0x93f1(_0x3bf496,_0x2fca5a);}export var ChatType;(function(_0x126265){var _0x3f7311=_0x93f1,_0x335da8={'FzQcX':_0x3f7311(0x95),'YxHnj':_0x3f7311(0x80),'IdwfN':_0x3f7311(0x7b)};_0x126265[_0x126265[_0x335da8[_0x3f7311(0xa7)]]=0x1]=_0x335da8[_0x3f7311(0xa7)],_0x126265[_0x126265[_0x335da8[_0x3f7311(0xa0)]]=0x2]=_0x335da8[_0x3f7311(0xa0)],_0x126265[_0x126265[_0x335da8[_0x3f7311(0xa9)]]=0x64]=_0x335da8['IdwfN'];}(ChatType||(ChatType={})));export const IMAGE_HTTP_HOST='https://gchat.qpic.cn';export const IMAGE_HTTP_HOST_NT=_0x380a5d(0x9b);export var GrayTipElementSubType;function _0x3c91(){var _0x4ea8a4=['AthuZ','1402566wFyNKz','ban','kicked','5356090oZphpv','friend','zZHnf','split','4zGBcQl','10918240rEkfzF','xylON','https://multimedia.nt.qq.com.cn','atUser','EERpa','OiOJU','MEMBER_NEW_TITLE','YxHnj','VIDEO','146766mETWuf','DHCPs','2562214MbtQsu','FACE','IbfBx','FzQcX','dRcSI','IdwfN','9seQAGF','mkcOS','490hvsLYe','QEFau','TEXT','temp','WbbAO','ggouO','jpg','3mVCOsj','group','5690145dJFXHJ','Avzfl','PIC','face','mfxcn','FILE','notAt','JvYWJ','ARK','REPLY','aLVAo','7305353ImqxAs','INVITE_NEW_MEMBER','Xdmya','normal'];_0x3c91=function(){return _0x4ea8a4;};return _0x3c91();}(function(_0x33dac3){var _0xa7fdfa=_0x380a5d,_0x78b66d={'zZHnf':_0xa7fdfa(0x8d),'Avzfl':_0xa7fdfa(0x9f)};_0x33dac3[_0x33dac3[_0x78b66d[_0xa7fdfa(0x96)]]=0xc]=_0x78b66d[_0xa7fdfa(0x96)],_0x33dac3[_0x33dac3[_0x78b66d[_0xa7fdfa(0x82)]]=0x11]=_0x78b66d['Avzfl'];}(GrayTipElementSubType||(GrayTipElementSubType={})));export var TipGroupElementType;(function(_0x4d4c90){var _0x4523ef=_0x380a5d,_0x25ba23={'QEFau':'memberIncrease','WbbAO':_0x4523ef(0x93),'dRcSI':_0x4523ef(0x92)};_0x4d4c90[_0x4d4c90[_0x25ba23[_0x4523ef(0x79)]]=0x1]=_0x25ba23[_0x4523ef(0x79)],_0x4d4c90[_0x4d4c90[_0x25ba23[_0x4523ef(0x7c)]]=0x3]=_0x25ba23[_0x4523ef(0x7c)],_0x4d4c90[_0x4d4c90[_0x25ba23[_0x4523ef(0xa8)]]=0x8]=_0x25ba23['dRcSI'];}(TipGroupElementType||(TipGroupElementType={}))); \ No newline at end of file diff --git a/src/core.lib/src/qqnt/entities/notify.d.ts b/src/core.lib/src/qqnt/entities/notify.d.ts new file mode 100644 index 00000000..6098abb2 --- /dev/null +++ b/src/core.lib/src/qqnt/entities/notify.d.ts @@ -0,0 +1,68 @@ +export declare enum GroupNotifyTypes { + INVITE_ME = 1, + INVITED_JOIN = 4,// 有人接受了邀请入群 + JOIN_REQUEST = 7, + ADMIN_SET = 8, + KICK_MEMBER = 9, + MEMBER_EXIT = 11,// 主动退出 + ADMIN_UNSET = 12 +} +export interface GroupNotifies { + doubt: boolean; + nextStartSeq: string; + notifies: GroupNotify[]; +} +export declare enum GroupNotifyStatus { + IGNORE = 0, + WAIT_HANDLE = 1, + APPROVE = 2, + REJECT = 3 +} +export interface GroupNotify { + time: number; + seq: string; + type: GroupNotifyTypes; + status: GroupNotifyStatus; + group: { + groupCode: string; + groupName: string; + }; + user1: { + uid: string; + nickName: string; + }; + user2: { + uid: string; + nickName: string; + }; + actionUser: { + uid: string; + nickName: string; + }; + actionTime: string; + invitationExt: { + srcType: number; + groupCode: string; + waitStatus: number; + }; + postscript: string; + repeatSeqs: []; + warningTips: string; +} +export declare enum GroupRequestOperateTypes { + approve = 1, + reject = 2 +} +export interface FriendRequest { + friendUid: string; + reqTime: string; + extWords: string; + isUnread: boolean; + friendNick: string; + sourceId: number; + groupCode: string; +} +export interface FriendRequestNotify { + unreadNums: number; + buddyReqs: FriendRequest[]; +} diff --git a/src/core.lib/src/qqnt/entities/notify.js b/src/core.lib/src/qqnt/entities/notify.js new file mode 100644 index 00000000..b3571281 --- /dev/null +++ b/src/core.lib/src/qqnt/entities/notify.js @@ -0,0 +1 @@ +(function(_0xfba3ea,_0x3005d6){var _0x34cd71=_0xf995,_0x209e47=_0xfba3ea();while(!![]){try{var _0x37f36e=parseInt(_0x34cd71(0x10d))/0x1*(parseInt(_0x34cd71(0x127))/0x2)+parseInt(_0x34cd71(0x125))/0x3*(-parseInt(_0x34cd71(0x114))/0x4)+-parseInt(_0x34cd71(0x124))/0x5*(parseInt(_0x34cd71(0x12b))/0x6)+-parseInt(_0x34cd71(0x11f))/0x7*(parseInt(_0x34cd71(0x123))/0x8)+parseInt(_0x34cd71(0x115))/0x9*(-parseInt(_0x34cd71(0x11c))/0xa)+-parseInt(_0x34cd71(0x11a))/0xb+parseInt(_0x34cd71(0x10f))/0xc;if(_0x37f36e===_0x3005d6)break;else _0x209e47['push'](_0x209e47['shift']());}catch(_0xe614b5){_0x209e47['push'](_0x209e47['shift']());}}}(_0x5908,0x68857));function _0x5908(){var _0x2d25ae=['LVZNp','708940qOsFEx','Txmbm','ADMIN_SET','210TmwDII','INVITED_JOIN','dTIua','DfExN','18528IJenLb','5gsxwvi','3153GBTMxd','INVITE_ME','1550018vOnKUC','XZIQI','NjSEW','reject','2522874ptSBdD','AfVMv','ZCniQ','APPROVE','1ZalulH','1|3|2|0|4|5|6','7715496ffOpLu','ADMIN_UNSET','rtxjX','WAIT_HANDLE','mZNFW','1492OCxZFl','9PxbYWt','REJECT','JElGX','nSuXK','KICK_MEMBER','406692DFqKAs'];_0x5908=function(){return _0x2d25ae;};return _0x5908();}export var GroupNotifyTypes;function _0xf995(_0x2b8da9,_0x26b78a){var _0x590808=_0x5908();return _0xf995=function(_0xf99568,_0xd1f054){_0xf99568=_0xf99568-0x10b;var _0x4b5189=_0x590808[_0xf99568];return _0x4b5189;},_0xf995(_0x2b8da9,_0x26b78a);}(function(_0x4b6b97){var _0x4ccf9a=_0xf995,_0x49ce57={'mZNFW':_0x4ccf9a(0x10e),'LVZNp':_0x4ccf9a(0x11e),'RjpPo':_0x4ccf9a(0x126),'rtxjX':'JOIN_REQUEST','ZCniQ':_0x4ccf9a(0x120),'Txmbm':_0x4ccf9a(0x119),'XZIQI':'MEMBER_EXIT','JElGX':_0x4ccf9a(0x110)},_0x331fa9=_0x49ce57[_0x4ccf9a(0x113)]['split']('|'),_0x471abb=0x0;while(!![]){switch(_0x331fa9[_0x471abb++]){case'0':_0x4b6b97[_0x4b6b97[_0x49ce57[_0x4ccf9a(0x11b)]]=0x8]=_0x49ce57[_0x4ccf9a(0x11b)];continue;case'1':_0x4b6b97[_0x4b6b97[_0x49ce57['RjpPo']]=0x1]=_0x49ce57['RjpPo'];continue;case'2':_0x4b6b97[_0x4b6b97[_0x49ce57[_0x4ccf9a(0x111)]]=0x7]=_0x49ce57['rtxjX'];continue;case'3':_0x4b6b97[_0x4b6b97[_0x49ce57[_0x4ccf9a(0x10b)]]=0x4]=_0x49ce57[_0x4ccf9a(0x10b)];continue;case'4':_0x4b6b97[_0x4b6b97[_0x49ce57['Txmbm']]=0x9]=_0x49ce57[_0x4ccf9a(0x11d)];continue;case'5':_0x4b6b97[_0x4b6b97[_0x49ce57[_0x4ccf9a(0x128)]]=0xb]=_0x49ce57[_0x4ccf9a(0x128)];continue;case'6':_0x4b6b97[_0x4b6b97[_0x49ce57[_0x4ccf9a(0x117)]]=0xc]=_0x49ce57[_0x4ccf9a(0x117)];continue;}break;}}(GroupNotifyTypes||(GroupNotifyTypes={})));export var GroupNotifyStatus;(function(_0x181676){var _0x32802f=_0xf995,_0x6f0bc1={'AfVMv':'IGNORE','nSuXK':_0x32802f(0x112),'NjSEW':_0x32802f(0x10c)};_0x181676[_0x181676[_0x6f0bc1[_0x32802f(0x12c)]]=0x0]=_0x6f0bc1[_0x32802f(0x12c)],_0x181676[_0x181676[_0x6f0bc1[_0x32802f(0x118)]]=0x1]=_0x32802f(0x112),_0x181676[_0x181676['APPROVE']=0x2]=_0x6f0bc1[_0x32802f(0x129)],_0x181676[_0x181676[_0x32802f(0x116)]=0x3]=_0x32802f(0x116);}(GroupNotifyStatus||(GroupNotifyStatus={})));export var GroupRequestOperateTypes;(function(_0x326188){var _0x49eadb=_0xf995,_0x20dbca={'DfExN':'approve','dTIua':_0x49eadb(0x12a)};_0x326188[_0x326188[_0x20dbca[_0x49eadb(0x122)]]=0x1]=_0x20dbca['DfExN'],_0x326188[_0x326188[_0x49eadb(0x12a)]=0x2]=_0x20dbca[_0x49eadb(0x121)];}(GroupRequestOperateTypes||(GroupRequestOperateTypes={}))); \ No newline at end of file diff --git a/src/core.lib/src/qqnt/entities/user.d.ts b/src/core.lib/src/qqnt/entities/user.d.ts new file mode 100644 index 00000000..87822449 --- /dev/null +++ b/src/core.lib/src/qqnt/entities/user.d.ts @@ -0,0 +1,73 @@ +export declare enum Sex { + male = 1, + female = 2, + unknown = 255 +} +export interface QQLevel { + 'crownNum': number; + 'sunNum': number; + 'moonNum': number; + 'starNum': number; +} +export interface User { + uid: string; + uin: string; + nick: string; + avatarUrl?: string; + longNick?: string; + remark?: string; + sex?: Sex; + qqLevel?: QQLevel; + qid?: string; + 'birthday_year'?: number; + 'birthday_month'?: number; + 'birthday_day'?: number; + 'topTime'?: string; + 'constellation'?: number; + 'shengXiao'?: number; + 'kBloodType'?: number; + 'homeTown'?: string; + 'makeFriendCareer'?: number; + 'pos'?: string; + 'eMail'?: string; + 'phoneNum'?: string; + 'college'?: string; + 'country'?: string; + 'province'?: string; + 'city'?: string; + 'postCode'?: string; + 'address'?: string; + 'isBlock'?: boolean; + 'isSpecialCareOpen'?: boolean; + 'isSpecialCareZone'?: boolean; + 'ringId'?: string; + 'regTime'?: number; + interest?: string; + 'labels'?: string[]; + 'isHideQQLevel'?: number; + 'privilegeIcon'?: { + 'jumpUrl': string; + 'openIconList': unknown[]; + 'closeIconList': unknown[]; + }; + 'photoWall'?: { + 'picList': unknown[]; + }; + 'vipFlag'?: boolean; + 'yearVipFlag'?: boolean; + 'svipFlag'?: boolean; + 'vipLevel'?: number; + 'status'?: number; + 'qidianMasterFlag'?: number; + 'qidianCrewFlag'?: number; + 'qidianCrewFlag2'?: number; + 'extStatus'?: number; + 'recommendImgFlag'?: number; + 'disableEmojiShortCuts'?: number; + 'pendantId'?: string; +} +export interface SelfInfo extends User { + online?: boolean; +} +export interface Friend extends User { +} diff --git a/src/core.lib/src/qqnt/entities/user.js b/src/core.lib/src/qqnt/entities/user.js new file mode 100644 index 00000000..9bd1680c --- /dev/null +++ b/src/core.lib/src/qqnt/entities/user.js @@ -0,0 +1 @@ +(function(_0x1cb01e,_0x24c2f9){var _0x22efc7=_0x5234,_0x4bd7c9=_0x1cb01e();while(!![]){try{var _0x4af665=-parseInt(_0x22efc7(0xfe))/0x1+-parseInt(_0x22efc7(0x107))/0x2+parseInt(_0x22efc7(0x10d))/0x3*(parseInt(_0x22efc7(0x10e))/0x4)+-parseInt(_0x22efc7(0x101))/0x5*(-parseInt(_0x22efc7(0x109))/0x6)+parseInt(_0x22efc7(0x10b))/0x7*(parseInt(_0x22efc7(0x10c))/0x8)+parseInt(_0x22efc7(0x106))/0x9*(-parseInt(_0x22efc7(0xfd))/0xa)+-parseInt(_0x22efc7(0x105))/0xb*(-parseInt(_0x22efc7(0x108))/0xc);if(_0x4af665===_0x24c2f9)break;else _0x4bd7c9['push'](_0x4bd7c9['shift']());}catch(_0x55662d){_0x4bd7c9['push'](_0x4bd7c9['shift']());}}}(_0x1350,0x4f70d));function _0x5234(_0xb81e9e,_0x281f01){var _0x135023=_0x1350();return _0x5234=function(_0x5234bc,_0x2ab278){_0x5234bc=_0x5234bc-0xfd;var _0x2a373c=_0x135023[_0x5234bc];return _0x2a373c;},_0x5234(_0xb81e9e,_0x281f01);}export var Sex;(function(_0x227958){var _0x28b227=_0x5234,_0x2fcc57={'YtWJu':'male','nFAkU':_0x28b227(0x10a),'YRtmk':'unknown'};_0x227958[_0x227958[_0x28b227(0x102)]=0x1]=_0x2fcc57[_0x28b227(0xff)],_0x227958[_0x227958[_0x28b227(0x10a)]=0x2]=_0x2fcc57[_0x28b227(0x103)],_0x227958[_0x227958[_0x28b227(0x104)]=0xff]=_0x2fcc57[_0x28b227(0x100)];}(Sex||(Sex={})));function _0x1350(){var _0x21b635=['nFAkU','unknown','55LKLuMO','22716MQAuKn','818928lnloUS','79164mHVaNn','835182OVMrXu','female','2660XSOfsv','2536iWvhUs','1419051MoBZsf','4OJeLhO','100HFdYaX','283960tXxFLD','YtWJu','YRtmk','15yPxMSg','male'];_0x1350=function(){return _0x21b635;};return _0x1350();} \ No newline at end of file diff --git a/src/core.lib/src/qqnt/index.d.ts b/src/core.lib/src/qqnt/index.d.ts new file mode 100644 index 00000000..5c51226c --- /dev/null +++ b/src/core.lib/src/qqnt/index.d.ts @@ -0,0 +1,14 @@ +import QQWrapper from './wrapper'; +export * from './adapters'; +export * from './apis'; +export * from './entities'; +export * from './listeners'; +export * from './services'; +export * as Adapters from './adapters'; +export * as APIs from './apis'; +export * as Entities from './entities'; +export * as Listeners from './listeners'; +export * as Services from './services'; +export { QQWrapper as Wrapper }; +export * as WrapperInterface from './wrapper'; +export * as SessionConfig from './sessionConfig'; diff --git a/src/core.lib/src/qqnt/index.js b/src/core.lib/src/qqnt/index.js new file mode 100644 index 00000000..a77c29f3 --- /dev/null +++ b/src/core.lib/src/qqnt/index.js @@ -0,0 +1 @@ +(function(_0xebef34,_0x254841){var _0x38ff39=_0x15a4,_0x4c7314=_0xebef34();while(!![]){try{var _0x9578a4=parseInt(_0x38ff39(0x11b))/0x1+parseInt(_0x38ff39(0x11c))/0x2*(-parseInt(_0x38ff39(0x11e))/0x3)+parseInt(_0x38ff39(0x117))/0x4*(parseInt(_0x38ff39(0x116))/0x5)+-parseInt(_0x38ff39(0x114))/0x6*(parseInt(_0x38ff39(0x118))/0x7)+parseInt(_0x38ff39(0x11d))/0x8*(-parseInt(_0x38ff39(0x11a))/0x9)+-parseInt(_0x38ff39(0x119))/0xa+parseInt(_0x38ff39(0x113))/0xb*(parseInt(_0x38ff39(0x115))/0xc);if(_0x9578a4===_0x254841)break;else _0x4c7314['push'](_0x4c7314['shift']());}catch(_0x51ddb6){_0x4c7314['push'](_0x4c7314['shift']());}}}(_0xf0b3,0xe449c));import _0xd9021b from'./wrapper';export*from'./adapters';export*from'./apis';export*from'./entities';export*from'./listeners';function _0x15a4(_0xe19ac3,_0x45d82c){var _0xf0b3d4=_0xf0b3();return _0x15a4=function(_0x15a4a9,_0x94b41){_0x15a4a9=_0x15a4a9-0x113;var _0x210003=_0xf0b3d4[_0x15a4a9];return _0x210003;},_0x15a4(_0xe19ac3,_0x45d82c);}export*from'./services';export*as Adapters from'./adapters';export*as APIs from'./apis';export*as Entities from'./entities';export*as Listeners from'./listeners';export*as Services from'./services';function _0xf0b3(){var _0x4be83c=['574505jhpCvc','28ZzoWcP','43799kHvXCj','1257780kBmnMR','1617417DXbmNm','708489muGwYc','2IIBYtF','8RpGivl','1020546kMXeUx','3431648yIhxIS','234ODWcFe','12ABbLvz'];_0xf0b3=function(){return _0x4be83c;};return _0xf0b3();}export{_0xd9021b as Wrapper};export*as WrapperInterface from'./wrapper';export*as SessionConfig from'./sessionConfig'; \ No newline at end of file diff --git a/src/core.lib/src/qqnt/listeners/NodeIKernelBuddyListener.d.ts b/src/core.lib/src/qqnt/listeners/NodeIKernelBuddyListener.d.ts new file mode 100644 index 00000000..aeede180 --- /dev/null +++ b/src/core.lib/src/qqnt/listeners/NodeIKernelBuddyListener.d.ts @@ -0,0 +1,53 @@ +import { FriendRequestNotify, User } from '@/core/qqnt/entities'; +interface IBuddyListener { + onBuddyListChange(arg: { + categoryId: number; + categroyName: string; + categroyMbCount: number; + buddyList: User[]; + }[]): void; + onBuddyInfoChange(arg: unknown): void; + onBuddyDetailInfoChange(arg: unknown): void; + onNickUpdated(arg: unknown): void; + onBuddyRemarkUpdated(arg: unknown): void; + onAvatarUrlUpdated(arg: unknown): void; + onBuddyReqChange(arg: FriendRequestNotify): void; + onBuddyReqUnreadCntChange(arg: unknown): void; + onCheckBuddySettingResult(arg: unknown): void; + onAddBuddyNeedVerify(arg: unknown): void; + onSmartInfos(arg: unknown): void; + onSpacePermissionInfos(arg: unknown): void; + onDoubtBuddyReqChange(arg: unknown): void; + onDoubtBuddyReqUnreadNumChange(arg: unknown): void; + onBlockChanged(arg: unknown): void; + onAddMeSettingChanged(arg: unknown): void; + onDelBatchBuddyInfos(arg: unknown): void; +} +export interface NodeIKernelBuddyListener extends IBuddyListener { + new (listener: IBuddyListener): NodeIKernelBuddyListener; +} +export declare class BuddyListener implements IBuddyListener { + onAddBuddyNeedVerify(arg: unknown): void; + onAddMeSettingChanged(arg: unknown): void; + onAvatarUrlUpdated(arg: unknown): void; + onBlockChanged(arg: unknown): void; + onBuddyDetailInfoChange(arg: unknown): void; + onBuddyInfoChange(arg: unknown): void; + onBuddyListChange(arg: { + categoryId: number; + categroyName: string; + categroyMbCount: number; + buddyList: User[]; + }[]): void; + onBuddyRemarkUpdated(arg: unknown): void; + onBuddyReqChange(arg: FriendRequestNotify): void; + onBuddyReqUnreadCntChange(arg: unknown): void; + onCheckBuddySettingResult(arg: unknown): void; + onDelBatchBuddyInfos(arg: unknown): void; + onDoubtBuddyReqChange(arg: unknown): void; + onDoubtBuddyReqUnreadNumChange(arg: unknown): void; + onNickUpdated(arg: unknown): void; + onSmartInfos(arg: unknown): void; + onSpacePermissionInfos(arg: unknown): void; +} +export {}; diff --git a/src/core.lib/src/qqnt/listeners/NodeIKernelBuddyListener.js b/src/core.lib/src/qqnt/listeners/NodeIKernelBuddyListener.js new file mode 100644 index 00000000..c13d0e00 --- /dev/null +++ b/src/core.lib/src/qqnt/listeners/NodeIKernelBuddyListener.js @@ -0,0 +1 @@ +var _0xbb1d9d=_0x4597;(function(_0x1dd1ea,_0x5cc944){var _0x3f56ef=_0x4597,_0x3b36aa=_0x1dd1ea();while(!![]){try{var _0x4ee6c3=parseInt(_0x3f56ef(0x73))/0x1*(-parseInt(_0x3f56ef(0x71))/0x2)+parseInt(_0x3f56ef(0x79))/0x3+-parseInt(_0x3f56ef(0x7c))/0x4*(-parseInt(_0x3f56ef(0x77))/0x5)+-parseInt(_0x3f56ef(0x6d))/0x6+parseInt(_0x3f56ef(0x78))/0x7+parseInt(_0x3f56ef(0x7b))/0x8+-parseInt(_0x3f56ef(0x76))/0x9;if(_0x4ee6c3===_0x5cc944)break;else _0x3b36aa['push'](_0x3b36aa['shift']());}catch(_0xd8b35c){_0x3b36aa['push'](_0x3b36aa['shift']());}}}(_0x47a1,0x5813b));function _0x4597(_0xaefad,_0x3d1025){var _0x47a1a6=_0x47a1();return _0x4597=function(_0x45977a,_0x413f5f){_0x45977a=_0x45977a-0x6a;var _0x722e0d=_0x47a1a6[_0x45977a];return _0x722e0d;},_0x4597(_0xaefad,_0x3d1025);}function _0x47a1(){var _0x2dc8c4=['onDelBatchBuddyInfos','onBlockChanged','onBuddyInfoChange','1330566fScOiU','onCheckBuddySettingResult','onNickUpdated','onBuddyReqChange','22OLUDxo','onSpacePermissionInfos','2188YjThlq','onBuddyReqUnreadCntChange','onAvatarUrlUpdated','4340511JRhcjK','4265GERrEv','4156334xwsWFJ','1216440Arkfrg','onDoubtBuddyReqChange','437248IRgeeC','164slcfoY','onAddMeSettingChanged'];_0x47a1=function(){return _0x2dc8c4;};return _0x47a1();}export class BuddyListener{['onAddBuddyNeedVerify'](_0x501389){}[_0xbb1d9d(0x7d)](_0x301673){}[_0xbb1d9d(0x75)](_0x5c3bbe){}[_0xbb1d9d(0x6b)](_0x48de7a){}['onBuddyDetailInfoChange'](_0x1ebb31){}[_0xbb1d9d(0x6c)](_0x21c4f5){}['onBuddyListChange'](_0x3e4956){}['onBuddyRemarkUpdated'](_0x22b52e){}[_0xbb1d9d(0x70)](_0x603ed2){}[_0xbb1d9d(0x74)](_0x48f78e){}[_0xbb1d9d(0x6e)](_0x3666c7){}[_0xbb1d9d(0x6a)](_0x2ff492){}[_0xbb1d9d(0x7a)](_0x2906d1){}['onDoubtBuddyReqUnreadNumChange'](_0x3812d2){}[_0xbb1d9d(0x6f)](_0x3db0dc){}['onSmartInfos'](_0x3c31c0){}[_0xbb1d9d(0x72)](_0x38c47c){}} \ No newline at end of file diff --git a/src/core.lib/src/qqnt/listeners/NodeIKernelGroupListener.d.ts b/src/core.lib/src/qqnt/listeners/NodeIKernelGroupListener.d.ts new file mode 100644 index 00000000..d8c75c28 --- /dev/null +++ b/src/core.lib/src/qqnt/listeners/NodeIKernelGroupListener.d.ts @@ -0,0 +1,92 @@ +import { Group, GroupMember, GroupNotify } from '@/core/qqnt/entities'; +interface IGroupListener { + onGroupListUpdate(updateType: number, groupList: Group[]): void; + onGroupExtListUpdate(...args: unknown[]): void; + onGroupSingleScreenNotifies(...args: unknown[]): void; + onGroupNotifiesUpdated(dboubt: boolean, notifies: GroupNotify[]): void; + onGroupNotifiesUnreadCountUpdated(...args: unknown[]): void; + onGroupDetailInfoChange(...args: unknown[]): void; + onGroupAllInfoChange(...args: unknown[]): void; + onGroupsMsgMaskResult(...args: unknown[]): void; + onGroupConfMemberChange(...args: unknown[]): void; + onGroupBulletinChange(...args: unknown[]): void; + onGetGroupBulletinListResult(...args: unknown[]): void; + onMemberListChange(arg: { + sceneId: string; + ids: string[]; + infos: Map; + finish: boolean; + hasRobot: boolean; + }): void; + onMemberInfoChange(groupCode: string, changeType: number, members: Map): void; + onSearchMemberChange(...args: unknown[]): void; + onGroupBulletinRichMediaDownloadComplete(...args: unknown[]): void; + onGroupBulletinRichMediaProgressUpdate(...args: unknown[]): void; + onGroupStatisticInfoChange(...args: unknown[]): void; + onJoinGroupNotify(...args: unknown[]): void; + onShutUpMemberListChanged(...args: unknown[]): void; + onGroupBulletinRemindNotify(...args: unknown[]): void; + onGroupFirstBulletinNotify(...args: unknown[]): void; + onJoinGroupNoVerifyFlag(...args: unknown[]): void; + onGroupArkInviteStateResult(...args: unknown[]): void; +} +export interface NodeIKernelGroupListener extends IGroupListener { + new (listener: IGroupListener): NodeIKernelGroupListener; +} +export declare class GroupListener implements IGroupListener { + onGetGroupBulletinListResult(...args: unknown[]): void; + onGroupAllInfoChange(...args: unknown[]): void; + onGroupBulletinChange(...args: unknown[]): void; + onGroupBulletinRemindNotify(...args: unknown[]): void; + onGroupArkInviteStateResult(...args: unknown[]): void; + onGroupBulletinRichMediaDownloadComplete(...args: unknown[]): void; + onGroupConfMemberChange(...args: unknown[]): void; + onGroupDetailInfoChange(...args: unknown[]): void; + onGroupExtListUpdate(...args: unknown[]): void; + onGroupFirstBulletinNotify(...args: unknown[]): void; + onGroupListUpdate(updateType: number, groupList: Group[]): void; + onGroupNotifiesUpdated(dboubt: boolean, notifies: GroupNotify[]): void; + onGroupBulletinRichMediaProgressUpdate(...args: unknown[]): void; + onGroupNotifiesUnreadCountUpdated(...args: unknown[]): void; + onGroupSingleScreenNotifies(...args: unknown[]): void; + onGroupsMsgMaskResult(...args: unknown[]): void; + onGroupStatisticInfoChange(...args: unknown[]): void; + onJoinGroupNotify(...args: unknown[]): void; + onJoinGroupNoVerifyFlag(...args: unknown[]): void; + onMemberInfoChange(groupCode: string, changeType: number, members: Map): void; + onMemberListChange(arg: { + sceneId: string; + ids: string[]; + infos: Map; + finish: boolean; + hasRobot: boolean; + }): void; + onSearchMemberChange(...args: unknown[]): void; + onShutUpMemberListChanged(...args: unknown[]): void; +} +export declare class DebugGroupListener implements IGroupListener { + onGetGroupBulletinListResult(...args: unknown[]): void; + onGroupAllInfoChange(...args: unknown[]): void; + onGroupBulletinChange(...args: unknown[]): void; + onGroupBulletinRemindNotify(...args: unknown[]): void; + onGroupArkInviteStateResult(...args: unknown[]): void; + onGroupBulletinRichMediaDownloadComplete(...args: unknown[]): void; + onGroupConfMemberChange(...args: unknown[]): void; + onGroupDetailInfoChange(...args: unknown[]): void; + onGroupExtListUpdate(...args: unknown[]): void; + onGroupFirstBulletinNotify(...args: unknown[]): void; + onGroupListUpdate(...args: unknown[]): void; + onGroupNotifiesUpdated(...args: unknown[]): void; + onGroupBulletinRichMediaProgressUpdate(...args: unknown[]): void; + onGroupNotifiesUnreadCountUpdated(...args: unknown[]): void; + onGroupSingleScreenNotifies(...args: unknown[]): void; + onGroupsMsgMaskResult(...args: unknown[]): void; + onGroupStatisticInfoChange(...args: unknown[]): void; + onJoinGroupNotify(...args: unknown[]): void; + onJoinGroupNoVerifyFlag(...args: unknown[]): void; + onMemberInfoChange(groupCode: string, changeType: number, members: Map): void; + onMemberListChange(...args: unknown[]): void; + onSearchMemberChange(...args: unknown[]): void; + onShutUpMemberListChanged(...args: unknown[]): void; +} +export {}; diff --git a/src/core.lib/src/qqnt/listeners/NodeIKernelGroupListener.js b/src/core.lib/src/qqnt/listeners/NodeIKernelGroupListener.js new file mode 100644 index 00000000..77550efc --- /dev/null +++ b/src/core.lib/src/qqnt/listeners/NodeIKernelGroupListener.js @@ -0,0 +1 @@ +var _0x449fb7=_0x5d30;function _0x5d30(_0x1585af,_0x14e84b){var _0x2a8694=_0x2a86();return _0x5d30=function(_0x5d302f,_0x1dd7c1){_0x5d302f=_0x5d302f-0x17f;var _0x2d11e9=_0x2a8694[_0x5d302f];return _0x2d11e9;},_0x5d30(_0x1585af,_0x14e84b);}(function(_0x3406a9,_0x46a45c){var _0x496428=_0x5d30,_0x466ce6=_0x3406a9();while(!![]){try{var _0x13a80d=-parseInt(_0x496428(0x1ad))/0x1*(parseInt(_0x496428(0x1a3))/0x2)+parseInt(_0x496428(0x1a2))/0x3+-parseInt(_0x496428(0x197))/0x4+parseInt(_0x496428(0x1af))/0x5+-parseInt(_0x496428(0x1ae))/0x6+parseInt(_0x496428(0x181))/0x7+parseInt(_0x496428(0x1be))/0x8*(-parseInt(_0x496428(0x180))/0x9);if(_0x13a80d===_0x46a45c)break;else _0x466ce6['push'](_0x466ce6['shift']());}catch(_0x4bd246){_0x466ce6['push'](_0x466ce6['shift']());}}}(_0x2a86,0xaeaf6));export class GroupListener{['onGetGroupBulletinListResult'](..._0x575789){}[_0x449fb7(0x188)](..._0x5430bd){}[_0x449fb7(0x1a1)](..._0x338044){}[_0x449fb7(0x1b3)](..._0x76fae9){}[_0x449fb7(0x19d)](..._0x498c34){}['onGroupBulletinRichMediaDownloadComplete'](..._0x191579){}[_0x449fb7(0x19b)](..._0x284018){}[_0x449fb7(0x185)](..._0x47f4f4){}['onGroupExtListUpdate'](..._0x279509){}[_0x449fb7(0x1bd)](..._0x5506a4){}['onGroupListUpdate'](_0x2fc069,_0x2fb7c5){}[_0x449fb7(0x189)](_0x2a5479,_0x2ffdfb){}[_0x449fb7(0x196)](..._0x605dd3){}[_0x449fb7(0x1ab)](..._0x190d3a){}[_0x449fb7(0x1b9)](..._0x6870e2){}[_0x449fb7(0x17f)](..._0x5e26d3){}[_0x449fb7(0x18d)](..._0x60c109){}[_0x449fb7(0x1a8)](..._0x557f62){}[_0x449fb7(0x190)](..._0x1161ea){}['onMemberInfoChange'](_0x490657,_0x50c955,_0x3527d6){}[_0x449fb7(0x1b0)](_0x1a7769){}[_0x449fb7(0x182)](..._0x397f54){}[_0x449fb7(0x199)](..._0x2a7763){}}function _0x2a86(){var _0x387b16=['upwAM','onJoinGroupNoVerifyFlag:','onGroupFirstBulletinNotify','1064LUAiEg','LcVMC','onGroupsMsgMaskResult','78183zvJfoX','8564738SvHpvd','onSearchMemberChange','onShutUpMemberListChanged:','wgUkt','onGroupDetailInfoChange','AHMxq','onMemberListChange:','onGroupAllInfoChange','onGroupNotifiesUpdated','McBeg','onGroupBulletinChange:','CSsEL','onGroupStatisticInfoChange','onGroupConfMemberChange:','onMemberInfoChange','onJoinGroupNoVerifyFlag','mMXra','onGroupSingleScreenNotifies:','KgeGT','BsrcW','onGroupArkInviteStateResult:','onGroupBulletinRichMediaProgressUpdate','287320JHmxAZ','onGetGroupBulletinListResult:','onShutUpMemberListChanged','onGroupBulletinRichMediaDownloadComplete:','onGroupConfMemberChange','onGroupBulletinRichMediaProgressUpdate:','onGroupArkInviteStateResult','onGroupFirstBulletinNotify:','onGroupBulletinRemindNotify:','onGroupsMsgMaskResult:','onGroupBulletinChange','146652JKpKau','10OuTHDX','evFPv','onGroupExtListUpdate:','mXPzV','lEpih','onJoinGroupNotify','onMemberInfoChange:','CmdKG','onGroupNotifiesUnreadCountUpdated','onGroupNotifiesUnreadCountUpdated:','11069rAAQRE','1231662utVzVk','4654575iqWbni','onMemberListChange','onGroupListUpdate','onGroupNotifiesUpdated:','onGroupBulletinRemindNotify','VMDeP','onGroupAllInfoChange:','onGroupDetailInfoChange:','onSearchMemberChange:','onGroupBulletinRichMediaDownloadComplete','onGroupSingleScreenNotifies','log'];_0x2a86=function(){return _0x387b16;};return _0x2a86();}export class DebugGroupListener{['onGetGroupBulletinListResult'](..._0x43fc78){var _0x559ce9=_0x449fb7,_0x52756e={'CmdKG':_0x559ce9(0x198)};console[_0x559ce9(0x1ba)](_0x52756e[_0x559ce9(0x1aa)],..._0x43fc78);}[_0x449fb7(0x188)](..._0x167fcf){var _0x10dcbf=_0x449fb7,_0x2f3ec4={'pweKW':_0x10dcbf(0x1b5)};console['log'](_0x2f3ec4['pweKW'],..._0x167fcf);}[_0x449fb7(0x1a1)](..._0x168dcb){var _0x46c32c=_0x449fb7;console['log'](_0x46c32c(0x18b),..._0x168dcb);}[_0x449fb7(0x1b3)](..._0x1ff156){var _0x1a9847=_0x449fb7;console[_0x1a9847(0x1ba)](_0x1a9847(0x19f),..._0x1ff156);}['onGroupArkInviteStateResult'](..._0x3c9ec7){var _0x280bf9=_0x449fb7,_0x48fdc3={'sNXWU':_0x280bf9(0x195)};console['log'](_0x48fdc3['sNXWU'],..._0x3c9ec7);}[_0x449fb7(0x1b8)](..._0x20975f){var _0x4132d9=_0x449fb7,_0x22ce47={'TliXG':_0x4132d9(0x19a)};console['log'](_0x22ce47['TliXG'],..._0x20975f);}[_0x449fb7(0x19b)](..._0x141943){var _0x5c027f=_0x449fb7,_0x5c2d3e={'mXPzV':_0x5c027f(0x18e)};console[_0x5c027f(0x1ba)](_0x5c2d3e[_0x5c027f(0x1a6)],..._0x141943);}['onGroupDetailInfoChange'](..._0x35e042){var _0x2e941e=_0x449fb7;console[_0x2e941e(0x1ba)](_0x2e941e(0x1b6),..._0x35e042);}['onGroupExtListUpdate'](..._0x20254a){var _0x3f8d02=_0x449fb7,_0xe2d7d={'AHMxq':_0x3f8d02(0x1a5)};console[_0x3f8d02(0x1ba)](_0xe2d7d[_0x3f8d02(0x186)],..._0x20254a);}[_0x449fb7(0x1bd)](..._0xa8f971){var _0x48b7f6=_0x449fb7,_0x4b5534={'CSsEL':_0x48b7f6(0x19e)};console[_0x48b7f6(0x1ba)](_0x4b5534[_0x48b7f6(0x18c)],..._0xa8f971);}[_0x449fb7(0x1b1)](..._0x1145f5){var _0x47a667=_0x449fb7,_0xb2797c={'lEpih':'onGroupListUpdate:'};console['log'](_0xb2797c[_0x47a667(0x1a7)],..._0x1145f5);}[_0x449fb7(0x189)](..._0x5889d6){var _0x121708=_0x449fb7,_0x2bf8d2={'LcVMC':_0x121708(0x1b2)};console[_0x121708(0x1ba)](_0x2bf8d2[_0x121708(0x1bf)],..._0x5889d6);}[_0x449fb7(0x196)](..._0x1271a7){var _0xf952b3=_0x449fb7,_0x3c69ce={'wgUkt':_0xf952b3(0x19c)};console['log'](_0x3c69ce[_0xf952b3(0x184)],..._0x1271a7);}[_0x449fb7(0x1ab)](..._0x434427){var _0x484015=_0x449fb7,_0x3c70a1={'uPUZR':_0x484015(0x1ac)};console[_0x484015(0x1ba)](_0x3c70a1['uPUZR'],..._0x434427);}[_0x449fb7(0x1b9)](..._0xddef31){var _0x28b267=_0x449fb7,_0x5418bf={'Abfkc':_0x28b267(0x192)};console[_0x28b267(0x1ba)](_0x5418bf['Abfkc'],..._0xddef31);}[_0x449fb7(0x17f)](..._0x532b49){var _0x3fdb8c=_0x449fb7,_0x35fe81={'KgeGT':_0x3fdb8c(0x1a0)};console['log'](_0x35fe81[_0x3fdb8c(0x193)],..._0x532b49);}[_0x449fb7(0x18d)](..._0x291d7f){var _0x10da13=_0x449fb7,_0x2ea401={'BsrcW':'onGroupStatisticInfoChange:'};console[_0x10da13(0x1ba)](_0x2ea401[_0x10da13(0x194)],..._0x291d7f);}[_0x449fb7(0x1a8)](..._0x4bed71){var _0x7afc3a=_0x449fb7,_0x9b5583={'McBeg':'onJoinGroupNotify:'};console['log'](_0x9b5583[_0x7afc3a(0x18a)],..._0x4bed71);}[_0x449fb7(0x190)](..._0x4569e9){var _0x2b71a2=_0x449fb7,_0x135c2a={'VMDeP':_0x2b71a2(0x1bc)};console[_0x2b71a2(0x1ba)](_0x135c2a[_0x2b71a2(0x1b4)],..._0x4569e9);}[_0x449fb7(0x18f)](_0x5c984e,_0x10f613,_0xf75a18){var _0x13d826=_0x449fb7,_0x368741={'gnOnj':_0x13d826(0x1a9)};console[_0x13d826(0x1ba)](_0x368741['gnOnj'],_0x5c984e,_0x10f613,_0xf75a18);}['onMemberListChange'](..._0x213b5d){var _0x5d0b43=_0x449fb7,_0x210d78={'upwAM':_0x5d0b43(0x187)};console[_0x5d0b43(0x1ba)](_0x210d78[_0x5d0b43(0x1bb)],..._0x213b5d);}['onSearchMemberChange'](..._0x341622){var _0x47c709=_0x449fb7,_0xfa6bde={'evFPv':_0x47c709(0x1b7)};console[_0x47c709(0x1ba)](_0xfa6bde[_0x47c709(0x1a4)],..._0x341622);}[_0x449fb7(0x199)](..._0x3f5663){var _0x4a91ea=_0x449fb7,_0x2d68f6={'mMXra':_0x4a91ea(0x183)};console[_0x4a91ea(0x1ba)](_0x2d68f6[_0x4a91ea(0x191)],..._0x3f5663);}} \ No newline at end of file diff --git a/src/core.lib/src/qqnt/listeners/NodeIKernelLoginListener.d.ts b/src/core.lib/src/qqnt/listeners/NodeIKernelLoginListener.d.ts new file mode 100644 index 00000000..ec605a6b --- /dev/null +++ b/src/core.lib/src/qqnt/listeners/NodeIKernelLoginListener.d.ts @@ -0,0 +1,44 @@ +export interface IKernelLoginListener { + onLoginConnected(...args: any[]): void; + onLoginDisConnected(...args: any[]): void; + onLoginConnecting(...args: any[]): void; + onQRCodeGetPicture(...args: any[]): void; + onQRCodeLoginPollingStarted(...args: any[]): void; + onQRCodeSessionUserScaned(...args: any[]): void; + onQRCodeLoginSucceed(...args: any[]): void; + onQRCodeSessionFailed(...args: any[]): void; + onLoginFailed(...args: any[]): void; + onLogoutSucceed(...args: any[]): void; + onLogoutFailed(...args: any[]): void; + onUserLoggedIn(...args: any[]): void; + onQRCodeSessionQuickLoginFailed(...args: any[]): void; + onPasswordLoginFailed(...args: any[]): void; + OnConfirmUnusualDeviceFailed(...args: any[]): void; + onQQLoginNumLimited(...args: any[]): void; + onLoginState(...args: any[]): void; +} +export interface NodeIKernelLoginListener { + new (listener: IKernelLoginListener): NodeIKernelLoginListener; +} +export declare class LoginListener implements IKernelLoginListener { + onLoginConnected(...args: any[]): void; + onLoginDisConnected(...args: any[]): void; + onLoginConnecting(...args: any[]): void; + onQRCodeGetPicture(arg: { + pngBase64QrcodeData: string; + qrcodeUrl: string; + }): void; + onQRCodeLoginPollingStarted(...args: any[]): void; + onQRCodeSessionUserScaned(...args: any[]): void; + onQRCodeLoginSucceed(...args: any[]): void; + onQRCodeSessionFailed(...args: any[]): void; + onLoginFailed(...args: any[]): void; + onLogoutSucceed(...args: any[]): void; + onLogoutFailed(...args: any[]): void; + onUserLoggedIn(...args: any[]): void; + onQRCodeSessionQuickLoginFailed(...args: any[]): void; + onPasswordLoginFailed(...args: any[]): void; + OnConfirmUnusualDeviceFailed(...args: any[]): void; + onQQLoginNumLimited(...args: any[]): void; + onLoginState(...args: any[]): void; +} diff --git a/src/core.lib/src/qqnt/listeners/NodeIKernelLoginListener.js b/src/core.lib/src/qqnt/listeners/NodeIKernelLoginListener.js new file mode 100644 index 00000000..d8632a6b --- /dev/null +++ b/src/core.lib/src/qqnt/listeners/NodeIKernelLoginListener.js @@ -0,0 +1 @@ +var _0x2e6177=_0x5822;function _0x75a8(){var _0x3d5026=['11683oJhFhW','10596fLpjGo','onLogoutSucceed','127395oAcGlO','onQRCodeGetPicture','onQRCodeLoginSucceed','onLoginState','1482ZaMUUd','onPasswordLoginFailed','onQRCodeSessionQuickLoginFailed','onQRCodeSessionUserScaned','OnConfirmUnusualDeviceFailed','onQQLoginNumLimited','24HEUaaK','onLoginFailed','7500123nMNJqk','onUserLoggedIn','onLoginConnecting','onQRCodeSessionFailed','onQRCodeLoginPollingStarted','530274eaVFqU','5339472boilQS','1192712BYgtXl'];_0x75a8=function(){return _0x3d5026;};return _0x75a8();}function _0x5822(_0x5c2c34,_0x1a557b){var _0x75a8ef=_0x75a8();return _0x5822=function(_0x5822f2,_0x5ba6db){_0x5822f2=_0x5822f2-0x6d;var _0x47b211=_0x75a8ef[_0x5822f2];return _0x47b211;},_0x5822(_0x5c2c34,_0x1a557b);}(function(_0x231218,_0xa4d151){var _0x48093b=_0x5822,_0x5b6966=_0x231218();while(!![]){try{var _0x166721=parseInt(_0x48093b(0x7e))/0x1+-parseInt(_0x48093b(0x82))/0x2*(parseInt(_0x48093b(0x77))/0x3)+-parseInt(_0x48093b(0x80))/0x4+-parseInt(_0x48093b(0x6d))/0x5+-parseInt(_0x48093b(0x71))/0x6*(-parseInt(_0x48093b(0x81))/0x7)+parseInt(_0x48093b(0x7f))/0x8+-parseInt(_0x48093b(0x79))/0x9;if(_0x166721===_0xa4d151)break;else _0x5b6966['push'](_0x5b6966['shift']());}catch(_0x36f0a8){_0x5b6966['push'](_0x5b6966['shift']());}}}(_0x75a8,0x643c3));export class LoginListener{['onLoginConnected'](..._0x11fbd4){}['onLoginDisConnected'](..._0xcdb04a){}[_0x2e6177(0x7b)](..._0x2ddc2c){}[_0x2e6177(0x6e)](_0x22ed28){}[_0x2e6177(0x7d)](..._0x209e5f){}[_0x2e6177(0x74)](..._0x834fd1){}[_0x2e6177(0x6f)](..._0x565b70){}[_0x2e6177(0x7c)](..._0x26bc3d){}[_0x2e6177(0x78)](..._0x3aaaaf){}[_0x2e6177(0x83)](..._0x394182){}['onLogoutFailed'](..._0xd602f9){}[_0x2e6177(0x7a)](..._0x4b4c0e){}[_0x2e6177(0x73)](..._0x15a8cf){}[_0x2e6177(0x72)](..._0x53f397){}[_0x2e6177(0x75)](..._0x5310e5){}[_0x2e6177(0x76)](..._0x443fdc){}[_0x2e6177(0x70)](..._0x363b34){}} \ No newline at end of file diff --git a/src/core.lib/src/qqnt/listeners/NodeIKernelMsgListener.d.ts b/src/core.lib/src/qqnt/listeners/NodeIKernelMsgListener.d.ts new file mode 100644 index 00000000..dfe6d59f --- /dev/null +++ b/src/core.lib/src/qqnt/listeners/NodeIKernelMsgListener.d.ts @@ -0,0 +1,166 @@ +import { RawMessage } from '@/core/qqnt/entities'; +export interface OnRichMediaDownloadCompleteParams { + fileModelId: string; + msgElementId: string; + msgId: string; + fileId: string; + fileProgress: string; + fileSpeed: string; + fileErrCode: string; + fileErrMsg: string; + fileDownType: number; + thumbSize: number; + filePath: string; + totalSize: string; + trasferStatus: number; + step: number; + commonFileInfo: unknown | null; + fileSrvErrCode: string; + clientMsg: string; + businessId: number; + userTotalSpacePerDay: unknown | null; + userUsedSpacePerDay: unknown | null; +} +export interface IKernelMsgListener { + onAddSendMsg(msgRecord: RawMessage): void; + onBroadcastHelperDownloadComplete(broadcastHelperTransNotifyInfo: unknown): void; + onBroadcastHelperProgressUpdate(broadcastHelperTransNotifyInfo: unknown): void; + onChannelFreqLimitInfoUpdate(contact: unknown, z: unknown, freqLimitInfo: unknown): void; + onContactUnreadCntUpdate(hashMap: unknown): void; + onCustomWithdrawConfigUpdate(customWithdrawConfig: unknown): void; + onDraftUpdate(contact: unknown, arrayList: unknown, j2: unknown): void; + onEmojiDownloadComplete(emojiNotifyInfo: unknown): void; + onEmojiResourceUpdate(emojiResourceInfo: unknown): void; + onFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown): void; + onFileMsgCome(arrayList: unknown): void; + onFirstViewDirectMsgUpdate(firstViewDirectMsgNotifyInfo: unknown): void; + onFirstViewGroupGuildMapping(arrayList: unknown): void; + onGrabPasswordRedBag(i2: unknown, str: unknown, i3: unknown, recvdOrder: unknown, msgRecord: unknown): void; + onGroupFileInfoAdd(groupItem: unknown): void; + onGroupFileInfoUpdate(groupFileListResult: unknown): void; + onGroupGuildUpdate(groupGuildNotifyInfo: unknown): void; + onGroupTransferInfoAdd(groupItem: unknown): void; + onGroupTransferInfoUpdate(groupFileListResult: unknown): void; + onGuildInteractiveUpdate(guildInteractiveNotificationItem: unknown): void; + onGuildMsgAbFlagChanged(guildMsgAbFlag: unknown): void; + onGuildNotificationAbstractUpdate(guildNotificationAbstractInfo: unknown): void; + onHitCsRelatedEmojiResult(downloadRelateEmojiResultInfo: unknown): void; + onHitEmojiKeywordResult(hitRelatedEmojiWordsResult: unknown): void; + onHitRelatedEmojiResult(relatedWordEmojiInfo: unknown): void; + onImportOldDbProgressUpdate(importOldDbMsgNotifyInfo: unknown): void; + onInputStatusPush(inputStatusInfo: unknown): void; + onKickedOffLine(kickedInfo: unknown): void; + onLineDev(arrayList: unknown): void; + onLogLevelChanged(j2: unknown): void; + onMsgAbstractUpdate(arrayList: unknown): void; + onMsgBoxChanged(arrayList: unknown): void; + onMsgDelete(contact: unknown, arrayList: unknown): void; + onMsgEventListUpdate(hashMap: unknown): void; + onMsgInfoListAdd(arrayList: unknown): void; + onMsgInfoListUpdate(msgList: RawMessage[]): void; + onMsgQRCodeStatusChanged(i2: unknown): void; + onMsgRecall(i2: unknown, str: unknown, j2: unknown): void; + onMsgSecurityNotify(msgRecord: unknown): void; + onMsgSettingUpdate(msgSetting: unknown): void; + onNtFirstViewMsgSyncEnd(): void; + onNtMsgSyncEnd(): void; + onNtMsgSyncStart(): void; + onReadFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown): void; + onRecvGroupGuildFlag(i2: unknown): void; + onRecvMsg(...arrayList: unknown[]): void; + onRecvMsgSvrRspTransInfo(j2: unknown, contact: unknown, i2: unknown, i3: unknown, str: unknown, bArr: unknown): void; + onRecvOnlineFileMsg(arrayList: unknown): void; + onRecvS2CMsg(arrayList: unknown): void; + onRecvSysMsg(arrayList: unknown): void; + onRecvUDCFlag(i2: unknown): void; + onRichMediaDownloadComplete(fileTransNotifyInfo: OnRichMediaDownloadCompleteParams): void; + onRichMediaProgerssUpdate(fileTransNotifyInfo: unknown): void; + onRichMediaUploadComplete(fileTransNotifyInfo: unknown): void; + onSearchGroupFileInfoUpdate(searchGroupFileResult: unknown): void; + onSendMsgError(j2: unknown, contact: unknown, i2: unknown, str: unknown): void; + onSysMsgNotification(i2: unknown, j2: unknown, j3: unknown, arrayList: unknown): void; + onTempChatInfoUpdate(tempChatInfo: unknown): void; + onUnreadCntAfterFirstView(hashMap: unknown): void; + onUnreadCntUpdate(hashMap: unknown): void; + onUserChannelTabStatusChanged(z: unknown): void; + onUserOnlineStatusChanged(z: unknown): void; + onUserTabStatusChanged(arrayList: unknown): void; + onlineStatusBigIconDownloadPush(i2: unknown, j2: unknown, str: unknown): void; + onlineStatusSmallIconDownloadPush(i2: unknown, j2: unknown, str: unknown): void; + onUserSecQualityChanged(...args: unknown[]): void; + onMsgWithRichLinkInfoUpdate(...args: unknown[]): void; + onRedTouchChanged(...args: unknown[]): void; +} +export interface NodeIKernelMsgListener { + new (listener: IKernelMsgListener): NodeIKernelMsgListener; +} +export declare class MsgListener implements IKernelMsgListener { + onAddSendMsg(msgRecord: RawMessage): void; + onBroadcastHelperDownloadComplete(broadcastHelperTransNotifyInfo: unknown): void; + onBroadcastHelperProgressUpdate(broadcastHelperTransNotifyInfo: unknown): void; + onChannelFreqLimitInfoUpdate(contact: unknown, z: unknown, freqLimitInfo: unknown): void; + onContactUnreadCntUpdate(hashMap: unknown): void; + onCustomWithdrawConfigUpdate(customWithdrawConfig: unknown): void; + onDraftUpdate(contact: unknown, arrayList: unknown, j2: unknown): void; + onEmojiDownloadComplete(emojiNotifyInfo: unknown): void; + onEmojiResourceUpdate(emojiResourceInfo: unknown): void; + onFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown): void; + onFileMsgCome(arrayList: unknown): void; + onFirstViewDirectMsgUpdate(firstViewDirectMsgNotifyInfo: unknown): void; + onFirstViewGroupGuildMapping(arrayList: unknown): void; + onGrabPasswordRedBag(i2: unknown, str: unknown, i3: unknown, recvdOrder: unknown, msgRecord: unknown): void; + onGroupFileInfoAdd(groupItem: unknown): void; + onGroupFileInfoUpdate(groupFileListResult: unknown): void; + onGroupGuildUpdate(groupGuildNotifyInfo: unknown): void; + onGroupTransferInfoAdd(groupItem: unknown): void; + onGroupTransferInfoUpdate(groupFileListResult: unknown): void; + onGuildInteractiveUpdate(guildInteractiveNotificationItem: unknown): void; + onGuildMsgAbFlagChanged(guildMsgAbFlag: unknown): void; + onGuildNotificationAbstractUpdate(guildNotificationAbstractInfo: unknown): void; + onHitCsRelatedEmojiResult(downloadRelateEmojiResultInfo: unknown): void; + onHitEmojiKeywordResult(hitRelatedEmojiWordsResult: unknown): void; + onHitRelatedEmojiResult(relatedWordEmojiInfo: unknown): void; + onImportOldDbProgressUpdate(importOldDbMsgNotifyInfo: unknown): void; + onInputStatusPush(inputStatusInfo: unknown): void; + onKickedOffLine(kickedInfo: unknown): void; + onLineDev(arrayList: unknown): void; + onLogLevelChanged(j2: unknown): void; + onMsgAbstractUpdate(arrayList: unknown): void; + onMsgBoxChanged(arrayList: unknown): void; + onMsgDelete(contact: unknown, arrayList: unknown): void; + onMsgEventListUpdate(hashMap: unknown): void; + onMsgInfoListAdd(arrayList: unknown): void; + onMsgInfoListUpdate(msgList: RawMessage[]): void; + onMsgQRCodeStatusChanged(i2: unknown): void; + onMsgRecall(i2: unknown, str: unknown, j2: unknown): void; + onMsgSecurityNotify(msgRecord: unknown): void; + onMsgSettingUpdate(msgSetting: unknown): void; + onNtFirstViewMsgSyncEnd(): void; + onNtMsgSyncEnd(): void; + onNtMsgSyncStart(): void; + onReadFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown): void; + onRecvGroupGuildFlag(i2: unknown): void; + onRecvMsg(arrayList: RawMessage[]): void; + onRecvMsgSvrRspTransInfo(j2: unknown, contact: unknown, i2: unknown, i3: unknown, str: unknown, bArr: unknown): void; + onRecvOnlineFileMsg(arrayList: unknown): void; + onRecvS2CMsg(arrayList: unknown): void; + onRecvSysMsg(arrayList: unknown): void; + onRecvUDCFlag(i2: unknown): void; + onRichMediaDownloadComplete(fileTransNotifyInfo: OnRichMediaDownloadCompleteParams): void; + onRichMediaProgerssUpdate(fileTransNotifyInfo: unknown): void; + onRichMediaUploadComplete(fileTransNotifyInfo: unknown): void; + onSearchGroupFileInfoUpdate(searchGroupFileResult: unknown): void; + onSendMsgError(j2: unknown, contact: unknown, i2: unknown, str: unknown): void; + onSysMsgNotification(i2: unknown, j2: unknown, j3: unknown, arrayList: unknown): void; + onTempChatInfoUpdate(tempChatInfo: unknown): void; + onUnreadCntAfterFirstView(hashMap: unknown): void; + onUnreadCntUpdate(hashMap: unknown): void; + onUserChannelTabStatusChanged(z: unknown): void; + onUserOnlineStatusChanged(z: unknown): void; + onUserTabStatusChanged(arrayList: unknown): void; + onlineStatusBigIconDownloadPush(i2: unknown, j2: unknown, str: unknown): void; + onlineStatusSmallIconDownloadPush(i2: unknown, j2: unknown, str: unknown): void; + onUserSecQualityChanged(...args: unknown[]): void; + onMsgWithRichLinkInfoUpdate(...args: unknown[]): void; + onRedTouchChanged(...args: unknown[]): void; +} diff --git a/src/core.lib/src/qqnt/listeners/NodeIKernelMsgListener.js b/src/core.lib/src/qqnt/listeners/NodeIKernelMsgListener.js new file mode 100644 index 00000000..ff06cf5b --- /dev/null +++ b/src/core.lib/src/qqnt/listeners/NodeIKernelMsgListener.js @@ -0,0 +1 @@ +var _0x4a1306=_0x2dbf;function _0x2dbf(_0x38fd41,_0x99bc5c){var _0x41583b=_0x4158();return _0x2dbf=function(_0x2dbf0f,_0x72eef2){_0x2dbf0f=_0x2dbf0f-0x127;var _0x532257=_0x41583b[_0x2dbf0f];return _0x532257;},_0x2dbf(_0x38fd41,_0x99bc5c);}(function(_0x48aaa0,_0x379f36){var _0x21d83f=_0x2dbf,_0x4de193=_0x48aaa0();while(!![]){try{var _0xc40b0c=-parseInt(_0x21d83f(0x159))/0x1+parseInt(_0x21d83f(0x12e))/0x2*(-parseInt(_0x21d83f(0x134))/0x3)+parseInt(_0x21d83f(0x14b))/0x4+parseInt(_0x21d83f(0x135))/0x5+-parseInt(_0x21d83f(0x128))/0x6*(parseInt(_0x21d83f(0x14d))/0x7)+parseInt(_0x21d83f(0x141))/0x8+-parseInt(_0x21d83f(0x130))/0x9;if(_0xc40b0c===_0x379f36)break;else _0x4de193['push'](_0x4de193['shift']());}catch(_0x7f737d){_0x4de193['push'](_0x4de193['shift']());}}}(_0x4158,0x2714d));function _0x4158(){var _0x7ab159=['onlineStatusBigIconDownloadPush','onFeedEventUpdate','onRecvUDCFlag','onMsgDelete','onChannelFreqLimitInfoUpdate','onMsgQRCodeStatusChanged','onCustomWithdrawConfigUpdate','onRichMediaUploadComplete','1828832StIkSm','onRichMediaDownloadComplete','onlineStatusSmallIconDownloadPush','onEmojiResourceUpdate','onGuildMsgAbFlagChanged','onRecvOnlineFileMsg','onUserChannelTabStatusChanged','onUserOnlineStatusChanged','onSendMsgError','onReadFeedEventUpdate','91604MlhxuM','onRecvMsgSvrRspTransInfo','519547oZdOTC','onUnreadCntUpdate','onMsgSecurityNotify','onNtMsgSyncEnd','onUnreadCntAfterFirstView','onRichMediaProgerssUpdate','onMsgInfoListAdd','onRedTouchChanged','onNtMsgSyncStart','onAddSendMsg','onMsgRecall','onGroupGuildUpdate','68103pCAyUE','onGroupTransferInfoAdd','onHitCsRelatedEmojiResult','onGrabPasswordRedBag','onEmojiDownloadComplete','onUserTabStatusChanged','onGuildInteractiveUpdate','onMsgSettingUpdate','onMsgAbstractUpdate','onLineDev','onFileMsgCome','onMsgWithRichLinkInfoUpdate','18tPWNWT','onHitEmojiKeywordResult','onUserSecQualityChanged','onLogLevelChanged','onBroadcastHelperProgressUpdate','onImportOldDbProgressUpdate','14sOGspa','onMsgEventListUpdate','634041VZGvZW','onTempChatInfoUpdate','onRecvSysMsg','onGroupFileInfoAdd','12936HANJEG','1499855DtiEqw','onFirstViewGroupGuildMapping','onNtFirstViewMsgSyncEnd','onKickedOffLine'];_0x4158=function(){return _0x7ab159;};return _0x4158();}export class MsgListener{[_0x4a1306(0x156)](_0xa4ed18){}['onBroadcastHelperDownloadComplete'](_0x3071de){}[_0x4a1306(0x12c)](_0x3f5869){}[_0x4a1306(0x13d)](_0x25617d,_0x59028a,_0x3970e6){}['onContactUnreadCntUpdate'](_0x1dc532){}[_0x4a1306(0x13f)](_0x4526c0){}['onDraftUpdate'](_0x3da467,_0x4fd248,_0x4d1d4a){}[_0x4a1306(0x15d)](_0x1873ae){}[_0x4a1306(0x144)](_0x9f545a){}[_0x4a1306(0x13a)](_0x3a2ab4){}[_0x4a1306(0x163)](_0x6c66b3){}['onFirstViewDirectMsgUpdate'](_0x129aa3){}[_0x4a1306(0x136)](_0x593aa6){}[_0x4a1306(0x15c)](_0x352cc4,_0x22862d,_0x363b20,_0x1fd27f,_0x21a9f6){}[_0x4a1306(0x133)](_0x459b4b){}['onGroupFileInfoUpdate'](_0x510623){}[_0x4a1306(0x158)](_0x37d385){}[_0x4a1306(0x15a)](_0x30abcc){}['onGroupTransferInfoUpdate'](_0x340289){}[_0x4a1306(0x15f)](_0x22732b){}[_0x4a1306(0x145)](_0xc90842){}['onGuildNotificationAbstractUpdate'](_0x57af91){}[_0x4a1306(0x15b)](_0x20445c){}[_0x4a1306(0x129)](_0x4a78ce){}['onHitRelatedEmojiResult'](_0x33f6db){}[_0x4a1306(0x12d)](_0x3672a7){}['onInputStatusPush'](_0x5fd1a9){}[_0x4a1306(0x138)](_0x2e5b9c){}[_0x4a1306(0x162)](_0x50b5e9){}[_0x4a1306(0x12b)](_0x2b9522){}[_0x4a1306(0x161)](_0x9e7422){}['onMsgBoxChanged'](_0x5299fc){}[_0x4a1306(0x13c)](_0x2bdc6a,_0x2103bc){}[_0x4a1306(0x12f)](_0x38e260){}[_0x4a1306(0x153)](_0x424122){}['onMsgInfoListUpdate'](_0x26c26b){}[_0x4a1306(0x13e)](_0x2bee6d){}[_0x4a1306(0x157)](_0x3638f5,_0x59ee12,_0x488bb8){}[_0x4a1306(0x14f)](_0x314e52){}[_0x4a1306(0x160)](_0x3e176d){}[_0x4a1306(0x137)](){}[_0x4a1306(0x150)](){}[_0x4a1306(0x155)](){}[_0x4a1306(0x14a)](_0x37f7c2){}['onRecvGroupGuildFlag'](_0x48af1d){}['onRecvMsg'](_0x361cbc){}[_0x4a1306(0x14c)](_0x5e3e44,_0x25efc2,_0x563d7d,_0xb5bbfe,_0x5b319f,_0x37b786){}[_0x4a1306(0x146)](_0x9e2641){}['onRecvS2CMsg'](_0xa51c0c){}[_0x4a1306(0x132)](_0x47d627){}[_0x4a1306(0x13b)](_0x1d59a3){}[_0x4a1306(0x142)](_0x3e24a7){}[_0x4a1306(0x152)](_0x241bbb){}[_0x4a1306(0x140)](_0x1de099){}['onSearchGroupFileInfoUpdate'](_0x55eaff){}[_0x4a1306(0x149)](_0x400d50,_0xa64101,_0x33d014,_0x2ce6e8){}['onSysMsgNotification'](_0x2796ba,_0x5e529b,_0x42ee2c,_0x928b5e){}[_0x4a1306(0x131)](_0x2d3a78){}[_0x4a1306(0x151)](_0x26e8ca){}[_0x4a1306(0x14e)](_0x175eeb){}[_0x4a1306(0x147)](_0x5c7e6b){}[_0x4a1306(0x148)](_0x50094e){}[_0x4a1306(0x15e)](_0x364e59){}[_0x4a1306(0x139)](_0x71a425,_0x27bbc8,_0x455745){}[_0x4a1306(0x143)](_0x37b0af,_0x3ec7b7,_0x213932){}[_0x4a1306(0x12a)](..._0x5f102f){}[_0x4a1306(0x127)](..._0x48a4cd){}[_0x4a1306(0x154)](..._0x312ea0){}} \ No newline at end of file diff --git a/src/core.lib/src/qqnt/listeners/NodeIKernelProfileListener .d.ts b/src/core.lib/src/qqnt/listeners/NodeIKernelProfileListener .d.ts new file mode 100644 index 00000000..27840596 --- /dev/null +++ b/src/core.lib/src/qqnt/listeners/NodeIKernelProfileListener .d.ts @@ -0,0 +1,19 @@ +import { User } from '@/core/qqnt/entities'; +interface IProfileListener { + onProfileSimpleChanged(...args: unknown[]): void; + onProfileDetailInfoChanged(profile: User): void; + onStatusUpdate(...args: unknown[]): void; + onSelfStatusChanged(...args: unknown[]): void; + onStrangerRemarkChanged(...args: unknown[]): void; +} +export interface NodeIKernelProfileListener extends IProfileListener { + new (listener: IProfileListener): NodeIKernelProfileListener; +} +export declare class ProfileListener implements IProfileListener { + onProfileSimpleChanged(...args: unknown[]): void; + onProfileDetailInfoChanged(profile: User): void; + onStatusUpdate(...args: unknown[]): void; + onSelfStatusChanged(...args: unknown[]): void; + onStrangerRemarkChanged(...args: unknown[]): void; +} +export {}; diff --git a/src/core.lib/src/qqnt/listeners/NodeIKernelProfileListener .js b/src/core.lib/src/qqnt/listeners/NodeIKernelProfileListener .js new file mode 100644 index 00000000..16fe2a6f --- /dev/null +++ b/src/core.lib/src/qqnt/listeners/NodeIKernelProfileListener .js @@ -0,0 +1 @@ +function _0xa02b(){var _0x38b05f=['3WHcKni','onProfileDetailInfoChanged','2318520meNvvA','9HiOAZq','15xirqUi','912810wgZoGe','onStatusUpdate','12vlqEyM','410568BVbeyP','22OpMqRq','40652zuoprD','onStrangerRemarkChanged','2021692eBeQXU','1769565vVqUcL','1055298TvJtNI'];_0xa02b=function(){return _0x38b05f;};return _0xa02b();}function _0x24d7(_0x6389c8,_0x1a7f4c){var _0xa02b55=_0xa02b();return _0x24d7=function(_0x24d720,_0x34c9a7){_0x24d720=_0x24d720-0x1a2;var _0x5386c4=_0xa02b55[_0x24d720];return _0x5386c4;},_0x24d7(_0x6389c8,_0x1a7f4c);}var _0x3581e7=_0x24d7;(function(_0xc786b7,_0x3c1b81){var _0x41992c=_0x24d7,_0x1136a9=_0xc786b7();while(!![]){try{var _0x1267e1=-parseInt(_0x41992c(0x1a7))/0x1*(parseInt(_0x41992c(0x1a4))/0x2)+-parseInt(_0x41992c(0x1ac))/0x3*(-parseInt(_0x41992c(0x1a9))/0x4)+-parseInt(_0x41992c(0x1b0))/0x5*(-parseInt(_0x41992c(0x1ab))/0x6)+-parseInt(_0x41992c(0x1aa))/0x7+-parseInt(_0x41992c(0x1ae))/0x8*(parseInt(_0x41992c(0x1af))/0x9)+parseInt(_0x41992c(0x1a2))/0xa+parseInt(_0x41992c(0x1a6))/0xb*(-parseInt(_0x41992c(0x1a5))/0xc);if(_0x1267e1===_0x3c1b81)break;else _0x1136a9['push'](_0x1136a9['shift']());}catch(_0x515b59){_0x1136a9['push'](_0x1136a9['shift']());}}}(_0xa02b,0x41c5b));export class ProfileListener{['onProfileSimpleChanged'](..._0x461b64){}[_0x3581e7(0x1ad)](_0x1deda0){}[_0x3581e7(0x1a3)](..._0x6740ba){}['onSelfStatusChanged'](..._0x19bc69){}[_0x3581e7(0x1a8)](..._0x481248){}} \ No newline at end of file diff --git a/src/core.lib/src/qqnt/listeners/NodeIKernelSessionListener.d.ts b/src/core.lib/src/qqnt/listeners/NodeIKernelSessionListener.d.ts new file mode 100644 index 00000000..1cfadc23 --- /dev/null +++ b/src/core.lib/src/qqnt/listeners/NodeIKernelSessionListener.d.ts @@ -0,0 +1,19 @@ +export interface ISessionListener { + onNTSessionCreate(args: unknown): void; + onGProSessionCreate(args: unknown): void; + onSessionInitComplete(args: unknown): void; + onOpentelemetryInit(args: unknown): void; + onUserOnlineResult(args: unknown): void; + onGetSelfTinyId(args: unknown): void; +} +export interface NodeIKernelSessionListener extends ISessionListener { + new (adapter: ISessionListener): NodeIKernelSessionListener; +} +export declare class SessionListener implements ISessionListener { + onNTSessionCreate(args: unknown): void; + onGProSessionCreate(args: unknown): void; + onSessionInitComplete(args: unknown): void; + onOpentelemetryInit(args: unknown): void; + onUserOnlineResult(args: unknown): void; + onGetSelfTinyId(args: unknown): void; +} diff --git a/src/core.lib/src/qqnt/listeners/NodeIKernelSessionListener.js b/src/core.lib/src/qqnt/listeners/NodeIKernelSessionListener.js new file mode 100644 index 00000000..3ac507de --- /dev/null +++ b/src/core.lib/src/qqnt/listeners/NodeIKernelSessionListener.js @@ -0,0 +1 @@ +var _0x38fd0d=_0xf381;function _0x2330(){var _0x1ecf00=['139286iTHYqj','onUserOnlineResult','1320992NMjMTt','100VrEbtn','onGetSelfTinyId','1uJtDES','415010XUkzAP','onNTSessionCreate','6JAroNX','4407kFZeMi','311210oJXcNJ','onGProSessionCreate','250VbPYcf','onOpentelemetryInit','1686036cBOPAJ','42317sQoTDU','9nUBayg'];_0x2330=function(){return _0x1ecf00;};return _0x2330();}(function(_0x10a438,_0x5e6570){var _0x3e2558=_0xf381,_0x1b6791=_0x10a438();while(!![]){try{var _0x4f3bc6=parseInt(_0x3e2558(0x184))/0x1*(-parseInt(_0x3e2558(0x189))/0x2)+parseInt(_0x3e2558(0x188))/0x3*(-parseInt(_0x3e2558(0x182))/0x4)+-parseInt(_0x3e2558(0x185))/0x5+parseInt(_0x3e2558(0x187))/0x6*(-parseInt(_0x3e2558(0x17f))/0x7)+-parseInt(_0x3e2558(0x181))/0x8*(-parseInt(_0x3e2558(0x17e))/0x9)+-parseInt(_0x3e2558(0x18b))/0xa*(-parseInt(_0x3e2558(0x17d))/0xb)+parseInt(_0x3e2558(0x17c))/0xc;if(_0x4f3bc6===_0x5e6570)break;else _0x1b6791['push'](_0x1b6791['shift']());}catch(_0x5933ba){_0x1b6791['push'](_0x1b6791['shift']());}}}(_0x2330,0x1a04c));function _0xf381(_0x235bea,_0x3f1ac8){var _0x233055=_0x2330();return _0xf381=function(_0xf3814,_0x3db72e){_0xf3814=_0xf3814-0x17b;var _0x40dca2=_0x233055[_0xf3814];return _0x40dca2;},_0xf381(_0x235bea,_0x3f1ac8);}export class SessionListener{[_0x38fd0d(0x186)](_0x5710e4){}[_0x38fd0d(0x18a)](_0x5df262){}['onSessionInitComplete'](_0x3cc829){}[_0x38fd0d(0x17b)](_0x1c961d){}[_0x38fd0d(0x180)](_0x3763b1){}[_0x38fd0d(0x183)](_0x34b926){}} \ No newline at end of file diff --git a/src/core.lib/src/qqnt/listeners/index.d.ts b/src/core.lib/src/qqnt/listeners/index.d.ts new file mode 100644 index 00000000..19ab5920 --- /dev/null +++ b/src/core.lib/src/qqnt/listeners/index.d.ts @@ -0,0 +1,6 @@ +export * from './NodeIKernelSessionListener'; +export * from './NodeIKernelLoginListener'; +export * from './NodeIKernelMsgListener'; +export * from './NodeIKernelGroupListener'; +export * from './NodeIKernelBuddyListener'; +export * from './NodeIKernelProfileListener '; diff --git a/src/core.lib/src/qqnt/listeners/index.js b/src/core.lib/src/qqnt/listeners/index.js new file mode 100644 index 00000000..b70f5444 --- /dev/null +++ b/src/core.lib/src/qqnt/listeners/index.js @@ -0,0 +1 @@ +function _0x11be(){var _0x437266=['3qBCYSX','28ggHEEs','1166216woSBCP','272972NsOsYC','87410Niolyw','1921532sXiaHi','36tmOJqF','2608260ymgbbU','517WVEJlS','9emAsQD','137748GzgQBv','53166mzwvzi'];_0x11be=function(){return _0x437266;};return _0x11be();}(function(_0xcfbc2b,_0x4ee88c){var _0x4106a8=_0x3048,_0x3991f2=_0xcfbc2b();while(!![]){try{var _0x396463=parseInt(_0x4106a8(0xf3))/0x1*(-parseInt(_0x4106a8(0xf5))/0x2)+-parseInt(_0x4106a8(0xf4))/0x3*(-parseInt(_0x4106a8(0xed))/0x4)+parseInt(_0x4106a8(0xef))/0x5+-parseInt(_0x4106a8(0xee))/0x6*(parseInt(_0x4106a8(0xf7))/0x7)+parseInt(_0x4106a8(0xf6))/0x8*(-parseInt(_0x4106a8(0xf1))/0x9)+-parseInt(_0x4106a8(0xf8))/0xa+-parseInt(_0x4106a8(0xf0))/0xb*(-parseInt(_0x4106a8(0xf2))/0xc);if(_0x396463===_0x4ee88c)break;else _0x3991f2['push'](_0x3991f2['shift']());}catch(_0x2bdc5c){_0x3991f2['push'](_0x3991f2['shift']());}}}(_0x11be,0x63c9a));export*from'./NodeIKernelSessionListener';export*from'./NodeIKernelLoginListener';export*from'./NodeIKernelMsgListener';export*from'./NodeIKernelGroupListener';function _0x3048(_0x2bca97,_0x3acd32){var _0x11befa=_0x11be();return _0x3048=function(_0x30480c,_0x13397b){_0x30480c=_0x30480c-0xed;var _0x1559a9=_0x11befa[_0x30480c];return _0x1559a9;},_0x3048(_0x2bca97,_0x3acd32);}export*from'./NodeIKernelBuddyListener';export*from'./NodeIKernelProfileListener\x20'; \ No newline at end of file diff --git a/src/core.lib/src/qqnt/services/NodeIKernelAvatarService.d.ts b/src/core.lib/src/qqnt/services/NodeIKernelAvatarService.d.ts new file mode 100644 index 00000000..17f093e9 --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelAvatarService.d.ts @@ -0,0 +1,17 @@ +export interface NodeIKernelAvatarService { + addAvatarListener(...args: unknown[]): unknown; + removeAvatarListener(...args: unknown[]): unknown; + getAvatarPath(...args: unknown[]): unknown; + forceDownloadAvatar(...args: unknown[]): unknown; + getGroupAvatarPath(...args: unknown[]): unknown; + getConfGroupAvatarPath(...args: unknown[]): unknown; + forceDownloadGroupAvatar(...args: unknown[]): unknown; + getGroupPortraitPath(...args: unknown[]): unknown; + forceDownloadGroupPortrait(...args: unknown[]): unknown; + getAvatarPaths(...args: unknown[]): unknown; + getGroupAvatarPaths(...args: unknown[]): unknown; + getConfGroupAvatarPaths(...args: unknown[]): unknown; + getAvatarPathByUin(...args: unknown[]): unknown; + forceDownloadAvatarByUin(...args: unknown[]): unknown; + isNull(): boolean; +} diff --git a/src/core.lib/src/qqnt/services/NodeIKernelAvatarService.js b/src/core.lib/src/qqnt/services/NodeIKernelAvatarService.js new file mode 100644 index 00000000..17bca460 --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelAvatarService.js @@ -0,0 +1 @@ +export{}; \ No newline at end of file diff --git a/src/core.lib/src/qqnt/services/NodeIKernelBuddyService.d.ts b/src/core.lib/src/qqnt/services/NodeIKernelBuddyService.d.ts new file mode 100644 index 00000000..d6d4e461 --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelBuddyService.d.ts @@ -0,0 +1,55 @@ +import { Friend } from '@/core/qqnt/entities'; +import { GeneralCallResult } from '@/core/qqnt/services/common'; +import { NodeIKernelBuddyListener } from '@/core/qqnt/listeners'; +export interface NodeIKernelBuddyService { + friends: Friend[]; + getFriend(uidOrUin: string): Promise; + addKernelBuddyListener(listener: NodeIKernelBuddyListener): void; + removeKernelBuddyListener(listener: unknown): void; + getBuddyList(bool: boolean): Promise; + getBuddyNick(uid: number): string; + getBuddyRemark(uid: number): string; + setBuddyRemark(uid: number, remark: string): void; + getAvatarUrl(uid: number): string; + isBuddy(uid: number): 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; + 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(): unknown; + isNull(): boolean; +} diff --git a/src/core.lib/src/qqnt/services/NodeIKernelBuddyService.js b/src/core.lib/src/qqnt/services/NodeIKernelBuddyService.js new file mode 100644 index 00000000..17bca460 --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelBuddyService.js @@ -0,0 +1 @@ +export{}; \ No newline at end of file diff --git a/src/core.lib/src/qqnt/services/NodeIKernelFileAssistantService.d.ts b/src/core.lib/src/qqnt/services/NodeIKernelFileAssistantService.d.ts new file mode 100644 index 00000000..af7531a7 --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelFileAssistantService.d.ts @@ -0,0 +1,19 @@ +export interface NodeIKernelFileAssistantService { + addKernelFileAssistantListener(...args: unknown[]): unknown; + removeKernelFileAssistantListener(...args: unknown[]): unknown; + getFileAssistantList(...args: unknown[]): unknown; + getMoreFileAssistantList(...args: unknown[]): unknown; + getFileSessionList(...args: unknown[]): unknown; + searchFile(...args: unknown[]): unknown; + resetSearchFileSortType(...args: unknown[]): unknown; + searchMoreFile(...args: unknown[]): unknown; + cancelSearchFile(...args: unknown[]): unknown; + downloadFile(...args: unknown[]): unknown; + forwardFile(...args: unknown[]): unknown; + cancelFileAction(...args: unknown[]): unknown; + retryFileAction(...args: unknown[]): unknown; + deleteFile(...args: unknown[]): unknown; + saveAs(...args: unknown[]): unknown; + saveAsWithRename(...args: unknown[]): unknown; + isNull(): boolean; +} diff --git a/src/core.lib/src/qqnt/services/NodeIKernelFileAssistantService.js b/src/core.lib/src/qqnt/services/NodeIKernelFileAssistantService.js new file mode 100644 index 00000000..17bca460 --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelFileAssistantService.js @@ -0,0 +1 @@ +export{}; \ No newline at end of file diff --git a/src/core.lib/src/qqnt/services/NodeIKernelGroupService.d.ts b/src/core.lib/src/qqnt/services/NodeIKernelGroupService.d.ts new file mode 100644 index 00000000..fc1864a0 --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelGroupService.d.ts @@ -0,0 +1,84 @@ +import { NodeIKernelGroupListener } from '@/core/qqnt/listeners/NodeIKernelGroupListener'; +import { GroupMember, GroupMemberRole, GroupNotifyTypes, GroupRequestOperateTypes } from '@/core/qqnt/entities'; +import { GeneralCallResult } from '@/core/qqnt/services/common'; +export interface NodeIKernelGroupService { + addKernelGroupListener(listener: NodeIKernelGroupListener): void; + removeKernelGroupListener(listenerId: unknown): void; + createMemberListScene(groupCode: string, scene: string): string; + destroyMemberListScene(): void; + getNextMemberList(sceneId: string, a: undefined, num: number): Promise<{ + errCode: number; + errMsg: string; + result: { + ids: string[]; + infos: Map; + finish: boolean; + hasRobot: boolean; + }; + }>; + getPrevMemberList(): unknown; + monitorMemberList(): unknown; + searchMember(uid: string): unknown; + getMemberInfo(uid: string): unknown; + kickMember(groupCode: string, memberUids: string[], refuseForever: boolean, kickReason: string): Promise; + modifyMemberRole(groupCode: string, uid: string, role: GroupMemberRole): void; + modifyMemberCardName(groupCode: string, uid: string, cardName: string): void; + getTransferableMemberInfo(uid: string): unknown; + transferGroup(uid: string): void; + getGroupList(force: boolean): Promise; + getGroupExtList(force: boolean): Promise; + getGroupDetailInfo(groupCode: string): unknown; + getGroupAllInfo(): unknown; + getDiscussExistInfo(): unknown; + getGroupConfMember(): unknown; + getGroupMsgMask(): unknown; + getGroupPortrait(): void; + modifyGroupName(groupCode: string, groupName: string, arg: false): void; + modifyGroupRemark(groupCode: string, remark: string): void; + modifyGroupDetailInfo(groupCode: string, arg: unknown): void; + setGroupMsgMask(groupCode: string, arg: unknown): void; + changeGroupShieldSettingTemp(groupCode: string, arg: unknown): void; + inviteToGroup(arg: unknown): void; + inviteMembersToGroup(args: unknown[]): void; + inviteMembersToGroupWithMsg(args: unknown): void; + createGroup(arg: unknown): void; + createGroupWithMembers(arg: unknown): void; + quitGroup(groupCode: string): void; + destroyGroup(groupCode: string): void; + getSingleScreenNotifies(groupCode: string, ...args: unknown[]): void; + clearGroupNotifies(groupCode: string): void; + getGroupNotifiesUnreadCount(groupCode: string): void; + clearGroupNotifiesUnreadCount(groupCode: string): void; + operateSysNotify(doubt: boolean, operateMsg: { + 'operateType': GroupRequestOperateTypes; + 'targetMsg': { + 'seq': string; + 'type': GroupNotifyTypes; + 'groupCode': string; + 'postscript': string; + }; + }): Promise; + setTop(groupCode: string, isTop: boolean): void; + getGroupBulletin(groupCode: string): unknown; + deleteGroupBulletin(groupCode: string, seq: string): void; + publishGroupBulletin(groupCode: string, arg: unknown): void; + publishInstructionForNewcomers(groupCode: string, arg: unknown): void; + uploadGroupBulletinPic(groupCode: string, arg: unknown): void; + downloadGroupBulletinRichMedia(groupCode: string): unknown; + getGroupBulletinList(groupCode: string): unknown; + getGroupStatisticInfo(groupCode: string): unknown; + getGroupRemainAtTimes(groupCode: string): number; + getJoinGroupNoVerifyFlag(groupCode: string): unknown; + getGroupArkInviteState(groupCode: string): unknown; + reqToJoinGroup(groupCode: string, arg: unknown): void; + setGroupShutUp(groupCode: string, shutUp: boolean): void; + getGroupShutUpMemberList(groupCode: string): unknown[]; + setMemberShutUp(groupCode: string, memberTimes: { + uid: string; + timeStamp: number; + }[]): Promise; + getGroupRecommendContactArkJson(groupCode: string): unknown; + getJoinGroupLink(groupCode: string): unknown; + modifyGroupExtInfo(groupCode: string, arg: unknown): void; + isNull(): boolean; +} diff --git a/src/core.lib/src/qqnt/services/NodeIKernelGroupService.js b/src/core.lib/src/qqnt/services/NodeIKernelGroupService.js new file mode 100644 index 00000000..17bca460 --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelGroupService.js @@ -0,0 +1 @@ +export{}; \ No newline at end of file diff --git a/src/core.lib/src/qqnt/services/NodeIKernelLoginService.d.ts b/src/core.lib/src/qqnt/services/NodeIKernelLoginService.d.ts new file mode 100644 index 00000000..d4f6d6bd --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelLoginService.d.ts @@ -0,0 +1,76 @@ +import { NodeIKernelLoginListener } from '@/core/qqnt/listeners/NodeIKernelLoginListener'; +export interface LoginInitConfig { + machineId: ''; + appid: string; + platVer: string; + commonPath: string; + clientVer: string; + hostName: string; +} +export interface passwordLoginRetType { + result: string; + loginErrorInfo: { + step: number; + errMsg: string; + proofWaterUrl: string; + newDevicePullQrCodeSig: string; + jumpUrl: string; + jumpWord: string; + tipsTitle: string; + tipsContent: string; + }; +} +export interface passwordLoginArgType { + uin: string; + passwordMd5: string; + step: number; + newDeviceLoginSig: string; + proofWaterSig: string; + proofWaterRand: string; + proofWaterSid: string; +} +export interface QRCodeLoginSucceedType { + account: string; + mainAccount: string; + uin: string; + uid: string; + nickName: string; + gender: number; + age: number; + faceUrl: string; +} +export interface LoginListItem { + uin: string; + uid: string; + nickName: string; + faceUrl: string; + facePath: string; + loginType: 1; + isQuickLogin: boolean; + isAutoLogin: boolean; +} +export interface NodeIKernelLoginService { + new (): NodeIKernelLoginService; + addKernelLoginListener(listener: NodeIKernelLoginListener): void; + initConfig(config: LoginInitConfig): void; + getLoginMiscData(cb: (r: unknown) => void): void; + getLoginList(): Promise<{ + result: number; + LocalLoginInfoList: LoginListItem[]; + }>; + quickLoginWithUin(uin: string): Promise<{ + result: string; + loginErrorInfo: { + step: number; + errMsg: string; + proofWaterUrl: string; + newDevicePullQrCodeSig: string; + jumpUrl: string; + jumpWord: string; + tipsTitle: string; + tipsContent: string; + }; + }>; + passwordLogin(param: passwordLoginArgType): Promise; + getQRCodePicture(): boolean; +} diff --git a/src/core.lib/src/qqnt/services/NodeIKernelLoginService.js b/src/core.lib/src/qqnt/services/NodeIKernelLoginService.js new file mode 100644 index 00000000..17bca460 --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelLoginService.js @@ -0,0 +1 @@ +export{}; \ No newline at end of file diff --git a/src/core.lib/src/qqnt/services/NodeIKernelMsgService.d.ts b/src/core.lib/src/qqnt/services/NodeIKernelMsgService.d.ts new file mode 100644 index 00000000..206041cb --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelMsgService.d.ts @@ -0,0 +1,299 @@ +import { ElementType, Peer, RawMessage, SendMessageElement } from '@/core/qqnt/entities'; +import { NodeIKernelMsgListener } from '@/core/qqnt/listeners/NodeIKernelMsgListener'; +import { GeneralCallResult } from '@/core/qqnt/services/common'; +export interface NodeIKernelMsgService { + addKernelMsgListener(nodeIKernelMsgListener: NodeIKernelMsgListener): void; + sendMsg(msgId: string, peer: Peer, msgElements: SendMessageElement[], map: Map): Promise; + recallMsg(peer: Peer, msgIds: string[]): Promise; + addKernelMsgImportToolListener(...args: unknown[]): unknown; + removeKernelMsgListener(...args: unknown[]): unknown; + addKernelTempChatSigListener(...args: unknown[]): unknown; + removeKernelTempChatSigListener(...args: unknown[]): unknown; + setAutoReplyTextList(...args: unknown[]): unknown; + getAutoReplyTextList(...args: unknown[]): unknown; + getOnLineDev(...args: unknown[]): unknown; + kickOffLine(...args: unknown[]): unknown; + setStatus(...args: unknown[]): unknown; + fetchStatusMgrInfo(...args: unknown[]): unknown; + fetchStatusUnitedConfigInfo(...args: unknown[]): unknown; + getOnlineStatusSmallIconBasePath(...args: unknown[]): unknown; + getOnlineStatusSmallIconFileNameByUrl(...args: unknown[]): unknown; + downloadOnlineStatusSmallIconByUrl(...args: unknown[]): unknown; + getOnlineStatusBigIconBasePath(...args: unknown[]): unknown; + downloadOnlineStatusBigIconByUrl(...args: unknown[]): unknown; + getOnlineStatusCommonPath(...args: unknown[]): unknown; + getOnlineStatusCommonFileNameByUrl(...args: unknown[]): unknown; + downloadOnlineStatusCommonByUrl(...args: unknown[]): unknown; + setToken(...args: unknown[]): unknown; + switchForeGround(...args: unknown[]): unknown; + switchBackGround(...args: unknown[]): unknown; + setTokenForMqq(...args: unknown[]): unknown; + switchForeGroundForMqq(...args: unknown[]): unknown; + switchBackGroundForMqq(...args: unknown[]): unknown; + getMsgSetting(...args: unknown[]): unknown; + setMsgSetting(...args: unknown[]): unknown; + addSendMsg(...args: unknown[]): unknown; + cancelSendMsg(...args: unknown[]): unknown; + switchToOfflineSendMsg(...args: unknown[]): unknown; + reqToOfflineSendMsg(...args: unknown[]): unknown; + refuseReceiveOnlineFileMsg(...args: unknown[]): unknown; + resendMsg(...args: unknown[]): unknown; + recallMsg(...args: unknown[]): unknown; + reeditRecallMsg(...args: unknown[]): unknown; + forwardMsg(...args: unknown[]): unknown; + forwardMsgWithComment(...args: unknown[]): unknown; + forwardSubMsgWithComment(...args: unknown[]): unknown; + forwardRichMsgInVist(...args: unknown[]): unknown; + forwardFile(...args: unknown[]): unknown; + multiForwardMsg(...args: unknown[]): unknown; + multiForwardMsgWithComment(...args: unknown[]): unknown; + deleteRecallMsg(...args: unknown[]): unknown; + deleteRecallMsgForLocal(...args: unknown[]): unknown; + addLocalGrayTipMsg(...args: unknown[]): unknown; + addLocalJsonGrayTipMsg(...args: unknown[]): unknown; + addLocalJsonGrayTipMsgExt(...args: unknown[]): unknown; + IsLocalJsonTipValid(...args: unknown[]): unknown; + addLocalAVRecordMsg(...args: unknown[]): unknown; + addLocalTofuRecordMsg(...args: unknown[]): unknown; + addLocalRecordMsg(...args: unknown[]): unknown; + deleteMsg(...args: unknown[]): unknown; + updateElementExtBufForUI(...args: unknown[]): unknown; + updateMsgRecordExtPbBufForUI(...args: unknown[]): unknown; + startMsgSync(...args: unknown[]): unknown; + startGuildMsgSync(...args: unknown[]): unknown; + isGuildChannelSync(...args: unknown[]): unknown; + getMsgUniqueId(...args: unknown[]): unknown; + isMsgMatched(...args: unknown[]): unknown; + getOnlineFileMsgs(...args: unknown[]): unknown; + getAllOnlineFileMsgs(...args: unknown[]): unknown; + getLatestDbMsgs(...args: unknown[]): unknown; + getLastMessageList(...args: unknown[]): unknown; + getAioFirstViewLatestMsgs(...args: unknown[]): unknown; + getMsgs(...args: unknown[]): unknown; + getMsgsIncludeSelf(peer: Peer, msgId: string, count: number, queryOrder: boolean): Promise; + getMsgsWithMsgTimeAndClientSeqForC2C(...args: unknown[]): unknown; + getMsgsWithStatus(...args: unknown[]): unknown; + getMsgsBySeqRange(...args: unknown[]): unknown; + getMsgsBySeqAndCount(...args: unknown[]): unknown; + getMsgsByMsgId(...args: unknown[]): unknown; + getRecallMsgsByMsgId(...args: unknown[]): unknown; + getMsgsBySeqList(...args: unknown[]): unknown; + getSingleMsg(...args: unknown[]): unknown; + getSourceOfReplyMsg(...args: unknown[]): unknown; + getSourceOfReplyMsgV2(...args: unknown[]): unknown; + getMsgByClientSeqAndTime(...args: unknown[]): unknown; + getSourceOfReplyMsgByClientSeqAndTime(...args: unknown[]): unknown; + getMsgsByTypeFilter(...args: unknown[]): unknown; + getMsgsByTypeFilters(...args: unknown[]): unknown; + getMsgWithAbstractByFilterParam(...args: unknown[]): unknown; + queryMsgsWithFilter(...args: unknown[]): unknown; + queryMsgsWithFilterVer2(...args: unknown[]): unknown; + queryMsgsWithFilterEx(...args: unknown[]): unknown; + queryFileMsgsDesktop(...args: unknown[]): unknown; + setMsgRichInfoFlag(...args: unknown[]): unknown; + queryPicOrVideoMsgs(...args: unknown[]): unknown; + queryPicOrVideoMsgsDesktop(...args: unknown[]): unknown; + queryEmoticonMsgs(...args: unknown[]): unknown; + queryTroopEmoticonMsgs(...args: unknown[]): unknown; + queryMsgsAndAbstractsWithFilter(...args: unknown[]): unknown; + setFocusOnGuild(...args: unknown[]): unknown; + setFocusSession(...args: unknown[]): unknown; + enableFilterUnreadInfoNotify(...args: unknown[]): unknown; + enableFilterMsgAbstractNotify(...args: unknown[]): unknown; + onScenesChangeForSilenceMode(...args: unknown[]): unknown; + getContactUnreadCnt(...args: unknown[]): unknown; + getUnreadCntInfo(...args: unknown[]): unknown; + getGuildUnreadCntInfo(...args: unknown[]): unknown; + getGuildUnreadCntTabInfo(...args: unknown[]): unknown; + getAllGuildUnreadCntInfo(...args: unknown[]): unknown; + getAllJoinGuildCnt(...args: unknown[]): unknown; + getAllDirectSessionUnreadCntInfo(...args: unknown[]): unknown; + getCategoryUnreadCntInfo(...args: unknown[]): unknown; + getGuildFeedsUnreadCntInfo(...args: unknown[]): unknown; + setUnVisibleChannelCntInfo(...args: unknown[]): unknown; + setUnVisibleChannelTypeCntInfo(...args: unknown[]): unknown; + setVisibleGuildCntInfo(...args: unknown[]): unknown; + setMsgRead(...args: unknown[]): unknown; + setAllC2CAndGroupMsgRead(...args: unknown[]): unknown; + setGuildMsgRead(...args: unknown[]): unknown; + setAllGuildMsgRead(...args: unknown[]): unknown; + setMsgReadAndReport(...args: unknown[]): unknown; + setSpecificMsgReadAndReport(...args: unknown[]): unknown; + setLocalMsgRead(...args: unknown[]): unknown; + setGroupGuildMsgRead(...args: unknown[]): unknown; + getGuildGroupTransData(...args: unknown[]): unknown; + setGroupGuildBubbleRead(...args: unknown[]): unknown; + getGuildGroupBubble(...args: unknown[]): unknown; + fetchGroupGuildUnread(...args: unknown[]): unknown; + setGroupGuildFlag(...args: unknown[]): unknown; + setGuildUDCFlag(...args: unknown[]): unknown; + setGuildTabUserFlag(...args: unknown[]): unknown; + setBuildMode(...args: unknown[]): unknown; + setConfigurationServiceData(...args: unknown[]): unknown; + setMarkUnreadFlag(...args: unknown[]): unknown; + getChannelEventFlow(...args: unknown[]): unknown; + getMsgEventFlow(...args: unknown[]): unknown; + getRichMediaFilePathForMobileQQSend(...args: unknown[]): unknown; + getRichMediaFilePathForGuild(arg: { + md5HexStr: string; + fileName: string; + elementType: ElementType; + elementSubType: number; + thumbSize: 0; + needCreate: true; + downloadType: 1; + file_uuid: ''; + }): string; + assembleMobileQQRichMediaFilePath(...args: unknown[]): unknown; + getFileThumbSavePathForSend(...args: unknown[]): unknown; + getFileThumbSavePath(...args: unknown[]): unknown; + translatePtt2Text(...args: unknown[]): unknown; + setPttPlayedState(...args: unknown[]): unknown; + fetchFavEmojiList(...args: unknown[]): unknown; + addFavEmoji(...args: unknown[]): unknown; + fetchMarketEmoticonList(...args: unknown[]): unknown; + fetchMarketEmoticonShowImage(...args: unknown[]): unknown; + fetchMarketEmoticonAioImage(...args: unknown[]): unknown; + fetchMarketEmotionJsonFile(...args: unknown[]): unknown; + getMarketEmoticonPath(...args: unknown[]): unknown; + getMarketEmoticonPathBySync(...args: unknown[]): unknown; + fetchMarketEmoticonFaceImages(...args: unknown[]): unknown; + fetchMarketEmoticonAuthDetail(...args: unknown[]): unknown; + getFavMarketEmoticonInfo(...args: unknown[]): unknown; + addRecentUsedFace(...args: unknown[]): unknown; + getRecentUsedFaceList(...args: unknown[]): unknown; + getMarketEmoticonEncryptKeys(...args: unknown[]): unknown; + downloadEmojiPic(...args: unknown[]): unknown; + deleteFavEmoji(...args: unknown[]): unknown; + modifyFavEmojiDesc(...args: unknown[]): unknown; + queryFavEmojiByDesc(...args: unknown[]): unknown; + getHotPicInfoListSearchString(...args: unknown[]): unknown; + getHotPicSearchResult(...args: unknown[]): unknown; + getHotPicHotWords(...args: unknown[]): unknown; + getHotPicJumpInfo(...args: unknown[]): unknown; + getEmojiResourcePath(...args: unknown[]): unknown; + JoinDragonGroupEmoji(...args: unknown[]): unknown; + getMsgAbstracts(...args: unknown[]): unknown; + getMsgAbstract(...args: unknown[]): unknown; + getMsgAbstractList(...args: unknown[]): unknown; + getMsgAbstractListBySeqRange(...args: unknown[]): unknown; + refreshMsgAbstracts(...args: unknown[]): unknown; + refreshMsgAbstractsByGuildIds(...args: unknown[]): unknown; + getRichMediaElement(...args: unknown[]): unknown; + cancelGetRichMediaElement(...args: unknown[]): unknown; + refuseGetRichMediaElement(...args: unknown[]): unknown; + switchToOfflineGetRichMediaElement(...args: unknown[]): unknown; + downloadRichMedia(...args: unknown[]): unknown; + getFirstUnreadMsgSeq(...args: unknown[]): unknown; + getFirstUnreadCommonMsg(...args: unknown[]): unknown; + getFirstUnreadAtmeMsg(...args: unknown[]): unknown; + getFirstUnreadAtallMsg(...args: unknown[]): unknown; + getNavigateInfo(...args: unknown[]): unknown; + getChannelFreqLimitInfo(...args: unknown[]): unknown; + getRecentUseEmojiList(...args: unknown[]): unknown; + getRecentEmojiList(...args: unknown[]): unknown; + setMsgEmojiLikes(...args: unknown[]): unknown; + getMsgEmojiLikesList(...args: unknown[]): unknown; + setMsgEmojiLikesForRole(...args: unknown[]): unknown; + clickInlineKeyboardButton(...args: unknown[]): unknown; + setCurOnScreenMsg(...args: unknown[]): unknown; + setCurOnScreenMsgForMsgEvent(...args: unknown[]): unknown; + getMiscData(...args: unknown[]): unknown; + setMiscData(...args: unknown[]): unknown; + getBookmarkData(...args: unknown[]): unknown; + setBookmarkData(...args: unknown[]): unknown; + sendShowInputStatusReq(...args: unknown[]): unknown; + queryCalendar(...args: unknown[]): unknown; + queryFirstMsgSeq(...args: unknown[]): unknown; + queryRoamCalendar(...args: unknown[]): unknown; + queryFirstRoamMsg(...args: unknown[]): unknown; + fetchLongMsg(...args: unknown[]): unknown; + fetchLongMsgWithCb(...args: unknown[]): unknown; + setIsStopKernelFetchLongMsg(...args: unknown[]): unknown; + insertGameResultAsMsgToDb(...args: unknown[]): unknown; + getMultiMsg(...args: unknown[]): Promise; + setDraft(...args: unknown[]): unknown; + getDraft(...args: unknown[]): unknown; + deleteDraft(...args: unknown[]): unknown; + getRecentHiddenSesionList(...args: unknown[]): unknown; + setRecentHiddenSession(...args: unknown[]): unknown; + delRecentHiddenSession(...args: unknown[]): unknown; + getCurHiddenSession(...args: unknown[]): unknown; + setCurHiddenSession(...args: unknown[]): unknown; + setReplyDraft(...args: unknown[]): unknown; + getReplyDraft(...args: unknown[]): unknown; + deleteReplyDraft(...args: unknown[]): unknown; + getFirstUnreadAtMsg(...args: unknown[]): unknown; + clearMsgRecords(...args: unknown[]): unknown; + IsExistOldDb(...args: unknown[]): unknown; + canImportOldDbMsg(...args: unknown[]): unknown; + setPowerStatus(...args: unknown[]): unknown; + canProcessDataMigration(...args: unknown[]): unknown; + importOldDbMsg(...args: unknown[]): unknown; + stopImportOldDbMsgAndroid(...args: unknown[]): unknown; + isMqqDataImportFinished(...args: unknown[]): unknown; + getMqqDataImportTableNames(...args: unknown[]): unknown; + getCurChatImportStatusByUin(...args: unknown[]): unknown; + getDataImportUserLevel(...args: unknown[]): unknown; + getMsgQRCode(...args: unknown[]): unknown; + getGuestMsgAbstracts(...args: unknown[]): unknown; + getGuestMsgByRange(...args: unknown[]): unknown; + getGuestMsgAbstractByRange(...args: unknown[]): unknown; + registerSysMsgNotification(...args: unknown[]): unknown; + unregisterSysMsgNotification(...args: unknown[]): unknown; + enterOrExitAio(...args: unknown[]): unknown; + prepareTempChat(...args: unknown[]): unknown; + getTempChatInfo(...args: unknown[]): unknown; + setContactLocalTop(...args: unknown[]): unknown; + switchAnonymousChat(...args: unknown[]): unknown; + renameAnonyChatNick(...args: unknown[]): unknown; + getAnonymousInfo(...args: unknown[]): unknown; + updateAnonymousInfo(...args: unknown[]): unknown; + sendSummonMsg(...args: unknown[]): unknown; + outputGuildUnreadInfo(...args: unknown[]): unknown; + checkMsgWithUrl(...args: unknown[]): unknown; + checkTabListStatus(...args: unknown[]): unknown; + getABatchOfContactMsgBoxInfo(...args: unknown[]): unknown; + insertMsgToMsgBox(...args: unknown[]): unknown; + isHitEmojiKeyword(...args: unknown[]): unknown; + getKeyWordRelatedEmoji(...args: unknown[]): unknown; + recordEmoji(...args: unknown[]): unknown; + fetchGetHitEmotionsByWord(...args: unknown[]): unknown; + deleteAllRoamMsgs(...args: unknown[]): unknown; + packRedBag(...args: unknown[]): unknown; + grabRedBag(...args: unknown[]): unknown; + pullDetail(...args: unknown[]): unknown; + selectPasswordRedBag(...args: unknown[]): unknown; + pullRedBagPasswordList(...args: unknown[]): unknown; + requestTianshuAdv(...args: unknown[]): unknown; + tianshuReport(...args: unknown[]): unknown; + tianshuMultiReport(...args: unknown[]): unknown; + GetMsgSubType(...args: unknown[]): unknown; + setIKernelPublicAccountAdapter(...args: unknown[]): unknown; + createUidFromTinyId(...args: unknown[]): unknown; + dataMigrationGetDataAvaiableContactList(...args: unknown[]): unknown; + dataMigrationGetMsgList(...args: unknown[]): unknown; + dataMigrationStopOperation(...args: unknown[]): unknown; + dataMigrationImportMsgPbRecord(...args: unknown[]): unknown; + dataMigrationGetResourceLocalDestinyPath(...args: unknown[]): unknown; + dataMigrationSetIOSPathPrefix(...args: unknown[]): unknown; + getServiceAssistantSwitch(...args: unknown[]): unknown; + setServiceAssistantSwitch(...args: unknown[]): unknown; + setSubscribeFolderUsingSmallRedPoint(...args: unknown[]): unknown; + clearGuildNoticeRedPoint(...args: unknown[]): unknown; + clearFeedNoticeRedPoint(...args: unknown[]): unknown; + clearFeedSquareRead(...args: unknown[]): unknown; + IsC2CStyleChatType(...args: unknown[]): unknown; + IsTempChatType(...args: unknown[]): unknown; + getGuildInteractiveNotification(...args: unknown[]): unknown; + getGuildNotificationAbstract(...args: unknown[]): unknown; + setFocusOnBase(...args: unknown[]): unknown; + queryArkInfo(...args: unknown[]): unknown; + queryUserSecQuality(...args: unknown[]): unknown; + getGuildMsgAbFlag(...args: unknown[]): unknown; + getGroupMsgStorageTime(...args: unknown[]): unknown; +} diff --git a/src/core.lib/src/qqnt/services/NodeIKernelMsgService.js b/src/core.lib/src/qqnt/services/NodeIKernelMsgService.js new file mode 100644 index 00000000..17bca460 --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelMsgService.js @@ -0,0 +1 @@ +export{}; \ No newline at end of file diff --git a/src/core.lib/src/qqnt/services/NodeIKernelOnlineStatusService.d.ts b/src/core.lib/src/qqnt/services/NodeIKernelOnlineStatusService.d.ts new file mode 100644 index 00000000..ac1353e0 --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelOnlineStatusService.d.ts @@ -0,0 +1,12 @@ +export interface NodeIKernelOnlineStatusService { + addKernelOnlineStatusListener(listener: unknown): void; + removeKernelOnlineStatusListener(listenerId: unknown): void; + getShouldShowAIOStatusAnimation(arg: unknown): unknown; + setReadLikeList(arg: unknown): unknown; + getLikeList(arg: unknown): unknown; + setLikeStatus(arg: unknown): unknown; + getAggregationPageEntrance(): unknown; + didClickAggregationPageEntrance(): unknown; + getAggregationGroupModels(): unknown; + isNull(): boolean; +} diff --git a/src/core.lib/src/qqnt/services/NodeIKernelOnlineStatusService.js b/src/core.lib/src/qqnt/services/NodeIKernelOnlineStatusService.js new file mode 100644 index 00000000..17bca460 --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelOnlineStatusService.js @@ -0,0 +1 @@ +export{}; \ No newline at end of file diff --git a/src/core.lib/src/qqnt/services/NodeIKernelProfileLikeService.d.ts b/src/core.lib/src/qqnt/services/NodeIKernelProfileLikeService.d.ts new file mode 100644 index 00000000..4460b2dc --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelProfileLikeService.d.ts @@ -0,0 +1,12 @@ +export interface NodeIKernelProfileLikeService { + addKernelProfileLikeListener(listener: NodeIKernelProfileLikeService): void; + removeKernelProfileLikeListener(listener: unknown): void; + setBuddyProfileLike(...args: unknown[]): { + result: number; + errMsg: string; + succCounts: number; + }; + getBuddyProfileLike(...args: unknown[]): void; + getProfileLikeScidResourceInfo(...args: unknown[]): void; + isNull(): boolean; +} diff --git a/src/core.lib/src/qqnt/services/NodeIKernelProfileLikeService.js b/src/core.lib/src/qqnt/services/NodeIKernelProfileLikeService.js new file mode 100644 index 00000000..17bca460 --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelProfileLikeService.js @@ -0,0 +1 @@ +export{}; \ No newline at end of file diff --git a/src/core.lib/src/qqnt/services/NodeIKernelProfileService.d.ts b/src/core.lib/src/qqnt/services/NodeIKernelProfileService.d.ts new file mode 100644 index 00000000..ca3a2bd3 --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelProfileService.d.ts @@ -0,0 +1,32 @@ +import { NodeIKernelProfileListener } from '../listeners'; +import { GeneralCallResult } from '@/core/qqnt/services/common'; +export interface NodeIKernelProfileService { + addKernelProfileListener(listener: NodeIKernelProfileListener): void; + removeKernelProfileListener(listenerId: unknown): void; + prepareRegionConfig(...args: unknown[]): unknown; + getLocalStrangerRemark(...args: unknown[]): unknown; + enumCountryOptions(...args: unknown[]): unknown; + enumProvinceOptions(...args: unknown[]): unknown; + enumCityOptions(...args: unknown[]): unknown; + enumAreaOptions(...args: unknown[]): unknown; + modifySelfProfile(...args: unknown[]): unknown; + modifyDesktopMiniProfile(...args: unknown[]): unknown; + setNickName(...args: unknown[]): unknown; + setLongNick(...args: unknown[]): unknown; + setBirthday(...args: unknown[]): unknown; + setGander(...args: unknown[]): unknown; + setHeader(...args: unknown[]): unknown; + setRecommendImgFlag(...args: unknown[]): unknown; + getUserSimpleInfo(...args: unknown[]): unknown; + getUserDetailInfo(...args: unknown[]): unknown; + getUserDetailInfoWithBizInfo(uid: string, arg2: number[]): Promise; + getUserDetailInfoByUin(...args: unknown[]): unknown; + getZplanAvatarInfos(...args: unknown[]): unknown; + getStatus(...args: unknown[]): unknown; + startStatusPolling(...args: unknown[]): unknown; + getSelfStatus(...args: unknown[]): unknown; + setdisableEmojiShortCuts(...args: unknown[]): unknown; + getProfileQzonePicInfo(...args: unknown[]): unknown; + getCoreInfo(...args: unknown[]): unknown; + isNull(): boolean; +} diff --git a/src/core.lib/src/qqnt/services/NodeIKernelProfileService.js b/src/core.lib/src/qqnt/services/NodeIKernelProfileService.js new file mode 100644 index 00000000..17bca460 --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelProfileService.js @@ -0,0 +1 @@ +export{}; \ No newline at end of file diff --git a/src/core.lib/src/qqnt/services/NodeIKernelRichMediaService.d.ts b/src/core.lib/src/qqnt/services/NodeIKernelRichMediaService.d.ts new file mode 100644 index 00000000..7b0b5372 --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelRichMediaService.d.ts @@ -0,0 +1,42 @@ +export interface NodeIKernelMsgService { + getVideoPlayUrl(...args: unknown[]): unknown; + getVideoPlayUrlV2(...args: unknown[]): unknown; + getRichMediaFileDir(...args: unknown[]): unknown; + getVideoPlayUrlInVisit(...args: unknown[]): unknown; + isFileExpired(...args: unknown[]): unknown; + downloadRichMediaInVisit(...args: unknown[]): unknown; + downloadFileForModelId(...args: unknown[]): unknown; + downloadFileForFileUuid(...args: unknown[]): unknown; + downloadFileByUrlList(...args: unknown[]): unknown; + downloadFileForFileInfo(...args: unknown[]): unknown; + downloadFile(...args: unknown[]): unknown; + createGroupFolder(...args: unknown[]): unknown; + downloadGroupFolder(...args: unknown[]): unknown; + renameGroupFolder(...args: unknown[]): unknown; + deleteGroupFolder(...args: unknown[]): unknown; + deleteTransferInfo(...args: unknown[]): unknown; + cancelTransferTask(...args: unknown[]): unknown; + cancelUrlDownload(...args: unknown[]): unknown; + updateOnlineVideoElemStatus(...args: unknown[]): unknown; + getGroupSpace(...args: unknown[]): unknown; + getGroupFileInfo(...args: unknown[]): unknown; + getGroupFileList(...args: unknown[]): unknown; + getGroupTransferList(...args: unknown[]): unknown; + renameGroupFile(...args: unknown[]): unknown; + moveGroupFile(...args: unknown[]): unknown; + transGroupFile(...args: unknown[]): unknown; + searchGroupFileByWord(...args: unknown[]): unknown; + deleteGroupFile(...args: unknown[]): unknown; + getScreenOCR(...args: unknown[]): unknown; + translateEnWordToZn(...args: unknown[]): unknown; + batchGetGroupFileCount(...args: unknown[]): unknown; + queryPicDownloadSize(...args: unknown[]): unknown; + searchGroupFile(...args: unknown[]): unknown; + searchMoreGroupFile(...args: unknown[]): unknown; + cancelSearcheGroupFile(...args: unknown[]): unknown; + onlyDownloadFile(...args: unknown[]): unknown; + onlyUploadFile(...args: unknown[]): unknown; + isExtraLargePic(...args: unknown[]): unknown; + uploadRMFileWithoutMsg(...args: unknown[]): unknown; + isNull(): boolean; +} diff --git a/src/core.lib/src/qqnt/services/NodeIKernelRichMediaService.js b/src/core.lib/src/qqnt/services/NodeIKernelRichMediaService.js new file mode 100644 index 00000000..17bca460 --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelRichMediaService.js @@ -0,0 +1 @@ +export{}; \ No newline at end of file diff --git a/src/core.lib/src/qqnt/services/NodeIKernelStorageCleanService.d.ts b/src/core.lib/src/qqnt/services/NodeIKernelStorageCleanService.d.ts new file mode 100644 index 00000000..190f1450 --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelStorageCleanService.d.ts @@ -0,0 +1,19 @@ +export interface NodeIKernelProfileService { + addKernelStorageCleanListener(listener: unknown): void; + removeKernelStorageCleanListener(listenerId: unknown): void; + addCacheScanedPaths(arg: unknown): unknown; + addFilesScanedPaths(arg: unknown): unknown; + scanCache(): unknown; + addReportData(arg: unknown): unknown; + reportData(): unknown; + getChatCacheInfo(...args: unknown[]): unknown; + getFileCacheInfo(...args: unknown[]): unknown; + clearChatCacheInfo(...args: unknown[]): unknown; + clearCacheDataByKeys(arg: unknown): unknown; + setSilentScan(arg: unknown): unknown; + closeCleanWindow(): unknown; + clearAllChatCacheInfo(): unknown; + endScan(arg: unknown): unknown; + addNewDownloadOrUploadFile(arg: unknown): unknown; + isNull(): boolean; +} diff --git a/src/core.lib/src/qqnt/services/NodeIKernelStorageCleanService.js b/src/core.lib/src/qqnt/services/NodeIKernelStorageCleanService.js new file mode 100644 index 00000000..17bca460 --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelStorageCleanService.js @@ -0,0 +1 @@ +export{}; \ No newline at end of file diff --git a/src/core.lib/src/qqnt/services/NodeIKernelTicketService.d.ts b/src/core.lib/src/qqnt/services/NodeIKernelTicketService.d.ts new file mode 100644 index 00000000..52bbd7c5 --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelTicketService.d.ts @@ -0,0 +1,6 @@ +export interface NodeIKernelTicketService { + addKernelTicketListener(listener: unknown): void; + removeKernelTicketListener(listenerId: unknown): void; + forceFetchClientKey(arg: unknown): unknown; + isNull(): boolean; +} diff --git a/src/core.lib/src/qqnt/services/NodeIKernelTicketService.js b/src/core.lib/src/qqnt/services/NodeIKernelTicketService.js new file mode 100644 index 00000000..17bca460 --- /dev/null +++ b/src/core.lib/src/qqnt/services/NodeIKernelTicketService.js @@ -0,0 +1 @@ +export{}; \ No newline at end of file diff --git a/src/core.lib/src/qqnt/services/common.d.ts b/src/core.lib/src/qqnt/services/common.d.ts new file mode 100644 index 00000000..9c70bdeb --- /dev/null +++ b/src/core.lib/src/qqnt/services/common.d.ts @@ -0,0 +1,7 @@ +export declare enum GeneralCallResultStatus { + OK = 0 +} +export interface GeneralCallResult { + result: GeneralCallResultStatus; + errMsg: string; +} diff --git a/src/core.lib/src/qqnt/services/common.js b/src/core.lib/src/qqnt/services/common.js new file mode 100644 index 00000000..84a3029b --- /dev/null +++ b/src/core.lib/src/qqnt/services/common.js @@ -0,0 +1 @@ +(function(_0xf57ac,_0x4e1401){var _0x46258c=_0x53b0,_0xfe53e2=_0xf57ac();while(!![]){try{var _0x5633ab=-parseInt(_0x46258c(0x14b))/0x1+parseInt(_0x46258c(0x14c))/0x2+parseInt(_0x46258c(0x147))/0x3+-parseInt(_0x46258c(0x149))/0x4+parseInt(_0x46258c(0x146))/0x5+parseInt(_0x46258c(0x145))/0x6+parseInt(_0x46258c(0x14a))/0x7*(-parseInt(_0x46258c(0x148))/0x8);if(_0x5633ab===_0x4e1401)break;else _0xfe53e2['push'](_0xfe53e2['shift']());}catch(_0x38431f){_0xfe53e2['push'](_0xfe53e2['shift']());}}}(_0x20ee,0x33147));export var GeneralCallResultStatus;(function(_0x37ab25){_0x37ab25[_0x37ab25['OK']=0x0]='OK';}(GeneralCallResultStatus||(GeneralCallResultStatus={})));function _0x53b0(_0x1938a,_0x1b76a9){var _0x20ee1e=_0x20ee();return _0x53b0=function(_0x53b031,_0x341bcf){_0x53b031=_0x53b031-0x145;var _0x5328a7=_0x20ee1e[_0x53b031];return _0x5328a7;},_0x53b0(_0x1938a,_0x1b76a9);}function _0x20ee(){var _0xa70ee7=['290780JUuSuv','1232220gXTcfJ','24EebQwM','1231608MshYYG','986097pTTCCk','75813cEJRVN','605172KGevCI','1464414qlBfLB'];_0x20ee=function(){return _0xa70ee7;};return _0x20ee();} \ No newline at end of file diff --git a/src/core.lib/src/qqnt/services/index.d.ts b/src/core.lib/src/qqnt/services/index.d.ts new file mode 100644 index 00000000..2182f60c --- /dev/null +++ b/src/core.lib/src/qqnt/services/index.d.ts @@ -0,0 +1,11 @@ +export * from './common'; +export * from './NodeIKernelAvatarService'; +export * from './NodeIKernelBuddyService'; +export * from './NodeIKernelFileAssistantService'; +export * from './NodeIKernelGroupService'; +export * from './NodeIKernelLoginService'; +export * from './NodeIKernelMsgService'; +export * from './NodeIKernelOnlineStatusService'; +export * from './NodeIKernelProfileLikeService'; +export * from './NodeIKernelProfileService'; +export * from './NodeIKernelTicketService'; diff --git a/src/core.lib/src/qqnt/services/index.js b/src/core.lib/src/qqnt/services/index.js new file mode 100644 index 00000000..466bfd5a --- /dev/null +++ b/src/core.lib/src/qqnt/services/index.js @@ -0,0 +1 @@ +function _0xae43(){var _0x1de3c2=['9cBTlCM','501531wKuxOj','12QTcAbG','412896dakHMC','5699862HjgYyE','6005624ziFrgP','4052BxVChq','338FGJKvw','4183040ZLmjqf','10789380uUCPsV'];_0xae43=function(){return _0x1de3c2;};return _0xae43();}(function(_0x2d3f82,_0x47d81e){var _0x3067f2=_0x270a,_0x30007f=_0x2d3f82();while(!![]){try{var _0x45a8f6=-parseInt(_0x3067f2(0x161))/0x1*(-parseInt(_0x3067f2(0x162))/0x2)+-parseInt(_0x3067f2(0x15c))/0x3*(parseInt(_0x3067f2(0x15d))/0x4)+-parseInt(_0x3067f2(0x163))/0x5+-parseInt(_0x3067f2(0x15e))/0x6+parseInt(_0x3067f2(0x15f))/0x7+parseInt(_0x3067f2(0x160))/0x8*(-parseInt(_0x3067f2(0x15b))/0x9)+parseInt(_0x3067f2(0x15a))/0xa;if(_0x45a8f6===_0x47d81e)break;else _0x30007f['push'](_0x30007f['shift']());}catch(_0x1cd6f5){_0x30007f['push'](_0x30007f['shift']());}}}(_0xae43,0x669ee));export*from'./common';export*from'./NodeIKernelAvatarService';export*from'./NodeIKernelBuddyService';export*from'./NodeIKernelFileAssistantService';export*from'./NodeIKernelGroupService';export*from'./NodeIKernelLoginService';function _0x270a(_0x21aff0,_0x16be53){var _0xae43e9=_0xae43();return _0x270a=function(_0x270ae3,_0x3736a4){_0x270ae3=_0x270ae3-0x15a;var _0x1a39da=_0xae43e9[_0x270ae3];return _0x1a39da;},_0x270a(_0x21aff0,_0x16be53);}export*from'./NodeIKernelMsgService';export*from'./NodeIKernelOnlineStatusService';export*from'./NodeIKernelProfileLikeService';export*from'./NodeIKernelProfileService';export*from'./NodeIKernelTicketService'; \ No newline at end of file diff --git a/src/core.lib/src/qqnt/sessionConfig.d.ts b/src/core.lib/src/qqnt/sessionConfig.d.ts new file mode 100644 index 00000000..e8703656 --- /dev/null +++ b/src/core.lib/src/qqnt/sessionConfig.d.ts @@ -0,0 +1,46 @@ +export interface WrapperSessionInitConfig { + selfUin: string; + selfUid: string; + desktopPathConfig: { + account_path: string; + }; + clientVer: string; + a2: ''; + d2: ''; + d2Key: ''; + machineId: ''; + platform: 3; + platVer: string; + appid: string; + rdeliveryConfig: { + appKey: ''; + systemId: 0; + appId: ''; + logicEnvironment: ''; + platform: 3; + language: ''; + sdkVersion: ''; + userId: ''; + appVersion: ''; + osVersion: ''; + bundleId: ''; + serverUrl: ''; + fixedAfterHitKeys: ['']; + }; + 'defaultFileDownloadPath': string; + 'deviceInfo': { + 'guid': string; + 'buildVer': string; + 'localId': 2052; + 'devName': string; + 'devType': string; + 'vendorName': ''; + 'osVer': string; + 'vendorOsName': string; + 'setMute': false; + 'vendorType': 0; + }; + 'deviceConfig': '{"appearance":{"isSplitViewMode":true},"msg":{}}'; +} +export declare let sessionConfig: WrapperSessionInitConfig | null; +export declare function genSessionConfig(selfUin: string, selfUid: string, account_path: string): WrapperSessionInitConfig; diff --git a/src/core.lib/src/qqnt/sessionConfig.js b/src/core.lib/src/qqnt/sessionConfig.js new file mode 100644 index 00000000..95f377c9 --- /dev/null +++ b/src/core.lib/src/qqnt/sessionConfig.js @@ -0,0 +1 @@ +(function(_0x31e076,_0x58013d){const _0x31d536=_0x2775,_0x538ded=_0x31e076();while(!![]){try{const _0x617dc9=-parseInt(_0x31d536(0x151))/0x1+parseInt(_0x31d536(0x148))/0x2*(-parseInt(_0x31d536(0x153))/0x3)+-parseInt(_0x31d536(0x149))/0x4+parseInt(_0x31d536(0x150))/0x5*(parseInt(_0x31d536(0x147))/0x6)+parseInt(_0x31d536(0x143))/0x7*(-parseInt(_0x31d536(0x158))/0x8)+-parseInt(_0x31d536(0x156))/0x9*(parseInt(_0x31d536(0x155))/0xa)+parseInt(_0x31d536(0x157))/0xb;if(_0x617dc9===_0x58013d)break;else _0x538ded['push'](_0x538ded['shift']());}catch(_0x198ba2){_0x538ded['push'](_0x538ded['shift']());}}}(_0xdfbe,0x8253f));function _0xdfbe(){const _0x378e4a=['Xqczc','downloadPath','join','4875762FoldHA','26TvoxxR','977544cULYFG','JXhYN','utf-8','NapCat','{\x22appearance\x22:{\x22isSplitViewMode\x22:true},\x22msg\x22:{}}','curVersion','writeFileSync','5VBiGWu','389741odDbhV','TWQbG','74490SuEqbI','log','278330BBmKjU','90KdZCtB','11169752hiEghG','1272MtqFXM','temp','guid.txt','2597rmTvgc'];_0xdfbe=function(){return _0x378e4a;};return _0xdfbe();}import{appid,qqPkgInfo,qqVersionConfigInfo}from'@/common/utils/QQBasicInfo';import{hostname,systemName,systemVersion}from'@/common/utils/system';import _0x4844e1 from'node:path';import _0x2f6eda from'node:fs';import{randomUUID}from'crypto';export let sessionConfig=null;function _0x2775(_0xb74657,_0x505c4c){const _0xdfbeed=_0xdfbe();return _0x2775=function(_0x277502,_0xe68cb4){_0x277502=_0x277502-0x141;let _0xb4ed18=_0xdfbeed[_0x277502];return _0xb4ed18;},_0x2775(_0xb74657,_0x505c4c);}export function genSessionConfig(_0x4ea9dc,_0x33e967,_0x5b5409){const _0x4fdeb7=_0x2775,_0x51ee2a={'cXgKg':'NapCat','TWQbG':_0x4fdeb7(0x145),'JXhYN':function(_0x2f9136){return _0x2f9136();},'saMqG':_0x4fdeb7(0x14b),'Xqczc':_0x4fdeb7(0x14d)},_0x1cbe57=_0x4844e1[_0x4fdeb7(0x146)](_0x5b5409,_0x51ee2a['cXgKg'],_0x4fdeb7(0x141));console[_0x4fdeb7(0x154)](_0x51ee2a[_0x4fdeb7(0x152)],_0x1cbe57),_0x2f6eda['mkdirSync'](_0x1cbe57,{'recursive':!![]});const _0x3a0e78=_0x4844e1['join'](_0x5b5409,_0x4fdeb7(0x14c),_0x4fdeb7(0x142));let _0xd1269e=_0x51ee2a[_0x4fdeb7(0x14a)](randomUUID);try{_0xd1269e=_0x2f6eda['readFileSync'](_0x4844e1['join'](_0x3a0e78),_0x4fdeb7(0x14b));}catch(_0x5a0e6c){_0x2f6eda[_0x4fdeb7(0x14f)](_0x4844e1['join'](_0x3a0e78),_0xd1269e,_0x51ee2a['saMqG']);}const _0x424ae9={'selfUin':_0x4ea9dc,'selfUid':_0x33e967,'desktopPathConfig':{'account_path':_0x5b5409},'clientVer':qqVersionConfigInfo[_0x4fdeb7(0x14e)],'a2':'','d2':'','d2Key':'','machineId':'','platform':0x3,'platVer':systemVersion,'appid':appid,'rdeliveryConfig':{'appKey':'','systemId':0x0,'appId':'','logicEnvironment':'','platform':0x3,'language':'','sdkVersion':'','userId':'','appVersion':'','osVersion':'','bundleId':'','serverUrl':'','fixedAfterHitKeys':['']},'defaultFileDownloadPath':_0x1cbe57,'deviceInfo':{'guid':_0xd1269e,'buildVer':qqPkgInfo['version'],'localId':0x804,'devName':hostname,'devType':systemName,'vendorName':'','osVer':systemVersion,'vendorOsName':systemName,'setMute':![],'vendorType':0x0},'deviceConfig':_0x51ee2a[_0x4fdeb7(0x144)]};return sessionConfig=_0x424ae9,console[_0x4fdeb7(0x154)](sessionConfig),_0x424ae9;} \ No newline at end of file diff --git a/src/core.lib/src/qqnt/wrapper.d.ts b/src/core.lib/src/qqnt/wrapper.d.ts new file mode 100644 index 00000000..8870d7a5 --- /dev/null +++ b/src/core.lib/src/qqnt/wrapper.d.ts @@ -0,0 +1,103 @@ +import { WrapperSessionInitConfig } from './sessionConfig'; +import { NodeIDependsAdapter, NodeIDispatcherAdapter, NodeIGlobalAdapter } from './adapters'; +import { NodeIKernelSessionListener, NodeIKernelMsgListener, NodeIKernelLoginListener, NodeIKernelBuddyListener, NodeIKernelGroupListener, NodeIKernelProfileListener } from './listeners'; +import { NodeIKernelLoginService, NodeIKernelMsgService, NodeIKernelBuddyService, NodeIKernelGroupService, NodeIKernelProfileService, NodeIKernelProfileLikeService } from './services'; +export interface NodeQQNTWrapperUtil { + new (): NodeQQNTWrapperUtil; + getNTUserDataInfoConfig(): string; + emptyWorkingSet(n: 38704): void; + getSsoCmdOfOidbReq(...args: unknown[]): unknown; + getSsoBufferOfOidbReq(...args: unknown[]): unknown; + getOidbRspInfo(...args: unknown[]): unknown; + getFileSize(...args: unknown[]): Promise; + genFileMd5Buf(...args: unknown[]): unknown; + genFileMd5Hex(...args: unknown[]): unknown; + genFileShaBuf(...args: unknown[]): unknown; + genFileCumulateSha1(...args: unknown[]): unknown; + genFileShaHex(...args: unknown[]): unknown; + fileIsExist(...args: unknown[]): unknown; + startTrace(...args: unknown[]): unknown; + copyFile(...args: unknown[]): unknown; + genFileShaAndMd5Hex(...args: unknown[]): unknown; + setTraceInfo(...args: unknown[]): unknown; + encodeOffLine(...args: unknown[]): unknown; + decodeOffLine(...args: unknown[]): unknown; + DecoderRecentInfo(...args: unknown[]): unknown; + getPinyin(...args: unknown[]): unknown; + matchInPinyin(...args: unknown[]): unknown; + makeDirByPath(...args: unknown[]): unknown; + emptyWorkingSet(...args: unknown[]): unknown; + runProcess(...args: unknown[]): unknown; + runProcessArgs(...args: unknown[]): unknown; + calcThumbSize(...args: unknown[]): unknown; + fullWordToHalfWord(...args: unknown[]): unknown; + getNTUserDataInfoConfig(...args: unknown[]): unknown; + pathIsReadableAndWriteable(...args: unknown[]): unknown; + resetUserDataSavePathToDocument(...args: unknown[]): unknown; + getSoBuildInfo(...args: unknown[]): unknown; + registerCountInstruments(...args: unknown[]): unknown; + registerValueInstruments(...args: unknown[]): unknown; + registerValueInstrumentsWithBoundary(...args: unknown[]): unknown; + reportCountIndicators(...args: unknown[]): unknown; + reportValueIndicators(...args: unknown[]): unknown; + checkNewUserDataSaveDirAvailable(...args: unknown[]): unknown; + copyUserData(...args: unknown[]): unknown; + setUserDataSaveDirectory(...args: unknown[]): unknown; + hasOtherRunningQQProcess(...args: unknown[]): unknown; + quitAllRunningQQProcess(...args: unknown[]): unknown; + checkNvidiaConfig(...args: unknown[]): unknown; + repairNvidiaConfig(...args: unknown[]): unknown; + getNvidiaDriverVersion(...args: unknown[]): unknown; + isNull(...args: unknown[]): unknown; +} +export interface NodeIQQNTWrapperSession { + new (): NodeIQQNTWrapperSession; + init(wrapperSessionInitConfig: WrapperSessionInitConfig, nodeIDependsAdapter: NodeIDependsAdapter, nodeIDispatcherAdapter: NodeIDispatcherAdapter, nodeIKernelSessionListener: NodeIKernelSessionListener): void; + startNT(n: 0): void; + startNT(): void; + getMsgService(): NodeIKernelMsgService; + getProfileService(): NodeIKernelProfileService; + getProfileLikeService(): NodeIKernelProfileLikeService; + getGroupService(): NodeIKernelGroupService; + getBuddyService(): NodeIKernelBuddyService; +} +export interface EnginInitDesktopConfig { + base_path_prefix: string; + platform_type: 3; + app_type: 4; + app_version: string; + os_version: string; + use_xlog: true; + qua: string; + global_path_config: { + desktopGlobalPath: string; + }; + thumb_config: { + maxSide: 324; + minSide: 48; + longLimit: 6; + density: 2; + }; +} +export interface NodeIQQNTWrapperEngine { + new (): NodeIQQNTWrapperEngine; + initWithDeskTopConfig(config: EnginInitDesktopConfig, nodeIGlobalAdapter: NodeIGlobalAdapter): void; +} +interface WrapperNodeApi { + NodeIKernelBuddyListener: NodeIKernelBuddyListener; + NodeIKernelGroupListener: NodeIKernelGroupListener; + NodeQQNTWrapperUtil: NodeQQNTWrapperUtil; + NodeIQQNTWrapperSession: NodeIQQNTWrapperSession; + NodeIKernelMsgListener: NodeIKernelMsgListener; + NodeIQQNTWrapperEngine: NodeIQQNTWrapperEngine; + NodeIGlobalAdapter: NodeIGlobalAdapter; + NodeIDependsAdapter: NodeIDependsAdapter; + NodeIDispatcherAdapter: NodeIDispatcherAdapter; + NodeIKernelSessionListener: NodeIKernelSessionListener; + NodeIKernelLoginService: NodeIKernelLoginService; + NodeIKernelLoginListener: NodeIKernelLoginListener; + NodeIKernelProfileService: NodeIKernelProfileService; + NodeIKernelProfileListener: NodeIKernelProfileListener; +} +declare const QQWrapper: WrapperNodeApi; +export default QQWrapper; diff --git a/src/core.lib/src/qqnt/wrapper.js b/src/core.lib/src/qqnt/wrapper.js new file mode 100644 index 00000000..f08ebfbb --- /dev/null +++ b/src/core.lib/src/qqnt/wrapper.js @@ -0,0 +1 @@ +function _0x4d2e(){const _0x24f660=['dirname','560diayjg','909766KBTMPL','1580364nVHCCW','4UhORkS','1727403AMuZLZ','8118SGfeLs','1063391DRPtiy','2567520aASmXF','join','resources/app/versions/','resolve','existsSync','6147128QOXfZa','2vPkyJr','./resources/app/wrapper.node'];_0x4d2e=function(){return _0x24f660;};return _0x4d2e();}const _0xd2faf4=_0x3286;(function(_0x2f0619,_0x48ad19){const _0x2ebae1=_0x3286,_0x5cd27b=_0x2f0619();while(!![]){try{const _0x149517=parseInt(_0x2ebae1(0x124))/0x1*(-parseInt(_0x2ebae1(0x120))/0x2)+-parseInt(_0x2ebae1(0x117))/0x3*(-parseInt(_0x2ebae1(0x126))/0x4)+parseInt(_0x2ebae1(0x11a))/0x5+-parseInt(_0x2ebae1(0x125))/0x6+-parseInt(_0x2ebae1(0x119))/0x7+parseInt(_0x2ebae1(0x11f))/0x8+parseInt(_0x2ebae1(0x118))/0x9*(parseInt(_0x2ebae1(0x123))/0xa);if(_0x149517===_0x48ad19)break;else _0x5cd27b['push'](_0x5cd27b['shift']());}catch(_0x37e354){_0x5cd27b['push'](_0x5cd27b['shift']());}}}(_0x4d2e,0x8e5df));import _0x2ce2a8 from'node:path';function _0x3286(_0x214c65,_0xcf0d67){const _0x4d2e34=_0x4d2e();return _0x3286=function(_0x32869b,_0x169250){_0x32869b=_0x32869b-0x117;let _0x2f6ba6=_0x4d2e34[_0x32869b];return _0x2f6ba6;},_0x3286(_0x214c65,_0xcf0d67);}import _0x33e602 from'node:fs';import{qqVersionConfigInfo}from'@/common/utils/QQBasicInfo';let wrapperNodePath=_0x2ce2a8[_0xd2faf4(0x11d)](_0x2ce2a8[_0xd2faf4(0x122)](process['execPath']),_0xd2faf4(0x121));!_0x33e602[_0xd2faf4(0x11e)](wrapperNodePath)&&(wrapperNodePath=_0x2ce2a8[_0xd2faf4(0x11b)](_0x2ce2a8[_0xd2faf4(0x122)](process['execPath']),_0xd2faf4(0x11c)+qqVersionConfigInfo['curVersion']+'/wrapper.node'));const QQWrapper=require(wrapperNodePath);export default QQWrapper; \ No newline at end of file diff --git a/src/core.lib/src/service/buddy.d.ts b/src/core.lib/src/service/buddy.d.ts new file mode 100644 index 00000000..25061797 --- /dev/null +++ b/src/core.lib/src/service/buddy.d.ts @@ -0,0 +1,19 @@ +import { BuddyListener } from '../qqnt/listeners'; +import { NodeIKernelBuddyService } from '../qqnt/services'; +/** + * NapCat 服务相关核心好友子类 + * + * **【注意】**:只有在调用 `init` 方法后才会被真正初始化! + */ +export declare class NapCatCoreServiceBuddy { + kernelService: NodeIKernelBuddyService | null; + readonly listener: BuddyListener; + constructor(); + /** + * 初始化好友服务 + * @param {NodeIKernelBuddyService} service 好友服务 + * @returns {void} + */ + init(service: NodeIKernelBuddyService): void; + addBuddyListener(listener: BuddyListener): void; +} diff --git a/src/core.lib/src/service/buddy.js b/src/core.lib/src/service/buddy.js new file mode 100644 index 00000000..c2014c2c --- /dev/null +++ b/src/core.lib/src/service/buddy.js @@ -0,0 +1 @@ +const _0x98c163=_0x2d99;(function(_0x1d8dee,_0xaff6be){const _0x5e81e4=_0x2d99,_0x129d1f=_0x1d8dee();while(!![]){try{const _0x567f48=-parseInt(_0x5e81e4(0xec))/0x1+-parseInt(_0x5e81e4(0xee))/0x2+-parseInt(_0x5e81e4(0xf0))/0x3*(-parseInt(_0x5e81e4(0xfe))/0x4)+-parseInt(_0x5e81e4(0xf1))/0x5+parseInt(_0x5e81e4(0xea))/0x6+-parseInt(_0x5e81e4(0xf4))/0x7+parseInt(_0x5e81e4(0xeb))/0x8;if(_0x567f48===_0xaff6be)break;else _0x129d1f['push'](_0x129d1f['shift']());}catch(_0x3ad9b2){_0x129d1f['push'](_0x129d1f['shift']());}}}(_0x289f,0x62ae2));function _0x289f(){const _0xd1a900=['491840ZBZqwB','get','6wIPrZH','167905kqdKoS','uin','then','5576725OdBhoQ','onBuddyListChange','uid','MessageService\x20already\x20initialized!','assign','kernelService','listener','buddyList','addKernelBuddyListener','addBuddyListener','566792UkClbM','1472628qfARXb','13555032YyooJl','742843bXECxb','NodeIKernelBuddyListener'];_0x289f=function(){return _0xd1a900;};return _0x289f();}function _0x2d99(_0x2eadc8,_0x122239){const _0x289f27=_0x289f();return _0x2d99=function(_0x2d999d,_0xb1df70){_0x2d999d=_0x2d999d-0xea;let _0x641dc5=_0x289f27[_0x2d999d];return _0x641dc5;},_0x2d99(_0x2eadc8,_0x122239);}import{Wrapper as _0x11bf57}from'../qqnt';import{BuddyListener}from'../qqnt/listeners';import{friends,uid2UinMap}from'@/common/data';export class NapCatCoreServiceBuddy{[_0x98c163(0xf9)]=null;['listener'];constructor(){this['listener']=new BuddyListener();}['init'](_0x36c779){const _0x5d496d=_0x98c163,_0x56fff9={'sOPmo':function(_0x45088b,_0x236f7d){return _0x45088b!==_0x236f7d;}};if(_0x56fff9['sOPmo'](this[_0x5d496d(0xf9)],null))throw new Error(_0x5d496d(0xf7));this[_0x5d496d(0xf9)]=_0x36c779,this[_0x5d496d(0xfa)][_0x5d496d(0xf5)]=_0x5a2a1a=>{const _0x34eb95=_0x5d496d;for(const _0x20f40c of _0x5a2a1a){for(const _0x44acea of _0x20f40c[_0x34eb95(0xfb)]){const _0x3fa65a=friends[_0x34eb95(0xef)](_0x44acea[_0x34eb95(0xf6)]);uid2UinMap[_0x44acea['uid']]=_0x44acea[_0x34eb95(0xf2)],_0x3fa65a?Object[_0x34eb95(0xf8)](_0x3fa65a,_0x44acea):friends['set'](_0x44acea[_0x34eb95(0xf6)],_0x44acea);}}},this['kernelService'][_0x5d496d(0xfc)](new _0x11bf57['NodeIKernelBuddyListener'](this['listener'])),this[_0x5d496d(0xf9)]['getBuddyList'](!![])[_0x5d496d(0xf3)](_0x3f4c49=>{});}[_0x98c163(0xfd)](_0x3d73b6){const _0x43e3eb=_0x98c163;this[_0x43e3eb(0xf9)]?.['addKernelBuddyListener'](new _0x11bf57[(_0x43e3eb(0xed))](_0x3d73b6));}} \ No newline at end of file diff --git a/src/core.lib/src/service/group.d.ts b/src/core.lib/src/service/group.d.ts new file mode 100644 index 00000000..4752579a --- /dev/null +++ b/src/core.lib/src/service/group.d.ts @@ -0,0 +1,19 @@ +import { GroupListener } from '../qqnt/listeners'; +import { NodeIKernelGroupService } from '../qqnt/services'; +/** + * NapCat 服务相关核心群聊子类 + * + * **【注意】**:只有在调用 `init` 方法后才会被真正初始化! + */ +export declare class NapCatCoreServiceGroup { + kernelService: NodeIKernelGroupService | null; + readonly listener: GroupListener; + constructor(); + /** + * 初始化群聊服务 + * @param {NodeIKernelGroupService} service 群聊服务 + * @returns {void} + */ + init(service: NodeIKernelGroupService): void; + addGroupListener(listener: GroupListener): void; +} diff --git a/src/core.lib/src/service/group.js b/src/core.lib/src/service/group.js new file mode 100644 index 00000000..0426cd32 --- /dev/null +++ b/src/core.lib/src/service/group.js @@ -0,0 +1 @@ +const _0x576214=_0x5ebe;(function(_0x129ca7,_0x12d023){const _0x2c4003=_0x5ebe,_0x11ce59=_0x129ca7();while(!![]){try{const _0x222654=-parseInt(_0x2c4003(0x8c))/0x1+parseInt(_0x2c4003(0x81))/0x2*(parseInt(_0x2c4003(0x89))/0x3)+parseInt(_0x2c4003(0x80))/0x4+-parseInt(_0x2c4003(0x92))/0x5*(parseInt(_0x2c4003(0x79))/0x6)+-parseInt(_0x2c4003(0x75))/0x7+parseInt(_0x2c4003(0x88))/0x8+-parseInt(_0x2c4003(0x90))/0x9;if(_0x222654===_0x12d023)break;else _0x11ce59['push'](_0x11ce59['shift']());}catch(_0x167a8d){_0x11ce59['push'](_0x11ce59['shift']());}}}(_0x45a0,0x26796));import{Wrapper as _0x25730d}from'../qqnt';function _0x45a0(){const _0x79fab9=['addKernelGroupListener','forEach','onMemberListChange','1486520Abnssi','14631yFxCdT','GroupService\x20already\x20initialized!','get','90525linqUW','sceneId','groupCode','assign','2011338QgJwwT','kernelService','46015WQzUau','136892Ddcvql','uin','onMemberInfoChange','listener','60FgfuDr','addGroupListener','split','then','iZQXc','has','infos','867676lYRVgT','74hOWeEP','set','NodeIKernelGroupListener','map'];_0x45a0=function(){return _0x79fab9;};return _0x45a0();}import{GroupListener}from'../qqnt/listeners';function _0x5ebe(_0x243fd4,_0x3aacb5){const _0x45a01d=_0x45a0();return _0x5ebe=function(_0x5ebeda,_0x15a048){_0x5ebeda=_0x5ebeda-0x75;let _0x5ef5e1=_0x45a01d[_0x5ebeda];return _0x5ef5e1;},_0x5ebe(_0x243fd4,_0x3aacb5);}import{groupMembers,groups,uid2UinMap}from'@/common/data';export class NapCatCoreServiceGroup{[_0x576214(0x91)]=null;[_0x576214(0x78)];constructor(){this['listener']=new GroupListener();}['init'](_0x5458a0){const _0x1af8c7=_0x576214,_0x1f9776={'iZQXc':'groupMemberList_MainWindow'};if(this['kernelService']!==null)throw new Error(_0x1af8c7(0x8a));this[_0x1af8c7(0x91)]=_0x5458a0,this[_0x1af8c7(0x78)]['onGroupListUpdate']=(_0x4bb8a6,_0x56b65f)=>{const _0x13f0b3=_0x1af8c7;_0x56b65f[_0x13f0b3(0x84)](_0x185f56=>{const _0x2db7b0=_0x13f0b3,_0x162455=groups['get'](_0x185f56[_0x2db7b0(0x8e)]);if(_0x162455)Object[_0x2db7b0(0x8f)](_0x162455,_0x185f56);else{groups[_0x2db7b0(0x82)](_0x185f56[_0x2db7b0(0x8e)],_0x185f56);const _0x1cf381=this[_0x2db7b0(0x91)]?.['createMemberListScene'](_0x185f56[_0x2db7b0(0x8e)],_0x1f9776[_0x2db7b0(0x7d)]);this[_0x2db7b0(0x91)]?.['getNextMemberList'](_0x1cf381,undefined,0xbb8)[_0x2db7b0(0x7c)](_0x2c6f7c=>{});}});},this['listener'][_0x1af8c7(0x87)]=_0x1a16ae=>{const _0x435627=_0x1af8c7,_0x3709b3=_0x1a16ae[_0x435627(0x8d)][_0x435627(0x7b)]('_')[0x0];if(groupMembers[_0x435627(0x7e)](_0x3709b3)){const _0x195200=groupMembers['get'](_0x3709b3);_0x1a16ae[_0x435627(0x7f)]['forEach']((_0x3d4b70,_0x1438a7)=>{const _0x174ae0=_0x435627,_0x4bef31=_0x195200['get'](_0x1438a7);_0x4bef31?Object[_0x174ae0(0x8f)](_0x4bef31,_0x3d4b70):_0x195200[_0x174ae0(0x82)](_0x1438a7,_0x3d4b70);});}else groupMembers[_0x435627(0x82)](_0x3709b3,_0x1a16ae[_0x435627(0x7f)]);},this[_0x1af8c7(0x78)][_0x1af8c7(0x77)]=(_0x2fd3fd,_0x3b9f20,_0x50c3e9)=>{const _0x54701b=_0x1af8c7;_0x50c3e9[_0x54701b(0x86)]((_0x233e13,_0x1dcd45)=>{const _0x28bc2d=_0x54701b;uid2UinMap[_0x1dcd45]=_0x233e13[_0x28bc2d(0x76)];});const _0x45ae85=groupMembers[_0x54701b(0x8b)](_0x2fd3fd);_0x45ae85?_0x50c3e9['forEach']((_0x588286,_0x2e44eb)=>{const _0xbf9ef7=_0x54701b,_0x2fdba9=_0x45ae85[_0xbf9ef7(0x8b)](_0x2e44eb);_0x2fdba9?Object[_0xbf9ef7(0x8f)](_0x2fdba9,_0x588286):_0x45ae85[_0xbf9ef7(0x82)](_0x2e44eb,_0x588286);}):groupMembers[_0x54701b(0x82)](_0x2fd3fd,_0x50c3e9);},this[_0x1af8c7(0x91)][_0x1af8c7(0x85)](new _0x25730d[(_0x1af8c7(0x83))](this['listener']));}[_0x576214(0x7a)](_0x3e2566){const _0x4735a1=_0x576214;this[_0x4735a1(0x91)]?.[_0x4735a1(0x85)](new _0x25730d[(_0x4735a1(0x83))](_0x3e2566));}} \ No newline at end of file diff --git a/src/core.lib/src/service/index.d.ts b/src/core.lib/src/service/index.d.ts new file mode 100644 index 00000000..d5bbfd22 --- /dev/null +++ b/src/core.lib/src/service/index.d.ts @@ -0,0 +1,35 @@ +import { NapCatCoreServiceMessage } from './message'; +import { NapCatCoreServiceGroup } from './group'; +import { NapCatCoreServiceBuddy } from './buddy'; +import { NapCatCoreServiceProfile } from './profile'; +import { NapCatCoreServiceProfileLike } from './profileLike'; +import { NodeIKernelBuddyService, NodeIKernelGroupService, NodeIKernelMsgService, NodeIKernelProfileService, NodeIKernelProfileLikeService } from '../qqnt/services'; +import { NapCatCore } from '..'; +/** + * NapCat 服务相关核心类 + * + * 本核心类分有三个小类,分别为 `messgae`、`group` 和 `buddy` 类。每个小类内包含其服务和监听器。 + * + * **【注意】**:只有在调用 `init` 方法后才会被真正初始化! + */ +export declare class NapCatCoreService { + private isInit; + private readonly core; + msg: NapCatCoreServiceMessage; + group: NapCatCoreServiceGroup; + buddy: NapCatCoreServiceBuddy; + profile: NapCatCoreServiceProfile; + profileLike: NapCatCoreServiceProfileLike; + constructor(core: NapCatCore); + /** + * 初始化服务,需在初始化 WrapperSession 后调用。相关服务请通过调用初始化后的 WrapperSession 获取。 + * @param {NodeIKernelMsgService} msg 消息通知服务 + * @param {NodeIKernelGroupService} group 群聊相关服务 + * @param {NodeIKernelBuddyService} buddy 好友相关服务 + * @param profile + * @param profileLike + * @returns {void} + */ + init(msg: NodeIKernelMsgService, group: NodeIKernelGroupService, buddy: NodeIKernelBuddyService, profile: NodeIKernelProfileService, profileLike: NodeIKernelProfileLikeService): void; + private initListener; +} diff --git a/src/core.lib/src/service/index.js b/src/core.lib/src/service/index.js new file mode 100644 index 00000000..ff1e3246 --- /dev/null +++ b/src/core.lib/src/service/index.js @@ -0,0 +1 @@ +const _0x357ff6=_0x1dc0;(function(_0x173f24,_0x2113ce){const _0xc626f2=_0x1dc0,_0x1b7510=_0x173f24();while(!![]){try{const _0x2e4edd=parseInt(_0xc626f2(0xb9))/0x1+parseInt(_0xc626f2(0xb3))/0x2+parseInt(_0xc626f2(0xc6))/0x3+parseInt(_0xc626f2(0xc4))/0x4*(-parseInt(_0xc626f2(0xae))/0x5)+-parseInt(_0xc626f2(0xab))/0x6*(parseInt(_0xc626f2(0xba))/0x7)+parseInt(_0xc626f2(0xbf))/0x8+-parseInt(_0xc626f2(0xbe))/0x9;if(_0x2e4edd===_0x2113ce)break;else _0x1b7510['push'](_0x1b7510['shift']());}catch(_0x3eb59c){_0x1b7510['push'](_0x1b7510['shift']());}}}(_0x2cda,0xad53f));import{NapCatCoreServiceMessage}from'./message';import{NapCatCoreServiceGroup}from'./group';import{NapCatCoreServiceBuddy}from'./buddy';import{NapCatCoreServiceProfile}from'./profile';import{NapCatCoreServiceProfileLike}from'./profileLike';function _0x2cda(){const _0x3cd756=['30nUvLWP','onRecvMsg','6|0|5|2|7|1|3|4','5FjcdOy','SloWw','OCuvr','core','msg','225682MUjQMk','profileLike','group','emit','IISUP','5|1|3|4|2|0','1362295YXInyh','168483RnRhWK','listener','QsESJ','buddy','10722978JkEwaL','1358872pZZuyd','message','message.private','isInit','profile','579868STMGjp','initListener','1565130qcJYZe','peerUin','split','axNLG','init'];_0x2cda=function(){return _0x3cd756;};return _0x2cda();}function _0x1dc0(_0x157f05,_0x25aab6){const _0x2cda56=_0x2cda();return _0x1dc0=function(_0x1dc0b1,_0x5ebd1a){_0x1dc0b1=_0x1dc0b1-0xa7;let _0x34fc7b=_0x2cda56[_0x1dc0b1];return _0x34fc7b;},_0x1dc0(_0x157f05,_0x25aab6);}export class NapCatCoreService{[_0x357ff6(0xc2)]=![];['core'];[_0x357ff6(0xb2)];[_0x357ff6(0xb5)];[_0x357ff6(0xbd)];[_0x357ff6(0xc3)];[_0x357ff6(0xb4)];constructor(_0x359075){const _0x2a4f35=_0x357ff6,_0x3af7d0={'QsESJ':_0x2a4f35(0xb8)},_0x144e59=_0x3af7d0[_0x2a4f35(0xbc)][_0x2a4f35(0xa8)]('|');let _0x548f1c=0x0;while(!![]){switch(_0x144e59[_0x548f1c++]){case'0':this[_0x2a4f35(0xb4)]=new NapCatCoreServiceProfileLike();continue;case'1':this['msg']=new NapCatCoreServiceMessage();continue;case'2':this[_0x2a4f35(0xc3)]=new NapCatCoreServiceProfile();continue;case'3':this[_0x2a4f35(0xb5)]=new NapCatCoreServiceGroup();continue;case'4':this['buddy']=new NapCatCoreServiceBuddy();continue;case'5':this[_0x2a4f35(0xb1)]=_0x359075;continue;}break;}}[_0x357ff6(0xaa)](_0x4eaf3c,_0x3ecf05,_0x2297ff,_0x2d2cd2,_0x3a8b26){const _0x346ca4=_0x357ff6,_0xc339a1={'axNLG':_0x346ca4(0xad),'SloWw':'Services\x20already\x20initialized!'},_0x12234e=_0xc339a1[_0x346ca4(0xa9)]['split']('|');let _0x2d6f9a=0x0;while(!![]){switch(_0x12234e[_0x2d6f9a++]){case'0':this[_0x346ca4(0xb2)][_0x346ca4(0xaa)](_0x4eaf3c);continue;case'1':this[_0x346ca4(0xb4)][_0x346ca4(0xaa)](_0x3a8b26);continue;case'2':this[_0x346ca4(0xbd)][_0x346ca4(0xaa)](_0x2297ff);continue;case'3':this[_0x346ca4(0xc5)]();continue;case'4':this['isInit']=!![];continue;case'5':this[_0x346ca4(0xb5)]['init'](_0x3ecf05);continue;case'6':if(this[_0x346ca4(0xc2)])throw new Error(_0xc339a1[_0x346ca4(0xaf)]);continue;case'7':this['profile'][_0x346ca4(0xaa)](_0x2d2cd2);continue;}break;}}[_0x357ff6(0xc5)](){const _0x1e635d=_0x357ff6,_0xbf913c={'OCuvr':_0x1e635d(0xc0),'IISUP':_0x1e635d(0xc1)};this[_0x1e635d(0xb2)][_0x1e635d(0xbb)][_0x1e635d(0xac)]=_0x19a5c5=>{const _0x30452e=_0x1e635d;for(const _0x254a6c of _0x19a5c5){this[_0x30452e(0xb1)][_0x30452e(0xb6)](_0xbf913c[_0x30452e(0xb0)],_0x254a6c);if(_0x254a6c[_0x30452e(0xa7)]!==_0x254a6c['senderUin'])this[_0x30452e(0xb1)]['emit']('message.group',_0x254a6c);else this['core']['emit'](_0xbf913c[_0x30452e(0xb7)],_0x254a6c);}};}} \ No newline at end of file diff --git a/src/core.lib/src/service/message.d.ts b/src/core.lib/src/service/message.d.ts new file mode 100644 index 00000000..9e7e509e --- /dev/null +++ b/src/core.lib/src/service/message.d.ts @@ -0,0 +1,19 @@ +import { MsgListener } from '../qqnt/listeners'; +import { NodeIKernelMsgService } from '../qqnt/services'; +/** + * NapCat 服务相关核心消息子类 + * + * **【注意】**:只有在调用 `init` 方法后才会被真正初始化! + */ +export declare class NapCatCoreServiceMessage { + kernelService: NodeIKernelMsgService | null; + readonly listener: MsgListener; + constructor(); + /** + * 初始化消息服务 + * @param {NodeIKernelMsgService} service 消息服务 + * @returns {void} + */ + init(service: NodeIKernelMsgService): void; + addMsgListener(listener: MsgListener): void | undefined; +} diff --git a/src/core.lib/src/service/message.js b/src/core.lib/src/service/message.js new file mode 100644 index 00000000..6cf8c74e --- /dev/null +++ b/src/core.lib/src/service/message.js @@ -0,0 +1 @@ +var _0x4b1a9f=_0x4a83;function _0x350a(){var _0x477b1c=['listener','MessageService\x20already\x20initialized!','msgId','catch','209860JRocFF','addMsg','NodeIKernelMsgListener','kernelService','1610915paRRgK','getMsgByLongId','309290dGcFHh','2093958qppgrU','1018179IJTFGr','637441LodAHY','then','72CKKOIx','addKernelMsgListener','recallTime','map','394056JTHAlT','onMsgInfoListUpdate','PKHFF'];_0x350a=function(){return _0x477b1c;};return _0x350a();}function _0x4a83(_0x76aabf,_0x4f5869){var _0x350a0a=_0x350a();return _0x4a83=function(_0x4a83da,_0x1c1b2c){_0x4a83da=_0x4a83da-0x1d1;var _0x41d8ab=_0x350a0a[_0x4a83da];return _0x41d8ab;},_0x4a83(_0x76aabf,_0x4f5869);}(function(_0x324314,_0x2f62d4){var _0xe9a213=_0x4a83,_0x73f2c1=_0x324314();while(!![]){try{var _0x38bab4=-parseInt(_0xe9a213(0x1da))/0x1+parseInt(_0xe9a213(0x1d4))/0x2+-parseInt(_0xe9a213(0x1dc))/0x3+-parseInt(_0xe9a213(0x1e3))/0x4+-parseInt(_0xe9a213(0x1d8))/0x5+parseInt(_0xe9a213(0x1db))/0x6+parseInt(_0xe9a213(0x1dd))/0x7*(parseInt(_0xe9a213(0x1df))/0x8);if(_0x38bab4===_0x2f62d4)break;else _0x73f2c1['push'](_0x73f2c1['shift']());}catch(_0x3959b8){_0x73f2c1['push'](_0x73f2c1['shift']());}}}(_0x350a,0x31d4e));import{Wrapper as _0x1d15ae}from'../qqnt';import{MsgListener}from'../qqnt/listeners';import{dbUtil}from'@/common/utils/db';export class NapCatCoreServiceMessage{[_0x4b1a9f(0x1d7)]=null;[_0x4b1a9f(0x1e6)];constructor(){var _0x211a25=_0x4b1a9f,_0x28f7b5={'qnjLW':function(_0x53936d,_0x518d20){return _0x53936d===_0x518d20;}};this[_0x211a25(0x1e6)]=new MsgListener(),this[_0x211a25(0x1e6)][_0x211a25(0x1e4)]=_0x58b7f7=>{var _0x40441d=_0x211a25,_0x1c3d99={'gASlk':function(_0x44b279,_0x3d2ba3){return _0x28f7b5['qnjLW'](_0x44b279,_0x3d2ba3);}};_0x58b7f7[_0x40441d(0x1e2)](_0x2caf55=>{var _0x218fd3=_0x40441d;_0x1c3d99['gASlk'](_0x2caf55['recallTime'],'0')?dbUtil[_0x218fd3(0x1d5)](_0x2caf55)[_0x218fd3(0x1de)]()[_0x218fd3(0x1d3)]():dbUtil[_0x218fd3(0x1d9)](_0x2caf55[_0x218fd3(0x1d2)])[_0x218fd3(0x1de)](_0x2c5688=>{var _0x14002b=_0x218fd3;_0x2c5688&&(_0x2c5688[_0x14002b(0x1e1)]=_0x2caf55[_0x14002b(0x1e1)],dbUtil['updateMsg'](_0x2c5688)[_0x14002b(0x1de)]());});});};}['init'](_0x1c6849){var _0x2d227f=_0x4b1a9f,_0x5a327e={'uGyMG':function(_0x933a45,_0xbe6956){return _0x933a45!==_0xbe6956;},'PKHFF':_0x2d227f(0x1d1)};if(_0x5a327e['uGyMG'](this[_0x2d227f(0x1d7)],null))throw new Error(_0x5a327e[_0x2d227f(0x1e5)]);this[_0x2d227f(0x1d7)]=_0x1c6849,this[_0x2d227f(0x1d7)]['addKernelMsgListener'](new _0x1d15ae[(_0x2d227f(0x1d6))](this[_0x2d227f(0x1e6)]));}['addMsgListener'](_0x125226){var _0x42e09f=_0x4b1a9f;return this[_0x42e09f(0x1d7)]?.[_0x42e09f(0x1e0)](new _0x1d15ae[(_0x42e09f(0x1d6))](_0x125226));}} \ No newline at end of file diff --git a/src/core.lib/src/service/profile.d.ts b/src/core.lib/src/service/profile.d.ts new file mode 100644 index 00000000..cdd7217d --- /dev/null +++ b/src/core.lib/src/service/profile.d.ts @@ -0,0 +1,9 @@ +import { ProfileListener } from '../qqnt/listeners'; +import { NodeIKernelProfileService } from '../qqnt/services'; +export declare class NapCatCoreServiceProfile { + kernelService: NodeIKernelProfileService | null; + readonly listener: ProfileListener; + constructor(); + init(service: NodeIKernelProfileService): void; + addProfileListener(listener: ProfileListener): void | undefined; +} diff --git a/src/core.lib/src/service/profile.js b/src/core.lib/src/service/profile.js new file mode 100644 index 00000000..2b4a7552 --- /dev/null +++ b/src/core.lib/src/service/profile.js @@ -0,0 +1 @@ +var _0x5be53b=_0x3d88;(function(_0x549ab2,_0xe6c83a){var _0x3eba08=_0x3d88,_0x357266=_0x549ab2();while(!![]){try{var _0x44955d=-parseInt(_0x3eba08(0x178))/0x1+-parseInt(_0x3eba08(0x167))/0x2+parseInt(_0x3eba08(0x173))/0x3+-parseInt(_0x3eba08(0x172))/0x4*(parseInt(_0x3eba08(0x16c))/0x5)+parseInt(_0x3eba08(0x17a))/0x6*(-parseInt(_0x3eba08(0x16a))/0x7)+parseInt(_0x3eba08(0x16e))/0x8*(parseInt(_0x3eba08(0x168))/0x9)+parseInt(_0x3eba08(0x16b))/0xa;if(_0x44955d===_0xe6c83a)break;else _0x357266['push'](_0x357266['shift']());}catch(_0x1e6934){_0x357266['push'](_0x357266['shift']());}}}(_0x5a12,0xdfada));function _0x5a12(){var _0x202b29=['listener','kernelService','addKernelProfileListener','1311719JGYCLb','getUserDetailInfoWithBizInfo','780FDNQEP','XHxTW','2482184fUguwu','2429613ildvPv','NodeIKernelProfileListener','55776DEWGZH','42541230lySDdu','5LRqpGZ','GjsPT','32FyFxPH','ProfileService\x20already\x20initialized!','assign','onProfileDetailInfoChanged','6727064QTkbGX','2557956OKrtuQ','uid'];_0x5a12=function(){return _0x202b29;};return _0x5a12();}function _0x3d88(_0x33913d,_0x25cc53){var _0x5a12ec=_0x5a12();return _0x3d88=function(_0x3d8858,_0x17fc81){_0x3d8858=_0x3d8858-0x167;var _0x5aef74=_0x5a12ec[_0x3d8858];return _0x5aef74;},_0x3d88(_0x33913d,_0x25cc53);}import{Wrapper as _0x3b59ed}from'../qqnt';import{ProfileListener}from'../qqnt/listeners';import{selfInfo}from'@/common/data';export class NapCatCoreServiceProfile{['kernelService']=null;[_0x5be53b(0x175)];constructor(){var _0x23ec05=_0x5be53b,_0x47dc44={'XHxTW':function(_0x1cc2f3,_0x4297fe){return _0x1cc2f3===_0x4297fe;}};this[_0x23ec05(0x175)]=new ProfileListener(),this[_0x23ec05(0x175)][_0x23ec05(0x171)]=_0x20498b=>{var _0x38e7b9=_0x23ec05;_0x47dc44[_0x38e7b9(0x17b)](_0x20498b[_0x38e7b9(0x174)],selfInfo[_0x38e7b9(0x174)])&&Object[_0x38e7b9(0x170)](selfInfo,_0x20498b);};}['init'](_0x26d1b8){var _0x4befb3=_0x5be53b,_0xeb46b7={'GjsPT':function(_0x3bebac,_0x51ebd4){return _0x3bebac!==_0x51ebd4;}};if(_0xeb46b7[_0x4befb3(0x16d)](this[_0x4befb3(0x176)],null))throw new Error(_0x4befb3(0x16f));this[_0x4befb3(0x176)]=_0x26d1b8,this[_0x4befb3(0x176)][_0x4befb3(0x177)](new _0x3b59ed[(_0x4befb3(0x169))](this['listener'])),this[_0x4befb3(0x176)][_0x4befb3(0x179)](selfInfo[_0x4befb3(0x174)],[0x1,0x0]);}['addProfileListener'](_0x46cab2){var _0x213739=_0x5be53b;return this[_0x213739(0x176)]?.[_0x213739(0x177)](new _0x3b59ed[(_0x213739(0x169))](_0x46cab2));}} \ No newline at end of file diff --git a/src/core.lib/src/service/profileLike.d.ts b/src/core.lib/src/service/profileLike.d.ts new file mode 100644 index 00000000..dfd01a93 --- /dev/null +++ b/src/core.lib/src/service/profileLike.d.ts @@ -0,0 +1,5 @@ +import { NodeIKernelProfileLikeService } from '../qqnt/services'; +export declare class NapCatCoreServiceProfileLike { + kernelService: NodeIKernelProfileLikeService | null; + init(service: NodeIKernelProfileLikeService): void; +} diff --git a/src/core.lib/src/service/profileLike.js b/src/core.lib/src/service/profileLike.js new file mode 100644 index 00000000..c2c31b72 --- /dev/null +++ b/src/core.lib/src/service/profileLike.js @@ -0,0 +1 @@ +var _0x160c15=_0x4946;function _0x33d2(){var _0x2691ae=['ProfileLikeService\x20already\x20initialized!','init','729305lxZYmZ','205646LzZZwv','393768sbZWuy','1432779SVlOYX','kernelService','487657rFEwAe','8IBhOtM','3620385doIfJw','3784767qbyjGm','6yBYhlT'];_0x33d2=function(){return _0x2691ae;};return _0x33d2();}(function(_0x4185ad,_0x2c6124){var _0x4f53db=_0x4946,_0x243e41=_0x4185ad();while(!![]){try{var _0x1aaa99=parseInt(_0x4f53db(0x1e6))/0x1+parseInt(_0x4f53db(0x1e2))/0x2+-parseInt(_0x4f53db(0x1e4))/0x3+-parseInt(_0x4f53db(0x1e3))/0x4+-parseInt(_0x4f53db(0x1e1))/0x5*(-parseInt(_0x4f53db(0x1de))/0x6)+parseInt(_0x4f53db(0x1dd))/0x7+-parseInt(_0x4f53db(0x1e7))/0x8*(parseInt(_0x4f53db(0x1e8))/0x9);if(_0x1aaa99===_0x2c6124)break;else _0x243e41['push'](_0x243e41['shift']());}catch(_0x2608e3){_0x243e41['push'](_0x243e41['shift']());}}}(_0x33d2,0x48ee2));function _0x4946(_0x9665f2,_0x4f5ef8){var _0x33d27c=_0x33d2();return _0x4946=function(_0x494671,_0x103238){_0x494671=_0x494671-0x1dd;var _0x2d4c95=_0x33d27c[_0x494671];return _0x2d4c95;},_0x4946(_0x9665f2,_0x4f5ef8);}export class NapCatCoreServiceProfileLike{[_0x160c15(0x1e5)]=null;[_0x160c15(0x1e0)](_0x186581){var _0x429b44=_0x160c15,_0x30e00e={'hsBlk':function(_0x11caf1,_0x5d4824){return _0x11caf1!==_0x5d4824;}};if(_0x30e00e['hsBlk'](this[_0x429b44(0x1e5)],null))throw new Error(_0x429b44(0x1df));this['kernelService']=_0x186581;}} \ No newline at end of file diff --git a/src/core.lib/src/session.d.ts b/src/core.lib/src/session.d.ts new file mode 100644 index 00000000..6c717802 --- /dev/null +++ b/src/core.lib/src/session.d.ts @@ -0,0 +1,20 @@ +import { NodeIQQNTWrapperSession } from './qqnt/wrapper'; +import { SessionListener } from './qqnt/listeners'; +/** + * NapCat WrapperSession 相关核心类 + * + * **【注意】**:只有在调用 `init` 方法后才会被真正初始化! + */ +export declare class NapCatCoreSession { + wrapper: NodeIQQNTWrapperSession; + readonly listener: SessionListener; + constructor(); + /** + * 初始化 Wrapper。本方法应当在登陆成功后调用。 + * @param {string} uin 登陆账号的 uin + * @param {string} uid 登陆账号的 uid + * @param dataPath + * @returns {Promise} 返回回调状态码,不为 `0` 则抛出错误。 + */ + init(uin: string, uid: string, dataPath: string): Promise; +} diff --git a/src/core.lib/src/session.js b/src/core.lib/src/session.js new file mode 100644 index 00000000..4db5d5b6 --- /dev/null +++ b/src/core.lib/src/session.js @@ -0,0 +1 @@ +const _0x3e758b=_0x83f3;(function(_0x3c3bee,_0x10dd09){const _0xb175a3=_0x83f3,_0x171036=_0x3c3bee();while(!![]){try{const _0x42a44a=parseInt(_0xb175a3(0x11a))/0x1+-parseInt(_0xb175a3(0x120))/0x2+parseInt(_0xb175a3(0x11e))/0x3+parseInt(_0xb175a3(0x125))/0x4*(-parseInt(_0xb175a3(0x11f))/0x5)+-parseInt(_0xb175a3(0x117))/0x6*(-parseInt(_0xb175a3(0x122))/0x7)+-parseInt(_0xb175a3(0x119))/0x8+-parseInt(_0xb175a3(0x11b))/0x9*(-parseInt(_0xb175a3(0x124))/0xa);if(_0x42a44a===_0x10dd09)break;else _0x171036['push'](_0x171036['shift']());}catch(_0x5076bd){_0x171036['push'](_0x171036['shift']());}}}(_0x31da,0x38efc));import{Wrapper as _0x32ef1e}from'./qqnt';import{genSessionConfig}from'./qqnt/sessionConfig';import{DependsAdapter,DispatcherAdapter}from'./qqnt/adapters';import{SessionListener}from'./qqnt/listeners';export class NapCatCoreSession{['wrapper'];[_0x3e758b(0x128)];constructor(){const _0x1cb384=_0x3e758b;this[_0x1cb384(0x118)]=new _0x32ef1e['NodeIQQNTWrapperSession'](),this[_0x1cb384(0x128)]=new SessionListener();}[_0x3e758b(0x115)](_0x23e26b,_0xfb81fd,_0x14e661){const _0x5283ca=_0x3e758b,_0x1a7e9e={'gfJKY':function(_0x13baa0,_0x4209fd){return _0x13baa0===_0x4209fd;},'cJpvb':function(_0xda9e0e,_0x46ccef){return _0xda9e0e(_0x46ccef);},'cZtCg':_0x5283ca(0x121)};return new Promise((_0x310e11,_0x363c44)=>{const _0x28cac0=_0x5283ca,_0x252257=genSessionConfig(_0x23e26b,_0xfb81fd,_0x14e661);this['listener']['onSessionInitComplete']=_0x1459fd=>{const _0x4eedb1=_0x83f3;if(_0x1a7e9e['gfJKY'](_0x1459fd,0x0))return _0x1a7e9e[_0x4eedb1(0x11c)](_0x310e11,0x0);_0x363c44(_0x1459fd);},this[_0x28cac0(0x118)][_0x28cac0(0x115)](_0x252257,new _0x32ef1e[(_0x28cac0(0x11d))](new DependsAdapter()),new _0x32ef1e[(_0x28cac0(0x127))](new DispatcherAdapter()),new _0x32ef1e[(_0x28cac0(0x116))](this[_0x28cac0(0x128)]));try{this[_0x28cac0(0x118)]['startNT'](0x0);}catch(_0x35f0d0){try{this[_0x28cac0(0x118)][_0x28cac0(0x123)]();}catch(_0x2e55dd){console['error'](_0x1a7e9e[_0x28cac0(0x126)],_0x2e55dd);}}});}}function _0x83f3(_0x25861e,_0x50fc0f){const _0x31da7f=_0x31da();return _0x83f3=function(_0x83f338,_0x2db38a){_0x83f338=_0x83f338-0x115;let _0x17c240=_0x31da7f[_0x83f338];return _0x17c240;},_0x83f3(_0x25861e,_0x50fc0f);}function _0x31da(){const _0x384585=['listener','init','NodeIKernelSessionListener','6xHUDgv','wrapper','1981752whMzfA','42967xdqkVO','121221xvgcDy','cJpvb','NodeIDependsAdapter','1179045GaspyH','5FwpBaY','541876EgcVES','init\x20failed','286867rZEXRg','startNT','470vthzxS','1432548YZhApi','cZtCg','NodeIDispatcherAdapter'];_0x31da=function(){return _0x384585;};return _0x31da();} \ No newline at end of file diff --git a/src/core.lib/src/wrapper.d.ts b/src/core.lib/src/wrapper.d.ts new file mode 100644 index 00000000..a147155b --- /dev/null +++ b/src/core.lib/src/wrapper.d.ts @@ -0,0 +1,29 @@ +import { NodeIQQNTWrapperEngine, NodeQQNTWrapperUtil, EnginInitDesktopConfig } from './qqnt/wrapper'; +import { NodeIGlobalAdapter } from './qqnt/adapters'; +/** + * NapCat Wrapper 相关核心类 + * + * **【注意】**:本类初始化分为两个阶段,请参考本类的 `init` 和 `initPostLogin` 方法。 + */ +export declare class NapCatCoreWrapper { + engine: NodeIQQNTWrapperEngine; + util: NodeQQNTWrapperUtil; + constructor(); + /** + * 获取 QQNT 的数据目录 + * @returns {string} 数据目录绝对位置 + */ + get dataPath(): string; + /** + * 获取 QQNT 的全局数据目录 + * @returns {string} 数据目录绝对位置 + */ + get dataPathGlobal(): string; + /** + * 初始化 Wrapper。本方法应当在应用被创建时调用 + * @param {EnginInitDesktopConfig} engineConfig WrapperEngine 配置参数 + * @param {NodeIGlobalAdapter} globalAdapter 适配器,暂时未知其作用,待补充 + * @returns {void} + */ + init(engineConfig: EnginInitDesktopConfig, globalAdapter: NodeIGlobalAdapter): void; +} diff --git a/src/core.lib/src/wrapper.js b/src/core.lib/src/wrapper.js new file mode 100644 index 00000000..0945a51b --- /dev/null +++ b/src/core.lib/src/wrapper.js @@ -0,0 +1 @@ +const _0x521d21=_0x5c65;(function(_0x49f3ab,_0x36ea0d){const _0x1cf05c=_0x5c65,_0x1bb62f=_0x49f3ab();while(!![]){try{const _0x1f52f0=parseInt(_0x1cf05c(0x161))/0x1*(parseInt(_0x1cf05c(0x160))/0x2)+-parseInt(_0x1cf05c(0x16d))/0x3*(parseInt(_0x1cf05c(0x171))/0x4)+-parseInt(_0x1cf05c(0x170))/0x5+-parseInt(_0x1cf05c(0x15f))/0x6+-parseInt(_0x1cf05c(0x16b))/0x7*(-parseInt(_0x1cf05c(0x15c))/0x8)+-parseInt(_0x1cf05c(0x16c))/0x9*(-parseInt(_0x1cf05c(0x16e))/0xa)+parseInt(_0x1cf05c(0x165))/0xb*(parseInt(_0x1cf05c(0x15b))/0xc);if(_0x1f52f0===_0x36ea0d)break;else _0x1bb62f['push'](_0x1bb62f['shift']());}catch(_0x4f0181){_0x1bb62f['push'](_0x1bb62f['shift']());}}}(_0x35d8,0xe2ac6));function _0x5c65(_0x30e19a,_0x251aa6){const _0x35d877=_0x35d8();return _0x5c65=function(_0x5c6592,_0x40734a){_0x5c6592=_0x5c6592-0x15b;let _0x19c334=_0x35d877[_0x5c6592];return _0x19c334;},_0x5c65(_0x30e19a,_0x251aa6);}import _0x22ff4b from'node:os';function _0x35d8(){const _0x448e27=['ABjKe','init','dataPathGlobal','5397OGMmaF','43911bdHfLl','97551HpnpLw','1720czoHpU','NodeIQQNTWrapperEngine','791740rUqYKT','172jIsIox','131964xyaCvE','8216VmxsfA','initWithDeskTopConfig','dataPath','11120466feztiF','65002XojFlE','18siIoQP','engine','util','resolve','2123FZoqFK','./nt_qq/global','NodeQQNTWrapperUtil'];_0x35d8=function(){return _0x448e27;};return _0x35d8();}import _0x1311bd from'node:fs';import _0xa3f4f2 from'node:path';import{Wrapper as _0xe906ff}from'./qqnt';export class NapCatCoreWrapper{[_0x521d21(0x162)];[_0x521d21(0x163)];constructor(){const _0x3c41e6=_0x521d21;this[_0x3c41e6(0x162)]=new _0xe906ff[(_0x3c41e6(0x16f))](),this[_0x3c41e6(0x163)]=new _0xe906ff[(_0x3c41e6(0x167))]();}get['dataPath'](){const _0x1c4952=_0x521d21;let _0x2c17f2=this[_0x1c4952(0x163)]['getNTUserDataInfoConfig']();return!_0x2c17f2&&(_0x2c17f2=_0xa3f4f2[_0x1c4952(0x164)](_0x22ff4b['homedir'](),'./.config/QQ'),_0x1311bd['mkdirSync'](_0x2c17f2,{'recursive':!![]})),_0x2c17f2;}get[_0x521d21(0x16a)](){const _0x3e0d2a=_0x521d21,_0xb81e7={'ABjKe':_0x3e0d2a(0x166)};return _0xa3f4f2[_0x3e0d2a(0x164)](this[_0x3e0d2a(0x15e)],_0xb81e7[_0x3e0d2a(0x168)]);}[_0x521d21(0x169)](_0x1e461e,_0x15a4e3){const _0x92b7ea=_0x521d21;this[_0x92b7ea(0x162)][_0x92b7ea(0x15d)](_0x1e461e,_0x15a4e3);}} \ No newline at end of file diff --git a/src/onebot11/action/BaseAction.ts b/src/onebot11/action/BaseAction.ts new file mode 100644 index 00000000..eacc9b39 --- /dev/null +++ b/src/onebot11/action/BaseAction.ts @@ -0,0 +1,49 @@ +import { ActionName, BaseCheckResult } from './types'; +import { OB11Response } from './OB11Response'; +import { OB11Return } from '../types'; + +import { log } from '../../common/utils/log'; + +class BaseAction { + actionName: ActionName; + + protected async check(payload: PayloadType): Promise { + return { + valid: true, + }; + } + + public async handle(payload: PayloadType): Promise> { + const result = await this.check(payload); + if (!result.valid) { + return OB11Response.error(result.message, 400); + } + try { + const resData = await this._handle(payload); + return OB11Response.ok(resData); + } catch (e) { + log('发生错误', e); + return OB11Response.error(e?.toString() || e?.stack?.toString() || '未知错误,可能操作超时', 200); + } + } + + public async websocketHandle(payload: PayloadType, echo: any): Promise> { + const result = await this.check(payload); + if (!result.valid) { + return OB11Response.error(result.message, 1400); + } + try { + const resData = await this._handle(payload); + return OB11Response.ok(resData, echo); + } catch (e) { + log('发生错误', e); + return OB11Response.error(e.stack?.toString() || e.toString(), 1200, echo); + } + } + + protected async _handle(payload: PayloadType): Promise { + throw `pleas override ${this.actionName} _handle`; + } +} + +export default BaseAction; \ No newline at end of file diff --git a/src/onebot11/action/OB11Response.ts b/src/onebot11/action/OB11Response.ts new file mode 100644 index 00000000..ddc9d72b --- /dev/null +++ b/src/onebot11/action/OB11Response.ts @@ -0,0 +1,32 @@ +import { OB11Return } from '../types'; + +import { isNull } from '../../common/utils/helper'; + +export class OB11Response { + static res(data: T, status: string, retcode: number, message: string = ''): OB11Return { + return { + status: status, + retcode: retcode, + data: data, + message: message, + wording: message, + echo: null + }; + } + + static ok(data: T, echo: any = null) { + const res = OB11Response.res(data, 'ok', 0); + if (!isNull(echo)) { + res.echo = echo; + } + return res; + } + + static error(err: string, retcode: number, echo: any = null) { + const res = OB11Response.res(null, 'failed', retcode, err); + if (!isNull(echo)) { + res.echo = echo; + } + return res; + } +} diff --git a/src/onebot11/action/file/GetFile.ts b/src/onebot11/action/file/GetFile.ts new file mode 100644 index 00000000..f755e730 --- /dev/null +++ b/src/onebot11/action/file/GetFile.ts @@ -0,0 +1,116 @@ +import BaseAction from '../BaseAction'; +import fs from 'fs/promises'; +import { dbUtil } from '@/common/utils/db'; +import { ob11Config } from '@/onebot11/config'; +import { log } from '@/common/utils/log'; +import { sleep } from '@/common/utils/helper'; +import { uri2local } from '@/common/utils/file'; +import { ActionName } from '../types'; +import { FileElement, RawMessage, VideoElement } from '@/core/qqnt/entities'; +import { NTQQFileApi } from '@/core/qqnt/apis'; + +export interface GetFilePayload { + file: string; // 文件名或者fileUuid +} + +export interface GetFileResponse { + file?: string; // path + url?: string; + file_size?: string; + file_name?: string; + base64?: string; +} + + +export class GetFileBase extends BaseAction { + private getElement(msg: RawMessage): { id: string, element: VideoElement | FileElement } { + let element = msg.elements.find(e => e.fileElement); + if (!element) { + element = msg.elements.find(e => e.videoElement); + if (element) { + return { id: element.elementId, element: element.videoElement }; + } else { + throw new Error('找不到文件'); + } + } + return { id: element.elementId, element: element.fileElement }; + } + + protected async _handle(payload: GetFilePayload): Promise { + let cache = await dbUtil.getFileCacheByName(payload.file); + if (!cache) { + cache = await dbUtil.getFileCacheByUuid(payload.file); + } + if (!cache) { + throw new Error('file not found'); + } + const { enableLocalFile2Url } = ob11Config; + try { + await fs.access(cache.path, fs.constants.F_OK); + } catch (e) { + log('local file not found, start download...'); + // if (cache.url) { + // const downloadResult = await uri2local(cache.url); + // if (downloadResult.success) { + // cache.path = downloadResult.path; + // dbUtil.updateFileCache(cache).then(); + // } else { + // throw new Error('file download failed. ' + downloadResult.errMsg); + // } + // } else { + // // 没有url的可能是私聊文件或者群文件,需要自己下载 + // log('需要调用 NTQQ 下载文件api'); + let msg = await dbUtil.getMsgByLongId(cache.msgId); + // log('文件 msg', msg); + if (msg) { + // 构建下载函数 + const downloadPath = await NTQQFileApi.downloadMedia(msg.msgId, msg.chatType, msg.peerUid, + cache.elementId, '', ''); + // await sleep(1000); + + // log('download result', downloadPath); + msg = await dbUtil.getMsgByLongId(cache.msgId); + // log('下载完成后的msg', msg); + cache.path = downloadPath!; + dbUtil.updateFileCache(cache).then(); + // log('下载完成后的msg', msg); + // } + } + + } + // log('file found', cache); + const res: GetFileResponse = { + file: cache.path, + url: cache.url, + file_size: cache.size.toString(), + file_name: cache.name + }; + if (enableLocalFile2Url) { + if (!cache.url) { + try { + res.base64 = await fs.readFile(cache.path, 'base64'); + } catch (e) { + throw new Error('文件下载失败. ' + e); + } + } + } + // if (autoDeleteFile) { + // setTimeout(() => { + // fs.unlink(cache.filePath) + // }, autoDeleteFileSecond * 1000) + // } + return res; + } +} + +export default class GetFile extends GetFileBase { + actionName = ActionName.GetFile; + + protected async _handle(payload: { file_id: string, file: string }): Promise { + if (!payload.file_id) { + throw new Error('file_id 不能为空'); + } + payload.file = payload.file_id; + return super._handle(payload); + } +} diff --git a/src/onebot11/action/file/GetImage.ts b/src/onebot11/action/file/GetImage.ts new file mode 100644 index 00000000..457ccb29 --- /dev/null +++ b/src/onebot11/action/file/GetImage.ts @@ -0,0 +1,7 @@ +import { GetFileBase } from './GetFile'; +import { ActionName } from '../types'; + + +export default class GetImage extends GetFileBase { + actionName = ActionName.GetImage; +} \ No newline at end of file diff --git a/src/onebot11/action/file/GetRecord.ts b/src/onebot11/action/file/GetRecord.ts new file mode 100644 index 00000000..25435974 --- /dev/null +++ b/src/onebot11/action/file/GetRecord.ts @@ -0,0 +1,15 @@ +import { GetFileBase, GetFilePayload, GetFileResponse } from './GetFile'; +import { ActionName } from '../types'; + +interface Payload extends GetFilePayload { + out_format: 'mp3' | 'amr' | 'wma' | 'm4a' | 'spx' | 'ogg' | 'wav' | 'flac' +} + +export default class GetRecord extends GetFileBase { + actionName = ActionName.GetRecord; + + protected async _handle(payload: Payload): Promise { + const res = super._handle(payload); + return res; + } +} \ No newline at end of file diff --git a/src/onebot11/action/go-cqhttp/DownloadFile.ts b/src/onebot11/action/go-cqhttp/DownloadFile.ts new file mode 100644 index 00000000..1e8ecfe2 --- /dev/null +++ b/src/onebot11/action/go-cqhttp/DownloadFile.ts @@ -0,0 +1,73 @@ +import BaseAction from '../BaseAction'; +import { ActionName } from '../types'; +import fs from 'fs'; +import { join as joinPath } from 'node:path'; +import { calculateFileMD5, getTempDir, httpDownload } from '@/common/utils/file'; +import { v4 as uuid4 } from 'uuid'; + +interface Payload { + thread_count?: number; + url?: string; + base64?: string; + name?: string; + headers?: string | string[]; +} + +interface FileResponse { + file: string; +} + +export default class GoCQHTTPDownloadFile extends BaseAction { + actionName = ActionName.GoCQHTTP_DownloadFile; + + protected async _handle(payload: Payload): Promise { + const isRandomName = !payload.name; + const name = payload.name || uuid4(); + const filePath = joinPath(getTempDir(), name); + + if (payload.base64) { + fs.writeFileSync(filePath, payload.base64, 'base64'); + } else if (payload.url) { + const headers = this.getHeaders(payload.headers); + const buffer = await httpDownload({ url: payload.url, headers: headers }); + fs.writeFileSync(filePath, Buffer.from(buffer), 'binary'); + } else { + throw new Error('不存在任何文件, 无法下载'); + } + if (fs.existsSync(filePath)) { + + if (isRandomName) { + // 默认实现要名称未填写时文件名为文件 md5 + const md5 = await calculateFileMD5(filePath); + const newPath = joinPath(getTempDir(), md5); + fs.renameSync(filePath, newPath); + return { file: newPath }; + } + return { file: filePath }; + } else { + throw new Error('文件写入失败, 检查权限'); + } + } + + getHeaders(headersIn?: string | string[]): Record { + const headers: Record = {}; + if (typeof headersIn == 'string') { + headersIn = headersIn.split('[\\r\\n]'); + } + if (Array.isArray(headersIn)) { + for (const headerItem of headersIn) { + const spilt = headerItem.indexOf('='); + if (spilt < 0) { + headers[headerItem] = ''; + } else { + const key = headerItem.substring(0, spilt); + headers[key] = headerItem.substring(0, spilt + 1); + } + } + } + if (!headers['Content-Type']) { + headers['Content-Type'] = 'application/octet-stream'; + } + return headers; + } +} diff --git a/src/onebot11/action/go-cqhttp/GetForwardMsg.ts b/src/onebot11/action/go-cqhttp/GetForwardMsg.ts new file mode 100644 index 00000000..faf6c247 --- /dev/null +++ b/src/onebot11/action/go-cqhttp/GetForwardMsg.ts @@ -0,0 +1,43 @@ +import BaseAction from '../BaseAction'; +import { OB11ForwardMessage, OB11Message, OB11MessageData } from '../../types'; +import { NTQQMsgApi } from '@/core/qqnt/apis'; +import { dbUtil } from '@/common/utils/db'; +import { OB11Constructor } from '../../constructor'; +import { ActionName } from '../types'; + +interface Payload { + message_id: string; // long msg id +} + +interface Response { + messages: (OB11Message & { content: OB11MessageData })[]; +} + +export class GoCQHTTGetForwardMsgAction extends BaseAction { + actionName = ActionName.GoCQHTTP_GetForwardMsg; + + protected async _handle(payload: Payload): Promise { + const rootMsg = await dbUtil.getMsgByLongId(payload.message_id); + if (!rootMsg) { + throw Error('msg not found'); + } + const data = await NTQQMsgApi.getMultiMsg({ + chatType: rootMsg.chatType, + peerUid: rootMsg.peerUid + }, rootMsg.msgId, rootMsg.msgId); + if (!data || data.result !== 0) { + throw Error('找不到相关的聊天记录' + data?.errMsg); + } + const msgList = data.msgList; + const messages = await Promise.all(msgList.map(async msg => { + const resMsg = await OB11Constructor.message(msg); + resMsg.message_id = await dbUtil.addMsg(msg); + return resMsg; + })); + messages.map(msg => { + (msg).content = msg.message; + delete (msg).message; + }); + return {messages}; + } +} diff --git a/src/onebot11/action/go-cqhttp/GetGroupMsgHistory.ts b/src/onebot11/action/go-cqhttp/GetGroupMsgHistory.ts new file mode 100644 index 00000000..2a9c0245 --- /dev/null +++ b/src/onebot11/action/go-cqhttp/GetGroupMsgHistory.ts @@ -0,0 +1,43 @@ +import BaseAction from '../BaseAction'; +import { OB11Message, OB11User } from '../../types'; +import { getGroup, groups } from '@/common/data'; +import { ActionName } from '../types'; +import { ChatType } from '@/core/qqnt/entities'; +import { dbUtil } from '@/common/utils/db'; +import { NTQQMsgApi } from '@/core/qqnt/apis/msg'; +import { OB11Constructor } from '../../constructor'; + + +interface Payload { + group_id: number + message_seq: number, + count: number +} + +interface Response { + messages: OB11Message[]; +} + +export default class GoCQHTTPGetGroupMsgHistory extends BaseAction { + actionName = ActionName.GoCQHTTP_GetGroupMsgHistory; + + protected async _handle(payload: Payload): Promise { + const group = await getGroup(payload.group_id.toString()); + if (!group) { + throw `群${payload.group_id}不存在`; + } + const startMsgId = (await dbUtil.getMsgByShortId(payload.message_seq))?.msgId || '0'; + // log("startMsgId", startMsgId) + const historyResult = (await NTQQMsgApi.getMsgHistory({ + chatType: ChatType.group, + peerUid: group.groupCode + }, startMsgId, parseInt(payload.count?.toString()) || 20)); + console.log(historyResult); + const msgList = historyResult.msgList; + await Promise.all(msgList.map(async msg => { + msg.id = await dbUtil.addMsg(msg); + })); + const ob11MsgList = await Promise.all(msgList.map(msg => OB11Constructor.message(msg))); + return { 'messages': ob11MsgList }; + } +} diff --git a/src/onebot11/action/go-cqhttp/GetStrangerInfo.ts b/src/onebot11/action/go-cqhttp/GetStrangerInfo.ts new file mode 100644 index 00000000..7f218a30 --- /dev/null +++ b/src/onebot11/action/go-cqhttp/GetStrangerInfo.ts @@ -0,0 +1,22 @@ +import BaseAction from '../BaseAction'; +import { OB11User } from '../../types'; +import { getUidByUin, uid2UinMap } from '@/common/data'; +import { OB11Constructor } from '../../constructor'; +import { ActionName } from '../types'; +import { NTQQUserApi } from '@/core/qqnt/apis/user'; +import { log } from '@/common/utils/log'; + + +export default class GoCQHTTPGetStrangerInfo extends BaseAction<{ user_id: number }, OB11User> { + actionName = ActionName.GoCQHTTP_GetStrangerInfo; + + protected async _handle(payload: { user_id: number }): Promise { + const user_id = payload.user_id.toString(); + log('uidMaps', uid2UinMap); + const uid = getUidByUin(user_id); + if (!uid) { + throw new Error('查无此人'); + } + return OB11Constructor.stranger(await NTQQUserApi.getUserDetailInfo(uid)); + } +} diff --git a/src/onebot11/action/go-cqhttp/SendForwardMsg.ts b/src/onebot11/action/go-cqhttp/SendForwardMsg.ts new file mode 100644 index 00000000..a2c2ce34 --- /dev/null +++ b/src/onebot11/action/go-cqhttp/SendForwardMsg.ts @@ -0,0 +1,20 @@ +import SendMsg, { convertMessage2List } from '../msg/SendMsg'; +import { OB11PostSendMsg } from '../../types'; +import { ActionName } from '../types'; + +export class GoCQHTTPSendForwardMsg extends SendMsg { + actionName = ActionName.GoCQHTTP_SendForwardMsg; + + protected async check(payload: OB11PostSendMsg) { + if (payload.messages) payload.message = convertMessage2List(payload.messages); + return super.check(payload); + } +} + +export class GoCQHTTPSendPrivateForwardMsg extends GoCQHTTPSendForwardMsg { + actionName = ActionName.GoCQHTTP_SendPrivateForwardMsg; +} + +export class GoCQHTTPSendGroupForwardMsg extends GoCQHTTPSendForwardMsg { + actionName = ActionName.GoCQHTTP_SendGroupForwardMsg; +} \ No newline at end of file diff --git a/src/onebot11/action/go-cqhttp/UploadGroupFile.ts b/src/onebot11/action/go-cqhttp/UploadGroupFile.ts new file mode 100644 index 00000000..e2fa46e0 --- /dev/null +++ b/src/onebot11/action/go-cqhttp/UploadGroupFile.ts @@ -0,0 +1,37 @@ +import BaseAction from '../BaseAction'; +import { getGroup } from '@/common/data'; +import { ActionName } from '../types'; +import { SendMsgElementConstructor } from '@/core/qqnt/entities/constructor'; +import { ChatType, SendFileElement } from '@/core/qqnt/entities'; +import fs from 'fs'; +import { NTQQMsgApi } from '@/core/qqnt/apis/msg'; +import { uri2local } from '@/common/utils/file'; + +interface Payload { + group_id: number; + file: string; + name: string; + folder: string; +} + +export default class GoCQHTTPUploadGroupFile extends BaseAction { + actionName = ActionName.GoCQHTTP_UploadGroupFile; + + protected async _handle(payload: Payload): Promise { + const group = await getGroup(payload.group_id.toString()); + if (!group) { + throw new Error(`群组${payload.group_id}不存在`); + } + let file = payload.file; + if (fs.existsSync(file)) { + file = `file://${file}`; + } + const downloadResult = await uri2local(file); + if (downloadResult.errMsg) { + throw new Error(downloadResult.errMsg); + } + const sendFileEle: SendFileElement = await SendMsgElementConstructor.file(downloadResult.path, payload.name); + await NTQQMsgApi.sendMsg({ chatType: ChatType.group, peerUid: group.groupCode }, [sendFileEle]); + return null; + } +} diff --git a/src/onebot11/action/group/GetGroupInfo.ts b/src/onebot11/action/group/GetGroupInfo.ts new file mode 100644 index 00000000..78592149 --- /dev/null +++ b/src/onebot11/action/group/GetGroupInfo.ts @@ -0,0 +1,24 @@ +import { getGroup } from '@/common/data'; +import { OB11Group } from '../../types'; +import { OB11Constructor } from '../../constructor'; +import BaseAction from '../BaseAction'; +import { ActionName } from '../types'; + +interface PayloadType { + group_id: number +} + +class GetGroupInfo extends BaseAction { + actionName = ActionName.GetGroupInfo; + + protected async _handle(payload: PayloadType) { + const group = await getGroup(payload.group_id.toString()); + if (group) { + return OB11Constructor.group(group); + } else { + throw `群${payload.group_id}不存在`; + } + } +} + +export default GetGroupInfo; diff --git a/src/onebot11/action/group/GetGroupList.ts b/src/onebot11/action/group/GetGroupList.ts new file mode 100644 index 00000000..24d1c8a3 --- /dev/null +++ b/src/onebot11/action/group/GetGroupList.ts @@ -0,0 +1,20 @@ +import { OB11Group } from '../../types'; +import { OB11Constructor } from '../../constructor'; +import BaseAction from '../BaseAction'; +import { ActionName } from '../types'; +import { groups } from '@/common/data'; + + +class GetGroupList extends BaseAction { + actionName = ActionName.GetGroupList; + + protected async _handle(payload: null) { + // if (groups.length === 0) { + // const groups = await NTQQGroupApi.getGroups(true) + // log("get groups", groups) + // } + return OB11Constructor.groups(Array.from(groups.values())); + } +} + +export default GetGroupList; diff --git a/src/onebot11/action/group/GetGroupMemberInfo.ts b/src/onebot11/action/group/GetGroupMemberInfo.ts new file mode 100644 index 00000000..4bab508d --- /dev/null +++ b/src/onebot11/action/group/GetGroupMemberInfo.ts @@ -0,0 +1,38 @@ +import { OB11GroupMember } from '../../types'; +import { getGroupMember } from '../../../common/data'; +import { OB11Constructor } from '../../constructor'; +import BaseAction from '../BaseAction'; +import { ActionName } from '../types'; +import { NTQQUserApi } from '@/core/qqnt/apis/user'; +import { log } from '../../../common/utils/log'; +import { isNull } from '../../../common/utils/helper'; + + +export interface PayloadType { + group_id: number; + user_id: number; +} + +class GetGroupMemberInfo extends BaseAction { + actionName = ActionName.GetGroupMemberInfo; + + protected async _handle(payload: PayloadType) { + const member = await getGroupMember(payload.group_id.toString(), payload.user_id.toString()); + // log(member); + if (member) { + log('获取群成员详细信息'); + try { + const info = (await NTQQUserApi.getUserDetailInfo(member.uid)); + log('群成员详细信息结果', info); + Object.assign(member, info); + } catch (e) { + log('获取群成员详细信息失败, 只能返回基础信息', e); + } + return OB11Constructor.groupMember(payload.group_id.toString(), member); + } else { + throw (`群成员${payload.user_id}不存在`); + } + } +} + +export default GetGroupMemberInfo; diff --git a/src/onebot11/action/group/GetGroupMemberList.ts b/src/onebot11/action/group/GetGroupMemberList.ts new file mode 100644 index 00000000..84ec1a7b --- /dev/null +++ b/src/onebot11/action/group/GetGroupMemberList.ts @@ -0,0 +1,26 @@ +import { getGroup } from '@/common/data'; +import { OB11GroupMember } from '../../types'; +import { OB11Constructor } from '../../constructor'; +import BaseAction from '../BaseAction'; +import { ActionName } from '../types'; +import { napCatCore } from '@/core'; + +export interface PayloadType { + group_id: number +} + + +class GetGroupMemberList extends BaseAction { + actionName = ActionName.GetGroupMemberList; + + protected async _handle(payload: PayloadType) { + const group = await getGroup(payload.group_id.toString()); + if (group) { + return OB11Constructor.groupMembers(group); + } else { + throw (`群${payload.group_id}不存在`); + } + } +} + +export default GetGroupMemberList; diff --git a/src/onebot11/action/group/GetGuildList.ts b/src/onebot11/action/group/GetGuildList.ts new file mode 100644 index 00000000..ea36304b --- /dev/null +++ b/src/onebot11/action/group/GetGuildList.ts @@ -0,0 +1,10 @@ +import BaseAction from '../BaseAction'; +import { ActionName } from '../types'; + +export default class GetGuildList extends BaseAction { + actionName = ActionName.GetGuildList; + + protected async _handle(payload: null): Promise { + return null; + } +} \ No newline at end of file diff --git a/src/onebot11/action/group/SendGroupMsg.ts b/src/onebot11/action/group/SendGroupMsg.ts new file mode 100644 index 00000000..c3dfad91 --- /dev/null +++ b/src/onebot11/action/group/SendGroupMsg.ts @@ -0,0 +1,16 @@ +import SendMsg from '../msg/SendMsg'; +import { ActionName, BaseCheckResult } from '../types'; +import { OB11PostSendMsg } from '../../types'; + + +class SendGroupMsg extends SendMsg { + actionName = ActionName.SendGroupMsg; + + protected async check(payload: OB11PostSendMsg): Promise { + delete payload.user_id; + payload.message_type = 'group'; + return super.check(payload); + } +} + +export default SendGroupMsg; diff --git a/src/onebot11/action/group/SetGroupAddRequest.ts b/src/onebot11/action/group/SetGroupAddRequest.ts new file mode 100644 index 00000000..95bc3787 --- /dev/null +++ b/src/onebot11/action/group/SetGroupAddRequest.ts @@ -0,0 +1,31 @@ +import BaseAction from '../BaseAction'; +import { GroupRequestOperateTypes } from '@/core/qqnt/entities'; +import { ActionName } from '../types'; +import { NTQQGroupApi } from '@/core/qqnt/apis/group'; +import { groupNotifies } from '@/common/data'; + +interface Payload { + flag: string, + // sub_type: "add" | "invite", + // type: "add" | "invite" + approve: boolean, + reason: string +} + +export default class SetGroupAddRequest extends BaseAction { + actionName = ActionName.SetGroupAddRequest; + + protected async _handle(payload: Payload): Promise { + const flag = payload.flag.toString(); + const approve = payload.approve.toString() === 'true'; + const notify = groupNotifies[flag]; + if (!notify) { + throw `${flag}对应的加群通知不存在`; + } + await NTQQGroupApi.handleGroupRequest(notify, + approve ? GroupRequestOperateTypes.approve : GroupRequestOperateTypes.reject, + payload.reason + ); + return null; + } +} diff --git a/src/onebot11/action/group/SetGroupAdmin.ts b/src/onebot11/action/group/SetGroupAdmin.ts new file mode 100644 index 00000000..c229d9dc --- /dev/null +++ b/src/onebot11/action/group/SetGroupAdmin.ts @@ -0,0 +1,25 @@ +import BaseAction from '../BaseAction'; +import { getGroupMember } from '@/common/data'; +import { GroupMemberRole } from '@/core/qqnt/entities'; +import { ActionName } from '../types'; +import { NTQQGroupApi } from '@/core/qqnt/apis/group'; + +interface Payload { + group_id: number, + user_id: number, + enable: boolean +} + +export default class SetGroupAdmin extends BaseAction { + actionName = ActionName.SetGroupAdmin; + + protected async _handle(payload: Payload): Promise { + const member = await getGroupMember(payload.group_id, payload.user_id); + const enable = payload.enable.toString() === 'true'; + if (!member) { + throw `群成员${payload.user_id}不存在`; + } + await NTQQGroupApi.setMemberRole(payload.group_id.toString(), member.uid, enable ? GroupMemberRole.admin : GroupMemberRole.normal); + return null; + } +} diff --git a/src/onebot11/action/group/SetGroupBan.ts b/src/onebot11/action/group/SetGroupBan.ts new file mode 100644 index 00000000..a162ecb2 --- /dev/null +++ b/src/onebot11/action/group/SetGroupBan.ts @@ -0,0 +1,24 @@ +import BaseAction from '../BaseAction'; +import { getGroupMember } from '../../../common/data'; +import { ActionName } from '../types'; +import { NTQQGroupApi } from '@/core/qqnt/apis/group'; + +interface Payload { + group_id: number, + user_id: number, + duration: number +} + +export default class SetGroupBan extends BaseAction { + actionName = ActionName.SetGroupBan; + + protected async _handle(payload: Payload): Promise { + const member = await getGroupMember(payload.group_id, payload.user_id); + if (!member) { + throw `群成员${payload.user_id}不存在`; + } + await NTQQGroupApi.banMember(payload.group_id.toString(), + [{ uid: member.uid, timeStamp: parseInt(payload.duration.toString()) }]); + return null; + } +} \ No newline at end of file diff --git a/src/onebot11/action/group/SetGroupCard.ts b/src/onebot11/action/group/SetGroupCard.ts new file mode 100644 index 00000000..d47941ff --- /dev/null +++ b/src/onebot11/action/group/SetGroupCard.ts @@ -0,0 +1,23 @@ +import BaseAction from '../BaseAction'; +import { getGroupMember } from '../../../common/data'; +import { ActionName } from '../types'; +import { NTQQGroupApi } from '@/core/qqnt/apis/group'; + +interface Payload { + group_id: number, + user_id: number, + card: string +} + +export default class SetGroupCard extends BaseAction { + actionName = ActionName.SetGroupCard; + + protected async _handle(payload: Payload): Promise { + const member = await getGroupMember(payload.group_id, payload.user_id); + if (!member) { + throw `群成员${payload.user_id}不存在`; + } + await NTQQGroupApi.setMemberCard(payload.group_id.toString(), member.uid, payload.card || ''); + return null; + } +} \ No newline at end of file diff --git a/src/onebot11/action/group/SetGroupKick.ts b/src/onebot11/action/group/SetGroupKick.ts new file mode 100644 index 00000000..8668e2f9 --- /dev/null +++ b/src/onebot11/action/group/SetGroupKick.ts @@ -0,0 +1,23 @@ +import BaseAction from '../BaseAction'; +import { getGroupMember } from '../../../common/data'; +import { ActionName } from '../types'; +import { NTQQGroupApi } from '@/core/qqnt/apis/group'; + +interface Payload { + group_id: number, + user_id: number, + reject_add_request: boolean +} + +export default class SetGroupKick extends BaseAction { + actionName = ActionName.SetGroupKick; + + protected async _handle(payload: Payload): Promise { + const member = await getGroupMember(payload.group_id, payload.user_id); + if (!member) { + throw `群成员${payload.user_id}不存在`; + } + await NTQQGroupApi.kickMember(payload.group_id.toString(), [member.uid], !!payload.reject_add_request); + return null; + } +} diff --git a/src/onebot11/action/group/SetGroupLeave.ts b/src/onebot11/action/group/SetGroupLeave.ts new file mode 100644 index 00000000..e78bc650 --- /dev/null +++ b/src/onebot11/action/group/SetGroupLeave.ts @@ -0,0 +1,22 @@ +import BaseAction from '../BaseAction'; +import { ActionName } from '../types'; +import { NTQQGroupApi } from '@/core/qqnt/apis/group'; +import { log } from '../../../common/utils/log'; + +interface Payload { + group_id: number, + is_dismiss: boolean +} + +export default class SetGroupLeave extends BaseAction { + actionName = ActionName.SetGroupLeave; + + protected async _handle(payload: Payload): Promise { + try { + await NTQQGroupApi.quitGroup(payload.group_id.toString()); + } catch (e) { + log('退群失败', e); + throw e; + } + } +} \ No newline at end of file diff --git a/src/onebot11/action/group/SetGroupName.ts b/src/onebot11/action/group/SetGroupName.ts new file mode 100644 index 00000000..ff51006a --- /dev/null +++ b/src/onebot11/action/group/SetGroupName.ts @@ -0,0 +1,18 @@ +import BaseAction from '../BaseAction'; +import { ActionName } from '../types'; +import { NTQQGroupApi } from '@/core/qqnt/apis/group'; + +interface Payload { + group_id: number, + group_name: string +} + +export default class SetGroupName extends BaseAction { + actionName = ActionName.SetGroupName; + + protected async _handle(payload: Payload): Promise { + + await NTQQGroupApi.setGroupName(payload.group_id.toString(), payload.group_name); + return null; + } +} \ No newline at end of file diff --git a/src/onebot11/action/group/SetGroupWholeBan.ts b/src/onebot11/action/group/SetGroupWholeBan.ts new file mode 100644 index 00000000..5264becc --- /dev/null +++ b/src/onebot11/action/group/SetGroupWholeBan.ts @@ -0,0 +1,18 @@ +import BaseAction from '../BaseAction'; +import { ActionName } from '../types'; +import { NTQQGroupApi } from '@/core/qqnt/apis/group'; + +interface Payload { + group_id: number, + enable: boolean +} + +export default class SetGroupWholeBan extends BaseAction { + actionName = ActionName.SetGroupWholeBan; + + protected async _handle(payload: Payload): Promise { + const enable = payload.enable.toString() === 'true'; + await NTQQGroupApi.banGroup(payload.group_id.toString(), enable); + return null; + } +} \ No newline at end of file diff --git a/src/onebot11/action/index.ts b/src/onebot11/action/index.ts new file mode 100644 index 00000000..6e8d1546 --- /dev/null +++ b/src/onebot11/action/index.ts @@ -0,0 +1,104 @@ +import GetMsg from './msg/GetMsg'; +import GetLoginInfo from './system/GetLoginInfo'; +import GetFriendList from './user/GetFriendList'; +import GetGroupList from './group/GetGroupList'; +import GetGroupInfo from './group/GetGroupInfo'; +import GetGroupMemberList from './group/GetGroupMemberList'; +import GetGroupMemberInfo from './group/GetGroupMemberInfo'; +import SendGroupMsg from './group/SendGroupMsg'; +import SendPrivateMsg from './msg/SendPrivateMsg'; +import SendMsg from './msg/SendMsg'; +import DeleteMsg from './msg/DeleteMsg'; +import BaseAction from './BaseAction'; +import GetVersionInfo from './system/GetVersionInfo'; +import CanSendRecord from './system/CanSendRecord'; +import CanSendImage from './system/CanSendImage'; +import GetStatus from './system/GetStatus'; +import { + GoCQHTTPSendForwardMsg, + GoCQHTTPSendGroupForwardMsg, + GoCQHTTPSendPrivateForwardMsg +} from './go-cqhttp/SendForwardMsg'; +import GoCQHTTPGetStrangerInfo from './go-cqhttp/GetStrangerInfo'; +import SendLike from './user/SendLike'; +import SetGroupAddRequest from './group/SetGroupAddRequest'; +import SetGroupLeave from './group/SetGroupLeave'; +import GetGuildList from './group/GetGuildList'; +import Debug from './llonebot/Debug'; +import SetFriendAddRequest from './user/SetFriendAddRequest'; +import SetGroupWholeBan from './group/SetGroupWholeBan'; +import SetGroupName from './group/SetGroupName'; +import SetGroupBan from './group/SetGroupBan'; +import SetGroupKick from './group/SetGroupKick'; +import SetGroupAdmin from './group/SetGroupAdmin'; +import SetGroupCard from './group/SetGroupCard'; +import GetImage from './file/GetImage'; +import GetRecord from './file/GetRecord'; +import GoCQHTTPMarkMsgAsRead from './msg/MarkMsgAsRead'; +import CleanCache from './system/CleanCache'; +import GoCQHTTPUploadGroupFile from './go-cqhttp/UploadGroupFile'; +import { GetConfigAction, SetConfigAction } from './llonebot/Config'; +import GetGroupAddRequest from './llonebot/GetGroupAddRequest'; +import SetQQAvatar from './llonebot/SetQQAvatar'; +import GoCQHTTPDownloadFile from './go-cqhttp/DownloadFile'; +import GoCQHTTPGetGroupMsgHistory from './go-cqhttp/GetGroupMsgHistory'; +import GetFile from './file/GetFile'; +import { GoCQHTTGetForwardMsgAction } from './go-cqhttp/GetForwardMsg'; + +export const actionHandlers = [ + new GetFile(), + new Debug(), + // new GetConfigAction(), + // new SetConfigAction(), + // new GetGroupAddRequest(), + new SetQQAvatar(), + // onebot11 + new SendLike(), + new GetMsg(), + new GetLoginInfo(), + new GetFriendList(), + new GetGroupList(), new GetGroupInfo(), + new GetGroupMemberList(), new GetGroupMemberInfo(), + new SendGroupMsg(), new SendPrivateMsg(), new SendMsg(), + new DeleteMsg(), + new SetGroupAddRequest(), + new SetFriendAddRequest(), + new SetGroupLeave(), + new GetVersionInfo(), + new CanSendRecord(), + new CanSendImage(), + new GetStatus(), + new SetGroupWholeBan(), + new SetGroupBan(), + new SetGroupKick(), + new SetGroupAdmin(), + new SetGroupName(), + new SetGroupCard(), + new GetImage(), + new GetRecord(), + // new CleanCache(), + + //以下为go-cqhttp api + new GoCQHTTPSendForwardMsg(), + new GoCQHTTPSendGroupForwardMsg(), + new GoCQHTTPSendPrivateForwardMsg(), + new GoCQHTTPGetStrangerInfo(), + new GoCQHTTPDownloadFile(), + new GetGuildList(), + new GoCQHTTPMarkMsgAsRead(), + new GoCQHTTPUploadGroupFile(), + new GoCQHTTPGetGroupMsgHistory(), + new GoCQHTTGetForwardMsgAction(), + +]; + +function initActionMap() { + const actionMap = new Map>(); + for (const action of actionHandlers) { + actionMap.set(action.actionName, action); + } + + return actionMap; +} + +export const actionMap = initActionMap(); diff --git a/src/onebot11/action/llonebot/Config.ts b/src/onebot11/action/llonebot/Config.ts new file mode 100644 index 00000000..a0b7a4f3 --- /dev/null +++ b/src/onebot11/action/llonebot/Config.ts @@ -0,0 +1,20 @@ +import BaseAction from '../BaseAction'; +import { OB11Config, ob11Config } from '@/onebot11/config'; +import { ActionName } from '../types'; + + +export class GetConfigAction extends BaseAction { + actionName = ActionName.GetConfig; + + protected async _handle(payload: null): Promise { + return ob11Config; + } +} + +export class SetConfigAction extends BaseAction { + actionName = ActionName.SetConfig; + + protected async _handle(payload: OB11Config): Promise { + ob11Config.save(payload); + } +} diff --git a/src/onebot11/action/llonebot/Debug.ts b/src/onebot11/action/llonebot/Debug.ts new file mode 100644 index 00000000..a23b6fc4 --- /dev/null +++ b/src/onebot11/action/llonebot/Debug.ts @@ -0,0 +1,44 @@ +import BaseAction from '../BaseAction'; +// import * as ntqqApi from "../../../ntqqapi/api"; +import { + NTQQMsgApi, + NTQQFriendApi, + NTQQGroupApi, + NTQQUserApi, + NTQQFileApi, + // NTQQFileCacheApi, + NTQQWindowApi, +} from '@/core/qqnt/apis'; +import { ActionName } from '../types'; +import { log } from '../../../common/utils/log'; + +interface Payload { + method: string, + args: any[], +} + +export default class Debug extends BaseAction { + actionName = ActionName.Debug; + + protected async _handle(payload: Payload): Promise { + log('debug call ntqq api', payload); + const ntqqApi = [NTQQMsgApi, NTQQFriendApi, NTQQGroupApi, NTQQUserApi, NTQQFileApi, + // NTQQFileCacheApi, + NTQQWindowApi]; + for (const ntqqApiClass of ntqqApi) { + log('ntqqApiClass', ntqqApiClass); + const method = (ntqqApiClass)[payload.method]; + if (method) { + const result = method(...payload.args); + if (method.constructor.name === 'AsyncFunction') { + return await result; + } + return result; + } + } + throw `${payload.method}方法 不存在`; + + // const info = await NTQQApi.getUserDetailInfo(friends[0].uid); + // return info + } +} diff --git a/src/onebot11/action/llonebot/GetGroupAddRequest.ts b/src/onebot11/action/llonebot/GetGroupAddRequest.ts new file mode 100644 index 00000000..e6e143a6 --- /dev/null +++ b/src/onebot11/action/llonebot/GetGroupAddRequest.ts @@ -0,0 +1,33 @@ +import { GroupNotify, GroupNotifyStatus } from '../../../ntqqapi/types'; +import BaseAction from '../BaseAction'; +import { ActionName } from '../types'; +import { uid2UinMap } from '../../../common/data'; +import { NTQQUserApi } from '@/core/qqnt/apis/user'; +import { NTQQGroupApi } from '@/core/qqnt/apis/group'; +import { log } from '../../../common/utils/log'; + +interface OB11GroupRequestNotify { + group_id: number, + user_id: number, + flag: string +} + +export default class GetGroupAddRequest extends BaseAction { + actionName = ActionName.GetGroupIgnoreAddRequest; + + protected async _handle(payload: null): Promise { + const data = await NTQQGroupApi.getGroupIgnoreNotifies(); + // log(data); + const notifies: GroupNotify[] = data.notifies.filter(notify => notify.status === GroupNotifyStatus.WAIT_HANDLE); + const returnData: OB11GroupRequestNotify[] = []; + for (const notify of notifies) { + const uin = uid2UinMap[notify.user1.uid] || (await NTQQUserApi.getUserDetailInfo(notify.user1.uid))?.uin; + returnData.push({ + group_id: parseInt(notify.group.groupCode), + user_id: parseInt(uin), + flag: notify.seq + }); + } + return returnData; + } +} diff --git a/src/onebot11/action/llonebot/SetQQAvatar.ts b/src/onebot11/action/llonebot/SetQQAvatar.ts new file mode 100644 index 00000000..6ff17f48 --- /dev/null +++ b/src/onebot11/action/llonebot/SetQQAvatar.ts @@ -0,0 +1,43 @@ +import BaseAction from '../BaseAction'; +import { ActionName } from '../types'; +import * as fs from 'node:fs'; +import { NTQQUserApi } from '@/core/qqnt/apis/user'; +import { checkFileReceived, uri2local } from '../../../common/utils/file'; +// import { log } from "../../../common/utils"; + +interface Payload { + file: string +} + +export default class SetAvatar extends BaseAction { + actionName = ActionName.SetQQAvatar; + + protected async _handle(payload: Payload): Promise { + const { path, isLocal, errMsg } = (await uri2local(payload.file)); + if (errMsg){ + throw `头像${payload.file}设置失败,file字段可能格式不正确`; + } + if (path) { + await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃,需要提前判断 + const ret = await NTQQUserApi.setQQAvatar(path); + if (!isLocal){ + fs.unlink(path, () => {}); + } + if (!ret) { + throw `头像${payload.file}设置失败,api无返回`; + } + // log(`头像设置返回:${JSON.stringify(ret)}`) + if (ret['result'] == 1004022) { + throw `头像${payload.file}设置失败,文件可能不是图片格式`; + } else if(ret['result'] != 0) { + throw `头像${payload.file}设置失败,未知的错误,${ret['result']}:${ret['errMsg']}`; + } + } else { + if (!isLocal){ + fs.unlink(path, () => {}); + } + throw `头像${payload.file}设置失败,无法获取头像,文件可能不存在`; + } + return null; + } +} \ No newline at end of file diff --git a/src/onebot11/action/msg/DeleteMsg.ts b/src/onebot11/action/msg/DeleteMsg.ts new file mode 100644 index 00000000..580827d1 --- /dev/null +++ b/src/onebot11/action/msg/DeleteMsg.ts @@ -0,0 +1,22 @@ +import { NTQQMsgApi } from '@/core/qqnt/apis'; +import { ActionName } from '../types'; +import BaseAction from '../BaseAction'; +import { dbUtil } from '@/common/utils/db'; +import { napCatCore } from '@/core'; + +interface Payload { + message_id: number +} + +class DeleteMsg extends BaseAction { + actionName = ActionName.DeleteMsg; + + protected async _handle(payload: Payload) { + const msg = await dbUtil.getMsgByShortId(payload.message_id); + if (msg) { + await NTQQMsgApi.recallMsg({ peerUid: msg.peerUid, chatType: msg.chatType }, [msg.msgId]); + } + } +} + +export default DeleteMsg; diff --git a/src/onebot11/action/msg/GetMsg.ts b/src/onebot11/action/msg/GetMsg.ts new file mode 100644 index 00000000..742941bc --- /dev/null +++ b/src/onebot11/action/msg/GetMsg.ts @@ -0,0 +1,33 @@ +import { OB11Message } from '../../types'; +import { OB11Constructor } from '../../constructor'; +import BaseAction from '../BaseAction'; +import { ActionName } from '../types'; +import { dbUtil } from '@/common/utils/db'; + + +export interface PayloadType { + message_id: number +} + +export type ReturnDataType = OB11Message + +class GetMsg extends BaseAction { + actionName = ActionName.GetMsg; + + protected async _handle(payload: PayloadType) { + // log("history msg ids", Object.keys(msgHistory)); + if (!payload.message_id) { + throw ('参数message_id不能为空'); + } + let msg = await dbUtil.getMsgByShortId(payload.message_id); + if (!msg) { + msg = await dbUtil.getMsgByLongId(payload.message_id.toString()); + } + if (!msg) { + throw ('消息不存在'); + } + return await OB11Constructor.message(msg); + } +} + +export default GetMsg; diff --git a/src/onebot11/action/msg/MarkMsgAsRead.ts b/src/onebot11/action/msg/MarkMsgAsRead.ts new file mode 100644 index 00000000..06b8916a --- /dev/null +++ b/src/onebot11/action/msg/MarkMsgAsRead.ts @@ -0,0 +1,14 @@ +import BaseAction from '../BaseAction'; +import { ActionName } from '../types'; + +interface Payload{ + message_id: number +} + +export default class GoCQHTTPMarkMsgAsRead extends BaseAction{ + actionName = ActionName.GoCQHTTP_MarkMsgAsRead; + + protected async _handle(payload: Payload): Promise { + return null; + } +} \ No newline at end of file diff --git a/src/onebot11/action/msg/SendMsg.ts b/src/onebot11/action/msg/SendMsg.ts new file mode 100644 index 00000000..f5aa924a --- /dev/null +++ b/src/onebot11/action/msg/SendMsg.ts @@ -0,0 +1,532 @@ +import { + AtType, + ChatType, + ElementType, + Group, PicSubType, + RawMessage, + SendArkElement, + SendMessageElement, + Peer +} from '@/core/qqnt/entities'; + +import { + OB11MessageCustomMusic, + OB11MessageData, + OB11MessageDataType, + OB11MessageMixType, + OB11MessageNode, + OB11PostSendMsg +} from '../../types'; +import { SendMsgElementConstructor } from '@/core/qqnt/entities/constructor'; +import BaseAction from '../BaseAction'; +import { ActionName, BaseCheckResult } from '../types'; +import * as fs from 'node:fs'; +import { decodeCQCode } from '../../cqcode'; +import { dbUtil } from '@/common/utils/db'; +import { log } from '@/common/utils/log'; +import { sleep } from '@/common/utils/helper'; +import { uri2local } from '@/common/utils/file'; +import { getFriend, getGroup, getGroupMember, getUidByUin, selfInfo } from '@/common/data'; +import { NTQQMsgApi } from '@/core/qqnt/apis/msg'; + +const ALLOW_SEND_TEMP_MSG = false; + +function checkSendMessage(sendMsgList: OB11MessageData[]) { + function checkUri(uri: string): boolean { + const pattern = /^(file:\/\/|http:\/\/|https:\/\/|base64:\/\/)/; + return pattern.test(uri); + } + + for (const msg of sendMsgList) { + if (msg['type'] && msg['data']) { + const type = msg['type']; + const data = msg['data']; + if (type === 'text' && !data['text']) { + return 400; + } else if (['image', 'voice', 'record'].includes(type)) { + if (!data['file']) { + return 400; + } else { + if (checkUri(data['file'])) { + return 200; + } else { + return 400; + } + } + + } else if (type === 'at' && !data['qq']) { + return 400; + } else if (type === 'reply' && !data['id']) { + return 400; + } + } else { + return 400; + } + } + return 200; +} + +export interface ReturnDataType { + message_id: number; +} + +export function convertMessage2List(message: OB11MessageMixType, autoEscape = false) { + if (typeof message === 'string') { + if (!autoEscape) { + message = decodeCQCode(message.toString()); + } else { + message = [{ + type: OB11MessageDataType.text, + data: { + text: message + } + }]; + } + } else if (!Array.isArray(message)) { + message = [message]; + } + return message; +} + +export async function createSendElements(messageData: OB11MessageData[], group: Group | undefined, ignoreTypes: OB11MessageDataType[] = []) { + const sendElements: SendMessageElement[] = []; + const deleteAfterSentFiles: string[] = []; + for (const sendMsg of messageData) { + if (ignoreTypes.includes(sendMsg.type)) { + continue; + } + switch (sendMsg.type) { + case OB11MessageDataType.text: { + const text = sendMsg.data?.text; + if (text) { + sendElements.push(SendMsgElementConstructor.text(sendMsg.data!.text)); + } + } + break; + case OB11MessageDataType.at: { + if (!group) { + continue; + } + let atQQ = sendMsg.data?.qq; + if (atQQ) { + atQQ = atQQ.toString(); + if (atQQ === 'all') { + sendElements.push(SendMsgElementConstructor.at(atQQ, atQQ, AtType.atAll, '全体成员')); + } else { + // const atMember = group?.members.find(m => m.uin == atQQ) + const atMember = await getGroupMember(group?.groupCode, atQQ); + if (atMember) { + sendElements.push(SendMsgElementConstructor.at(atQQ, atMember.uid, AtType.atUser, atMember.cardName || atMember.nick)); + } + } + } + } + break; + case OB11MessageDataType.reply: { + const replyMsgId = sendMsg.data.id; + if (replyMsgId) { + const replyMsg = await dbUtil.getMsgByShortId(parseInt(replyMsgId)); + if (replyMsg) { + sendElements.push(SendMsgElementConstructor.reply(replyMsg.msgSeq, replyMsg.msgId, replyMsg.senderUin!, replyMsg.senderUin!)); + } + } + } + break; + case OB11MessageDataType.face: { + const faceId = sendMsg.data?.id; + if (faceId) { + sendElements.push(SendMsgElementConstructor.face(parseInt(faceId))); + } + } + break; + + case OB11MessageDataType.image: + case OB11MessageDataType.file: + case OB11MessageDataType.video: + case OB11MessageDataType.voice: { + const file = sendMsg.data?.file; + const payloadFileName = sendMsg.data?.name; + if (file) { + // todo: 使用缓存文件发送 + // const cache = await dbUtil.getFileCache(file); + // if (cache) { + // if (fs.existsSync(cache.filePath)) { + // file = "file://" + cache.filePath; + // } else if (cache.downloadFunc) { + // await cache.downloadFunc(); + // file = cache.filePath; + // } else if (cache.url) { + // file = cache.url; + // } + // log("找到文件缓存", file); + // } + const {path, isLocal, fileName, errMsg} = (await uri2local(file)); + if (errMsg) { + throw errMsg; + } + if (path) { + if (!isLocal) { // 只删除http和base64转过来的文件 + deleteAfterSentFiles.push(path); + } + if (sendMsg.type === OB11MessageDataType.file) { + log('发送文件', path, payloadFileName || fileName); + sendElements.push(await SendMsgElementConstructor.file(path, payloadFileName || fileName)); + } else if (sendMsg.type === OB11MessageDataType.video) { + log('发送视频', path, payloadFileName || fileName); + let thumb = sendMsg.data?.thumb; + if (thumb) { + const uri2LocalRes = await uri2local(thumb); + if (uri2LocalRes.success) { + thumb = uri2LocalRes.path; + } + } + sendElements.push(await SendMsgElementConstructor.video(path, payloadFileName || fileName, thumb)); + } else if (sendMsg.type === OB11MessageDataType.voice) { + sendElements.push(await SendMsgElementConstructor.ptt(path)); + } else if (sendMsg.type === OB11MessageDataType.image) { + sendElements.push(await SendMsgElementConstructor.pic(path, sendMsg.data.summary || '', parseInt(sendMsg.data?.subType?.toString() || '0'))); + } + } + } + } + break; + case OB11MessageDataType.json: { + sendElements.push(SendMsgElementConstructor.ark(sendMsg.data.data)); + } + break; + } + + } + + return { + sendElements, + deleteAfterSentFiles + }; +} + +export async function sendMsg(peer: Peer, sendElements: SendMessageElement[], deleteAfterSentFiles: string[], waitComplete = true) { + if (!sendElements.length) { + throw ('消息体无法解析'); + } + const returnMsg = await NTQQMsgApi.sendMsg(peer, sendElements, waitComplete, 20000); + try { + returnMsg.id = await dbUtil.addMsg(returnMsg, false); + } catch (e: any) { + log('发送消息id获取失败', e); + returnMsg.id = 0; + } + // log('消息发送结果', returnMsg); + deleteAfterSentFiles.map(f => fs.unlink(f, () => { + })); + return returnMsg; +} + +export class SendMsg extends BaseAction { + actionName = ActionName.SendMsg; + + protected async check(payload: OB11PostSendMsg): Promise { + const messages = convertMessage2List(payload.message); + const fmNum = this.getSpecialMsgNum(payload, OB11MessageDataType.node); + if (fmNum && fmNum != messages.length) { + return { + valid: false, + message: '转发消息不能和普通消息混在一起发送,转发需要保证message只有type为node的元素' + }; + } + if (payload.message_type !== 'private' && payload.group_id && !(await getGroup(payload.group_id))) { + return { + valid: false, + message: `群${payload.group_id}不存在` + }; + } + if (payload.user_id && payload.message_type !== 'group') { + if (!(await getFriend(payload.user_id))) { + if (!ALLOW_SEND_TEMP_MSG + && !(await dbUtil.getUidByTempUin(payload.user_id.toString())) + ) { + return { + valid: false, + message: '不能发送临时消息' + }; + } + } + } + return { + valid: true, + }; + } + + protected async _handle(payload: OB11PostSendMsg): Promise<{ message_id: number }> { + + const peer: Peer = { + chatType: ChatType.friend, + peerUid: '' + }; + let isTempMsg = false; + let group: Group | undefined = undefined; + const genGroupPeer = async () => { + if (payload.group_id) { + group = await getGroup(payload.group_id.toString()); + if (group) { + peer.chatType = ChatType.group; + // peer.name = group.name + peer.peerUid = group.groupCode; + } + + } + }; + + const genFriendPeer = async () => { + if (!payload.user_id) { + return; + } + const friend = await getFriend(payload.user_id.toString()); + if (friend) { + // peer.name = friend.nickName + peer.peerUid = friend.uid; + } else { + peer.chatType = ChatType.temp; + const tempUserUid = getUidByUin(payload.user_id.toString()); + if (!tempUserUid) { + throw (`找不到私聊对象${payload.user_id}`); + } + // peer.name = tempUser.nickName + isTempMsg = true; + peer.peerUid = tempUserUid; + } + }; + if (payload?.group_id && payload.message_type === 'group') { + await genGroupPeer(); + + } else if (payload?.user_id) { + await genFriendPeer(); + } else if (payload.group_id) { + await genGroupPeer(); + } else { + throw ('发送消息参数错误, 请指定group_id或user_id'); + } + const messages = convertMessage2List(payload.message); + if (this.getSpecialMsgNum(payload, OB11MessageDataType.node)) { + try { + const returnMsg = await this.handleForwardNode(peer, messages as OB11MessageNode[], group); + return {message_id: returnMsg!.id!}; + } catch (e: any) { + throw ('发送转发消息失败 ' + e.toString()); + } + } else { + if (this.getSpecialMsgNum(payload, OB11MessageDataType.music)) { + const music: OB11MessageCustomMusic = messages[0] as OB11MessageCustomMusic; + if (music) { + const {url, audio, title, content, image} = music.data; + const selfPeer: Peer = {peerUid: selfInfo.uid, chatType: ChatType.friend}; + // 搞不定! + // const musicMsg = await this.send(selfPeer, [this.genMusicElement(url, audio, title, content, image)], [], false) + // 转发 + // const res = await NTQQApi.forwardMsg(selfPeer, peer, [musicMsg.msgId]) + // log("转发音乐消息成功", res); + // return {message_id: musicMsg.msgShortId} + } + } + } + // log("send msg:", peer, sendElements) + const {sendElements, deleteAfterSentFiles} = await createSendElements(messages, group); + const returnMsg = await sendMsg(peer, sendElements, deleteAfterSentFiles); + deleteAfterSentFiles.map(f => fs.unlink(f, () => { + })); + + const res = {message_id: returnMsg.id!}; + // console.log(res); + return res; + } + + + private getSpecialMsgNum(payload: OB11PostSendMsg, msgType: OB11MessageDataType): number { + if (Array.isArray(payload.message)) { + return payload.message.filter(msg => msg.type == msgType).length; + } + return 0; + } + + private async cloneMsg(msg: RawMessage): Promise { + log('克隆的目标消息', msg); + const sendElements: SendMessageElement[] = []; + for (const ele of msg.elements) { + sendElements.push(ele as SendMessageElement); + // Object.keys(ele).forEach((eleKey) => { + // if (eleKey.endsWith("Element")) { + // } + + } + if (sendElements.length === 0) { + log('需要clone的消息无法解析,将会忽略掉', msg); + } + log('克隆消息', sendElements); + try { + const nodeMsg = await NTQQMsgApi.sendMsg({ + chatType: ChatType.friend, + peerUid: selfInfo.uid + }, sendElements, true); + await sleep(500); + return nodeMsg; + } catch (e) { + log(e, '克隆转发消息失败,将忽略本条消息', msg); + } + + } + + // 返回一个合并转发的消息id + private async handleForwardNode(destPeer: Peer, messageNodes: OB11MessageNode[], group: Group | undefined): Promise { + + const selfPeer = { + chatType: ChatType.friend, + peerUid: selfInfo.uid + }; + let nodeMsgIds: string[] = []; + // 先判断一遍是不是id和自定义混用 + const needClone = messageNodes.filter(node => node.data.id).length && messageNodes.filter(node => !node.data.id).length; + for (const messageNode of messageNodes) { + // 一个node表示一个人的消息 + const nodeId = messageNode.data.id; + // 有nodeId表示一个子转发消息卡片 + if (nodeId) { + const nodeMsg = await dbUtil.getMsgByShortId(parseInt(nodeId)); + if (!needClone) { + nodeMsgIds.push(nodeMsg!.msgId); + } else { + if (nodeMsg!.peerUid !== selfInfo.uid) { + const cloneMsg = await this.cloneMsg(nodeMsg!); + if (cloneMsg) { + nodeMsgIds.push(cloneMsg.msgId); + } + } + } + } else { + // 自定义的消息 + // 提取消息段,发给自己生成消息id + try { + const { + sendElements, + deleteAfterSentFiles + } = await createSendElements(convertMessage2List(messageNode.data.content), group); + log('开始生成转发节点', sendElements); + const sendElementsSplit: SendMessageElement[][] = []; + let splitIndex = 0; + for (const ele of sendElements) { + if (!sendElementsSplit[splitIndex]) { + sendElementsSplit[splitIndex] = []; + } + + if (ele.elementType === ElementType.FILE || ele.elementType === ElementType.VIDEO) { + if (sendElementsSplit[splitIndex].length > 0) { + splitIndex++; + } + sendElementsSplit[splitIndex] = [ele]; + splitIndex++; + } else { + sendElementsSplit[splitIndex].push(ele); + } + log(sendElementsSplit); + } + // log("分割后的转发节点", sendElementsSplit) + for (const eles of sendElementsSplit) { + const nodeMsg = await sendMsg(selfPeer, eles, [], true); + nodeMsgIds.push(nodeMsg.msgId); + await sleep(500); + log('转发节点生成成功', nodeMsg.msgId); + } + deleteAfterSentFiles.map(f => fs.unlink(f, () => { + })); + + } catch (e) { + log('生成转发消息节点失败', e); + } + } + } + + // 检查srcPeer是否一致,不一致则需要克隆成自己的消息, 让所有srcPeer都变成自己的,使其保持一致才能够转发 + const nodeMsgArray: Array = []; + let srcPeer: Peer | undefined = undefined; + let needSendSelf = false; + for (const [index, msgId] of nodeMsgIds.entries()) { + const nodeMsg = await dbUtil.getMsgByLongId(msgId); + if (nodeMsg) { + nodeMsgArray.push(nodeMsg); + if (!srcPeer) { + srcPeer = {chatType: nodeMsg.chatType, peerUid: nodeMsg.peerUid}; + } else if (srcPeer.peerUid !== nodeMsg.peerUid) { + needSendSelf = true; + srcPeer = selfPeer; + } + } + } + log('nodeMsgArray', nodeMsgArray); + nodeMsgIds = nodeMsgArray.map(msg => msg.msgId); + if (needSendSelf) { + log('需要克隆转发消息'); + for (const [index, msg] of nodeMsgArray.entries()) { + if (msg.peerUid !== selfInfo.uid) { + const cloneMsg = await this.cloneMsg(msg); + if (cloneMsg) { + nodeMsgIds[index] = cloneMsg.msgId; + } + } + } + } + // elements之间用换行符分隔 + // let _sendForwardElements: SendMessageElement[] = [] + // for(let i = 0; i < sendForwardElements.length; i++){ + // _sendForwardElements.push(sendForwardElements[i]) + // _sendForwardElements.push(SendMsgElementConstructor.text("\n\n")) + // } + // const nodeMsg = await NTQQApi.sendMsg(selfPeer, _sendForwardElements, true); + // nodeIds.push(nodeMsg.msgId) + // await sleep(500); + // 开发转发 + try { + log('开发转发', nodeMsgIds); + return await NTQQMsgApi.multiForwardMsg(srcPeer!, destPeer, nodeMsgIds); + } catch (e) { + log('forward failed', e); + return null; + } + } + + + private genMusicElement(url: string, audio: string, title: string, content: string, image: string): SendArkElement { + const musicJson = { + app: 'com.tencent.structmsg', + config: { + ctime: 1709689928, + forward: 1, + token: '5c1e4905f926dd3a64a4bd3841460351', + type: 'normal' + }, + extra: {app_type: 1, appid: 100497308, uin: selfInfo.uin}, + meta: { + news: { + action: '', + android_pkg_name: '', + app_type: 1, + appid: 100497308, + ctime: 1709689928, + desc: content || title, + jumpUrl: url, + musicUrl: audio, + preview: image, + source_icon: 'https://p.qpic.cn/qqconnect/0/app_100497308_1626060999/100?max-age=2592000&t=0', + source_url: '', + tag: 'QQ音乐', + title: title, + uin: selfInfo.uin, + } + }, + prompt: content || title, + ver: '0.0.0.1', + view: 'news' + }; + + return SendMsgElementConstructor.ark(musicJson); + } +} + +export default SendMsg; diff --git a/src/onebot11/action/msg/SendPrivateMsg.ts b/src/onebot11/action/msg/SendPrivateMsg.ts new file mode 100644 index 00000000..e8053307 --- /dev/null +++ b/src/onebot11/action/msg/SendPrivateMsg.ts @@ -0,0 +1,14 @@ +import SendMsg from './SendMsg'; +import { ActionName, BaseCheckResult } from '../types'; +import { OB11PostSendMsg } from '../../types'; + +class SendPrivateMsg extends SendMsg { + actionName = ActionName.SendPrivateMsg; + + protected async check(payload: OB11PostSendMsg): Promise { + payload.message_type = 'private'; + return super.check(payload); + } +} + +export default SendPrivateMsg; diff --git a/src/onebot11/action/system/CanSendImage.ts b/src/onebot11/action/system/CanSendImage.ts new file mode 100644 index 00000000..459c3e66 --- /dev/null +++ b/src/onebot11/action/system/CanSendImage.ts @@ -0,0 +1,10 @@ +import { ActionName } from '../types'; +import CanSendRecord from './CanSendRecord'; + +interface ReturnType { + yes: boolean +} + +export default class CanSendImage extends CanSendRecord { + actionName = ActionName.CanSendImage; +} diff --git a/src/onebot11/action/system/CanSendRecord.ts b/src/onebot11/action/system/CanSendRecord.ts new file mode 100644 index 00000000..7a370768 --- /dev/null +++ b/src/onebot11/action/system/CanSendRecord.ts @@ -0,0 +1,16 @@ +import BaseAction from '../BaseAction'; +import { ActionName } from '../types'; + +interface ReturnType { + yes: boolean +} + +export default class CanSendRecord extends BaseAction { + actionName = ActionName.CanSendRecord; + + protected async _handle(payload): Promise { + return { + yes: true + }; + } +} diff --git a/src/onebot11/action/system/CleanCache.ts b/src/onebot11/action/system/CleanCache.ts new file mode 100644 index 00000000..4a03496e --- /dev/null +++ b/src/onebot11/action/system/CleanCache.ts @@ -0,0 +1,105 @@ +import BaseAction from '../BaseAction'; +import { ActionName } from '../types'; +import fs from 'fs'; +import Path from 'path'; +import { + ChatType, + ChatCacheListItemBasic, + CacheFileType +} from '../../../ntqqapi/types'; +import { dbUtil } from '../../../common/db'; +import { NTQQFileApi, NTQQFileCacheApi } from '@/core/qqnt/apis/file'; + +export default class CleanCache extends BaseAction { + actionName = ActionName.CleanCache; + + protected _handle(): Promise { + return new Promise(async (res, rej) => { + try { + // dbUtil.clearCache(); + const cacheFilePaths: string[] = []; + + await NTQQFileCacheApi.setCacheSilentScan(false); + + cacheFilePaths.push((await NTQQFileCacheApi.getHotUpdateCachePath())); + cacheFilePaths.push((await NTQQFileCacheApi.getDesktopTmpPath())); + (await NTQQFileCacheApi.getCacheSessionPathList()).forEach(e => cacheFilePaths.push(e.value)); + + // await NTQQApi.addCacheScannedPaths(); // XXX: 调用就崩溃,原因目前还未知 + const cacheScanResult = await NTQQFileCacheApi.scanCache(); + const cacheSize = parseInt(cacheScanResult.size[6]); + + if (cacheScanResult.result !== 0) { + throw('Something went wrong while scanning cache. Code: ' + cacheScanResult.result); + } + + await NTQQFileCacheApi.setCacheSilentScan(true); + if (cacheSize > 0 && cacheFilePaths.length > 2) { // 存在缓存文件且大小不为 0 时执行清理动作 + // await NTQQApi.clearCache([ 'tmp', 'hotUpdate', ...cacheScanResult ]) // XXX: 也是调用就崩溃,调用 fs 删除得了 + deleteCachePath(cacheFilePaths); + } + + // 获取聊天记录列表 + // NOTE: 以防有人不需要删除聊天记录,暂时先注释掉,日后加个开关 + // const privateChatCache = await getCacheList(ChatType.friend); // 私聊消息 + // const groupChatCache = await getCacheList(ChatType.group); // 群聊消息 + // const chatCacheList = [ ...privateChatCache, ...groupChatCache ]; + const chatCacheList: ChatCacheListItemBasic[] = []; + + // 获取聊天缓存文件列表 + const cacheFileList: string[] = []; + + for (const name in CacheFileType) { + if (!isNaN(parseInt(name))) continue; + + const fileTypeAny: any = CacheFileType[name]; + const fileType: CacheFileType = fileTypeAny; + + cacheFileList.push(...(await NTQQFileCacheApi.getFileCacheInfo(fileType)).infos.map(file => file.fileKey)); + } + + // 一并清除 + await NTQQFileCacheApi.clearChatCache(chatCacheList, cacheFileList); + res(); + } catch(e) { + console.error('清理缓存时发生了错误'); + rej(e); + } + }); + } +} + +function deleteCachePath(pathList: string[]) { + const emptyPath = (path: string) => { + if (!fs.existsSync(path)) return; + const files = fs.readdirSync(path); + files.forEach(file => { + const filePath = Path.resolve(path, file); + const stats = fs.statSync(filePath); + if (stats.isDirectory()) emptyPath(filePath); + else fs.unlinkSync(filePath); + }); + fs.rmdirSync(path); + }; + + for (const path of pathList) { + emptyPath(path); + } +} + +function getCacheList(type: ChatType) { // NOTE: 做这个方法主要是因为目前还不支持针对频道消息的清理 + return new Promise>((res, rej) => { + NTQQFileCacheApi.getChatCacheList(type, 1000, 0) + .then(data => { + const list = data.infos.filter(e => e.chatType === type && parseInt(e.basicChatCacheInfo.chatSize) > 0); + const result = list.map(e => { + const result = { ...e.basicChatCacheInfo }; + result.chatType = type; + result.isChecked = true; + return result; + }); + res(result); + }) + .catch(e => rej(e)); + }); +} \ No newline at end of file diff --git a/src/onebot11/action/system/GetLoginInfo.ts b/src/onebot11/action/system/GetLoginInfo.ts new file mode 100644 index 00000000..dab1f958 --- /dev/null +++ b/src/onebot11/action/system/GetLoginInfo.ts @@ -0,0 +1,17 @@ +import { selfInfo } from '@/common/data'; +import { OB11User } from '../../types'; +import { OB11Constructor } from '../../constructor'; +import BaseAction from '../BaseAction'; +import { ActionName } from '../types'; +import { napCatCore } from '@/core'; + + +class GetLoginInfo extends BaseAction { + actionName = ActionName.GetLoginInfo; + + protected async _handle(payload: null) { + return OB11Constructor.selfInfo(selfInfo); + } +} + +export default GetLoginInfo; diff --git a/src/onebot11/action/system/GetStatus.ts b/src/onebot11/action/system/GetStatus.ts new file mode 100644 index 00000000..8007ddb9 --- /dev/null +++ b/src/onebot11/action/system/GetStatus.ts @@ -0,0 +1,16 @@ +import BaseAction from '../BaseAction'; +import { OB11Status } from '../../types'; +import { ActionName } from '../types'; +import { selfInfo } from '../../../common/data'; + + +export default class GetStatus extends BaseAction { + actionName = ActionName.GetStatus; + + protected async _handle(payload: any): Promise { + return { + online: !!selfInfo.online, + good: true + }; + } +} diff --git a/src/onebot11/action/system/GetVersionInfo.ts b/src/onebot11/action/system/GetVersionInfo.ts new file mode 100644 index 00000000..330a1c59 --- /dev/null +++ b/src/onebot11/action/system/GetVersionInfo.ts @@ -0,0 +1,16 @@ +import BaseAction from '../BaseAction'; +import { OB11Version } from '../../types'; +import { ActionName } from '../types'; +import { version } from '@/onebot11/version'; + +export default class GetVersionInfo extends BaseAction { + actionName = ActionName.GetVersionInfo; + + protected async _handle(payload: any): Promise { + return { + app_name: 'NapCat.Onebot', + protocol_version: 'v11', + app_version: version + }; + } +} diff --git a/src/onebot11/action/types.ts b/src/onebot11/action/types.ts new file mode 100644 index 00000000..8fb5df7d --- /dev/null +++ b/src/onebot11/action/types.ts @@ -0,0 +1,64 @@ +export type BaseCheckResult = ValidCheckResult | InvalidCheckResult + +export interface ValidCheckResult { + valid: true + + [k: string | number]: any +} + +export interface InvalidCheckResult { + valid: false + message: string + + [k: string | number]: any +} + +export enum ActionName { + // llonebot + GetGroupIgnoreAddRequest = 'get_group_ignore_add_request', + SetQQAvatar = 'set_qq_avatar', + GetConfig = 'get_config', + SetConfig = 'set_config', + Debug = 'llonebot_debug', + GetFile = 'get_file', + // onebot 11 + SendLike = 'send_like', + GetLoginInfo = 'get_login_info', + GetFriendList = 'get_friend_list', + GetGroupInfo = 'get_group_info', + GetGroupList = 'get_group_list', + GetGroupMemberInfo = 'get_group_member_info', + GetGroupMemberList = 'get_group_member_list', + GetMsg = 'get_msg', + SendMsg = 'send_msg', + SendGroupMsg = 'send_group_msg', + SendPrivateMsg = 'send_private_msg', + DeleteMsg = 'delete_msg', + SetGroupAddRequest = 'set_group_add_request', + SetFriendAddRequest = 'set_friend_add_request', + SetGroupLeave = 'set_group_leave', + GetVersionInfo = 'get_version_info', + GetStatus = 'get_status', + CanSendRecord = 'can_send_record', + CanSendImage = 'can_send_image', + SetGroupKick = 'set_group_kick', + SetGroupBan = 'set_group_ban', + SetGroupWholeBan = 'set_group_whole_ban', + SetGroupAdmin = 'set_group_admin', + SetGroupCard = 'set_group_card', + SetGroupName = 'set_group_name', + GetImage = 'get_image', + GetRecord = 'get_record', + CleanCache = 'clean_cache', + // 以下为go-cqhttp api + GoCQHTTP_SendForwardMsg = 'send_forward_msg', + GoCQHTTP_SendGroupForwardMsg = 'send_group_forward_msg', + GoCQHTTP_SendPrivateForwardMsg = 'send_private_forward_msg', + GoCQHTTP_GetStrangerInfo = 'get_stranger_info', + GetGuildList = 'get_guild_list', + GoCQHTTP_MarkMsgAsRead = 'mark_msg_as_read', + GoCQHTTP_UploadGroupFile = 'upload_group_file', + GoCQHTTP_DownloadFile = 'download_file', + GoCQHTTP_GetGroupMsgHistory = 'get_group_msg_history', + GoCQHTTP_GetForwardMsg = 'get_forward_msg', +} \ No newline at end of file diff --git a/src/onebot11/action/user/GetFriendList.ts b/src/onebot11/action/user/GetFriendList.ts new file mode 100644 index 00000000..55dce28f --- /dev/null +++ b/src/onebot11/action/user/GetFriendList.ts @@ -0,0 +1,16 @@ +import { OB11User } from '../../types'; +import { OB11Constructor } from '../../constructor'; +import { friends } from '../../../common/data'; +import BaseAction from '../BaseAction'; +import { ActionName } from '../types'; + + +class GetFriendList extends BaseAction { + actionName = ActionName.GetFriendList; + + protected async _handle(payload: null) { + return OB11Constructor.friends(Array.from(friends.values())); + } +} + +export default GetFriendList; diff --git a/src/onebot11/action/user/SendLike.ts b/src/onebot11/action/user/SendLike.ts new file mode 100644 index 00000000..801993ce --- /dev/null +++ b/src/onebot11/action/user/SendLike.ts @@ -0,0 +1,36 @@ +import { NTQQUserApi } from '@/core/qqnt/apis'; +import BaseAction from '../BaseAction'; +import { getFriend, getUidByUin, uid2UinMap } from '../../../common/data'; +import { ActionName } from '../types'; +import { log } from '../../../common/utils/log'; + +interface Payload { + user_id: number, + times: number +} + +export default class SendLike extends BaseAction { + actionName = ActionName.SendLike; + + protected async _handle(payload: Payload): Promise { + log('点赞参数', payload); + try { + const qq = payload.user_id.toString(); + const friend = await getFriend(qq); + let uid: string; + if (!friend) { + uid = getUidByUin(qq) || ''; + } else { + uid = friend.uid; + } + const result = await NTQQUserApi.like(uid, parseInt(payload.times?.toString()) || 1); + console.log('点赞结果', result); + if (result.result !== 0) { + throw Error(result.errMsg); + } + } catch (e) { + throw `点赞失败 ${e}`; + } + return null; + } +} diff --git a/src/onebot11/action/user/SetFriendAddRequest.ts b/src/onebot11/action/user/SetFriendAddRequest.ts new file mode 100644 index 00000000..b2f9de02 --- /dev/null +++ b/src/onebot11/action/user/SetFriendAddRequest.ts @@ -0,0 +1,21 @@ +import BaseAction from '../BaseAction'; +import { ActionName } from '../types'; +import { NTQQFriendApi } from '@/core/qqnt/apis/friend'; +import { friendRequests } from '@/common/data'; + +interface Payload { + flag: string, + approve: boolean, + remark?: string, +} + +export default class SetFriendAddRequest extends BaseAction { + actionName = ActionName.SetFriendAddRequest; + + protected async _handle(payload: Payload): Promise { + const approve = payload.approve.toString() === 'true'; + const request = friendRequests[payload.flag]; + await NTQQFriendApi.handleFriendRequest(request, approve); + return null; + } +} diff --git a/src/onebot11/config.ts b/src/onebot11/config.ts new file mode 100644 index 00000000..f523d09e --- /dev/null +++ b/src/onebot11/config.ts @@ -0,0 +1,80 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import { selfInfo } from '@/common/data'; + +export interface OB11Config { + httpPort: number; + httpPostUrls: string[]; + httpSecret: string; + wsPort: number; + wsReverseUrls: string[]; + enableHttp: boolean; + enableHttpPost: boolean; + enableWs: boolean; + enableWsReverse: boolean; + messagePostFormat: 'array' | 'string'; + reportSelfMessage: boolean; + enableLocalFile2Url: boolean; + debug: boolean; + heartInterval: number; + token: string; + + read(): OB11Config; + + save(config: OB11Config): void; +} + +const ob11ConfigDir = path.resolve(__dirname, 'config'); +fs.mkdirSync(ob11ConfigDir, { recursive: true }); + +class Config implements OB11Config { + httpPort: number = 3000; + httpPostUrls: string[] = []; + httpSecret = ''; + wsPort = 3001; + wsReverseUrls: string[] = []; + enableHttp = false; + enableHttpPost = false; + enableWs = false; + enableWsReverse = false; + messagePostFormat: 'array' | 'string' = 'array'; + reportSelfMessage = false; + debug = false; + enableLocalFile2Url = true; + heartInterval = 30000; + token = ''; + + constructor() { + } + + getConfigPath() { + return path.join(ob11ConfigDir, `onebot11_${selfInfo.uin}.json`); + } + + read() { + const ob11ConfigPath = this.getConfigPath(); + if (!fs.existsSync(ob11ConfigPath)) { + console.log(`onebot11配置文件 ${ob11ConfigPath} 不存在, 现已创建,请修改配置文件后重启NapCat`); + this.save(); + return this; + } + const data = fs.readFileSync(ob11ConfigPath, 'utf-8'); + try { + const jsonData = JSON.parse(data); + console.log('get config', jsonData); + Object.assign(this, jsonData); + // eslint-disable-next-line + } catch (e) { + } + return this; + } + + save(newConfig: OB11Config | null = null) { + if (newConfig) { + Object.assign(this, newConfig); + } + fs.writeFileSync(this.getConfigPath(), JSON.stringify(this, null, 4)); + } +} + +export const ob11Config = new Config(); diff --git a/src/onebot11/constructor.ts b/src/onebot11/constructor.ts new file mode 100644 index 00000000..277a3b36 --- /dev/null +++ b/src/onebot11/constructor.ts @@ -0,0 +1,486 @@ +import { + OB11Group, + OB11GroupMember, + OB11GroupMemberRole, + OB11Message, + OB11MessageData, + OB11MessageDataType, + OB11User, + OB11UserSex +} from './types'; +import { + AtType, + ChatType, + ElementType, + Friend, + GrayTipElementSubType, + Group, + GroupMember, + IMAGE_HTTP_HOST, + RawMessage, + SelfInfo, + Sex, + TipGroupElementType, + User +} from '@/core/qqnt/entities'; +import { EventType } from './event/OB11BaseEvent'; +import { encodeCQCode } from './cqcode'; +import { dbUtil } from '@/common/utils/db'; +import { OB11GroupIncreaseEvent } from './event/notice/OB11GroupIncreaseEvent'; +import { OB11GroupBanEvent } from './event/notice/OB11GroupBanEvent'; +import { OB11GroupUploadNoticeEvent } from './event/notice/OB11GroupUploadNoticeEvent'; +import { OB11GroupNoticeEvent } from './event/notice/OB11GroupNoticeEvent'; + +import { calcQQLevel } from '../common/utils/qqlevel'; +import { log } from '../common/utils/log'; +import { sleep } from '../common/utils/helper'; +import { OB11GroupTitleEvent } from './event/notice/OB11GroupTitleEvent'; +import { OB11GroupCardEvent } from './event/notice/OB11GroupCardEvent'; +import { OB11GroupDecreaseEvent } from './event/notice/OB11GroupDecreaseEvent'; +import { ob11Config } from '@/onebot11/config'; +import { getFriend, getGroupMember, groupMembers, selfInfo, tempGroupCodeMap } from '@/common/data'; + + +export class OB11Constructor { + static async message(msg: RawMessage): Promise { + const { messagePostFormat } = ob11Config; + const message_type = msg.chatType == ChatType.group ? 'group' : 'private'; + const resMsg: OB11Message = { + self_id: parseInt(selfInfo.uin), + user_id: parseInt(msg.senderUin!), + time: parseInt(msg.msgTime) || Date.now(), + message_id: msg.id!, + real_id: msg.id!, + message_type: msg.chatType == ChatType.group ? 'group' : 'private', + sender: { + user_id: parseInt(msg.senderUin!), + nickname: msg.sendNickName, + card: msg.sendMemberName || '', + }, + raw_message: '', + font: 14, + sub_type: 'friend', + message: messagePostFormat === 'string' ? '' : [], + message_format: messagePostFormat === 'string' ? 'string' : 'array', + post_type: selfInfo.uin == msg.senderUin ? EventType.MESSAGE_SENT : EventType.MESSAGE, + }; + if (msg.chatType == ChatType.group) { + resMsg.sub_type = 'normal'; // 这里go-cqhttp是group,而onebot11标准是normal, 蛋疼 + resMsg.group_id = parseInt(msg.peerUin); + const member = await getGroupMember(msg.peerUin, msg.senderUin!); + if (member) { + resMsg.sender.role = OB11Constructor.groupMemberRole(member.role); + resMsg.sender.nickname = member.nick; + } + } else if (msg.chatType == ChatType.friend) { + resMsg.sub_type = 'friend'; + const friend = await getFriend(msg.senderUin!); + if (friend) { + resMsg.sender.nickname = friend.nick; + } + } else if (msg.chatType == ChatType.temp) { + resMsg.sub_type = 'group'; + const tempGroupCode = tempGroupCodeMap[msg.peerUin]; + if (tempGroupCode) { + resMsg.group_id = parseInt(tempGroupCode); + } + } + + for (const element of msg.elements) { + const message_data: OB11MessageData | any = { + data: {}, + type: 'unknown' + }; + if (element.textElement && element.textElement?.atType !== AtType.notAt) { + message_data['type'] = OB11MessageDataType.at; + if (element.textElement.atType == AtType.atAll) { + // message_data["data"]["mention"] = "all" + message_data['data']['qq'] = 'all'; + } else { + const atUid = element.textElement.atNtUid; + let atQQ = element.textElement.atUid; + if (!atQQ || atQQ === '0') { + const atMember = await getGroupMember(msg.peerUin, atUid); + if (atMember) { + atQQ = atMember.uin; + } + } + if (atQQ) { + // message_data["data"]["mention"] = atQQ + message_data['data']['qq'] = atQQ; + } + } + } else if (element.textElement) { + message_data['type'] = 'text'; + const text = element.textElement.content; + if (!text.trim()) { + continue; + } + message_data['data']['text'] = text; + } else if (element.replyElement) { + message_data['type'] = 'reply'; + // log("收到回复消息", element.replyElement.replayMsgSeq) + try { + const replyMsg = await dbUtil.getMsgBySeq(msg.peerUid, element.replyElement.replayMsgSeq); + // log("找到回复消息", replyMsg.msgShortId, replyMsg.msgId) + if (replyMsg && replyMsg.id) { + message_data['data']['id'] = replyMsg.id!.toString(); + } else { + continue; + } + } catch (e: any) { + log('获取不到引用的消息', e.stack, element.replyElement.replayMsgSeq); + } + + } else if (element.picElement) { + message_data['type'] = 'image'; + // message_data["data"]["file"] = element.picElement.sourcePath + message_data['data']['file'] = element.picElement.fileName; + // message_data["data"]["path"] = element.picElement.sourcePath + const url = element.picElement.originImageUrl; + const md5HexStr = element.picElement.md5HexStr; + const fileMd5 = element.picElement.md5HexStr; + const fileUuid = element.picElement.fileUuid; + // let currentRKey = config.imageRKey || "CAQSKAB6JWENi5LMk0kc62l8Pm3Jn1dsLZHyRLAnNmHGoZ3y_gDZPqZt-64" + const currentRKey = 'CAQSKAB6JWENi5LMk0kc62l8Pm3Jn1dsLZHyRLAnNmHGoZ3y_gDZPqZt-64'; + if (url) { + if (url.startsWith('/download')) { + if (url.includes('&rkey=')) { + // 正则提取rkey + // const rkey = url.match(/&rkey=([^&]+)/)[1] + // // log("图片url已有rkey", rkey) + // if (rkey != currentRKey){ + // config.imageRKey = rkey + // if (Date.now() - lastRKeyUpdateTime > 1000 * 60) { + // lastRKeyUpdateTime = Date.now() + // getConfigUtil().setConfig(config) + // } + // } + message_data['data']['url'] = IMAGE_HTTP_HOST + url; + } else { + // 有可能会碰到appid为1406的,这个不能使用新的NT域名,并且需要把appid改为1407才可访问 + message_data['data']['url'] = `${IMAGE_HTTP_HOST}/download?appid=1407&fileid=${fileUuid}&rkey=${currentRKey}&spec=0`; + } + } else { + message_data['data']['url'] = IMAGE_HTTP_HOST + url; + } + } else if (fileMd5) { + message_data['data']['url'] = `${IMAGE_HTTP_HOST}/gchatpic_new/0/0-0-${fileMd5.toUpperCase()}/0`; + } + + if (!message_data['data']['url']) { + message_data['data']['url'] = `${IMAGE_HTTP_HOST}/gchatpic_new/0/0-0-${md5HexStr!.toUpperCase()}/0`; + } + // message_data["data"]["file_id"] = element.picElement.fileUuid + message_data['data']['file_size'] = element.picElement.fileSize; + dbUtil.addFileCache({ + name: element.picElement.fileName, + path: element.picElement.sourcePath, + size: element.picElement.fileSize, + url: message_data['data']['url'], + uuid: element.picElement.fileUuid || '', + msgId: msg.msgId, + element: element.picElement, + elementType: ElementType.PIC, + elementId: element.elementId + }).then(); + // 不自动下载图片 + + } else if (element.videoElement || element.fileElement) { + const videoOrFileElement = element.videoElement || element.fileElement; + const ob11MessageDataType = element.videoElement ? OB11MessageDataType.video : OB11MessageDataType.file; + message_data['type'] = ob11MessageDataType; + message_data['data']['file'] = videoOrFileElement.fileName; + message_data['data']['path'] = videoOrFileElement.filePath; + message_data['data']['file_id'] = videoOrFileElement.fileUuid; + message_data['data']['file_size'] = videoOrFileElement.fileSize; + // 怎么拿到url呢 + dbUtil.addFileCache({ + msgId: msg.msgId, + name: videoOrFileElement.fileName, + path: videoOrFileElement.filePath, + size: parseInt(videoOrFileElement.fileSize || '0'), + uuid: videoOrFileElement.fileUuid || '', + url: '', + element: element.videoElement || element.fileElement, + elementType: element.videoElement ? ElementType.VIDEO : ElementType.FILE, + elementId: element.elementId + }).then(); + } else if (element.pttElement) { + message_data['type'] = OB11MessageDataType.voice; + message_data['data']['file'] = element.pttElement.fileName; + message_data['data']['path'] = element.pttElement.filePath; + // message_data["data"]["file_id"] = element.pttElement.fileUuid + message_data['data']['file_size'] = element.pttElement.fileSize; + dbUtil.addFileCache({ + name: element.pttElement.fileName, + path: element.pttElement.filePath, + size: parseInt(element.pttElement.fileSize) || 0, + url: '', + uuid: element.pttElement.fileUuid || '', + msgId: msg.msgId, + element: element.pttElement, + elementType: ElementType.PTT, + elementId: element.elementId + }).then(); + + // log("收到语音消息", msg) + // window.LLAPI.Ptt2Text(message.raw.msgId, message.peer, messages).then(text => { + // console.log("语音转文字结果", text); + // }).catch(err => { + // console.log("语音转文字失败", err); + // }) + } else if (element.arkElement) { + message_data['type'] = OB11MessageDataType.json; + message_data['data']['data'] = element.arkElement.bytesData; + } else if (element.faceElement) { + message_data['type'] = OB11MessageDataType.face; + message_data['data']['id'] = element.faceElement.faceIndex.toString(); + } else if (element.marketFaceElement) { + message_data['type'] = OB11MessageDataType.mface; + message_data['data']['text'] = element.marketFaceElement.faceName; + } else if (element.markdownElement) { + message_data['type'] = OB11MessageDataType.markdown; + message_data['data']['data'] = element.markdownElement.content; + } else if (element.multiForwardMsgElement) { + message_data['type'] = OB11MessageDataType.forward; + message_data['data']['id'] = msg.msgId; + } + if (message_data.type !== 'unknown' && message_data.data) { + const cqCode = encodeCQCode(message_data); + if (messagePostFormat === 'string') { + (resMsg.message as string) += cqCode; + } else (resMsg.message as OB11MessageData[]).push(message_data); + resMsg.raw_message += cqCode; + } + } + resMsg.raw_message = resMsg.raw_message.trim(); + return resMsg; + } + + static async GroupEvent(msg: RawMessage): Promise { + if (msg.chatType !== ChatType.group) { + return; + } + if (msg.senderUin) { + const member = await getGroupMember(msg.peerUid, msg.senderUin); + if (member && member.cardName !== msg.sendMemberName) { + const newCardName = msg.sendMemberName || ''; + const event = new OB11GroupCardEvent(parseInt(msg.peerUid), parseInt(msg.senderUin), newCardName, member.cardName); + member.cardName = newCardName; + return event; + } + } + // log("group msg", msg); + for (const element of msg.elements) { + const grayTipElement = element.grayTipElement; + const groupElement = grayTipElement?.groupElement; + if (groupElement) { + // log("收到群提示消息", groupElement) + if (groupElement.type == TipGroupElementType.memberIncrease) { + log('收到群成员增加消息', groupElement); + await sleep(1000); + const member = await getGroupMember(msg.peerUid, groupElement.memberUid); + const memberUin = member?.uin; + // if (!memberUin) { + // memberUin = (await NTQQUserApi.getUserDetailInfo(groupElement.memberUid)).uin + // } + // log("获取新群成员QQ", memberUin) + const adminMember = await getGroupMember(msg.peerUid, groupElement.adminUid); + // log("获取同意新成员入群的管理员", adminMember) + if (memberUin) { + const operatorUin = adminMember?.uin || memberUin; + const event = new OB11GroupIncreaseEvent(parseInt(msg.peerUid), parseInt(memberUin), parseInt(operatorUin)); + // log("构造群增加事件", event) + return event; + } + } else if (groupElement.type === TipGroupElementType.ban) { + log('收到群群员禁言提示', groupElement); + const memberUid = groupElement.shutUp!.member.uid; + const adminUid = groupElement.shutUp!.admin.uid; + let memberUin: string = ''; + let duration = parseInt(groupElement.shutUp!.duration); + const sub_type: 'ban' | 'lift_ban' = duration > 0 ? 'ban' : 'lift_ban'; + // log('OB11被禁言事件', adminUid); + if (memberUid) { + memberUin = (await getGroupMember(msg.peerUid, memberUid))?.uin || ''; // || (await NTQQUserApi.getUserDetailInfo(memberUid))?.uin + } else { + memberUin = '0'; // 0表示全员禁言 + if (duration > 0) { + duration = -1; + } + } + const adminUin = (await getGroupMember(msg.peerUid, adminUid))?.uin; // || (await NTQQUserApi.getUserDetailInfo(adminUid))?.uin + // log('OB11被禁言事件', memberUin, adminUin, duration, sub_type); + if (memberUin && adminUin) { + const event = new OB11GroupBanEvent(parseInt(msg.peerUid), parseInt(memberUin), parseInt(adminUin), duration, sub_type); + return event; + } + } else if (groupElement.type == TipGroupElementType.kicked) { + log('收到我被踢出提示', groupElement); + const adminUin = (await getGroupMember(msg.peerUid, groupElement.adminUid))?.uin; //|| (await NTQQUserApi.getUserDetailInfo(groupElement.adminUid))?.uin + if (adminUin) { + return new OB11GroupDecreaseEvent(parseInt(msg.peerUid), parseInt(selfInfo.uin), parseInt(adminUin), 'kick_me'); + } + } + } else if (element.fileElement) { + return new OB11GroupUploadNoticeEvent(parseInt(msg.peerUid), parseInt(msg.senderUin || ''), { + id: element.fileElement.fileUuid!, + name: element.fileElement.fileName, + size: parseInt(element.fileElement.fileSize), + busid: element.fileElement.fileBizId || 0 + }); + } + + if (grayTipElement) { + if (grayTipElement.subElementType == GrayTipElementSubType.INVITE_NEW_MEMBER) { + log('收到新人被邀请进群消息', grayTipElement); + const xmlElement = grayTipElement.xmlElement; + if (xmlElement?.content) { + const regex = /jp="(\d+)"/g; + + const matches = []; + let match = null; + + while ((match = regex.exec(xmlElement.content)) !== null) { + matches.push(match[1]); + } + // log("新人进群匹配到的QQ号", matches) + if (matches.length === 2) { + const [inviter, invitee] = matches; + return new OB11GroupIncreaseEvent(parseInt(msg.peerUid), parseInt(invitee), parseInt(inviter), 'invite'); + } + } + } else if (grayTipElement.subElementType == GrayTipElementSubType.MEMBER_NEW_TITLE) { + const json = JSON.parse(grayTipElement.jsonGrayTipElement.jsonStr); + /* + { + align: 'center', + items: [ + { txt: '恭喜', type: 'nor' }, + { + col: '3', + jp: '5', + param: ["QQ号"], + txt: '林雨辰', + type: 'url' + }, + { txt: '获得群主授予的', type: 'nor' }, + { + col: '3', + jp: '', + txt: '好好好', + type: 'url' + }, + { txt: '头衔', type: 'nor' } + ] + } + + * */ + const memberUin = json.items[1].param[0]; + const title = json.items[3].txt; + log('收到群成员新头衔消息', json); + return new OB11GroupTitleEvent(parseInt(msg.peerUid), parseInt(memberUin), title); + } + } + } + } + + static friend(friend: User): OB11User { + return { + user_id: parseInt(friend.uin), + nickname: friend.nick, + remark: friend.remark, + sex: OB11Constructor.sex(friend.sex!), + level: friend.qqLevel && calcQQLevel(friend.qqLevel) || 0 + }; + } + + static selfInfo(selfInfo: SelfInfo): OB11User { + return { + user_id: parseInt(selfInfo.uin), + nickname: selfInfo.nick, + }; + } + + static friends(friends: Friend[]): OB11User[] { + const data: OB11User[] = []; + friends.forEach(friend => { + const sexValue = this.sex(friend.sex!); + data.push({ user_id: parseInt(friend.uin), nickname: friend.nick, remark: friend.remark, sex: sexValue, level: 0 }); + }); + return data; + } + + static groupMemberRole(role: number): OB11GroupMemberRole | undefined { + return { + 4: OB11GroupMemberRole.owner, + 3: OB11GroupMemberRole.admin, + 2: OB11GroupMemberRole.member + }[role]; + } + + static sex(sex: Sex): OB11UserSex { + const sexMap = { + [Sex.male]: OB11UserSex.male, + [Sex.female]: OB11UserSex.female, + [Sex.unknown]: OB11UserSex.unknown + }; + return sexMap[sex] || OB11UserSex.unknown; + } + + static groupMember(group_id: string, member: GroupMember): OB11GroupMember { + return { + group_id: parseInt(group_id), + user_id: parseInt(member.uin), + nickname: member.nick, + card: member.cardName, + sex: OB11Constructor.sex(member.sex!), + age: 0, + area: '', + level: 0, + qq_level: member.qqLevel && calcQQLevel(member.qqLevel) || 0, + join_time: 0, // 暂时没法获取 + last_sent_time: 0, // 暂时没法获取 + title_expire_time: 0, + unfriendly: false, + card_changeable: true, + is_robot: member.isRobot, + shut_up_timestamp: member.shutUpTime, + role: OB11Constructor.groupMemberRole(member.role), + title: member.memberSpecialTitle || '', + }; + } + + static stranger(user: User): OB11User { + log('construct ob11 stranger', user); + return { + ...user, + user_id: parseInt(user.uin), + nickname: user.nick, + sex: OB11Constructor.sex(user.sex!), + age: 0, + qid: user.qid, + login_days: 0, + level: user.qqLevel && calcQQLevel(user.qqLevel) || 0, + }; + } + + static groupMembers(group: Group): OB11GroupMember[] { + log('construct ob11 group members', group); + return Array.from(groupMembers.get(group.groupCode)?.values() || []).map(m => OB11Constructor.groupMember(group.groupCode, m)); + } + + static group(group: Group): OB11Group { + return { + group_id: parseInt(group.groupCode), + group_name: group.groupName, + member_count: group.memberCount, + max_member_count: group.maxMember + }; + } + + static groups(groups: Group[]): OB11Group[] { + return groups.map(OB11Constructor.group); + } +} diff --git a/src/onebot11/cqcode.ts b/src/onebot11/cqcode.ts new file mode 100644 index 00000000..4a525e3c --- /dev/null +++ b/src/onebot11/cqcode.ts @@ -0,0 +1,78 @@ +import { OB11MessageData } from './types'; + +const pattern = /\[CQ:(\w+)((,\w+=[^,\]]*)*)\]/; + +function unescape(source: string) { + return String(source) + .replace(/[/g, '[') + .replace(/]/g, ']') + .replace(/,/g, ',') + .replace(/&/g, '&'); +} + +function from(source: string) { + const capture = pattern.exec(source); + if (!capture) return null; + const [, type, attrs] = capture; + const data: Record = {}; + attrs && attrs.slice(1).split(',').forEach((str) => { + const index = str.indexOf('='); + data[str.slice(0, index)] = unescape(str.slice(index + 1)); + }); + return { type, data, capture }; +} + +function h(type: string, data: any) { + return { + type, + data, + }; +} + +export function decodeCQCode(source: string): OB11MessageData[] { + const elements: any[] = []; + let result: ReturnType; + while ((result = from(source))) { + const { type, data, capture } = result; + if (capture.index) { + elements.push(h('text', { text: unescape(source.slice(0, capture.index)) })); + } + elements.push(h(type, data)); + source = source.slice(capture.index + capture[0].length); + } + if (source) elements.push(h('text', { text: unescape(source) })); + return elements; +} + + +export function encodeCQCode(data: OB11MessageData) { + const CQCodeEscapeText = (text: string) => { + return text.replace(/&/g, '&') + .replace(/\[/g, '[') + .replace(/\]/g, ']'); + + }; + + const CQCodeEscape = (text: string) => { + return text.replace(/&/g, '&') + .replace(/\[/g, '[') + .replace(/\]/g, ']') + .replace(/,/g, ','); + }; + + if (data.type === 'text') { + return CQCodeEscapeText(data.data.text); + } + + let result = '[CQ:' + data.type; + for (const name in data.data) { + const value = data.data[name]; + result += `,${name}=${CQCodeEscape(value)}`; + } + result += ']'; + return result; +} + +// const result = parseCQCode("[CQ:at,qq=114514]早上好啊[CQ:image,file=http://baidu.com/1.jpg,type=show,id=40004]") +// const result = parseCQCode("好好好") +// console.log(JSON.stringify(result)) diff --git a/src/onebot11/event/OB11BaseEvent.ts b/src/onebot11/event/OB11BaseEvent.ts new file mode 100644 index 00000000..bacf85ce --- /dev/null +++ b/src/onebot11/event/OB11BaseEvent.ts @@ -0,0 +1,16 @@ +import { selfInfo } from '@/common/data'; + +export enum EventType { + META = 'meta_event', + REQUEST = 'request', + NOTICE = 'notice', + MESSAGE = 'message', + MESSAGE_SENT = 'message_sent', +} + + +export abstract class OB11BaseEvent { + time = Math.floor(Date.now() / 1000); + self_id = parseInt(selfInfo.uin); + post_type: EventType = EventType.META; +} \ No newline at end of file diff --git a/src/onebot11/event/message/OB11BaseMessageEvent.ts b/src/onebot11/event/message/OB11BaseMessageEvent.ts new file mode 100644 index 00000000..8ed0f8f6 --- /dev/null +++ b/src/onebot11/event/message/OB11BaseMessageEvent.ts @@ -0,0 +1,5 @@ +import { EventType, OB11BaseEvent } from '../OB11BaseEvent'; + +export abstract class OB11BaseMessageEvent extends OB11BaseEvent { + post_type = EventType.MESSAGE; +} \ No newline at end of file diff --git a/src/onebot11/event/meta/OB11BaseMetaEvent.ts b/src/onebot11/event/meta/OB11BaseMetaEvent.ts new file mode 100644 index 00000000..4a1b9344 --- /dev/null +++ b/src/onebot11/event/meta/OB11BaseMetaEvent.ts @@ -0,0 +1,6 @@ +import { EventType, OB11BaseEvent } from '../OB11BaseEvent'; + +export abstract class OB11BaseMetaEvent extends OB11BaseEvent { + post_type = EventType.META; + meta_event_type: string; +} \ No newline at end of file diff --git a/src/onebot11/event/meta/OB11HeartbeatEvent.ts b/src/onebot11/event/meta/OB11HeartbeatEvent.ts new file mode 100644 index 00000000..ad2a0c55 --- /dev/null +++ b/src/onebot11/event/meta/OB11HeartbeatEvent.ts @@ -0,0 +1,21 @@ +import { OB11BaseMetaEvent } from './OB11BaseMetaEvent'; + +interface HeartbeatStatus { + online: boolean | null, + good: boolean +} + +export class OB11HeartbeatEvent extends OB11BaseMetaEvent { + meta_event_type = 'heartbeat'; + status: HeartbeatStatus; + interval: number; + + public constructor(isOnline: boolean, isGood: boolean, interval: number) { + super(); + this.interval = interval; + this.status = { + online: isOnline, + good: isGood + }; + } +} \ No newline at end of file diff --git a/src/onebot11/event/meta/OB11LifeCycleEvent.ts b/src/onebot11/event/meta/OB11LifeCycleEvent.ts new file mode 100644 index 00000000..a28f91eb --- /dev/null +++ b/src/onebot11/event/meta/OB11LifeCycleEvent.ts @@ -0,0 +1,17 @@ +import { OB11BaseMetaEvent } from './OB11BaseMetaEvent'; + +export enum LifeCycleSubType { + ENABLE = 'enable', + DISABLE = 'disable', + CONNECT = 'connect' +} + +export class OB11LifeCycleEvent extends OB11BaseMetaEvent { + meta_event_type = 'lifecycle'; + sub_type: LifeCycleSubType; + + public constructor(subType: LifeCycleSubType) { + super(); + this.sub_type = subType; + } +} \ No newline at end of file diff --git a/src/onebot11/event/notice/OB11BaseNoticeEvent.ts b/src/onebot11/event/notice/OB11BaseNoticeEvent.ts new file mode 100644 index 00000000..15c45893 --- /dev/null +++ b/src/onebot11/event/notice/OB11BaseNoticeEvent.ts @@ -0,0 +1,5 @@ +import { EventType, OB11BaseEvent } from '../OB11BaseEvent'; + +export abstract class OB11BaseNoticeEvent extends OB11BaseEvent { + post_type = EventType.NOTICE; +} \ No newline at end of file diff --git a/src/onebot11/event/notice/OB11FriendRecallNoticeEvent.ts b/src/onebot11/event/notice/OB11FriendRecallNoticeEvent.ts new file mode 100644 index 00000000..2e374878 --- /dev/null +++ b/src/onebot11/event/notice/OB11FriendRecallNoticeEvent.ts @@ -0,0 +1,13 @@ +import { OB11BaseNoticeEvent } from './OB11BaseNoticeEvent'; + +export class OB11FriendRecallNoticeEvent extends OB11BaseNoticeEvent { + notice_type = 'friend_recall'; + user_id: number; + message_id: number; + + public constructor(userId: number, messageId: number) { + super(); + this.user_id = userId; + this.message_id = messageId; + } +} \ No newline at end of file diff --git a/src/onebot11/event/notice/OB11GroupAdminNoticeEvent.ts b/src/onebot11/event/notice/OB11GroupAdminNoticeEvent.ts new file mode 100644 index 00000000..f4697c57 --- /dev/null +++ b/src/onebot11/event/notice/OB11GroupAdminNoticeEvent.ts @@ -0,0 +1,6 @@ +import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent'; + +export class OB11GroupAdminNoticeEvent extends OB11GroupNoticeEvent { + notice_type = 'group_admin'; + sub_type: 'set' | 'unset'; // "set" | "unset" +} \ No newline at end of file diff --git a/src/onebot11/event/notice/OB11GroupBanEvent.ts b/src/onebot11/event/notice/OB11GroupBanEvent.ts new file mode 100644 index 00000000..9b47fc36 --- /dev/null +++ b/src/onebot11/event/notice/OB11GroupBanEvent.ts @@ -0,0 +1,17 @@ +import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent'; + +export class OB11GroupBanEvent extends OB11GroupNoticeEvent { + notice_type = 'group_ban'; + operator_id: number; + duration: number; + sub_type: 'ban' | 'lift_ban'; + + constructor(groupId: number, userId: number, operatorId: number, duration: number, sub_type: 'ban' | 'lift_ban') { + super(); + this.group_id = groupId; + this.operator_id = operatorId; + this.user_id = userId; + this.duration = duration; + this.sub_type = sub_type; + } +} diff --git a/src/onebot11/event/notice/OB11GroupCardEvent.ts b/src/onebot11/event/notice/OB11GroupCardEvent.ts new file mode 100644 index 00000000..1c2e4bc0 --- /dev/null +++ b/src/onebot11/event/notice/OB11GroupCardEvent.ts @@ -0,0 +1,16 @@ +import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent'; + +export class OB11GroupCardEvent extends OB11GroupNoticeEvent { + notice_type = 'group_card'; + card_new: string; + card_old: string; + + + constructor(groupId: number, userId: number, cardNew: string, cardOld: string) { + super(); + this.group_id = groupId; + this.user_id = userId; + this.card_new = cardNew; + this.card_old = cardOld; + } +} diff --git a/src/onebot11/event/notice/OB11GroupDecreaseEvent.ts b/src/onebot11/event/notice/OB11GroupDecreaseEvent.ts new file mode 100644 index 00000000..33da8563 --- /dev/null +++ b/src/onebot11/event/notice/OB11GroupDecreaseEvent.ts @@ -0,0 +1,17 @@ +import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent'; + +export type GroupDecreaseSubType = 'leave' | 'kick' | 'kick_me'; + +export class OB11GroupDecreaseEvent extends OB11GroupNoticeEvent { + notice_type = 'group_decrease'; + sub_type: GroupDecreaseSubType = 'leave'; // TODO: 实现其他几种子类型的识别 ("leave" | "kick" | "kick_me") + operator_id: number; + + constructor(groupId: number, userId: number, operatorId: number, subType: GroupDecreaseSubType = 'leave') { + super(); + this.group_id = groupId; + this.operator_id = operatorId; // 实际上不应该这么实现,但是现在还没有办法识别用户是被踢出的,还是自己主动退出的 + this.user_id = userId; + this.sub_type = subType; + } +} diff --git a/src/onebot11/event/notice/OB11GroupIncreaseEvent.ts b/src/onebot11/event/notice/OB11GroupIncreaseEvent.ts new file mode 100644 index 00000000..b0a86880 --- /dev/null +++ b/src/onebot11/event/notice/OB11GroupIncreaseEvent.ts @@ -0,0 +1,15 @@ +import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent'; + +type GroupIncreaseSubType = 'approve' | 'invite'; +export class OB11GroupIncreaseEvent extends OB11GroupNoticeEvent { + notice_type = 'group_increase'; + operator_id: number; + sub_type: GroupIncreaseSubType; + constructor(groupId: number, userId: number, operatorId: number, subType: GroupIncreaseSubType = 'approve') { + super(); + this.group_id = groupId; + this.operator_id = operatorId; + this.user_id = userId; + this.sub_type = subType; + } +} diff --git a/src/onebot11/event/notice/OB11GroupNoticeEvent.ts b/src/onebot11/event/notice/OB11GroupNoticeEvent.ts new file mode 100644 index 00000000..a1c1eab1 --- /dev/null +++ b/src/onebot11/event/notice/OB11GroupNoticeEvent.ts @@ -0,0 +1,6 @@ +import { OB11BaseNoticeEvent } from './OB11BaseNoticeEvent'; + +export abstract class OB11GroupNoticeEvent extends OB11BaseNoticeEvent { + group_id: number; + user_id: number; +} \ No newline at end of file diff --git a/src/onebot11/event/notice/OB11GroupRecallNoticeEvent.ts b/src/onebot11/event/notice/OB11GroupRecallNoticeEvent.ts new file mode 100644 index 00000000..8d35ca1b --- /dev/null +++ b/src/onebot11/event/notice/OB11GroupRecallNoticeEvent.ts @@ -0,0 +1,15 @@ +import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent'; + +export class OB11GroupRecallNoticeEvent extends OB11GroupNoticeEvent { + notice_type = 'group_recall'; + operator_id: number; + message_id: number; + + constructor(groupId: number, userId: number, operatorId: number, messageId: number) { + super(); + this.group_id = groupId; + this.user_id = userId; + this.operator_id = operatorId; + this.message_id = messageId; + } +} \ No newline at end of file diff --git a/src/onebot11/event/notice/OB11GroupTitleEvent.ts b/src/onebot11/event/notice/OB11GroupTitleEvent.ts new file mode 100644 index 00000000..41eace84 --- /dev/null +++ b/src/onebot11/event/notice/OB11GroupTitleEvent.ts @@ -0,0 +1,15 @@ +import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent'; + +export class OB11GroupTitleEvent extends OB11GroupNoticeEvent { + notice_type = 'notify'; + sub_type = 'title'; + title: string; + + + constructor(groupId: number, userId: number, title: string) { + super(); + this.group_id = groupId; + this.user_id = userId; + this.title = title; + } +} diff --git a/src/onebot11/event/notice/OB11GroupUploadNoticeEvent.ts b/src/onebot11/event/notice/OB11GroupUploadNoticeEvent.ts new file mode 100644 index 00000000..d5514872 --- /dev/null +++ b/src/onebot11/event/notice/OB11GroupUploadNoticeEvent.ts @@ -0,0 +1,20 @@ +import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent'; + +export interface GroupUploadFile{ + id: string, + name: string, + size: number, + busid: number, +} + +export class OB11GroupUploadNoticeEvent extends OB11GroupNoticeEvent { + notice_type = 'group_upload'; + file: GroupUploadFile; + + constructor(groupId: number, userId: number, file: GroupUploadFile) { + super(); + this.group_id = groupId; + this.user_id = userId; + this.file = file; + } +} \ No newline at end of file diff --git a/src/onebot11/event/notice/OB11PokeEvent.ts b/src/onebot11/event/notice/OB11PokeEvent.ts new file mode 100644 index 00000000..f41f3435 --- /dev/null +++ b/src/onebot11/event/notice/OB11PokeEvent.ts @@ -0,0 +1,30 @@ +import { OB11BaseNoticeEvent } from './OB11BaseNoticeEvent'; +import { selfInfo } from '../../../common/data'; +import { OB11BaseEvent } from '../OB11BaseEvent'; + +class OB11PokeEvent extends OB11BaseNoticeEvent{ + notice_type = 'notify'; + sub_type = 'poke'; + target_id = parseInt(selfInfo.uin); + user_id: number; +} + +export class OB11FriendPokeEvent extends OB11PokeEvent{ + sender_id: number; + constructor(user_id: number) { + super(); + this.user_id = user_id; + this.sender_id = user_id; + } +} + +export class OB11GroupPokeEvent extends OB11PokeEvent{ + group_id: number; + + constructor(group_id: number, user_id: number=0) { + super(); + this.group_id = group_id; + this.target_id = user_id; + this.user_id = user_id; + } +} diff --git a/src/onebot11/event/request/OB11FriendRequest.ts b/src/onebot11/event/request/OB11FriendRequest.ts new file mode 100644 index 00000000..522aa483 --- /dev/null +++ b/src/onebot11/event/request/OB11FriendRequest.ts @@ -0,0 +1,11 @@ +import { OB11BaseNoticeEvent } from '../notice/OB11BaseNoticeEvent'; +import { EventType } from '../OB11BaseEvent'; + + +export class OB11FriendRequestEvent extends OB11BaseNoticeEvent { + post_type = EventType.REQUEST; + user_id: number = 0; + request_type = 'friend' as const; + comment: string = ''; + flag: string = ''; +} diff --git a/src/onebot11/event/request/OB11GroupRequest.ts b/src/onebot11/event/request/OB11GroupRequest.ts new file mode 100644 index 00000000..e06677e6 --- /dev/null +++ b/src/onebot11/event/request/OB11GroupRequest.ts @@ -0,0 +1,11 @@ +import { OB11GroupNoticeEvent } from '../notice/OB11GroupNoticeEvent'; +import { EventType } from '../OB11BaseEvent'; + + +export class OB11GroupRequestEvent extends OB11GroupNoticeEvent { + post_type = EventType.REQUEST; + request_type = 'group' as const; + sub_type: 'add' | 'invite' = 'add'; + comment: string = ''; + flag: string = ''; +} diff --git a/src/onebot11/index.ts b/src/onebot11/index.ts new file mode 100644 index 00000000..c0c86de7 --- /dev/null +++ b/src/onebot11/index.ts @@ -0,0 +1,99 @@ +import { napCatCore } from '@/core'; +import { MsgListener } from '@/core/qqnt/listeners'; +import { NapCatOnebot11 } from '@/onebot11/main'; +import { ob11Config } from '@/onebot11/config'; +import { program } from 'commander'; +import qrcode from 'qrcode-terminal'; +import * as readline from 'node:readline'; +import fs from 'fs/promises'; +import path from 'node:path'; +import { noifyLoginStatus } from '@/common/utils/umami'; +import { checkVersion } from '@/common/utils/version'; + +program + .option('-q, --qq ', 'QQ号') + .parse(process.argv); + +const cmdOptions = program.opts(); +console.log(process.argv); + +checkVersion().then((remoteVersion: string) => { + const localVersion = require('./package.json').version; + const localVersionList = localVersion.split('.'); + const remoteVersionList = remoteVersion.split('.'); + for (const k of [0, 1, 2]) { + if (parseInt(remoteVersionList[k]) > parseInt(localVersionList[k])) { + console.log('检测到更新,请前往 https://github.com/NapNeko/NapCatQQ 下载 NapCatQQ V', remoteVersion); + } else if (parseInt(remoteVersionList[k]) < parseInt(localVersionList[k])) { + break; + } + } + console.log('当前已是最新版本,版本:', localVersion); +}); +new NapCatOnebot11(); +napCatCore.addLoginSuccessCallback(() => { + console.log('login success'); + noifyLoginStatus(); + const msgListener = new MsgListener(); + msgListener.onRecvMsg = (msg) => { + // console.log("onRecvMsg", msg) + }; + // napCatCore.getGroupService().getGroupExtList(true).then((res) => { + // console.log(res) + // }) + napCatCore.service.msg.addMsgListener(msgListener); +}); +napCatCore.on('system.login.qrcode', (qrCodeData: { url: string, base64: string }) => { + console.log('请扫描下面的二维码,然后在手Q上授权登录:'); + console.log('二维码解码URL:', qrCodeData.url); + const qrcodePath = path.join(__dirname, 'qrcode.png'); + fs.writeFile(qrcodePath, qrCodeData.base64.split('data:image/png;base64')[1], 'base64').then(() => { + console.log('二维码已保存到', qrcodePath); + }); + qrcode.generate(qrCodeData.url, {small: true}, (res) => { + console.log(res); + }); +}); +// console.log(cmdOptions); +const quickLoginQQ = cmdOptions.qq; +napCatCore.on('system.login.error', (result) => { + console.error('登录失败', result); + napCatCore.login.qrcode().then().catch(console.error); +}); +if (quickLoginQQ) { + console.log('quick login', quickLoginQQ); + napCatCore.login.quick(quickLoginQQ).then().catch((e) => { + console.error(`${quickLoginQQ}快速登录不可用,请检查是否已经登录了`, e); + napCatCore.login.qrcode().then(); + }); +} else { + console.info('没有 -q 参数指定快速登录的QQ,将使用二维码登录方式'); + napCatCore.login.qrcode().then(); +} + +// napCatCore.login.service.getLoginList().then((res) => { +// const quickLoginUinList = res.LocalLoginInfoList.filter((item) => item.isQuickLogin).map((item) => item.uin); +// if (quickLoginUinList.length !== 0) { +// const askQuickLoginUin = readline.createInterface({ +// input: process.stdin, +// output: process.stdout +// }); +// const prompt = `选择快速登录的账号\n\n ${quickLoginUinList.map((u, index) => `${index}: ${u}\n`)}\n输入对应序号按回车确定: `; +// askQuickLoginUin.question(prompt, (uinIndex) => { +// console.log('你选择的是:', uinIndex); +// const uin = quickLoginUinList[parseInt(uinIndex)]; +// if (!uin) { +// console.error('请输入正确的序号'); +// return; +// } +// console.log('开始登录', uin); +// napCatCore.login.quick(uin).then().catch((e) => { +// console.error(e); +// }); +// }); +// } +// } +// ); +//napCatCore.passwordLogin("", "").then(console.log).catch((e) => { +// console.log(e) +//}) diff --git a/src/onebot11/main.ts b/src/onebot11/main.ts new file mode 100644 index 00000000..9beed7ed --- /dev/null +++ b/src/onebot11/main.ts @@ -0,0 +1,335 @@ +import { napCatCore } from '@/core'; +import { MsgListener } from '@/core/qqnt/listeners'; +import { OB11Constructor } from '@/onebot11/constructor'; +import { postOB11Event } from '@/onebot11/server/postOB11Event'; +import { + ChatType, + FriendRequest, + Group, + GroupMemberRole, + GroupNotify, + GroupNotifyTypes, + RawMessage +} from '@/core/qqnt/entities'; +import { ob11Config } from '@/onebot11/config'; +import { ob11HTTPServer } from '@/onebot11/server/http'; +import { ob11WebsocketServer } from '@/onebot11/server/ws/WebsocketServer'; +import { ob11ReverseWebsockets } from '@/onebot11/server/ws/ReverseWebsocket'; +import { friendRequests, getFriend, getGroup, getGroupMember, groupNotifies, selfInfo } from '@/common/data'; +import { dbUtil } from '@/common/utils/db'; +import { BuddyListener, GroupListener, NodeIKernelBuddyListener } from '@/core/qqnt/listeners'; +import { OB11FriendRequestEvent } from '@/onebot11/event/request/OB11FriendRequest'; +import { NTQQGroupApi, NTQQUserApi } from '@/core/qqnt/apis'; +import { log } from '@/common/utils/log'; +import { OB11GroupRequestEvent } from '@/onebot11/event/request/OB11GroupRequest'; +import { OB11GroupAdminNoticeEvent } from '@/onebot11/event/notice/OB11GroupAdminNoticeEvent'; +import { GroupDecreaseSubType, OB11GroupDecreaseEvent } from '@/onebot11/event/notice/OB11GroupDecreaseEvent'; +import { OB11FriendRecallNoticeEvent } from '@/onebot11/event/notice/OB11FriendRecallNoticeEvent'; +import { OB11GroupRecallNoticeEvent } from '@/onebot11/event/notice/OB11GroupRecallNoticeEvent'; + + +export class NapCatOnebot11 { + private bootTime: number = Date.now() / 1000; + + + constructor() { + // console.log('ob11 init'); + napCatCore.addLoginSuccessCallback(this.onReady.bind(this)); + } + + public onReady() { + console.log('ob11 ready'); + ob11Config.read(); + if (ob11Config.enableHttp) { + ob11HTTPServer.start(ob11Config.httpPort); + } + if (ob11Config.enableWs) { + ob11WebsocketServer.start(ob11Config.wsPort); + } + if (ob11Config.enableWsReverse) { + ob11ReverseWebsockets.start(); + } + // MsgListener + const msgListener = new MsgListener(); + msgListener.onRecvSysMsg = (protobuf: number[]) => { + // todo: 解码protobuf,这里可以拿到戳一戳,但是群戳一戳只有群号 + const buffer = Buffer.from(protobuf); + // 转换为十六进制字符串 + const hexString = protobuf.map(byte => { + // 将负数转换为补码表示的正数 + byte = byte < 0 ? 256 + byte : byte; + // 转换为十六进制,确保结果为两位数 + return ('0' + byte.toString(16)).slice(-2); + }).join(''); + // console.log('ob11 onRecvSysMsg', hexString, Date.now() / 1000); + // console.log(buffer.toString()); + // console.log('ob11 onRecvSysMsg', JSON.stringify(msg, null, 2)); + }; + msgListener.onRecvMsg = (msg) => { + // console.log('ob11 onRecvMsg', JSON.stringify(msg, null, 2)); + for (const m of msg) { + if (this.bootTime > parseInt(m.msgTime)) { + continue; + } + new Promise((resolve) => { + dbUtil.addMsg(m).then(msgShortId => { + m.id = msgShortId; + this.postReceiveMsg([m]).then().catch(log); + }).catch(log); + }).then(); + } + }; + msgListener.onMsgInfoListUpdate = (msgList) => { + this.postRecallMsg(msgList).then().catch(log); + }; + msgListener.onAddSendMsg = (msg) => { + if (ob11Config.reportSelfMessage) { + dbUtil.addMsg(msg).then(id => { + msg.id = id; + this.postReceiveMsg([msg]).then().catch(log); + }); + } + }; + napCatCore.service.msg.addMsgListener(msgListener); + console.log('ob11 msg listener added'); + + // BuddyListener + const buddyListener = new BuddyListener(); + buddyListener.onBuddyReqChange = ((req) => { + this.postFriendRequest(req.buddyReqs).then().catch(log); + }); + napCatCore.service.buddy.addBuddyListener(buddyListener); + console.log('ob11 buddy listener added'); + + // GroupListener + const groupListener = new GroupListener(); + groupListener.onGroupNotifiesUpdated = (doubt, notifies) => { + // console.log('ob11 onGroupNotifiesUpdated', notifies); + this.postGroupNotifies(notifies).then().catch(e => log('postGroupNotifies error: ', e)); + }; + groupListener.onJoinGroupNotify = (...notify) => { + // console.log('ob11 onJoinGroupNotify', notify); + }; + groupListener.onGroupListUpdate = (updateType, groupList) => { + // console.log('ob11 onGroupListUpdate', updateType, groupList); + // this.postGroupMemberChange(groupList).then(); + }; + + napCatCore.service.group.addGroupListener(groupListener); + console.log('ob11 group listener added'); + } + + async postReceiveMsg(msgList: RawMessage[]) { + const {debug, reportSelfMessage} = ob11Config; + for (const message of msgList) { + // console.log("ob11 收到新消息", message) + // if (message.senderUin !== selfInfo.uin){ + // message.msgShortId = await dbUtil.addMsg(message); + // } + + OB11Constructor.message(message).then((msg) => { + if (debug) { + msg.raw = message; + } else { + if (msg.message.length === 0) { + return; + } + } + const isSelfMsg = msg.user_id.toString() == selfInfo.uin; + if (isSelfMsg && !reportSelfMessage) { + return; + } + if (isSelfMsg) { + msg.target_id = parseInt(message.peerUin); + } + postOB11Event(msg); + // log("post msg", msg) + }).catch(e => log('constructMessage error: ', e)); + OB11Constructor.GroupEvent(message).then(groupEvent => { + if (groupEvent) { + // log("post group event", groupEvent); + postOB11Event(groupEvent); + } + }).catch(e => log('constructGroupEvent error: ', e)); + } + } + + async postGroupNotifies(notifies: GroupNotify[]) { + for (const notify of notifies) { + try { + notify.time = Date.now(); + const notifyTime = parseInt(notify.seq) / 1000 / 1000; + // log(`群通知时间${notifyTime}`, `LLOneBot启动时间${this.bootTime}`); + if (notifyTime < this.bootTime) { + continue; + } + const flag = notify.group.groupCode + '|' + notify.seq; + const existNotify = groupNotifies[flag]; + if (existNotify) { + continue; + } + log('收到群通知', notify); + groupNotifies[flag] = notify; + // let member2: GroupMember; + // if (notify.user2.uid) { + // member2 = await getGroupMember(notify.group.groupCode, null, notify.user2.uid); + // } + if ([GroupNotifyTypes.ADMIN_SET, GroupNotifyTypes.ADMIN_UNSET].includes(notify.type)) { + const member1 = await getGroupMember(notify.group.groupCode, notify.user1.uid); + log('有管理员变动通知'); + // refreshGroupMembers(notify.group.groupCode).then(); + const groupAdminNoticeEvent = new OB11GroupAdminNoticeEvent(); + groupAdminNoticeEvent.group_id = parseInt(notify.group.groupCode); + log('开始获取变动的管理员'); + if (member1) { + log('变动管理员获取成功'); + groupAdminNoticeEvent.user_id = parseInt(member1.uin); + groupAdminNoticeEvent.sub_type = notify.type == GroupNotifyTypes.ADMIN_UNSET ? 'unset' : 'set'; + // member1.role = notify.type == GroupNotifyTypes.ADMIN_SET ? GroupMemberRole.admin : GroupMemberRole.normal; + postOB11Event(groupAdminNoticeEvent, true); + } else { + log('获取群通知的成员信息失败', notify, getGroup(notify.group.groupCode)); + } + } else if (notify.type == GroupNotifyTypes.MEMBER_EXIT || notify.type == GroupNotifyTypes.KICK_MEMBER) { + log('有成员退出通知', notify); + try { + const member1 = await NTQQUserApi.getUserDetailInfo(notify.user1.uid); + let operatorId = member1.uin; + let subType: GroupDecreaseSubType = 'leave'; + if (notify.user2.uid) { + // 是被踢的 + const member2 = await getGroupMember(notify.group.groupCode, notify.user2.uid); + if (member2) { + operatorId = member2.uin; + } + subType = 'kick'; + } + const groupDecreaseEvent = new OB11GroupDecreaseEvent(parseInt(notify.group.groupCode), parseInt(member1.uin), parseInt(operatorId), subType); + postOB11Event(groupDecreaseEvent, true); + } catch (e: any) { + log('获取群通知的成员信息失败', notify, e.stack.toString()); + } + } else if ([GroupNotifyTypes.JOIN_REQUEST].includes(notify.type)) { + log('有加群请求'); + const groupRequestEvent = new OB11GroupRequestEvent(); + groupRequestEvent.group_id = parseInt(notify.group.groupCode); + let requestQQ = ''; + try { + requestQQ = (await NTQQUserApi.getUserDetailInfo(notify.user1.uid)).uin; + } catch (e) { + log('获取加群人QQ号失败', e); + } + groupRequestEvent.user_id = parseInt(requestQQ) || 0; + groupRequestEvent.sub_type = 'add'; + groupRequestEvent.comment = notify.postscript; + groupRequestEvent.flag = flag; + postOB11Event(groupRequestEvent); + } else if (notify.type == GroupNotifyTypes.INVITE_ME) { + log('收到邀请我加群通知'); + const groupInviteEvent = new OB11GroupRequestEvent(); + groupInviteEvent.group_id = parseInt(notify.group.groupCode); + let user_id = (await getFriend(notify.user2.uid))?.uin; + if (!user_id) { + user_id = (await NTQQUserApi.getUserDetailInfo(notify.user2.uid))?.uin; + } + groupInviteEvent.user_id = parseInt(user_id); + groupInviteEvent.sub_type = 'invite'; + groupInviteEvent.flag = flag; + postOB11Event(groupInviteEvent); + } + } catch (e: any) { + log('解析群通知失败', e.stack.toString()); + } + } + + } + + async postRecallMsg(msgList: RawMessage[]) { + for (const message of msgList) { + // log("message update", message.sendStatus, message.msgId, message.msgSeq) + if (message.recallTime != '0') { //todo: 这个判断方法不太好,应该使用灰色消息元素来判断? + // 撤回消息上报 + const oriMessage = await dbUtil.getMsgByLongId(message.msgId); + if (!oriMessage) { + continue; + } + if (message.chatType == ChatType.friend) { + const friendRecallEvent = new OB11FriendRecallNoticeEvent(parseInt(message!.senderUin), oriMessage!.id!); + postOB11Event(friendRecallEvent); + } else if (message.chatType == ChatType.group) { + let operatorId = message.senderUin; + for (const element of message.elements) { + const operatorUid = element.grayTipElement?.revokeElement.operatorUid; + const operator = await getGroupMember(message.peerUin, operatorUid); + operatorId = operator?.uin || message.senderUin; + } + const groupRecallEvent = new OB11GroupRecallNoticeEvent( + parseInt(message.peerUin), + parseInt(message.senderUin), + parseInt(operatorId), + oriMessage.id! + ); + postOB11Event(groupRecallEvent); + } + } + } + } + + async postFriendRequest(reqs: FriendRequest[]) { + for (const req of reqs) { + if (parseInt(req.reqTime) < this.bootTime) { + continue; + } + const flag = req.friendUid + '|' + req.reqTime; + if (friendRequests[flag]) { + continue; + } + friendRequests[flag] = req; + const friendRequestEvent = new OB11FriendRequestEvent(); + try { + const requester = await NTQQUserApi.getUserDetailInfo(req.friendUid); + friendRequestEvent.user_id = parseInt(requester.uin); + } catch (e) { + log('获取加好友者QQ号失败', e); + } + friendRequestEvent.flag = flag; + friendRequestEvent.comment = req.extWords; + postOB11Event(friendRequestEvent); + } + } + + async postGroupMemberChange(groupList: Group[]) { + // todo: 有无更好的方法判断群成员变动 + const newGroupList = groupList; + for (const group of newGroupList) { + const existGroup = await getGroup(group.groupCode); + if (existGroup) { + if (existGroup.memberCount > group.memberCount) { + log(`群(${group.groupCode})成员数量减少${existGroup.memberCount} -> ${group.memberCount}`); + const oldMembers = existGroup.members; + const newMembers = await NTQQGroupApi.getGroupMembers(group.groupCode); + group.members = newMembers; + const newMembersSet = new Set(); // 建立索引降低时间复杂度 + + for (const member of newMembers) { + newMembersSet.add(member.uin); + } + + // 判断bot是否是管理员,如果是管理员不需要从这里得知有人退群,这里的退群无法得知是主动退群还是被踢 + const 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; + } + } + } + } + } + } +} + +// export const napCatOneBot11 = new NapCatOnebot11(); diff --git a/src/onebot11/onebot11.json b/src/onebot11/onebot11.json new file mode 100644 index 00000000..3c0f7eec --- /dev/null +++ b/src/onebot11/onebot11.json @@ -0,0 +1,17 @@ +{ + "enableHttp": false, + "httpPort": 3000, + "enableWs": false, + "wsPort": 3001, + "enableWsReverse": false, + "wsReverseUrls": [], + "enableHttpPost": false, + "httpPostUrls": [], + "httpSecret": "", + "messagePostFormat": "array", + "reportSelfMessage": false, + "debug": false, + "enableLocalFile2Url": true, + "heartInterval": 30000, + "token": "" +} diff --git a/src/onebot11/server/http.ts b/src/onebot11/server/http.ts new file mode 100644 index 00000000..da966da3 --- /dev/null +++ b/src/onebot11/server/http.ts @@ -0,0 +1,32 @@ +import { Response } from 'express'; +import { OB11Response } from '../action/OB11Response'; +import { HttpServerBase } from '@/common/server/http'; +import { actionHandlers } from '../action'; +import { ob11Config } from '@/onebot11/config'; + +class OB11HTTPServer extends HttpServerBase { + name = 'OneBot V11 server'; + + handleFailed(res: Response, payload: any, e: any) { + res.send(OB11Response.error(e.stack.toString(), 200)); + } + + protected listen(port: number) { + if (ob11Config.enableHttp) { + super.listen(port); + } + } +} + +export const ob11HTTPServer = new OB11HTTPServer(); + +setTimeout(() => { + for (const action of actionHandlers) { + for (const method of ['post', 'get']) { + ob11HTTPServer.registerRouter(method, action.actionName, (res, payload) => { + // @ts-expect-error wait fix + return action.handle(payload); + }); + } + } +}, 0); diff --git a/src/onebot11/server/postOB11Event.ts b/src/onebot11/server/postOB11Event.ts new file mode 100644 index 00000000..b4fde434 --- /dev/null +++ b/src/onebot11/server/postOB11Event.ts @@ -0,0 +1,185 @@ +import { OB11Message, OB11MessageAt, OB11MessageData } from '../types'; +import { OB11BaseMetaEvent } from '../event/meta/OB11BaseMetaEvent'; +import { OB11BaseNoticeEvent } from '../event/notice/OB11BaseNoticeEvent'; +import { WebSocket as WebSocketClass } from 'ws'; +import { wsReply } from './ws/reply'; +import { log } from '@/common/utils/log'; +import { ob11Config } from '@/onebot11/config'; +import crypto from 'crypto'; +import { ChatType, Group, GroupRequestOperateTypes, Peer } from '@/core/qqnt/entities'; +import { convertMessage2List, createSendElements, sendMsg } from '../action/msg/SendMsg'; +import { OB11FriendRequestEvent } from '../event/request/OB11FriendRequest'; +import { OB11GroupRequestEvent } from '../event/request/OB11GroupRequest'; +import { isNull } from '@/common/utils/helper'; +import { dbUtil } from '@/common/utils/db'; +import { friendRequests, getGroup, groupNotifies, selfInfo } from '@/common/data'; +import { NTQQFriendApi, NTQQGroupApi, NTQQMsgApi } from '@/core/qqnt/apis'; + +export type PostEventType = OB11Message | OB11BaseMetaEvent | OB11BaseNoticeEvent + +interface QuickActionPrivateMessage { + reply?: string; + auto_escape?: boolean; +} + +interface QuickActionGroupMessage extends QuickActionPrivateMessage { + // 回复群消息 + at_sender?: boolean; + delete?: boolean; + kick?: boolean; + ban?: boolean; + ban_duration?: number; + // +} + +interface QuickActionFriendRequest { + approve?: boolean; + remark?: string; +} + +interface QuickActionGroupRequest { + approve?: boolean; + reason?: string; +} + +type QuickAction = + QuickActionPrivateMessage + & QuickActionGroupMessage + & QuickActionFriendRequest + & QuickActionGroupRequest + +const eventWSList: WebSocketClass[] = []; + +export function registerWsEventSender(ws: WebSocketClass) { + eventWSList.push(ws); +} + +export function unregisterWsEventSender(ws: WebSocketClass) { + const index = eventWSList.indexOf(ws); + if (index !== -1) { + eventWSList.splice(index, 1); + } +} + +export function postWsEvent(event: PostEventType) { + for (const ws of eventWSList) { + new Promise(() => { + wsReply(ws, event); + }).then(); + } +} + +export function postOB11Event(msg: PostEventType, reportSelf = false) { + const config = ob11Config; + // 判断msg是否是event + if (!config.reportSelfMessage && !reportSelf) { + if (msg.post_type === 'message' && (msg as OB11Message).user_id.toString() == selfInfo.uin) { + return; + } + } + if (config.enableHttpPost) { + const msgStr = JSON.stringify(msg); + const hmac = crypto.createHmac('sha1', ob11Config.httpSecret); + hmac.update(msgStr); + const sig = hmac.digest('hex'); + const headers: Record = { + 'Content-Type': 'application/json', + 'x-self-id': selfInfo.uin + }; + if (config.httpSecret) { + headers['x-signature'] = 'sha1=' + sig; + } + for (const host of config.httpPostUrls) { + fetch(host, { + method: 'POST', + headers, + body: msgStr + }).then(async (res) => { + log(`新消息事件HTTP上报成功: ${host} `, msgStr); + // todo: 处理不够优雅,应该使用高级泛型进行QuickAction类型识别 + let resJson: QuickAction; + try { + resJson = await res.json(); + log('新消息事件HTTP上报返回快速操作: ', JSON.stringify(resJson)); + } catch (e) { + log('新消息事件HTTP上报没有返回快速操作,不需要处理'); + return; + } + if (msg.post_type === 'message') { + msg = msg as OB11Message; + const rawMessage = await dbUtil.getMsgByShortId(msg.message_id); + resJson = resJson as QuickActionPrivateMessage | QuickActionGroupMessage; + const reply = resJson.reply; + const peer: Peer = { + chatType: ChatType.friend, + peerUid: msg.user_id.toString() + }; + if (msg.message_type == 'private') { + if (msg.sub_type === 'group') { + peer.chatType = ChatType.temp; + } + } else { + peer.chatType = ChatType.group; + peer.peerUid = msg.group_id!.toString(); + } + if (reply) { + let group: Group | undefined; + let replyMessage: OB11MessageData[] = []; + + if (msg.message_type == 'group') { + group = await getGroup(msg.group_id!.toString()); + if ((resJson as QuickActionGroupMessage).at_sender) { + replyMessage.push({ + type: 'at', + data: { + qq: msg.user_id.toString() + } + } as OB11MessageAt); + } + } + replyMessage = replyMessage.concat(convertMessage2List(reply, resJson.auto_escape)); + const { sendElements, deleteAfterSentFiles } = await createSendElements(replyMessage, group); + sendMsg(peer, sendElements, deleteAfterSentFiles, false).then(); + } else if (resJson.delete) { + NTQQMsgApi.recallMsg(peer, [rawMessage!.msgId]).then(); + } else if (resJson.kick) { + NTQQGroupApi.kickMember(peer.peerUid, [rawMessage!.senderUid]).then(); + } else if (resJson.ban) { + NTQQGroupApi.banMember(peer.peerUid, [{ + uid: rawMessage!.senderUid, + timeStamp: resJson.ban_duration || 60 * 30 + }],).then(); + } + + } else if (msg.post_type === 'request') { + if ((msg as OB11FriendRequestEvent).request_type === 'friend') { + resJson = resJson as QuickActionFriendRequest; + if (!isNull(resJson.approve)) { + // todo: set remark + const flag = (msg as OB11FriendRequestEvent).flag; + // const [friendUid, seq] = flag.split('|'); + const request = friendRequests[flag]; + NTQQFriendApi.handleFriendRequest( + request, + !!resJson.approve, + ).then(); + } + } else if ((msg as OB11GroupRequestEvent).request_type === 'group') { + resJson = resJson as QuickActionGroupRequest; + if (!isNull(resJson.approve)) { + const flag = (msg as OB11GroupRequestEvent).flag; + const request = groupNotifies[flag]; + // const [groupCode, seq] = flag.split('|'); + NTQQGroupApi.handleGroupRequest(request, + resJson.approve ? GroupRequestOperateTypes.approve : GroupRequestOperateTypes.reject + ).then(); + } + } + } + }, (err: any) => { + log(`新消息事件HTTP上报失败: ${host} `, err, msg); + }); + } + } + postWsEvent(msg); +} diff --git a/src/onebot11/server/ws/ReverseWebsocket.ts b/src/onebot11/server/ws/ReverseWebsocket.ts new file mode 100644 index 00000000..3a392b43 --- /dev/null +++ b/src/onebot11/server/ws/ReverseWebsocket.ts @@ -0,0 +1,143 @@ +import { LifeCycleSubType, OB11LifeCycleEvent } from '../../event/meta/OB11LifeCycleEvent'; +import { ActionName } from '../../action/types'; +import { OB11Response } from '../../action/OB11Response'; +import BaseAction from '../../action/BaseAction'; +import { actionMap } from '../../action'; +import { postWsEvent, registerWsEventSender, unregisterWsEventSender } from '../postOB11Event'; +import { wsReply } from './reply'; +import { WebSocket as WebSocketClass } from 'ws'; +import { OB11HeartbeatEvent } from '../../event/meta/OB11HeartbeatEvent'; +import { log } from '../../../common/utils/log'; +import { ob11Config } from '@/onebot11/config'; +import { napCatCore } from '@/core'; +import { selfInfo } from '@/common/data'; + +export const rwsList: ReverseWebsocket[] = []; + +export class ReverseWebsocket { + public websocket: WebSocketClass | undefined; + public url: string; + private running: boolean = false; + + public constructor(url: string) { + this.url = url; + this.running = true; + this.connect(); + } + + public stop() { + this.running = false; + this.websocket!.close(); + } + + public onopen() { + wsReply(this.websocket!, new OB11LifeCycleEvent(LifeCycleSubType.CONNECT)); + } + + public async onmessage(msg: string) { + let receiveData: { action: ActionName | undefined, params: any, echo?: any } = { action: undefined, params: {} }; + let echo = null; + try { + receiveData = JSON.parse(msg.toString()); + echo = receiveData.echo; + log('收到反向Websocket消息', receiveData); + } catch (e) { + return wsReply(this.websocket!, OB11Response.error('json解析失败,请检查数据格式', 1400, echo)); + } + const action: BaseAction | undefined = actionMap.get(receiveData.action!); + if (!action) { + return wsReply(this.websocket!, OB11Response.error('不支持的api ' + receiveData.action, 1404, echo)); + } + try { + const handleResult = await action.websocketHandle(receiveData.params, echo); + wsReply(this.websocket!, handleResult); + } catch (e) { + wsReply(this.websocket!, OB11Response.error(`api处理出错:${e}`, 1200, echo)); + } + } + + public onclose = () => { + log('反向ws断开', this.url); + unregisterWsEventSender(this.websocket!); + if (this.running) { + this.reconnect(); + } + }; + + public send(msg: string) { + if (this.websocket && this.websocket.readyState == WebSocket.OPEN) { + this.websocket.send(msg); + } + } + + private reconnect() { + setTimeout(() => { + this.connect(); + }, 3000); // TODO: 重连间隔在配置文件中实现 + } + + private connect() { + const { token, heartInterval } = ob11Config; + this.websocket = new WebSocketClass(this.url, { + handshakeTimeout: 2000, + perMessageDeflate: false, + headers: { + 'X-Self-ID': selfInfo.uin, + 'Authorization': `Bearer ${token}`, + 'x-client-role': 'Universal', // koishi-adapter-onebot 需要这个字段 + } + }); + registerWsEventSender(this.websocket); + log('Trying to connect to the websocket server: ' + this.url); + + + this.websocket.on('open', () => { + log('Connected to the websocket server: ' + this.url); + this.onopen(); + }); + + this.websocket.on('message', async (data) => { + await this.onmessage(data.toString()); + }); + + this.websocket.on('error', log); + + const wsClientInterval = setInterval(() => { + postWsEvent(new OB11HeartbeatEvent(!!selfInfo.online, true, heartInterval)); + }, heartInterval); // 心跳包 + this.websocket.on('close', () => { + clearInterval(wsClientInterval); + log('The websocket connection: ' + this.url + ' closed, trying reconnecting...'); + this.onclose(); + }); + } +} + +class OB11ReverseWebsockets { + start() { + for (const url of ob11Config.wsReverseUrls) { + log('开始连接反向ws', url); + new Promise(() => { + try { + rwsList.push(new ReverseWebsocket(url)); + } catch (e: any) { + log(e.stack); + } + }).then(); + } + } + + stop() { + for (const rws of rwsList) { + rws.stop(); + } + } + + restart() { + this.stop(); + this.start(); + } +} + +export const ob11ReverseWebsockets = new OB11ReverseWebsockets(); + diff --git a/src/onebot11/server/ws/WebsocketServer.ts b/src/onebot11/server/ws/WebsocketServer.ts new file mode 100644 index 00000000..d2c4b9d3 --- /dev/null +++ b/src/onebot11/server/ws/WebsocketServer.ts @@ -0,0 +1,76 @@ +import { WebSocket } from 'ws'; +import { actionMap } from '../../action'; +import { OB11Response } from '../../action/OB11Response'; +import { postWsEvent, registerWsEventSender, unregisterWsEventSender } from '../postOB11Event'; +import { ActionName } from '../../action/types'; +import BaseAction from '../../action/BaseAction'; +import { LifeCycleSubType, OB11LifeCycleEvent } from '../../event/meta/OB11LifeCycleEvent'; +import { OB11HeartbeatEvent } from '../../event/meta/OB11HeartbeatEvent'; +import { WebsocketServerBase } from '@/common/server/websocket'; +import { IncomingMessage } from 'node:http'; +import { wsReply } from './reply'; +import { napCatCore } from '@/core'; +import { log } from '../../../common/utils/log'; +import { ob11Config } from '@/onebot11/config'; +import { selfInfo } from '@/common/data'; + +const heartbeatRunning = false; + +class OB11WebsocketServer extends WebsocketServerBase { + authorizeFailed(wsClient: WebSocket) { + wsClient.send(JSON.stringify(OB11Response.res(null, 'failed', 1403, 'token验证失败'))); + } + + async handleAction(wsClient: WebSocket, actionName: string, params: any, echo?: any) { + const action: BaseAction | undefined = actionMap.get(actionName); + if (!action) { + return wsReply(wsClient, OB11Response.error('不支持的api ' + actionName, 1404, echo)); + } + try { + const handleResult = await action.websocketHandle(params, echo); + wsReply(wsClient, handleResult); + } catch (e: any) { + wsReply(wsClient, OB11Response.error(`api处理出错:${e.stack}`, 1200, echo)); + } + } + + onConnect(wsClient: WebSocket, url: string, req: IncomingMessage) { + if (url == '/api' || url == '/api/' || url == '/') { + wsClient.on('message', async (msg) => { + let receiveData: { action: ActionName, params: any, echo?: any } = { action: '', params: {} }; + let echo = null; + try { + receiveData = JSON.parse(msg.toString()); + echo = receiveData.echo; + log('收到正向Websocket消息', receiveData); + } catch (e) { + return wsReply(wsClient, OB11Response.error('json解析失败,请检查数据格式', 1400, echo)); + } + this.handleAction(wsClient, receiveData.action, receiveData.params, receiveData.echo).then(); + }); + } + if (url == '/event' || url == '/event/' || url == '/') { + registerWsEventSender(wsClient); + + log('event上报ws客户端已连接'); + + try { + wsReply(wsClient, new OB11LifeCycleEvent(LifeCycleSubType.CONNECT)); + } catch (e) { + log('发送生命周期失败', e); + } + const { heartInterval } = ob11Config; + const wsClientInterval = setInterval(() => { + postWsEvent(new OB11HeartbeatEvent(!!selfInfo.online, true, heartInterval)); + }, heartInterval); // 心跳包 + wsClient.on('close', () => { + log('event上报ws客户端已断开'); + clearInterval(wsClientInterval); + unregisterWsEventSender(wsClient); + }); + } + } +} + +export const ob11WebsocketServer = new OB11WebsocketServer(); + diff --git a/src/onebot11/server/ws/reply.ts b/src/onebot11/server/ws/reply.ts new file mode 100644 index 00000000..0e470140 --- /dev/null +++ b/src/onebot11/server/ws/reply.ts @@ -0,0 +1,19 @@ +import { WebSocket as WebSocketClass } from 'ws'; +import { OB11Response } from '../../action/OB11Response'; +import { PostEventType } from '../postOB11Event'; +import { log } from '../../../common/utils/log'; +import { isNull } from '../../../common/utils/helper'; + + +export function wsReply(wsClient: WebSocketClass, data: OB11Response | PostEventType) { + try { + const packet = Object.assign({}, data); + if (isNull(packet['echo'])) { + delete packet['echo']; + } + wsClient.send(JSON.stringify(packet)); + log('ws 消息上报', wsClient.url || '', data); + } catch (e: any) { + log('websocket 回复失败', e.stack, data); + } +} diff --git a/src/onebot11/types.ts b/src/onebot11/types.ts new file mode 100644 index 00000000..65b21be3 --- /dev/null +++ b/src/onebot11/types.ts @@ -0,0 +1,242 @@ +import { PicSubType, RawMessage } from '@/core/entity'; +import { EventType } from './event/OB11BaseEvent'; + +export interface OB11User { + user_id: number; + nickname: string; + remark?: string; + sex?: OB11UserSex; + level?: number; + age?: number; + qid?: string; + login_days?: number; +} + +export enum OB11UserSex { + male = 'male', + female = 'female', + unknown = 'unknown' +} + +export enum OB11GroupMemberRole { + owner = 'owner', + admin = 'admin', + member = 'member', +} + +export interface OB11GroupMember { + group_id: number + user_id: number + nickname: string + card?: string + sex?: OB11UserSex + age?: number + join_time?: number + last_sent_time?: number + level?: number + qq_level?: number + role?: OB11GroupMemberRole + title?: string + area?: string + unfriendly?: boolean + title_expire_time?: number + card_changeable?: boolean + // 以下为gocq字段 + shut_up_timestamp?: number + // 以下为扩展字段 + is_robot?: boolean +} + +export interface OB11Group { + group_id: number + group_name: string + member_count?: number + max_member_count?: number +} + +interface OB11Sender { + user_id: number, + nickname: string, + sex?: OB11UserSex, + age?: number, + card?: string, // 群名片 + level?: string, // 群等级 + role?: OB11GroupMemberRole +} + +export enum OB11MessageType { + private = 'private', + group = 'group' +} + +export interface OB11Message { + target_id?: number; // 自己发送的消息才有此字段 + self_id?: number, + time: number, + message_id: number, + real_id: number, + user_id: number, + group_id?: number, + message_type: 'private' | 'group', + sub_type?: 'friend' | 'group' | 'normal', + sender: OB11Sender, + message: OB11MessageData[] | string, + message_format: 'array' | 'string', + raw_message: string, + font: number, + post_type?: EventType, + raw?: RawMessage +} + +export interface OB11ForwardMessage extends OB11Message { + content: OB11MessageData[] | string; +} + +export interface OB11Return { + status: string + retcode: number + data: DataType + message: string, + echo?: any, // ws调用api才有此字段 + wording?: string, // go-cqhttp字段,错误信息 +} + +export enum OB11MessageDataType { + text = 'text', + image = 'image', + music = 'music', + video = 'video', + voice = 'record', + file = 'file', + at = 'at', + reply = 'reply', + json = 'json', + face = 'face', + mface = 'mface', // 商城表情 + markdown = 'markdown', + node = 'node', // 合并转发消息节点 + forward = 'forward', // 合并转发消息,用于上报 + xml = 'xml' +} + +export interface OB11MessageMFace { + type: OB11MessageDataType.mface, + data: { + text: string + } +} + +export interface OB11MessageText { + type: OB11MessageDataType.text, + data: { + text: string, // 纯文本 + } +} + +interface OB11MessageFileBase { + data: { + thumb?: string; + name?: string; + file: string, + url?: string; + } +} + + +export interface OB11MessageImage extends OB11MessageFileBase { + type: OB11MessageDataType.image + data: OB11MessageFileBase['data'] & { + summary?: string; // 图片摘要 + subType?: PicSubType + }, +} + +export interface OB11MessageRecord extends OB11MessageFileBase { + type: OB11MessageDataType.voice +} + +export interface OB11MessageFile extends OB11MessageFileBase { + type: OB11MessageDataType.file +} + +export interface OB11MessageVideo extends OB11MessageFileBase { + type: OB11MessageDataType.video +} + +export interface OB11MessageAt { + type: OB11MessageDataType.at + data: { + qq: string | 'all' + } +} + +export interface OB11MessageReply { + type: OB11MessageDataType.reply + data: { + id: string + } +} + +export interface OB11MessageFace { + type: OB11MessageDataType.face + data: { + id: string + } +} + +export type OB11MessageMixType = OB11MessageData[] | string | OB11MessageData; + +export interface OB11MessageNode { + type: OB11MessageDataType.node + data: { + id?: string + user_id?: number + nickname: string + content: OB11MessageMixType + } +} + +export interface OB11MessageCustomMusic { + type: OB11MessageDataType.music + data: { + type: 'custom' + url: string, + audio: string, + title: string, + content?: string, + image?: string + } +} + +export interface OB11MessageJson { + type: OB11MessageDataType.json + data: { config: { token: string } } & any +} + +export type OB11MessageData = + OB11MessageText | + OB11MessageFace | OB11MessageMFace | + OB11MessageAt | OB11MessageReply | + OB11MessageImage | OB11MessageRecord | OB11MessageFile | OB11MessageVideo | + OB11MessageNode | OB11MessageCustomMusic | OB11MessageJson + +export interface OB11PostSendMsg { + message_type?: 'private' | 'group' + user_id?: string, + group_id?: string, + message: OB11MessageMixType; + messages?: OB11MessageMixType; // 兼容 go-cqhttp +} + +export interface OB11Version { + app_name: string + app_version: string + protocol_version: 'v11' +} + + +export interface OB11Status { + online: boolean | null, + good: boolean +} + diff --git a/src/onebot11/version.ts b/src/onebot11/version.ts new file mode 100644 index 00000000..266e19f2 --- /dev/null +++ b/src/onebot11/version.ts @@ -0,0 +1 @@ +export const version = '0.0.1'; diff --git a/src/test/index.ts b/src/test/index.ts new file mode 100644 index 00000000..d0c7cf06 --- /dev/null +++ b/src/test/index.ts @@ -0,0 +1,208 @@ +import path from 'node:path'; +import fs from 'node:fs'; +import * as log4js from 'log4js'; +import * as YAML from 'yaml'; +import qrcode from 'qrcode-terminal'; +import { NapCatCore, napCatCore } from '@/core'; +import { NapCatOnebot11 } from '@/onebot11/main'; +import PackageInfo from '@/../package.json'; +import { INapCatConfig } from './types'; +import { RawMessage } from '@/core/qqnt/entities'; + +const DefaultNapCatConfig: INapCatConfig = { + account: { + uin: '10086', + password: 'password', + noQuickLogin: false, + }, + heartbeat: { + interval: 5, + }, + adapters: { + onebot: { + address: '0.0.0.0', + port: 8123, + accessToken: 'token123456', + } + }, + log: { + level: 'info', + }, +}; + +function getLog4jConfig(logLevel = 'info', writeFile = false): log4js.Configuration { + const outputMethod = [ 'console' ]; + if (writeFile) outputMethod.push('file'); + + const defaultCategory = { + appenders: outputMethod, + level: logLevel, + }; + + return { + appenders: { + console: { + type: 'stdout' + }, + file: { + type: 'file', + }, + ascii: { + type: 'stdout', + layout: { + type: 'pattern', + pattern: '%[%m%]', + }, + }, + asciiNoColor: { + type: 'stdout', + layout: { + type: 'pattern', + pattern: '%m', + }, + }, + }, + categories: { + default: defaultCategory, + ascii: { + appenders: [ 'ascii' ], + level: 'info', + }, + asciiNoColor: { + appenders: [ 'asciiNoColor' ], + level: 'info', + } + }, + }; +} + +export class NapCat { + readonly dataPath: string; + readonly config: INapCatConfig; + + readonly core: NapCatCore; + readonly onebot: NapCatOnebot11; + + readonly log: log4js.Logger; + readonly logMsg: log4js.Logger; + + constructor() { + // Get data path (usually the same path of NapCat) + this.dataPath = path.resolve(__dirname, './'); + + // Init core + this.core = napCatCore; + this.onebot = new NapCatOnebot11(); + + // Get user config + if (!fs.existsSync(path.resolve(this.dataPath, './config.yml'))) { // Detect if no config file exist + // Use default logger + log4js.configure(getLog4jConfig('all')); + this.log = log4js.getLogger('App'); + this.logMsg = log4js.getLogger('Message'); + this.drawBootAscii(); + + this.config = DefaultNapCatConfig; + fs.writeFileSync(path.resolve(this.dataPath, './config.yml'), YAML.stringify(DefaultNapCatConfig)); + + this.log.error('未找到配置文件!'); + this.log.error('已为您创建了默认配置文件,请关闭 NapCatQQ 后填写配置文件再启动'); + this.log.error('完整的配置文件详解可前往 [DOC_URL] 查看'); + + return; + } + this.config = YAML.parse(fs.readFileSync(path.resolve(this.dataPath, './config.yml'), { encoding: 'utf8' })); + + // Apply log4j config before use it + log4js.configure(getLog4jConfig('all')); + // log4js.configure(getLog4jConfig(this.config.log.level)); + this.log = log4js.getLogger('App'); + this.logMsg = log4js.getLogger('Message'); + this.drawBootAscii(); + + // Init app + this.initApp(); + } + + // Output ASCII because i love it + private drawBootAscii() { + const logAscii = log4js.getLogger('ascii'); + [ + '', + ' _ _ _____ _ ____ ____', + ' | \\ | | / ____| | | / __ \\ / __ \\', + ' | \\| | __ _ _ __ | | __ _ | |_ | | | || | | |', + ' | . ` | / _` || \'_ \\ | | / _` || __|| | | || | | |', + ' | |\\ || (_| || |_) || |____ | (_| || |_ | |__| || |__| |', + ' |_| \\_| \\__,_|| .__/ \\_____| \\__,_| \\__| \\___\\_\\ \\___\\_\\', + ' | |', + ' |_| ', + ].forEach(i => { + logAscii.info(i); + }); + logAscii.info(`---------------------< NapCatQQ v${PackageInfo.version} >---------------------`); + } + + private initApp() { + this.core.on('system.login.qrcode', ({ url }: { url: string }) => { + this.log.info('请扫描下面的二维码,然后在手Q上授权登录:'); + const ascii = log4js.getLogger('asciiNoColor'); + qrcode.generate(url, { small: true }, (res) => { + ascii.info(res); + }); + }); + + this.core.on('system.login.slider', ({ url }: { url: string }) => { + this.log.info('登录需要验证,请访问下面的滑块验证链接,然后按下回车:'); + const ascii = log4js.getLogger('asciiNoColor'); + ascii.info(url); + }); + + this.core.on('system.online', () => { + this.onLoginSuccess(); + }); + + this.core.on('system.login.error', ({ code, message }: { code: string, message: string }) => { + this.log.error(`登录出现问题(${code})`); + this.log.error(message); + }); + + if (!this.config.account || !this.config.account.uin) { + this.log.info('未读取到账号配置,终止初始化...'); + return; + } + + this.log.info(`正在尝试登录账号 ${this.config.account.uin} ...`); + if (this.config.account.password) this.core.login.password(this.config.account.uin, this.config.account.password); + else if (!this.config.account.noQuickLogin) this.core.login.quick(this.config.account.uin); + else this.core.login.qrcode(); + } + + private onLoginSuccess() { + this.log.info('登录成功'); + + this.core.on('message.private', (e) => { + this.logMsg.info(`[Private] ${e.peerName}(${e.senderUin}) -> ${msgElementParser(e)}`); + }); + this.core.on('message.group', (e) => { + this.logMsg.info(`[Group] ${e.peerName}(${e.peerUin}) - ${e.sendMemberName ? e.sendMemberName : e.sendNickName}(${e.senderUin}) -> ${msgElementParser(e)}`); + }); + } +} + +const msgElementParser = (msg: RawMessage) => { + let result = ''; + for (const element of msg.elements) { + if (element.textElement) { + if (element.textElement.atType === 0) result += element.textElement.content; + else result += `[@${element.textElement.atType === 2 ? element.textElement.atUid : 'all'}]`; + } + if (element.picElement) result += `[Pic=${element.picElement.fileName}]`; + if (element.pttElement) result += '[Voice]'; + if (element.faceElement) result += `[Face=${element.faceElement.faceIndex}]`; + if (element.videoElement) result += `[Video=${element.videoElement.fileName}]`; + if (element.fileElement) result += `[File=${element.fileElement.fileName}]`; + if (element.marketFaceElement) result += `[MarketFace=${element.marketFaceElement.faceName}]`; + } + return result; +}; \ No newline at end of file diff --git a/src/test/types.ts b/src/test/types.ts new file mode 100644 index 00000000..59cc410e --- /dev/null +++ b/src/test/types.ts @@ -0,0 +1,26 @@ +export interface INapCatConfig { + account: INapCatConfigAccount, + heartbeat: INapCatConfigHeartbeat, + adapters: Record, + log: INapCatConfigLog, +} + +export interface INapCatConfigAccount { + uin: string, + password?: string, + noQuickLogin?: boolean, +} + +export interface INapCatConfigHeartbeat { + interval: number, +} + +export interface INapCatConfigLog { + level: string, +} + +export interface INapCatConfigAdapterBase { + address: string, + port: number, + accessToken?: string, +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..6f1485f3 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,44 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": [ + "ES2020", + "DOM", + "DOM.Iterable" + ], + "skipLibCheck": true, + "moduleResolution": "Node", + "allowImportingTsExtensions": false, + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "preserve", + "strict": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "noFallthroughCasesInSwitch": true, + "paths": { + "@*": [ + "./src*" + ], + "@/core": [ + "./src/core/src/index", + "./src/core.lib/src/index" + ], + "@/core/qqnt/*": [ + "./src/core/src/qqnt/*", + "./src/core.lib/src/qqnt/index" + ], + "@/core/*": [ + "./src/core/src/*", + "./src/core.lib/src" + ] + } + }, + "include": [ + "src/**/*.ts" + ] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 00000000..1b5f396d --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,117 @@ +// import PreprocessorDirectives from 'unplugin-preprocessor-directives/vite'; +import obfuscator from 'rollup-plugin-obfuscator'; +import cp from 'vite-plugin-cp'; +import { UserConfig, defineConfig } from 'vite'; +import { resolve } from 'path'; +import { PluginOption, Plugin } from 'vite'; +import nodeResolve from '@rollup/plugin-node-resolve'; +import commonjs from '@rollup/plugin-commonjs'; +import { builtinModules } from 'module'; +import os from 'node:os'; +import fs from 'node:fs'; + +const external = ['silk-wasm', 'ws', 'express', 'uuid', 'fluent-ffmpeg', 'sqlite3', 'log4js', + 'qrcode-terminal']; + +const nodeModules = [...builtinModules, builtinModules.map(m => `node:${m}`)].flat(); +// let nodeModules = ["fs", "path", "events", "buffer", "url", "crypto", "fs/promise", "fsPromise", "os", "http", "net"] +// nodeModules = [...nodeModules, ...nodeModules.map(m => `node:${m}`)] + +function genCpModule(module: string) { + return {src: `./node_modules/${module}`, dest: `dist/node_modules/${module}`, flatten: false}; +} + +const startScripts: string[] = ['./script/napcat.ps1', './script/napcat.bat', './script/napcat-utf8.bat', './script/napcat-utf8.ps1', './script/napcat-log.ps1', + './script/napcat.sh' +]; + +// if (os.platform() !== 'win32') { +// startScripts = ['./script/napcat.sh']; +// } + +const baseConfigPlugin: PluginOption[] = [ + // PreprocessorDirectives(), + cp({ + targets: [ + // ...external.map(genCpModule), + {src: './src/onebot11/onebot11.json', dest: 'dist/config/'}, + {src: './package.json', dest: 'dist'}, + {src: './README.md', dest: 'dist'}, + ...(startScripts.map((startScript) => { + return {src: startScript, dest: 'dist'}; + })), + ] + }), + nodeResolve(), + commonjs(), +]; + +let corePath = resolve(__dirname, './src/core/src'); +if (!fs.existsSync(corePath)) { + corePath = resolve(__dirname, './src/core.lib/src'); +} +const baseConfig = (mode: string = 'development') => defineConfig({ + resolve: { + conditions: ['node', 'default'], + alias: { + '@/core': corePath, + '@': resolve(__dirname, './src'), + './lib-cov/fluent-ffmpeg': './lib/fluent-ffmpeg', + }, + }, + build: { + target: 'esnext', + minify: mode === 'production' ? 'esbuild' : false, + lib: { + entry: 'src/onebot11/index.ts', + formats: ['cjs'], + fileName: () => 'napcat.cjs', + }, + rollupOptions: { + // external: [ /node:*/ ], + external: [...nodeModules, ...external] + }, + }, +}); + +export default defineConfig(({mode}): UserConfig => { + if (mode === 'production') { + return { + ...baseConfig(mode), + plugins: [ + ...baseConfigPlugin, + { + ...(obfuscator({ + options: { + compact: true, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 0.75, + deadCodeInjection: true, + deadCodeInjectionThreshold: 0.4, + debugProtection: false, + disableConsoleOutput: false, + identifierNamesGenerator: 'hexadecimal', + log: false, + renameGlobals: false, + rotateStringArray: true, + selfDefending: true, + stringArray: true, + stringArrayEncoding: ['base64'], + stringArrayThreshold: 0.75, + transformObjectKeys: true, + unicodeEscapeSequence: false + }, + include: ['src/**/*.js', 'src/**/*.ts'], + }) as Plugin), + enforce: 'post', + apply: 'build', + }, + ] + }; + } else { + return { + ...baseConfig(mode), + plugins: baseConfigPlugin, + }; + } +});