mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
76 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0f8af273ae | ||
![]() |
fa29a31da9 | ||
![]() |
9e0d2606d8 | ||
![]() |
338dedd6e0 | ||
![]() |
1f893b1393 | ||
![]() |
b783d6f928 | ||
![]() |
8ca0d40f05 | ||
![]() |
2f40a80434 | ||
![]() |
812d8eb5bb | ||
![]() |
bf5f548349 | ||
![]() |
ebf90e72b9 | ||
![]() |
31d7d42edf | ||
![]() |
833875b42f | ||
![]() |
b901c10f3c | ||
![]() |
8ab678bd97 | ||
![]() |
55d5072f46 | ||
![]() |
a379ffd0f2 | ||
![]() |
4501d73134 | ||
![]() |
5f15774ec7 | ||
![]() |
c9e057599e | ||
![]() |
66851f5625 | ||
![]() |
b33c235b4d | ||
![]() |
d6693b6114 | ||
![]() |
36b4d26c78 | ||
![]() |
617592d90a | ||
![]() |
15a77b8070 | ||
![]() |
606eccd22b | ||
![]() |
5613450313 | ||
![]() |
c59b5564af | ||
![]() |
330b086b8b | ||
![]() |
9837ef4f36 | ||
![]() |
add46b3251 | ||
![]() |
e169199107 | ||
![]() |
92fe654850 | ||
![]() |
b257486404 | ||
![]() |
bdf2e33f40 | ||
![]() |
224d361923 | ||
![]() |
3452fa56df | ||
![]() |
cd256235da | ||
![]() |
361a164f2a | ||
![]() |
0e60d4b198 | ||
![]() |
67b47e39b4 | ||
![]() |
8f54310f63 | ||
![]() |
c7a7494d7e | ||
![]() |
af88b3166d | ||
![]() |
b7837b2a14 | ||
![]() |
950ddc749e | ||
![]() |
df081ef0cf | ||
![]() |
7b24f90d9f | ||
![]() |
f2e4579fd8 | ||
![]() |
97cb351827 | ||
![]() |
c1ec53fdbb | ||
![]() |
98214aa429 | ||
![]() |
ce7deac2dd | ||
![]() |
612092b867 | ||
![]() |
92579d5949 | ||
![]() |
9ab07060ae | ||
![]() |
0d45125d79 | ||
![]() |
9ced152778 | ||
![]() |
3685ab2e3e | ||
![]() |
be605f11f2 | ||
![]() |
8cca8df976 | ||
![]() |
990a31e961 | ||
![]() |
5db201c342 | ||
![]() |
a625e30dd4 | ||
![]() |
b236cdd060 | ||
![]() |
2db9899184 | ||
![]() |
fe5d6db986 | ||
![]() |
7c7bf8fecf | ||
![]() |
76e3a46378 | ||
![]() |
16f3897fec | ||
![]() |
045e120854 | ||
![]() |
2b7fcce9b2 | ||
![]() |
9685931694 | ||
![]() |
1dc844435a | ||
![]() |
a29b1154a9 |
@@ -13,8 +13,20 @@ QQ Version: Windows 9.9.12-26000 / Linux 3.2.9-26000
|
|||||||
2. 重构消息发送 极限速度优化 ~ 优化性能
|
2. 重构消息发送 极限速度优化 ~ 优化性能
|
||||||
3. WebUi配置热重载优化 ~ 修复问题
|
3. WebUi配置热重载优化 ~ 修复问题
|
||||||
4. 修复偶现崩溃问题 ~ 修复问题
|
4. 修复偶现崩溃问题 ~ 修复问题
|
||||||
|
5. 修复群邀请通知事件多次推送问题 ~ 修复问题
|
||||||
|
6. 尝试修复因缓存引起的字段不全问题 ~ 修复问题
|
||||||
|
7. 修复在非常非常高并发的情况 上报自身消息 回复回错问题 ~ 修复问题
|
||||||
|
8. 修复图片SubType字段位置错误问题 ~ 修复问题
|
||||||
|
9. 修复Uid/Uin转换问题 ~ 修复问题
|
||||||
|
|
||||||
## 新增与调整
|
## 新增与调整
|
||||||
1. 最后发言时间重构 入群时间失效 ~ 替换功能
|
1. 最后发言时间重构 入群时间失效 ~ 替换功能
|
||||||
|
2. 重构文件发送/获取 ~ 优化性能
|
||||||
|
3. 支持GOCQ私聊上传接口 ~ 新增功能
|
||||||
|
4. 悄悄告诉你ws http可以同一个端口 ~ 新增功能
|
||||||
|
5. 根据config目录的默认配置初始化新的配置文件 ~ 新增功能
|
||||||
|
6. WebUi可以部署在nginx代理二级目录 配置端口设置为0可关闭WebUi ~ 新增功能
|
||||||
|
7. 新增收藏表情拉取接口 ~ 新增功能
|
||||||
|
8. 新增群头像设置接口 ~ 新增功能
|
||||||
|
|
||||||
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)
|
@@ -2,7 +2,7 @@
|
|||||||
"name": "napcat",
|
"name": "napcat",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "1.6.8",
|
"version": "1.7.2",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"watch:dev": "vite --mode development",
|
"watch:dev": "vite --mode development",
|
||||||
"watch:prod": "vite --mode production",
|
"watch:prod": "vite --mode production",
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
"@types/figlet": "^1.5.8",
|
"@types/figlet": "^1.5.8",
|
||||||
"@types/fluent-ffmpeg": "^2.1.24",
|
"@types/fluent-ffmpeg": "^2.1.24",
|
||||||
"@types/jest": "^29.5.12",
|
"@types/jest": "^29.5.12",
|
||||||
"@types/node": "^20.11.30",
|
"@types/node": "^22.0.0",
|
||||||
"@types/qrcode-terminal": "^0.12.2",
|
"@types/qrcode-terminal": "^0.12.2",
|
||||||
"@types/ws": "^8.5.10",
|
"@types/ws": "^8.5.10",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
||||||
|
@@ -42,4 +42,4 @@ if (!(Test-Path $QQpath)) {
|
|||||||
$Bootfile = Join-Path $PSScriptRoot "napcat.mjs"
|
$Bootfile = Join-Path $PSScriptRoot "napcat.mjs"
|
||||||
$env:ELECTRON_RUN_AS_NODE = 1
|
$env:ELECTRON_RUN_AS_NODE = 1
|
||||||
$commandInfo = Get-Command $QQpath -ErrorAction Stop
|
$commandInfo = Get-Command $QQpath -ErrorAction Stop
|
||||||
Start-Process powershell -ArgumentList "-noexit", "-noprofile", "-command &{& chcp 65001;& '$($commandInfo.Path)' --enable-logging $params}"
|
Start-Process powershell -ArgumentList "-noexit", "-noprofile", "-command &{& chcp 65001;& '$($commandInfo.Path)' --enable-logging }"
|
123
script/BootWay05.ps1
Normal file
123
script/BootWay05.ps1
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
# 检查当前会话是否具有管理员权限
|
||||||
|
function Test-Administrator {
|
||||||
|
$user = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||||
|
(New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not (Test-Administrator)) {
|
||||||
|
# 如果不是管理员,则重新启动脚本以管理员模式运行
|
||||||
|
$scriptPath = $myInvocation.MyCommand.Path
|
||||||
|
if (-not $scriptPath) {
|
||||||
|
$scriptPath = $PSCommandPath
|
||||||
|
}
|
||||||
|
$newProcess = New-Object System.Diagnostics.ProcessStartInfo "powershell";
|
||||||
|
$newProcess.Arguments = "-File `"$scriptPath`" $args"
|
||||||
|
$newProcess.Verb = "runas";
|
||||||
|
[System.Diagnostics.Process]::Start($newProcess);
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
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 "get QQ path error: $_"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function Select-QQPath {
|
||||||
|
Add-Type -AssemblyName System.Windows.Forms
|
||||||
|
[System.Windows.Forms.Application]::EnableVisualStyles()
|
||||||
|
|
||||||
|
$dialogTitle = "Select QQ.exe"
|
||||||
|
|
||||||
|
$filePicker = New-Object System.Windows.Forms.OpenFileDialog
|
||||||
|
$filePicker.Title = $dialogTitle
|
||||||
|
$filePicker.Filter = "Executable Files (*.exe)|*.exe|All Files (*.*)|*.*"
|
||||||
|
$filePicker.FilterIndex = 1
|
||||||
|
$null = $filePicker.ShowDialog()
|
||||||
|
if (-not ($filePicker.FileName)) {
|
||||||
|
throw "User did not select an .exe file."
|
||||||
|
}
|
||||||
|
return $filePicker.FileName
|
||||||
|
}
|
||||||
|
|
||||||
|
# 设置当前工作目录
|
||||||
|
$scriptDirectory = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
|
||||||
|
Set-Location $scriptDirectory
|
||||||
|
|
||||||
|
# 获取当前目录路径
|
||||||
|
$currentPath = Get-Location
|
||||||
|
|
||||||
|
# 替换\为/
|
||||||
|
$currentPath = $currentPath -replace '\\', '/'
|
||||||
|
|
||||||
|
# 生成JavaScript代码
|
||||||
|
$jsCode = @"
|
||||||
|
(async () => {
|
||||||
|
await import('file:///$currentPath/napcat.mjs');
|
||||||
|
})();
|
||||||
|
"@
|
||||||
|
|
||||||
|
# 将JavaScript代码保存到文件中
|
||||||
|
$jsFilePath = Join-Path $currentPath "loadScript.js"
|
||||||
|
$jsCode | Out-File -FilePath $jsFilePath -Encoding UTF8
|
||||||
|
|
||||||
|
Write-Output "JavaScript code has been generated and saved to $jsFilePath"
|
||||||
|
# 设置NAPCAT_PATH环境变量为 当前目录的loadScript.js地址
|
||||||
|
$env:NAPCAT_PATH = $jsFilePath
|
||||||
|
|
||||||
|
$params = $args -join " "
|
||||||
|
Try {
|
||||||
|
$QQpath = Get-QQpath
|
||||||
|
}
|
||||||
|
Catch {
|
||||||
|
$QQpath = Select-QQPath
|
||||||
|
}
|
||||||
|
# 拿不到QQ路径则退出
|
||||||
|
if (!(Test-Path $QQpath)) {
|
||||||
|
Write-Output "provided QQ path is invalid: $QQpath"
|
||||||
|
Read-Host "Press any key to continue..."
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
$commandInfo = Get-Command $QQpath -ErrorAction Stop
|
||||||
|
|
||||||
|
# 收集dbghelp.dll路径和HASH信息
|
||||||
|
$QQpath = Split-Path $QQpath
|
||||||
|
$oldDllPath = Join-Path $QQpath "dbghelp.dll"
|
||||||
|
$oldDllHash = Get-FileHash $oldDllPath -Algorithm MD5
|
||||||
|
$newDllPath = Join-Path $currentPath "dbghelp.dll"
|
||||||
|
$newDllHash = Get-FileHash $newDllPath -Algorithm MD5
|
||||||
|
# 如果文件一致则跳过
|
||||||
|
if ($oldDllHash.Hash -ne $newDllHash.Hash) {
|
||||||
|
$processes = Get-Process -Name QQ -ErrorAction SilentlyContinue
|
||||||
|
if ($processes) {
|
||||||
|
# 文件占用则退出
|
||||||
|
Write-Output "dbghelp.dll is in use by the following processes:"
|
||||||
|
$processes | ForEach-Object { Write-Output "$($_.Id) $($_.Name) $($_.Path)" }
|
||||||
|
Write-Output "dbghelp.dll is in use, cannot continue."
|
||||||
|
Read-Host "Press any key to continue..."
|
||||||
|
exit
|
||||||
|
} else {
|
||||||
|
# 文件未占用则尝试覆盖
|
||||||
|
try {
|
||||||
|
Copy-Item -Path "$newDllPath" -Destination "$oldDllPath" -Force
|
||||||
|
Write-Output "dbghelp.dll has been copied to $QQpath"
|
||||||
|
} catch {
|
||||||
|
Write-Output "Failed to copy dbghelp.dll: $_"
|
||||||
|
Read-Host "Press any key to continue..."
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# 带参数启动QQ
|
||||||
|
try {
|
||||||
|
Start-Process powershell -ArgumentList '-noexit', '-noprofile', "-command &{& chcp 65001;& '$($commandInfo.Path)' --enable-logging $params}" -NoNewWindow -ErrorAction Stop
|
||||||
|
} catch {
|
||||||
|
Write-Output "Failed to start process as administrator: $_"
|
||||||
|
Read-Host "Press any key to continue..."
|
||||||
|
}
|
BIN
script/dbghelp.dll
Normal file
BIN
script/dbghelp.dll
Normal file
Binary file not shown.
@@ -42,7 +42,7 @@ export class WebsocketServerBase {
|
|||||||
wss.emit('connection', ws, request);
|
wss.emit('connection', ws, request);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
log(`ws服务启动成功, 绑定到HTTP服务`);
|
log('ws服务启动成功, 绑定到HTTP服务');
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
throw Error('ws服务启动失败, 可能是绑定的HTTP服务异常' + e.toString());
|
throw Error('ws服务启动失败, 可能是绑定的HTTP服务异常' + e.toString());
|
||||||
}
|
}
|
||||||
|
@@ -14,8 +14,8 @@ fs.mkdirSync(configDir, { recursive: true });
|
|||||||
|
|
||||||
|
|
||||||
export class ConfigBase<T> {
|
export class ConfigBase<T> {
|
||||||
public name: string = 'default_config'
|
public name: string = 'default_config';
|
||||||
private pathName: string | null = null // 本次读取的文件路径
|
private pathName: string | null = null; // 本次读取的文件路径
|
||||||
constructor() {
|
constructor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,21 +30,21 @@ export class ConfigBase<T> {
|
|||||||
return configDir;
|
return configDir;
|
||||||
}
|
}
|
||||||
getConfigPath(pathName: string | null): string {
|
getConfigPath(pathName: string | null): string {
|
||||||
const suffix = pathName ? `_${pathName}` : ''
|
const suffix = pathName ? `_${pathName}` : '';
|
||||||
const filename = `${this.name}${suffix}.json`
|
const filename = `${this.name}${suffix}.json`;
|
||||||
return path.join(this.getConfigDir(), filename);
|
return path.join(this.getConfigDir(), filename);
|
||||||
}
|
}
|
||||||
read() {
|
read() {
|
||||||
// 尝试加载当前账号配置
|
// 尝试加载当前账号配置
|
||||||
if (this.read_from_file(selfInfo.uin, false)) return this
|
if (this.read_from_file(selfInfo.uin, false)) return this;
|
||||||
// 尝试加载默认配置
|
// 尝试加载默认配置
|
||||||
return this.read_from_file('', true)
|
return this.read_from_file('', true);
|
||||||
}
|
}
|
||||||
read_from_file(pathName: string, createIfNotExist: boolean) {
|
read_from_file(pathName: string, createIfNotExist: boolean) {
|
||||||
const configPath = this.getConfigPath(pathName);
|
const configPath = this.getConfigPath(pathName);
|
||||||
if (!fs.existsSync(configPath)) {
|
if (!fs.existsSync(configPath)) {
|
||||||
if (!createIfNotExist) return null
|
if (!createIfNotExist) return null;
|
||||||
this.pathName = pathName // 记录有效的设置文件
|
this.pathName = pathName; // 记录有效的设置文件
|
||||||
try {
|
try {
|
||||||
fs.writeFileSync(configPath, JSON.stringify(this, this.getKeys(), 2));
|
fs.writeFileSync(configPath, JSON.stringify(this, this.getKeys(), 2));
|
||||||
log(`配置文件${configPath}已创建\n如果修改此文件后需要重启 NapCat 生效`);
|
log(`配置文件${configPath}已创建\n如果修改此文件后需要重启 NapCat 生效`);
|
||||||
@@ -77,7 +77,7 @@ export class ConfigBase<T> {
|
|||||||
Object.assign(this, config);
|
Object.assign(this, config);
|
||||||
if (overwrite) {
|
if (overwrite) {
|
||||||
// 用户要求强制写入,则变更当前文件为目标文件
|
// 用户要求强制写入,则变更当前文件为目标文件
|
||||||
this.pathName = `${selfInfo.uin}`
|
this.pathName = `${selfInfo.uin}`;
|
||||||
}
|
}
|
||||||
const configPath = this.getConfigPath(this.pathName);
|
const configPath = this.getConfigPath(this.pathName);
|
||||||
try {
|
try {
|
||||||
|
@@ -96,7 +96,7 @@ export class NTEventWrapper {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
async CallNoListenerEvent<EventType extends (...args: any[]) => Promise<any>>(EventName = '', timeout: number = 3000, ...args: Parameters<EventType>) {
|
async CallNoListenerEvent<EventType extends (...args: any[]) => Promise<any> | any>(EventName = '', timeout: number = 3000, ...args: Parameters<EventType>) {
|
||||||
return new Promise<Awaited<ReturnType<EventType>>>(async (resolve, reject) => {
|
return new Promise<Awaited<ReturnType<EventType>>>(async (resolve, reject) => {
|
||||||
const EventFunc = this.CreatEventFunction<EventType>(EventName);
|
const EventFunc = this.CreatEventFunction<EventType>(EventName);
|
||||||
let complete = false;
|
let complete = false;
|
||||||
@@ -110,6 +110,45 @@ export class NTEventWrapper {
|
|||||||
resolve(retData);
|
resolve(retData);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
async RegisterListen<ListenerType extends (...args: any[]) => void>(ListenerName = '', waitTimes = 1, timeout = 5000, checker: (...args: Parameters<ListenerType>) => boolean) {
|
||||||
|
return new Promise<Parameters<ListenerType>>((resolve, reject) => {
|
||||||
|
const ListenerNameList = ListenerName.split('/');
|
||||||
|
const ListenerMainName = ListenerNameList[0];
|
||||||
|
const ListenerSubName = ListenerNameList[1];
|
||||||
|
const id = randomUUID();
|
||||||
|
let complete = 0;
|
||||||
|
let retData: Parameters<ListenerType> | undefined = undefined;
|
||||||
|
const databack = () => {
|
||||||
|
if (complete == 0) {
|
||||||
|
reject(new Error(' ListenerName:' + ListenerName + ' timeout'));
|
||||||
|
} else {
|
||||||
|
resolve(retData!);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const Timeouter = setTimeout(databack, timeout);
|
||||||
|
const eventCallbak = {
|
||||||
|
timeout: timeout,
|
||||||
|
createtime: Date.now(),
|
||||||
|
checker: checker,
|
||||||
|
func: (...args: Parameters<ListenerType>) => {
|
||||||
|
complete++;
|
||||||
|
retData = args;
|
||||||
|
if (complete >= waitTimes) {
|
||||||
|
clearTimeout(Timeouter);
|
||||||
|
databack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (!this.EventTask.get(ListenerMainName)) {
|
||||||
|
this.EventTask.set(ListenerMainName, new Map());
|
||||||
|
}
|
||||||
|
if (!(this.EventTask.get(ListenerMainName)?.get(ListenerSubName))) {
|
||||||
|
this.EventTask.get(ListenerMainName)?.set(ListenerSubName, new Map());
|
||||||
|
}
|
||||||
|
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallbak);
|
||||||
|
this.CreatListenerFunction(ListenerMainName);
|
||||||
|
});
|
||||||
|
}
|
||||||
async CallNormalEvent<EventType extends (...args: any[]) => Promise<any>, ListenerType extends (...args: any[]) => void>
|
async CallNormalEvent<EventType extends (...args: any[]) => Promise<any>, ListenerType extends (...args: any[]) => void>
|
||||||
(EventName = '', ListenerName = '', waitTimes = 1, timeout: number = 3000, checker: (...args: Parameters<ListenerType>) => boolean, ...args: Parameters<EventType>) {
|
(EventName = '', ListenerName = '', waitTimes = 1, timeout: number = 3000, checker: (...args: Parameters<ListenerType>) => boolean, ...args: Parameters<EventType>) {
|
||||||
return new Promise<[EventRet: Awaited<ReturnType<EventType>>, ...Parameters<ListenerType>]>(async (resolve, reject) => {
|
return new Promise<[EventRet: Awaited<ReturnType<EventType>>, ...Parameters<ListenerType>]>(async (resolve, reject) => {
|
||||||
@@ -119,16 +158,19 @@ export class NTEventWrapper {
|
|||||||
let retEvent: any = {};
|
let retEvent: any = {};
|
||||||
const databack = () => {
|
const databack = () => {
|
||||||
if (complete == 0) {
|
if (complete == 0) {
|
||||||
reject(new Error('NTEvent EventName:' + EventName + ' ListenerName:' + ListenerName + ' timeout'));
|
reject(new Error('Timeout: NTEvent EventName:' + EventName + ' ListenerName:' + ListenerName + ' EventRet:\n' + JSON.stringify(retEvent, null, 4) + '\n'));
|
||||||
} else {
|
} else {
|
||||||
resolve([retEvent as Awaited<ReturnType<EventType>>, ...retData!]);
|
resolve([retEvent as Awaited<ReturnType<EventType>>, ...retData!]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const Timeouter = setTimeout(databack, timeout);
|
|
||||||
|
|
||||||
const ListenerNameList = ListenerName.split('/');
|
const ListenerNameList = ListenerName.split('/');
|
||||||
const ListenerMainName = ListenerNameList[0];
|
const ListenerMainName = ListenerNameList[0];
|
||||||
const ListenerSubName = ListenerNameList[1];
|
const ListenerSubName = ListenerNameList[1];
|
||||||
|
|
||||||
|
const Timeouter = setTimeout(databack, timeout);
|
||||||
|
|
||||||
const eventCallbak = {
|
const eventCallbak = {
|
||||||
timeout: timeout,
|
timeout: timeout,
|
||||||
createtime: Date.now(),
|
createtime: Date.now(),
|
||||||
@@ -152,7 +194,6 @@ export class NTEventWrapper {
|
|||||||
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallbak);
|
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallbak);
|
||||||
this.CreatListenerFunction(ListenerMainName);
|
this.CreatListenerFunction(ListenerMainName);
|
||||||
const EventFunc = this.CreatEventFunction<EventType>(EventName);
|
const EventFunc = this.CreatEventFunction<EventType>(EventName);
|
||||||
//console.log("测试打点", args);
|
|
||||||
retEvent = await EventFunc!(...(args as any[]));
|
retEvent = await EventFunc!(...(args as any[]));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -15,10 +15,10 @@ class LimitedHashTable<K, V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set(key: K, value: V): void {
|
set(key: K, value: V): void {
|
||||||
const isExist = this.keyToValue.get(key);
|
// const isExist = this.keyToValue.get(key);
|
||||||
if (isExist && isExist === value) {
|
// if (isExist && isExist === value) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
this.keyToValue.set(key, value);
|
this.keyToValue.set(key, value);
|
||||||
this.valueToKey.set(value, key);
|
this.valueToKey.set(value, key);
|
||||||
while (this.keyToValue.size !== this.valueToKey.size) {
|
while (this.keyToValue.size !== this.valueToKey.size) {
|
||||||
@@ -61,6 +61,24 @@ class LimitedHashTable<K, V> {
|
|||||||
this.valueToKey.delete(value);
|
this.valueToKey.delete(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getKeyList(): K[] {
|
||||||
|
return Array.from(this.keyToValue.keys());
|
||||||
|
}
|
||||||
|
//获取最近刚写入的几个值
|
||||||
|
getHeads(size: number): { key: K; value: V }[] | undefined {
|
||||||
|
const keyList = this.getKeyList();
|
||||||
|
if (keyList.length === 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const result: { key: K; value: V }[] = [];
|
||||||
|
const listSize = Math.min(size, keyList.length);
|
||||||
|
for (let i = 0; i < listSize; i++) {
|
||||||
|
const key = keyList[listSize - i];
|
||||||
|
result.push({ key, value: this.keyToValue.get(key)! });
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MessageUniqueWrapper {
|
class MessageUniqueWrapper {
|
||||||
@@ -70,16 +88,24 @@ class MessageUniqueWrapper {
|
|||||||
this.msgIdMap = new LimitedHashTable<string, number>(maxMap);
|
this.msgIdMap = new LimitedHashTable<string, number>(maxMap);
|
||||||
this.msgDataMap = new LimitedHashTable<string, number>(maxMap);
|
this.msgDataMap = new LimitedHashTable<string, number>(maxMap);
|
||||||
}
|
}
|
||||||
|
getRecentMsgIds(Peer: Peer, size: number): string[] {
|
||||||
|
const heads = this.msgIdMap.getHeads(size);
|
||||||
|
if (!heads) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const data = heads.map((t) => MessageUnique.getMsgIdAndPeerByShortId(t.value));
|
||||||
|
const ret = data.filter((t) => t?.Peer.chatType === Peer.chatType && t?.Peer.peerUid === Peer.peerUid);
|
||||||
|
return ret.map((t) => t?.MsgId).filter((t) => t !== undefined);
|
||||||
|
}
|
||||||
createMsg(peer: Peer, msgId: string): number | undefined {
|
createMsg(peer: Peer, msgId: string): number | undefined {
|
||||||
const key = `${msgId}|${peer.chatType}|${peer.peerUid}`;
|
const key = `${msgId}|${peer.chatType}|${peer.peerUid}`;
|
||||||
const hash = crypto.createHash('sha1').update(key);
|
const hash = crypto.createHash('md5').update(key);
|
||||||
const shortId = parseInt(hash.digest('hex').slice(0, 8), 16);
|
const shortId = hash.digest().readInt32BE(0);
|
||||||
const isExist = this.msgIdMap.getKey(shortId);
|
//减少性能损耗
|
||||||
//console.log(`${peer.peerUid} ${msgId} ------- ${shortId}`);
|
// const isExist = this.msgIdMap.getKey(shortId);
|
||||||
if (isExist && isExist === msgId) {
|
// if (isExist && isExist === msgId) {
|
||||||
return shortId;
|
// return shortId;
|
||||||
}
|
// }
|
||||||
this.msgIdMap.set(msgId, shortId);
|
this.msgIdMap.set(msgId, shortId);
|
||||||
this.msgDataMap.set(key, shortId);
|
this.msgDataMap.set(key, shortId);
|
||||||
return shortId;
|
return shortId;
|
||||||
|
@@ -14,7 +14,7 @@ export function sleep(ms: number): Promise<void> {
|
|||||||
|
|
||||||
export function PromiseTimer<T>(promise: Promise<T>, ms: number): Promise<T> {
|
export function PromiseTimer<T>(promise: Promise<T>, ms: number): Promise<T> {
|
||||||
const timeoutPromise = new Promise<T>((_, reject) =>
|
const timeoutPromise = new Promise<T>((_, reject) =>
|
||||||
setTimeout(() => reject(new Error("PromiseTimer: Operation timed out")), ms)
|
setTimeout(() => reject(new Error('PromiseTimer: Operation timed out')), ms)
|
||||||
);
|
);
|
||||||
return Promise.race([promise, timeoutPromise]);
|
return Promise.race([promise, timeoutPromise]);
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,7 @@ import {
|
|||||||
CacheFileType,
|
CacheFileType,
|
||||||
ChatCacheListItemBasic,
|
ChatCacheListItemBasic,
|
||||||
ChatType,
|
ChatType,
|
||||||
ElementType, IMAGE_HTTP_HOST, IMAGE_HTTP_HOST_NT, RawMessage
|
ElementType, IMAGE_HTTP_HOST, IMAGE_HTTP_HOST_NT, Peer, PicElement, RawMessage
|
||||||
} from '@/core/entities';
|
} from '@/core/entities';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
@@ -19,6 +19,7 @@ import { rkeyManager } from '../utils/rkey';
|
|||||||
import { NTEventDispatch } from '@/common/utils/EventTask';
|
import { NTEventDispatch } from '@/common/utils/EventTask';
|
||||||
import { NodeIKernelSearchService } from '../services/NodeIKernelSearchService';
|
import { NodeIKernelSearchService } from '../services/NodeIKernelSearchService';
|
||||||
|
|
||||||
|
|
||||||
export class NTQQFileApi {
|
export class NTQQFileApi {
|
||||||
static async getFileType(filePath: string) {
|
static async getFileType(filePath: string) {
|
||||||
return fileType.fileTypeFromFile(filePath);
|
return fileType.fileTypeFromFile(filePath);
|
||||||
@@ -31,12 +32,8 @@ export class NTQQFileApi {
|
|||||||
static async getFileSize(filePath: string): Promise<number> {
|
static async getFileSize(filePath: string): Promise<number> {
|
||||||
return await napCatCore.util.getFileSize(filePath);
|
return await napCatCore.util.getFileSize(filePath);
|
||||||
}
|
}
|
||||||
static async getVideoUrl(msg: RawMessage, element: any) {
|
static async getVideoUrl(peer: Peer, msgId: string, elementId: string) {
|
||||||
return (await napCatCore.session.getRichMediaService().getVideoPlayUrlV2({
|
return (await napCatCore.session.getRichMediaService().getVideoPlayUrlV2(peer, msgId, elementId, 0, { downSourceType: 1, triggerType: 1 })).urlResult.domainUrl;
|
||||||
chatType: msg.chatType,
|
|
||||||
peerUid: msg.peerUid,
|
|
||||||
guildId: '0'
|
|
||||||
}, msg.msgId, element.elementId, 0, { downSourceType: 1, triggerType: 1 })).urlResult.domainUrl[0].url;
|
|
||||||
}
|
}
|
||||||
// 上传文件到QQ的文件夹
|
// 上传文件到QQ的文件夹
|
||||||
static async uploadFile(filePath: string, elementType: ElementType = ElementType.PIC, elementSubType: number = 0) {
|
static async uploadFile(filePath: string, elementType: ElementType = ElementType.PIC, elementSubType: number = 0) {
|
||||||
@@ -146,8 +143,65 @@ export class NTQQFileApi {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
static async searchfile(keys: string[]) {
|
static async addFileCache(peer: Peer, msgId: string, msgSeq: string, senderUid: string, elemId: string, elemType: string, fileSize: string, fileName: string) {
|
||||||
|
let GroupData;
|
||||||
|
let BuddyData;
|
||||||
|
if (peer.chatType === ChatType.group) {
|
||||||
|
GroupData =
|
||||||
|
[{
|
||||||
|
groupCode: peer.peerUid,
|
||||||
|
isConf: false,
|
||||||
|
hasModifyConfGroupFace: true,
|
||||||
|
hasModifyConfGroupName: true,
|
||||||
|
groupName: "NapCat.Cached",
|
||||||
|
remark: "NapCat.Cached"
|
||||||
|
}];
|
||||||
|
} else if (peer.chatType === ChatType.friend) {
|
||||||
|
BuddyData = [{
|
||||||
|
category_name: 'NapCat.Cached',
|
||||||
|
peerUid: peer.peerUid,
|
||||||
|
peerUin: peer.peerUid,
|
||||||
|
remark: 'NapCat.Cached'
|
||||||
|
}];
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return napCatCore.session.getSearchService().addSearchHistory({
|
||||||
|
type: 4,
|
||||||
|
contactList: [],
|
||||||
|
id: -1,
|
||||||
|
groupInfos: [],
|
||||||
|
msgs: [],
|
||||||
|
fileInfos: [
|
||||||
|
{
|
||||||
|
chatType: peer.chatType,
|
||||||
|
buddyChatInfo: BuddyData || [],
|
||||||
|
discussChatInfo: [],
|
||||||
|
groupChatInfo: GroupData || [],
|
||||||
|
dataLineChatInfo: [],
|
||||||
|
tmpChatInfo: [],
|
||||||
|
msgId: msgId,
|
||||||
|
msgSeq: msgSeq,
|
||||||
|
msgTime: Math.floor(Date.now() / 1000).toString(),
|
||||||
|
senderUid: senderUid,
|
||||||
|
senderNick: 'NapCat.Cached',
|
||||||
|
senderRemark: 'NapCat.Cached',
|
||||||
|
senderCard: 'NapCat.Cached',
|
||||||
|
elemId: elemId,
|
||||||
|
elemType: elemType,
|
||||||
|
fileSize: fileSize,
|
||||||
|
filePath: '',
|
||||||
|
fileName: fileName,
|
||||||
|
hits: [{
|
||||||
|
start: 12,
|
||||||
|
end: 14
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
static async searchfile(keys: string[]) {
|
||||||
type EventType = NodeIKernelSearchService['searchFileWithKeywords'];
|
type EventType = NodeIKernelSearchService['searchFileWithKeywords'];
|
||||||
interface OnListener {
|
interface OnListener {
|
||||||
searchId: string,
|
searchId: string,
|
||||||
@@ -187,22 +241,23 @@ export class NTQQFileApi {
|
|||||||
}[]
|
}[]
|
||||||
}[]
|
}[]
|
||||||
};
|
};
|
||||||
const [id, data] = await NTEventDispatch.CallNormalEvent<EventType, (params: OnListener) => void>(
|
const Event = await NTEventDispatch.CreatEventFunction<EventType>('NodeIKernelSearchService/searchFileWithKeywords');
|
||||||
'NodeIKernelSearchService/searchFileWithKeywords',
|
let id = '';
|
||||||
'NodeIKernelSearchListener/onSearchFileKeywordsResult',
|
const Listener = NTEventDispatch.RegisterListen<(params: OnListener) => void>('NodeIKernelSearchListener/onSearchFileKeywordsResult', 1, 20000, (params) => {
|
||||||
1,
|
if (id !== '' && params.searchId == id) {
|
||||||
10000,
|
return true
|
||||||
(arg): boolean => { return id == data.searchId },
|
|
||||||
keys,
|
|
||||||
12
|
|
||||||
);
|
|
||||||
return data.resultItems[0];
|
|
||||||
}
|
}
|
||||||
static async getImageUrl(element: { originImageUrl: any; md5HexStr?: any; fileUuid: any; }) {
|
return false;
|
||||||
|
});
|
||||||
|
id = await Event!(keys, 12);
|
||||||
|
let [ret] = (await Listener);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
static async getImageUrl(element: PicElement) {
|
||||||
if (!element) {
|
if (!element) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
const url: string = element.originImageUrl; // 没有域名
|
const url: string = element.originImageUrl!; // 没有域名
|
||||||
const md5HexStr = element.md5HexStr;
|
const md5HexStr = element.md5HexStr;
|
||||||
const fileMd5 = element.md5HexStr;
|
const fileMd5 = element.md5HexStr;
|
||||||
const fileUuid = element.fileUuid;
|
const fileUuid = element.fileUuid;
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { GroupMember, GroupRequestOperateTypes, GroupMemberRole, GroupNotify, Group, MemberExtSourceType, GroupNotifyTypes, ChatType } from '../entities';
|
import { GroupMember, GroupRequestOperateTypes, GroupMemberRole, GroupNotify, Group, MemberExtSourceType, GroupNotifyTypes, ChatType, Peer } from '../entities';
|
||||||
import { GeneralCallResult, NTQQUserApi, napCatCore } from '@/core';
|
import { GeneralCallResult, NTQQUserApi, napCatCore } from '@/core';
|
||||||
import { NTEventDispatch } from '@/common/utils/EventTask';
|
import { NTEventDispatch } from '@/common/utils/EventTask';
|
||||||
import { log } from '@/common/utils/log';
|
import { log } from '@/common/utils/log';
|
||||||
@@ -26,7 +26,6 @@ export class NTQQGroupApi {
|
|||||||
static async getGroupMemberLastestSendTimeCache(GroupCode: string) {
|
static async getGroupMemberLastestSendTimeCache(GroupCode: string) {
|
||||||
return NTQQGroupApi.getGroupMemberLastestSendTime(GroupCode);
|
return NTQQGroupApi.getGroupMemberLastestSendTime(GroupCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过QQ自带数据库获取群成员最后发言时间(仅返回有效数据 且消耗延迟大 需要进行缓存)
|
* 通过QQ自带数据库获取群成员最后发言时间(仅返回有效数据 且消耗延迟大 需要进行缓存)
|
||||||
* @param GroupCode 群号
|
* @param GroupCode 群号
|
||||||
@@ -84,15 +83,10 @@ export class NTQQGroupApi {
|
|||||||
static async getLastestMsg(GroupCode: string, uins: string[]) {
|
static async getLastestMsg(GroupCode: string, uins: string[]) {
|
||||||
let uids: Array<string> = [];
|
let uids: Array<string> = [];
|
||||||
for (let uin of uins) {
|
for (let uin of uins) {
|
||||||
try {
|
|
||||||
let uid = await NTQQUserApi.getUidByUin(uin)
|
let uid = await NTQQUserApi.getUidByUin(uin)
|
||||||
if (uid) {
|
if (uid) {
|
||||||
uids.push(uid);
|
uids.push(uid);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
|
||||||
log("getLastestMsg--->", error);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let ret = await napCatCore.session.getMsgService().queryMsgsWithFilterEx('0', '0', '0', {
|
let ret = await napCatCore.session.getMsgService().queryMsgsWithFilterEx('0', '0', '0', {
|
||||||
chatInfo: {
|
chatInfo: {
|
||||||
|
@@ -1,12 +1,15 @@
|
|||||||
import { GetFileListParam, Peer, RawMessage, SendMessageElement } from '@/core/entities';
|
import { ElementType, GetFileListParam, MessageElement, Peer, RawMessage, SendMessageElement, SendMsgElementConstructor } from '@/core/entities';
|
||||||
import { friends, groups, selfInfo } from '@/core/data';
|
import { friends, groups, selfInfo } from '@/core/data';
|
||||||
import { log, logWarn } from '@/common/utils/log';
|
import { log, logError, logWarn } from '@/common/utils/log';
|
||||||
import { sleep } from '@/common/utils/helper';
|
import { sleep } from '@/common/utils/helper';
|
||||||
import { napCatCore, NTQQUserApi } from '@/core';
|
import { napCatCore, NodeIKernelMsgService, NTQQUserApi } from '@/core';
|
||||||
import { onGroupFileInfoUpdateParamType } from '@/core/listeners';
|
import { NodeIKernelMsgListener, onGroupFileInfoUpdateParamType } from '@/core/listeners';
|
||||||
import { GeneralCallResult } from '@/core/services/common';
|
import { GeneralCallResult } from '@/core/services/common';
|
||||||
import { MessageUnique } from '../../../common/utils/MessageUnique';
|
import { MessageUnique } from '../../../common/utils/MessageUnique';
|
||||||
import { NTEventDispatch } from '@/common/utils/EventTask';
|
import { NTEventDispatch } from '@/common/utils/EventTask';
|
||||||
|
import { logNotice } from '@/onebot11/log';
|
||||||
|
let MsgSendMode = 2;
|
||||||
|
|
||||||
async function LoadMessageIdList(Peer: Peer, msgId: string) {
|
async function LoadMessageIdList(Peer: Peer, msgId: string) {
|
||||||
let msgList = await NTQQMsgApi.getMsgHistory(Peer, msgId, 50);
|
let msgList = await NTQQMsgApi.getMsgHistory(Peer, msgId, 50);
|
||||||
for (let j = 0; j < msgList.msgList.length; j++) {
|
for (let j = 0; j < msgList.msgList.length; j++) {
|
||||||
@@ -17,11 +20,12 @@ async function loadMessageUnique() {
|
|||||||
if (groups.size > 100) {
|
if (groups.size > 100) {
|
||||||
logWarn('群数量大于100,可能会导致性能问题');
|
logWarn('群数量大于100,可能会导致性能问题');
|
||||||
}
|
}
|
||||||
let predict = (groups.size + friends.size) / 5;
|
let predict = (groups.size + friends.size / 2) / 5;
|
||||||
predict = predict < 20 ? 20 : predict;
|
predict = predict < 20 ? 20 : predict;
|
||||||
predict = predict > 50 ? 50 : predict;
|
predict = predict > 50 ? 50 : predict;
|
||||||
//let waitpromise: Array<Promise<{ msgList: RawMessage[]; }>> = [];
|
//let waitpromise: Array<Promise<{ msgList: RawMessage[]; }>> = [];
|
||||||
MessageUnique.resize(predict * 50);
|
predict = Math.floor(predict * 50);
|
||||||
|
MessageUnique.resize(predict);
|
||||||
let RecentContact = await NTQQUserApi.getRecentContactListSnapShot(predict);
|
let RecentContact = await NTQQUserApi.getRecentContactListSnapShot(predict);
|
||||||
let LoadMessageIdDo: Array<Promise<void>> = new Array<Promise<void>>();
|
let LoadMessageIdDo: Array<Promise<void>> = new Array<Promise<void>>();
|
||||||
if (RecentContact?.info?.changedList && RecentContact?.info?.changedList?.length > 0) {
|
if (RecentContact?.info?.changedList && RecentContact?.info?.changedList?.length > 0) {
|
||||||
@@ -31,18 +35,55 @@ async function loadMessageUnique() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
await Promise.all(LoadMessageIdDo).then(() => {
|
await Promise.all(LoadMessageIdDo).then(() => {
|
||||||
log(`[消息序列] 加载 ${predict * 50} 条历史消息记录完成`);
|
log(`[消息序列] 加载 ${predict} 条历史消息记录完成`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
napCatCore.onLoginSuccess(async () => {
|
napCatCore.onLoginSuccess(async () => {
|
||||||
await sleep(100);
|
await sleep(100);
|
||||||
|
NTQQMsgApi.CheckSendMode().then().catch();
|
||||||
loadMessageUnique().then().catch();
|
loadMessageUnique().then().catch();
|
||||||
});
|
});
|
||||||
}, 100);
|
}, 100);
|
||||||
|
//歇菜LocalMsg压根不写Db
|
||||||
|
// setTimeout(async () => {
|
||||||
|
// let ele: MessageElement = { extBufForUI: '0x', ...SendMsgElementConstructor.text('测试消息') };
|
||||||
|
// let MsgId = await NTQQMsgApi.getMsgUniqueEx();
|
||||||
|
// let peer = { chatType: 2, peerUid: '', guildId: '' };
|
||||||
|
// console.log(await napCatCore.session.getTestPerformanceService().insertMsg(
|
||||||
|
// {
|
||||||
|
// peer: peer,
|
||||||
|
// msgTime: Math.floor(Date.now() / 1000).toString(),
|
||||||
|
// msgId: MsgId,
|
||||||
|
// msgSeq: '56564',
|
||||||
|
// batchNums: 1,
|
||||||
|
// timesPerBatch: 1,
|
||||||
|
// numPerTime: 1
|
||||||
|
// }, [ele]
|
||||||
|
// ));
|
||||||
|
// console.log(await NTQQMsgApi.multiForwardMsg(peer, peer, [MsgId]));
|
||||||
|
// }, 25000)
|
||||||
export class NTQQMsgApi {
|
export class NTQQMsgApi {
|
||||||
|
static async CheckSendMode() {
|
||||||
|
try {
|
||||||
|
NTQQMsgApi.sendMsgV2({ chatType: 1, peerUid: selfInfo.uid }, [SendMsgElementConstructor.text('消息队列模式测试')], true, 10000).then().catch();
|
||||||
|
MsgSendMode = 2;
|
||||||
|
logNotice('[消息队列] 消息模式确认: MsgId异步队列');
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
logNotice('[消息队列] 消息模式失败: MsgId异步队列');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
NTQQMsgApi.sendMsgV1({ chatType: 1, peerUid: selfInfo.uid }, [SendMsgElementConstructor.text('消息队列模式测试')], true, 10000).then().catch();
|
||||||
|
MsgSendMode = 1;
|
||||||
|
logNotice('[消息队列] 消息模式确认: MsgSeq异步队列');
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
logNotice('[消息队列] 消息模式失败: MsgSeq异步队列');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// static napCatCore: NapCatCore | null = null;
|
// static napCatCore: NapCatCore | null = null;
|
||||||
// enum BaseEmojiType {
|
// enum BaseEmojiType {
|
||||||
// NORMAL_EMOJI,
|
// NORMAL_EMOJI,
|
||||||
@@ -63,12 +104,46 @@ export class NTQQMsgApi {
|
|||||||
} | undefined> {
|
} | undefined> {
|
||||||
return napCatCore.session.getMsgService().getMultiMsg(peer, rootMsgId, parentMsgId);
|
return napCatCore.session.getMsgService().getMultiMsg(peer, rootMsgId, parentMsgId);
|
||||||
}
|
}
|
||||||
|
static async getLastestMsgByUids(peer: Peer) {
|
||||||
|
let ret = await napCatCore.session.getMsgService().queryMsgsWithFilterEx('0', '0', '0', {
|
||||||
|
chatInfo: peer,
|
||||||
|
filterMsgType: [],
|
||||||
|
filterSendersUid: [],
|
||||||
|
filterMsgToTime: '0',
|
||||||
|
filterMsgFromTime: '0',
|
||||||
|
isReverseOrder: false,
|
||||||
|
isIncludeCurrent: true,
|
||||||
|
pageLimit: 1,
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
static async getMsgsByMsgId(peer: Peer, msgIds: string[]) {
|
static async getMsgsByMsgId(peer: Peer, msgIds: string[]) {
|
||||||
return await napCatCore.session.getMsgService().getMsgsByMsgId(peer, msgIds);
|
return await napCatCore.session.getMsgService().getMsgsByMsgId(peer, msgIds);
|
||||||
}
|
}
|
||||||
|
static async getSingleMsg(peer: Peer, seq: string) {
|
||||||
|
return await napCatCore.session.getMsgService().getSingleMsg(peer, seq);
|
||||||
|
}
|
||||||
|
static async fetchFavEmojiList(num: number) {
|
||||||
|
return napCatCore.session.getMsgService().fetchFavEmojiList("", num, true, true)
|
||||||
|
}
|
||||||
|
static async queryMsgsWithFilterExWithSeq(peer: Peer, msgSeq: string) {
|
||||||
|
let ret = await napCatCore.session.getMsgService().queryMsgsWithFilterEx('0', '0', msgSeq, {
|
||||||
|
chatInfo: peer,
|
||||||
|
filterMsgType: [],
|
||||||
|
filterSendersUid: [],
|
||||||
|
filterMsgToTime: '0',
|
||||||
|
filterMsgFromTime: '0',
|
||||||
|
isReverseOrder: false,
|
||||||
|
isIncludeCurrent: true,
|
||||||
|
pageLimit: 1,
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
static async getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, z: boolean) {
|
static async getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, z: boolean) {
|
||||||
return await napCatCore.session.getMsgService().getMsgsBySeqAndCount(peer, seq, count, desc, z);
|
return await napCatCore.session.getMsgService().getMsgsBySeqAndCount(peer, seq, count, desc, z);
|
||||||
|
}
|
||||||
|
static async testMode() {
|
||||||
|
|
||||||
}
|
}
|
||||||
static async setMsgRead(peer: Peer) {
|
static async setMsgRead(peer: Peer) {
|
||||||
return napCatCore.session.getMsgService().setMsgRead(peer);
|
return napCatCore.session.getMsgService().setMsgRead(peer);
|
||||||
@@ -100,7 +175,16 @@ export class NTQQMsgApi {
|
|||||||
peerUid: peer.peerUid
|
peerUid: peer.peerUid
|
||||||
}, msgIds);
|
}, msgIds);
|
||||||
}
|
}
|
||||||
static async sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
|
static async sendMsgV2(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
|
||||||
|
// function generateMsgId() {
|
||||||
|
// const timestamp = Math.floor(Date.now() / 1000);
|
||||||
|
// const random = Math.floor(Math.random() * Math.pow(2, 32));
|
||||||
|
// const buffer = Buffer.alloc(8);
|
||||||
|
// buffer.writeUInt32BE(timestamp, 0);
|
||||||
|
// buffer.writeUInt32BE(random, 4);
|
||||||
|
// const msgId = BigInt("0x" + buffer.toString('hex')).toString();
|
||||||
|
// return msgId;
|
||||||
|
// }
|
||||||
let msgId = await NTQQMsgApi.getMsgUnique(await NTQQMsgApi.getServerTime());
|
let msgId = await NTQQMsgApi.getMsgUnique(await NTQQMsgApi.getServerTime());
|
||||||
let data = await NTEventDispatch.CallNormalEvent<
|
let data = await NTEventDispatch.CallNormalEvent<
|
||||||
(msgId: string, peer: Peer, msgElements: SendMessageElement[], map: Map<any, any>) => Promise<unknown>,
|
(msgId: string, peer: Peer, msgElements: SendMessageElement[], map: Map<any, any>) => Promise<unknown>,
|
||||||
@@ -130,16 +214,64 @@ export class NTQQMsgApi {
|
|||||||
});
|
});
|
||||||
return retMsg;
|
return retMsg;
|
||||||
}
|
}
|
||||||
static async getMsgUniqueEx(){
|
static sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
|
||||||
|
if (MsgSendMode == 1) {
|
||||||
|
return NTQQMsgApi.sendMsgV1(peer, msgElements, waitComplete, timeout);
|
||||||
|
} else if (MsgSendMode == 2) {
|
||||||
|
return NTQQMsgApi.sendMsgV2(peer, msgElements, waitComplete, timeout);
|
||||||
|
}
|
||||||
|
throw new Error('未知的发送消息模式');
|
||||||
|
}
|
||||||
|
static async sendMsgV1(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
|
||||||
|
let msgList = await NTQQMsgApi.getLastestMsgByUids(peer);
|
||||||
|
let msgCurrentSeq = 0n;
|
||||||
|
if (msgList.msgList.length > 0) {
|
||||||
|
msgCurrentSeq = BigInt(msgList.msgList[0].msgSeq);
|
||||||
|
}
|
||||||
|
let rawMsg: RawMessage | undefined;
|
||||||
|
let EventListener = NTEventDispatch.RegisterListen<NodeIKernelMsgListener['onAddSendMsg']>('NodeIKernelMsgListener/onAddSendMsg', 1, timeout, (msg: RawMessage) => {
|
||||||
|
//console.log("msgSeq:", msgCurrentSeq.toString(), JSON.stringify(msgList.msgList[0], null, 4));
|
||||||
|
if (msg.peerUid == peer.peerUid && (msgCurrentSeq == 0n || msgList.msgList[0].msgSeq == msgCurrentSeq.toString())) {
|
||||||
|
rawMsg = msg;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}).catch(logError);
|
||||||
|
let EventListener2 = NTEventDispatch.RegisterListen<NodeIKernelMsgListener['onMsgInfoListUpdate']>('NodeIKernelMsgListener/onMsgInfoListUpdate', 1, timeout,
|
||||||
|
(msgList: RawMessage[]) => {
|
||||||
|
for (let msg of msgList) {
|
||||||
|
if (msg.peerUid == peer.peerUid && rawMsg && rawMsg.msgId == msg.msgId && msg.sendStatus == 2) {
|
||||||
|
rawMsg = msg;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}).catch(logError);
|
||||||
|
await NTEventDispatch.CallNoListenerEvent<NodeIKernelMsgService['sendMsg']>('NodeIKernelMsgService/sendMsg', timeout, "0", peer, msgElements, new Map());
|
||||||
|
await EventListener;
|
||||||
|
await EventListener2;
|
||||||
|
// console.log("rawMsg", JSON.stringify(rawMsg, null, 4));
|
||||||
|
if (rawMsg) {
|
||||||
|
return rawMsg;
|
||||||
|
}
|
||||||
|
throw new Error('发送消息超时');
|
||||||
|
}
|
||||||
|
static async getMsgUniqueEx() {
|
||||||
let msgId = await NTQQMsgApi.getMsgUnique(await NTQQMsgApi.getServerTime());
|
let msgId = await NTQQMsgApi.getMsgUnique(await NTQQMsgApi.getServerTime());
|
||||||
return msgId;
|
return msgId;
|
||||||
}
|
}
|
||||||
static async getMsgUnique(time: string) {
|
static async getMsgUnique(time: string) {
|
||||||
return napCatCore.session.getMsgService().getMsgUniqueId(time);
|
return napCatCore.session.getMsgService().getMsgUniqueId(time);
|
||||||
}
|
}
|
||||||
|
static async getMsgUniqueByTimeV2() {
|
||||||
|
return NTEventDispatch.CallNoListenerEvent<NodeIKernelMsgService['getMsgUniqueId']>('NodeIKernelMsgService/getMsgUniqueId', 5000, await NTQQMsgApi.getServerTimeV2())
|
||||||
|
}
|
||||||
static async getServerTime() {
|
static async getServerTime() {
|
||||||
return napCatCore.session.getMSFService().getServerTime();
|
return napCatCore.session.getMSFService().getServerTime();
|
||||||
}
|
}
|
||||||
|
static async getServerTimeV2() {
|
||||||
|
return NTEventDispatch.CallNoListenerEvent<() => string>('NodeIKernelMsgService/getServerTime', 5000);
|
||||||
|
}
|
||||||
static async forwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]) {
|
static async forwardMsg(srcPeer: Peer, destPeer: Peer, msgIds: string[]) {
|
||||||
return napCatCore.session.getMsgService().forwardMsg(msgIds, srcPeer, [destPeer], new Map());
|
return napCatCore.session.getMsgService().forwardMsg(msgIds, srcPeer, [destPeer], new Map());
|
||||||
}
|
}
|
||||||
|
@@ -1,11 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
import { NTEventDispatch } from '@/common/utils/EventTask';
|
import { NTEventDispatch } from '@/common/utils/EventTask';
|
||||||
import { GeneralCallResult, NTQQUserApi, napCatCore } from '@/core';
|
import { GeneralCallResult, NTQQFileApi, NTQQUserApi, napCatCore } from '@/core';
|
||||||
// setTimeout(async () => {
|
|
||||||
// let ret = await NTQQSystemApi.getArkJsonCollection('1-2-162b9b42-65b9-4405-a8ed-2e256ec8aa50');
|
|
||||||
// console.log(ret);
|
|
||||||
// }, 20000)
|
|
||||||
export class NTQQSystemApi {
|
export class NTQQSystemApi {
|
||||||
static async hasOtherRunningQQProcess() {
|
static async hasOtherRunningQQProcess() {
|
||||||
return napCatCore.util.hasOtherRunningQQProcess();
|
return napCatCore.util.hasOtherRunningQQProcess();
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { ModifyProfileParams, SelfInfo, User, UserDetailInfoByUin } from '@/core/entities';
|
import { ModifyProfileParams, SelfInfo, User, UserDetailInfoByUin } from '@/core/entities';
|
||||||
import { friends, selfInfo } from '@/core/data';
|
import { friends, groupMembers, selfInfo } from '@/core/data';
|
||||||
import { CacheClassFuncAsync, CacheClassFuncAsyncExtend } from '@/common/utils/helper';
|
import { CacheClassFuncAsync, CacheClassFuncAsyncExtend } from '@/common/utils/helper';
|
||||||
import { napCatCore } from '@/core';
|
import { napCatCore } from '@/core';
|
||||||
import { NodeIKernelProfileListener, ProfileListener } from '@/core/listeners';
|
import { NodeIKernelProfileListener, ProfileListener } from '@/core/listeners';
|
||||||
@@ -143,30 +143,32 @@ export class NTQQUserApi {
|
|||||||
return false;
|
return false;
|
||||||
})
|
})
|
||||||
static async getUidByUin(Uin: string) {
|
static async getUidByUin(Uin: string) {
|
||||||
|
//Uid 接口转
|
||||||
let ret = await NTEventDispatch.CallNoListenerEvent
|
let ret = await NTEventDispatch.CallNoListenerEvent
|
||||||
<(Uin: string[]) => Promise<{ uidInfo: Map<string, string> }>>(
|
<(Uin: string[]) => Promise<{ uidInfo: Map<string, string> }>>(
|
||||||
'NodeIKernelUixConvertService/getUid',
|
'NodeIKernelUixConvertService/getUid',
|
||||||
5000,
|
5000,
|
||||||
[Uin]
|
[Uin]
|
||||||
);
|
);
|
||||||
let uid = ret.uidInfo.get(Uin); //通过QQ默认方式转换
|
let uid = ret.uidInfo.get(Uin);
|
||||||
|
// Uid 好友转
|
||||||
if (!uid) {
|
if (!uid) {
|
||||||
Array.from(friends.values()).forEach((t) => {
|
Array.from(friends.values()).forEach((t) => {
|
||||||
if (t.uin == Uin) {
|
if (t.uin == Uin) {
|
||||||
//logDebug('getUidByUin', t.uid, t.uin, Uin);
|
|
||||||
uid = t.uid;
|
uid = t.uid;
|
||||||
}
|
}
|
||||||
//console.log(t.uid, t.uin, Uin);
|
|
||||||
});
|
});
|
||||||
//uid = Array.from(friends.values()).find((t) => { t.uin == Uin })?.uid; // 从NC维护的QQ Buddy缓存 转换
|
|
||||||
}
|
}
|
||||||
|
//Uid 群友列表转
|
||||||
// if (!uid) {
|
if (!uid) {
|
||||||
// uid = (await NTQQFriendApi.getFriends(false)).find((t) => { t.uin == Uin })?.uid; //从QQ Native 缓存转换 方法一
|
for (let groupMembersList of groupMembers.values()) {
|
||||||
// }
|
for (let GroupMember of groupMembersList.values()) {
|
||||||
// if (!uid) {
|
if (GroupMember.uin == Uin) {
|
||||||
// uid = (await NTQQFriendApi.getFriends(true)).find((t) => { t.uin == Uin })?.uid; //从QQ Native 非缓存转换 方法二
|
uid = GroupMember.uid;
|
||||||
// }
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!uid) {
|
if (!uid) {
|
||||||
let unveifyUid = (await NTQQUserApi.getUserDetailInfoByUin(Uin)).info.uid;//从QQ Native 特殊转换 方法三
|
let unveifyUid = (await NTQQUserApi.getUserDetailInfoByUin(Uin)).info.uid;//从QQ Native 特殊转换 方法三
|
||||||
if (unveifyUid.indexOf("*") == -1) {
|
if (unveifyUid.indexOf("*") == -1) {
|
||||||
|
@@ -56,21 +56,23 @@ export enum ElementType {
|
|||||||
RECOMMENDEDMSG = 43,
|
RECOMMENDEDMSG = 43,
|
||||||
ACTIONBAR = 44
|
ACTIONBAR = 44
|
||||||
}
|
}
|
||||||
|
export interface ActionBarElement {
|
||||||
|
rows: InlineKeyboardRow[];
|
||||||
|
botAppid: string;
|
||||||
|
}
|
||||||
export interface SendActionBarElement {
|
export interface SendActionBarElement {
|
||||||
elementType: ElementType.ACTIONBAR;
|
elementType: ElementType.ACTIONBAR;
|
||||||
elementId: string;
|
elementId: string;
|
||||||
actionBarElement: {
|
actionBarElement: ActionBarElement;
|
||||||
|
}
|
||||||
|
export interface RecommendedMsgElement {
|
||||||
rows: InlineKeyboardRow[];
|
rows: InlineKeyboardRow[];
|
||||||
botAppid: string;
|
botAppid: string;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
export interface SendRecommendedMsgElement {
|
export interface SendRecommendedMsgElement {
|
||||||
elementType: ElementType.RECOMMENDEDMSG;
|
elementType: ElementType.RECOMMENDEDMSG;
|
||||||
elementId: string;
|
elementId: string;
|
||||||
recommendedMsgElement: {
|
recommendedMsgElement: RecommendedMsgElement;
|
||||||
rows: InlineKeyboardRow[];
|
|
||||||
botAppid: string;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
export interface InlineKeyboardButton {
|
export interface InlineKeyboardButton {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -93,20 +95,18 @@ export interface TofuElementContent {
|
|||||||
color: string;
|
color: string;
|
||||||
tittle: string;
|
tittle: string;
|
||||||
}
|
}
|
||||||
export interface SendTaskTopMsgElement {
|
export interface TaskTopMsgElement {
|
||||||
elementType: ElementType.TASKTOPMSG;
|
|
||||||
elementId: string;
|
|
||||||
taskTopMsgElement: {
|
|
||||||
msgTitle: string;
|
msgTitle: string;
|
||||||
msgSummary: string;
|
msgSummary: string;
|
||||||
iconUrl: string;
|
iconUrl: string;
|
||||||
topMsgType: number;
|
topMsgType: number;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
export interface SendTofuRecordElement {
|
export interface SendTaskTopMsgElement {
|
||||||
elementType: ElementType.TOFURECORD;
|
elementType: ElementType.TASKTOPMSG;
|
||||||
elementId: string;
|
elementId: string;
|
||||||
tofuRecordElement: {
|
taskTopMsgElement: TaskTopMsgElement;
|
||||||
|
}
|
||||||
|
export interface TofuRecordElement {
|
||||||
type: number;
|
type: number;
|
||||||
busiid: string;
|
busiid: string;
|
||||||
busiuuid: string;
|
busiuuid: string;
|
||||||
@@ -121,12 +121,14 @@ export interface SendTofuRecordElement {
|
|||||||
dependedmsgid: string;
|
dependedmsgid: string;
|
||||||
msgtime: string;
|
msgtime: string;
|
||||||
onscreennotify: boolean;
|
onscreennotify: boolean;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
export interface SendFaceBubbleElement {
|
export interface SendTofuRecordElement {
|
||||||
elementType: ElementType.FACEBUBBLE;
|
elementType: ElementType.TOFURECORD;
|
||||||
elementId: string;
|
elementId: string;
|
||||||
faceBubbleElement: {
|
tofuRecordElement: TofuRecordElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FaceBubbleElement {
|
||||||
faceCount: number;
|
faceCount: number;
|
||||||
faceSummary: string;
|
faceSummary: string;
|
||||||
faceFlag: number;
|
faceFlag: number;
|
||||||
@@ -140,20 +142,25 @@ export interface SendFaceBubbleElement {
|
|||||||
compatibleText: string;
|
compatibleText: string;
|
||||||
text: string;
|
text: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export interface SendFaceBubbleElement {
|
||||||
|
elementType: ElementType.FACEBUBBLE;
|
||||||
|
elementId: string;
|
||||||
|
faceBubbleElement: FaceBubbleElement;
|
||||||
|
|
||||||
}
|
}
|
||||||
export interface SendavRecordElement {
|
export interface AvRecordElement {
|
||||||
elementType: ElementType.AVRECORD;
|
|
||||||
elementId: string;
|
|
||||||
avRecordElement: {
|
|
||||||
type: number;
|
type: number;
|
||||||
time: string;
|
time: string;
|
||||||
text: string;
|
text: string;
|
||||||
mainType: number;
|
mainType: number;
|
||||||
hasRead: boolean;
|
hasRead: boolean;
|
||||||
extraType: number;
|
extraType: number;
|
||||||
}
|
}
|
||||||
|
export interface SendavRecordElement {
|
||||||
|
elementType: ElementType.AVRECORD;
|
||||||
|
elementId: string;
|
||||||
|
avRecordElement: AvRecordElement;
|
||||||
}
|
}
|
||||||
export interface YoloUserInfo {
|
export interface YoloUserInfo {
|
||||||
uid: string;
|
uid: string;
|
||||||
@@ -170,37 +177,40 @@ export interface SendInlineKeyboardElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
export interface YoloGameResultElement {
|
||||||
|
UserInfo: YoloUserInfo[];
|
||||||
|
}
|
||||||
export interface SendYoloGameResultElement {
|
export interface SendYoloGameResultElement {
|
||||||
elementType: ElementType.YOLOGAMERESULT;
|
elementType: ElementType.YOLOGAMERESULT;
|
||||||
yoloGameResultElement: {
|
yoloGameResultElement: YoloGameResultElement
|
||||||
UserInfo: YoloUserInfo[];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
export interface SendGiphyElement {
|
export interface GiphyElement {
|
||||||
elementType: ElementType.GIPHY;
|
|
||||||
elementId: string;
|
|
||||||
giphyElement: {
|
|
||||||
id: string;
|
id: string;
|
||||||
isClip: boolean;
|
isClip: boolean;
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
}
|
}
|
||||||
|
export interface SendGiphyElement {
|
||||||
|
elementType: ElementType.GIPHY;
|
||||||
|
elementId: string;
|
||||||
|
giphyElement: GiphyElement;
|
||||||
}
|
}
|
||||||
export interface SendWalletElement {
|
export interface SendWalletElement {
|
||||||
elementType: ElementType.UNKNOWN;//不做 设置位置
|
elementType: ElementType.UNKNOWN;//不做 设置位置
|
||||||
elementId: string;
|
elementId: string;
|
||||||
walletElement: {}
|
walletElement: {}
|
||||||
}
|
}
|
||||||
export interface SendCalendarElement {
|
export interface CalendarElement {
|
||||||
elementType: ElementType.CALENDAR;
|
|
||||||
elementId: string;
|
|
||||||
calendarElement: {
|
|
||||||
summary: string;
|
summary: string;
|
||||||
msg: string;
|
msg: string;
|
||||||
expireTimeMs: string;
|
expireTimeMs: string;
|
||||||
schemaType: number;
|
schemaType: number;
|
||||||
schema: string
|
schema: string
|
||||||
}
|
}
|
||||||
|
export interface SendCalendarElement {
|
||||||
|
elementType: ElementType.CALENDAR;
|
||||||
|
elementId: string;
|
||||||
|
calendarElement: CalendarElement;
|
||||||
}
|
}
|
||||||
export interface SendliveGiftElement {
|
export interface SendliveGiftElement {
|
||||||
elementType: ElementType.LIVEGIFT;
|
elementType: ElementType.LIVEGIFT;
|
||||||
@@ -252,32 +262,18 @@ export enum PicSubType {
|
|||||||
export interface SendPicElement {
|
export interface SendPicElement {
|
||||||
elementType: ElementType.PIC;
|
elementType: ElementType.PIC;
|
||||||
elementId: string;
|
elementId: string;
|
||||||
picElement: {
|
picElement: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 ReplyElement {
|
||||||
export interface SendReplyElement {
|
|
||||||
elementType: ElementType.REPLY;
|
|
||||||
elementId: string;
|
|
||||||
replyElement: {
|
|
||||||
replayMsgSeq: string;
|
replayMsgSeq: string;
|
||||||
replayMsgId: string;
|
replayMsgId: string;
|
||||||
senderUin: string;
|
senderUin: string;
|
||||||
senderUinStr: string;
|
senderUinStr: string;
|
||||||
}
|
}
|
||||||
|
export interface SendReplyElement {
|
||||||
|
elementType: ElementType.REPLY;
|
||||||
|
elementId: string;
|
||||||
|
replyElement: ReplyElement
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SendFaceElement {
|
export interface SendFaceElement {
|
||||||
@@ -293,10 +289,11 @@ export interface SendMarketFaceElement {
|
|||||||
export interface SendstructLongMsgElement {
|
export interface SendstructLongMsgElement {
|
||||||
elementType: ElementType.STRUCTLONGMSG;
|
elementType: ElementType.STRUCTLONGMSG;
|
||||||
elementId: string;
|
elementId: string;
|
||||||
structLongMsgElement: {
|
structLongMsgElement: StructLongMsgElement;
|
||||||
|
}
|
||||||
|
export interface StructLongMsgElement {
|
||||||
xmlContent: string;
|
xmlContent: string;
|
||||||
resId: string;
|
resId: string;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
export interface SendactionBarElement {
|
export interface SendactionBarElement {
|
||||||
elementType: ElementType.ACTIONBAR;
|
elementType: ElementType.ACTIONBAR;
|
||||||
@@ -306,13 +303,14 @@ export interface SendactionBarElement {
|
|||||||
botAppid: string;
|
botAppid: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export interface ShareLocationElement {
|
||||||
|
text: string;
|
||||||
|
ext: string;
|
||||||
|
}
|
||||||
export interface sendShareLocationElement {
|
export interface sendShareLocationElement {
|
||||||
elementType: ElementType.SHARELOCATION;
|
elementType: ElementType.SHARELOCATION;
|
||||||
elementId: string;
|
elementId: string;
|
||||||
shareLocationElement: {
|
shareLocationElement?: ShareLocationElement;
|
||||||
text: string;
|
|
||||||
ext: string;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FileElement {
|
export interface FileElement {
|
||||||
@@ -356,10 +354,51 @@ export interface SendMarkdownElement {
|
|||||||
elementId: string;
|
elementId: string;
|
||||||
markdownElement: MarkdownElement;
|
markdownElement: MarkdownElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SendMessageElement = SendTextElement | SendPttElement |
|
export type SendMessageElement = SendTextElement | SendPttElement |
|
||||||
SendPicElement | SendReplyElement | SendFaceElement | SendMarketFaceElement | SendFileElement | SendVideoElement | SendArkElement | SendMarkdownElement | sendShareLocationElement
|
SendPicElement | SendReplyElement | SendFaceElement | SendMarketFaceElement | SendFileElement |
|
||||||
|
SendVideoElement | SendArkElement | SendMarkdownElement | sendShareLocationElement;
|
||||||
|
|
||||||
|
export interface TextElement {
|
||||||
|
content: string;
|
||||||
|
atType: number;
|
||||||
|
atUid: string;
|
||||||
|
atTinyId: string;
|
||||||
|
atNtUid: string;
|
||||||
|
}
|
||||||
|
export interface MessageElement {
|
||||||
|
elementType: ElementType,
|
||||||
|
elementId: string,
|
||||||
|
extBufForUI: string,//"0x",
|
||||||
|
textElement?: TextElement;
|
||||||
|
faceElement?: FaceElement,
|
||||||
|
marketFaceElement?: MarkdownElement,
|
||||||
|
replyElement?: ReplyElement,
|
||||||
|
picElement?: PicElement,
|
||||||
|
pttElement?: PttElement,
|
||||||
|
videoElement?: VideoElement,
|
||||||
|
grayTipElement?: GrayTipElement,
|
||||||
|
arkElement?: ArkElement,
|
||||||
|
fileElement?: FileElement,
|
||||||
|
liveGiftElement?: null,
|
||||||
|
markdownElement?: MarkdownElement,
|
||||||
|
structLongMsgElement?: StructLongMsgElement,
|
||||||
|
multiForwardMsgElement?: MultiForwardMsgElement,
|
||||||
|
giphyElement?: GiphyElement,
|
||||||
|
walletElement?: null,
|
||||||
|
inlineKeyboardElement?: InlineKeyboardElement,
|
||||||
|
textGiftElement?: null,//????
|
||||||
|
calendarElement?: CalendarElement,
|
||||||
|
yoloGameResultElement?: YoloGameResultElement,
|
||||||
|
avRecordElement?: AvRecordElement,
|
||||||
|
structMsgElement?: null,
|
||||||
|
faceBubbleElement?: FaceBubbleElement,
|
||||||
|
shareLocationElement?: ShareLocationElement,
|
||||||
|
tofuRecordElement?: TofuRecordElement,
|
||||||
|
taskTopMsgElement?: TaskTopMsgElement,
|
||||||
|
recommendedMsgElement?: RecommendedMsgElement,
|
||||||
|
actionBarElement?:ActionBarElement
|
||||||
|
|
||||||
|
}
|
||||||
export enum AtType {
|
export enum AtType {
|
||||||
notAt = 0,
|
notAt = 0,
|
||||||
atAll = 1,
|
atAll = 1,
|
||||||
@@ -450,18 +489,23 @@ export const IMAGE_HTTP_HOST = 'https://gchat.qpic.cn';
|
|||||||
export const IMAGE_HTTP_HOST_NT = 'https://multimedia.nt.qq.com.cn';
|
export const IMAGE_HTTP_HOST_NT = 'https://multimedia.nt.qq.com.cn';
|
||||||
|
|
||||||
export interface PicElement {
|
export interface PicElement {
|
||||||
picSubType?: number;
|
md5HexStr?: string;
|
||||||
originImageUrl: string; // http url, 没有host,host是https://gchat.qpic.cn/, 带download参数的是https://multimedia.nt.qq.com.cn
|
fileSize: number | string;//number
|
||||||
originImageMd5?: string;
|
|
||||||
sourcePath: string; // 图片本地路径
|
|
||||||
thumbPath: Map<number, string>;
|
|
||||||
picWidth: number;
|
picWidth: number;
|
||||||
picHeight: number;
|
picHeight: number;
|
||||||
fileSize: number;
|
|
||||||
fileName: string;
|
fileName: string;
|
||||||
|
sourcePath: string;
|
||||||
|
original: boolean;
|
||||||
|
picType: PicType;
|
||||||
|
picSubType?: PicSubType;
|
||||||
fileUuid: string;
|
fileUuid: string;
|
||||||
md5HexStr?: string;
|
fileSubId: string;
|
||||||
}
|
thumbFileSize: number;
|
||||||
|
summary: string;
|
||||||
|
thumbPath: Map<number, string>;
|
||||||
|
originImageMd5?: string;
|
||||||
|
originImageUrl?: string; // http url, 没有host,host是https://gchat.qpic.cn/, 带download参数的是https://multimedia.nt.qq.com.cn
|
||||||
|
};
|
||||||
|
|
||||||
export enum GrayTipElementSubType {
|
export enum GrayTipElementSubType {
|
||||||
INVITE_NEW_MEMBER = 12,
|
INVITE_NEW_MEMBER = 12,
|
||||||
@@ -708,10 +752,12 @@ export interface RawMessage {
|
|||||||
chatType: ChatType;
|
chatType: ChatType;
|
||||||
sendStatus?: number; // 消息状态,别人发的2是已撤回,自己发的2是已发送
|
sendStatus?: number; // 消息状态,别人发的2是已撤回,自己发的2是已发送
|
||||||
recallTime: string; // 撤回时间, "0"是没有撤回
|
recallTime: string; // 撤回时间, "0"是没有撤回
|
||||||
|
records: RawMessage[];
|
||||||
elements: {
|
elements: {
|
||||||
elementId: string;
|
elementId: string;
|
||||||
elementType: ElementType;
|
elementType: ElementType;
|
||||||
replyElement: {
|
replyElement: {
|
||||||
|
sourceMsgIdInRecords: string;
|
||||||
senderUid: string; // 原消息发送者QQ号
|
senderUid: string; // 原消息发送者QQ号
|
||||||
sourceMsgIsIncPic: boolean; // 原消息是否有图片
|
sourceMsgIsIncPic: boolean; // 原消息是否有图片
|
||||||
sourceMsgText: string;
|
sourceMsgText: string;
|
||||||
|
@@ -226,7 +226,7 @@ export interface IKernelMsgListener {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NodeIKernelMsgListener {
|
export interface NodeIKernelMsgListener extends IKernelMsgListener {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||||
new(listener: IKernelMsgListener): NodeIKernelMsgListener;
|
new(listener: IKernelMsgListener): NodeIKernelMsgListener;
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { ElementType, Peer, RawMessage, SendMessageElement } from '@/core/entities';
|
import { ElementType, MessageElement, Peer, RawMessage, SendMessageElement } from '@/core/entities';
|
||||||
import { NodeIKernelMsgListener } from '@/core/listeners/NodeIKernelMsgListener';
|
import { NodeIKernelMsgListener } from '@/core/listeners/NodeIKernelMsgListener';
|
||||||
import { GeneralCallResult } from '@/core/services/common';
|
import { GeneralCallResult } from '@/core/services/common';
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ export interface NodeIKernelMsgService {
|
|||||||
|
|
||||||
cancelSendMsg(...args: unknown[]): unknown;
|
cancelSendMsg(...args: unknown[]): unknown;
|
||||||
|
|
||||||
switchToOfflineSendMsg(...args: unknown[]): unknown;
|
switchToOfflineSendMsg(peer: Peer, MsgId: string): unknown;
|
||||||
|
|
||||||
reqToOfflineSendMsg(...args: unknown[]): unknown;
|
reqToOfflineSendMsg(...args: unknown[]): unknown;
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ export interface NodeIKernelMsgService {
|
|||||||
|
|
||||||
addLocalTofuRecordMsg(...args: unknown[]): unknown;
|
addLocalTofuRecordMsg(...args: unknown[]): unknown;
|
||||||
|
|
||||||
addLocalRecordMsg(Peer: Peer, msgId: string, rawMessage: RawMessage, attr: Array<any> | number, front: boolean): Promise<unknown>;
|
addLocalRecordMsg(Peer: Peer, msgId: string, ele: MessageElement, attr: Array<any> | number, front: boolean): Promise<unknown>;
|
||||||
|
|
||||||
deleteMsg(...args: unknown[]): unknown;
|
deleteMsg(...args: unknown[]): unknown;
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ export interface NodeIKernelMsgService {
|
|||||||
|
|
||||||
getLastMessageList(peer: Peer[]): Promise<unknown>;
|
getLastMessageList(peer: Peer[]): Promise<unknown>;
|
||||||
|
|
||||||
getAioFirstViewLatestMsgs(peer: Peer, unknown: number): unknown;
|
getAioFirstViewLatestMsgs(peer: Peer, num: number): unknown;
|
||||||
|
|
||||||
getMsgs(peer: Peer, msgId: string, count: unknown, queryOrder: boolean): Promise<unknown>;
|
getMsgs(peer: Peer, msgId: string, count: unknown, queryOrder: boolean): Promise<unknown>;
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@ export interface NodeIKernelMsgService {
|
|||||||
// this.$clientSeq = j3;
|
// this.$clientSeq = j3;
|
||||||
// this.$cnt = i2;
|
// this.$cnt = i2;
|
||||||
|
|
||||||
getMsgsWithMsgTimeAndClientSeqForC2C(...args: unknown[]): Promise<unknown>;
|
getMsgsWithMsgTimeAndClientSeqForC2C(...args: unknown[]): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
||||||
|
|
||||||
getMsgsWithStatus(params: {
|
getMsgsWithStatus(params: {
|
||||||
peer: Peer
|
peer: Peer
|
||||||
@@ -164,9 +164,9 @@ export interface NodeIKernelMsgService {
|
|||||||
queryOrder: boolean
|
queryOrder: boolean
|
||||||
isIncludeSelf: boolean
|
isIncludeSelf: boolean
|
||||||
appid: unknown
|
appid: unknown
|
||||||
}): Promise<unknown>;
|
}): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
||||||
|
|
||||||
getMsgsBySeqRange(peer: Peer, startSeq: string, endSeq: string): Promise<unknown>;
|
getMsgsBySeqRange(peer: Peer, startSeq: string, endSeq: string): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
||||||
|
|
||||||
getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, unknownArg: boolean): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, unknownArg: boolean): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
||||||
|
|
||||||
@@ -174,9 +174,9 @@ export interface NodeIKernelMsgService {
|
|||||||
|
|
||||||
getRecallMsgsByMsgId(peer: Peer, MsgId: string[]): Promise<unknown>;
|
getRecallMsgsByMsgId(peer: Peer, MsgId: string[]): Promise<unknown>;
|
||||||
|
|
||||||
getMsgsBySeqList(peer: Peer, seqList: string[]): Promise<unknown>;
|
getMsgsBySeqList(peer: Peer, seqList: string[]): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
||||||
|
|
||||||
getSingleMsg(Peer: Peer, msgSeq: string): unknown;
|
getSingleMsg(Peer: Peer, msgSeq: string): Promise<GeneralCallResult & { msgList: RawMessage[] }>;
|
||||||
|
|
||||||
getSourceOfReplyMsg(...args: unknown[]): unknown;
|
getSourceOfReplyMsg(...args: unknown[]): unknown;
|
||||||
|
|
||||||
@@ -361,7 +361,7 @@ export interface NodeIKernelMsgService {
|
|||||||
|
|
||||||
setGuildTabUserFlag(...args: unknown[]): unknown;
|
setGuildTabUserFlag(...args: unknown[]): unknown;
|
||||||
|
|
||||||
setBuildMode(...args: unknown[]): unknown;
|
setBuildMode(flag: number/*0 1 3*/): unknown;
|
||||||
|
|
||||||
setConfigurationServiceData(...args: unknown[]): unknown;
|
setConfigurationServiceData(...args: unknown[]): unknown;
|
||||||
|
|
||||||
@@ -393,8 +393,35 @@ export interface NodeIKernelMsgService {
|
|||||||
translatePtt2Text(MsgId: string, Peer: {}, MsgElement: {}): unknown;
|
translatePtt2Text(MsgId: string, Peer: {}, MsgElement: {}): unknown;
|
||||||
|
|
||||||
setPttPlayedState(...args: unknown[]): unknown;
|
setPttPlayedState(...args: unknown[]): unknown;
|
||||||
|
// NodeIQQNTWrapperSession fetchFavEmojiList [
|
||||||
fetchFavEmojiList(...args: unknown[]): unknown;
|
// "",
|
||||||
|
// 48,
|
||||||
|
// true,
|
||||||
|
// true
|
||||||
|
// ]
|
||||||
|
fetchFavEmojiList(str: string, num: number, uk1: boolean, uk2: boolean): Promise<GeneralCallResult & {
|
||||||
|
emojiInfoList: Array<{
|
||||||
|
uin: string,
|
||||||
|
emoId: number,
|
||||||
|
emoPath: string,
|
||||||
|
isExist: boolean,
|
||||||
|
resId: string,
|
||||||
|
url: string,
|
||||||
|
md5: string,
|
||||||
|
emoOriginalPath: string,
|
||||||
|
thumbPath: string,
|
||||||
|
RomaingType: string,
|
||||||
|
isAPNG: false,
|
||||||
|
isMarkFace: false,
|
||||||
|
eId: string,
|
||||||
|
epId: string,
|
||||||
|
ocrWord: string,
|
||||||
|
modifyWord: string,
|
||||||
|
exposeNum: number,
|
||||||
|
clickNum: number,
|
||||||
|
desc: string
|
||||||
|
}>
|
||||||
|
}>;
|
||||||
|
|
||||||
addFavEmoji(...args: unknown[]): unknown;
|
addFavEmoji(...args: unknown[]): unknown;
|
||||||
|
|
||||||
@@ -485,7 +512,7 @@ export interface NodeIKernelMsgService {
|
|||||||
|
|
||||||
setMsgEmojiLikes(...args: unknown[]): unknown;
|
setMsgEmojiLikes(...args: unknown[]): unknown;
|
||||||
|
|
||||||
getMsgEmojiLikesList(...args: unknown[]): unknown;
|
getMsgEmojiLikesList(peer: Peer, msgSeq: string, emojiId: string, emojiType: string, cookie: string, bForward: boolean, number: number): Promise<unknown>;
|
||||||
|
|
||||||
setMsgEmojiLikesForRole(...args: unknown[]): unknown;
|
setMsgEmojiLikesForRole(...args: unknown[]): unknown;
|
||||||
|
|
||||||
@@ -513,7 +540,7 @@ export interface NodeIKernelMsgService {
|
|||||||
|
|
||||||
queryFirstRoamMsg(...args: unknown[]): unknown;
|
queryFirstRoamMsg(...args: unknown[]): unknown;
|
||||||
|
|
||||||
fetchLongMsg(...args: unknown[]): unknown;
|
fetchLongMsg(peer: Peer, msgId: string): unknown;
|
||||||
|
|
||||||
fetchLongMsgWithCb(...args: unknown[]): unknown;
|
fetchLongMsgWithCb(...args: unknown[]): unknown;
|
||||||
|
|
||||||
@@ -547,9 +574,9 @@ export interface NodeIKernelMsgService {
|
|||||||
|
|
||||||
deleteReplyDraft(...args: unknown[]): unknown;
|
deleteReplyDraft(...args: unknown[]): unknown;
|
||||||
|
|
||||||
getFirstUnreadAtMsg(...args: unknown[]): unknown;
|
getFirstUnreadAtMsg(peer: Peer): unknown;
|
||||||
|
|
||||||
clearMsgRecords(...args: unknown[]): unknown;//设置已读后调用我觉得比较好 清理记录
|
clearMsgRecords(...args: unknown[]): unknown;//设置已读后调用我觉得比较好 清理记录 现在别了
|
||||||
|
|
||||||
IsExistOldDb(...args: unknown[]): unknown;
|
IsExistOldDb(...args: unknown[]): unknown;
|
||||||
|
|
||||||
@@ -569,7 +596,7 @@ export interface NodeIKernelMsgService {
|
|||||||
|
|
||||||
getCurChatImportStatusByUin(...args: unknown[]): unknown;
|
getCurChatImportStatusByUin(...args: unknown[]): unknown;
|
||||||
|
|
||||||
getDataImportUserLevel(...args: unknown[]): unknown;
|
getDataImportUserLevel(): unknown;
|
||||||
|
|
||||||
getMsgQRCode(...args: unknown[]): unknown;
|
getMsgQRCode(...args: unknown[]): unknown;
|
||||||
|
|
||||||
@@ -624,7 +651,7 @@ export interface NodeIKernelMsgService {
|
|||||||
|
|
||||||
getABatchOfContactMsgBoxInfo(...args: unknown[]): unknown;
|
getABatchOfContactMsgBoxInfo(...args: unknown[]): unknown;
|
||||||
|
|
||||||
insertMsgToMsgBox(...args: unknown[]): unknown;
|
insertMsgToMsgBox(peer: Peer, msgId: string, arg: 2006): unknown;
|
||||||
|
|
||||||
isHitEmojiKeyword(...args: unknown[]): unknown;
|
isHitEmojiKeyword(...args: unknown[]): unknown;
|
||||||
|
|
||||||
@@ -664,7 +691,25 @@ export interface NodeIKernelMsgService {
|
|||||||
|
|
||||||
dataMigrationStopOperation(...args: unknown[]): unknown;
|
dataMigrationStopOperation(...args: unknown[]): unknown;
|
||||||
|
|
||||||
dataMigrationImportMsgPbRecord(...args: unknown[]): unknown;
|
//新的希望
|
||||||
|
dataMigrationImportMsgPbRecord(DataMigrationMsgInfo: Array<{
|
||||||
|
extensionData: string//"Hex"
|
||||||
|
extraData: string //""
|
||||||
|
chatType: number
|
||||||
|
chatUin: string
|
||||||
|
msgType: number
|
||||||
|
msgTime: string
|
||||||
|
msgSeq: string
|
||||||
|
msgRandom: string
|
||||||
|
}>, DataMigrationResourceInfo: {
|
||||||
|
extraData: string
|
||||||
|
filePath: string
|
||||||
|
fileSize: string
|
||||||
|
msgRandom: string
|
||||||
|
msgSeq: string
|
||||||
|
msgSubType: number
|
||||||
|
msgType: number
|
||||||
|
}): unknown;
|
||||||
|
|
||||||
dataMigrationGetResourceLocalDestinyPath(...args: unknown[]): unknown;
|
dataMigrationGetResourceLocalDestinyPath(...args: unknown[]): unknown;
|
||||||
|
|
||||||
|
@@ -1,6 +1,50 @@
|
|||||||
import { GetFileListParam, Peer } from "../entities";
|
import { GetFileListParam, MessageElement, Peer, SendMessageElement } from "../entities";
|
||||||
import { GeneralCallResult } from "./common";
|
import { GeneralCallResult } from "./common";
|
||||||
|
export enum UrlFileDownloadType {
|
||||||
|
KUNKNOWN,
|
||||||
|
KURLFILEDOWNLOADPRIVILEGEICON,
|
||||||
|
KURLFILEDOWNLOADPHOTOWALL,
|
||||||
|
KURLFILEDOWNLOADQZONE,
|
||||||
|
KURLFILEDOWNLOADCOMMON,
|
||||||
|
KURLFILEDOWNLOADINSTALLAPP
|
||||||
|
}
|
||||||
|
export enum RMBizTypeEnum {
|
||||||
|
KUNKNOWN,
|
||||||
|
KC2CFILE,
|
||||||
|
KGROUPFILE,
|
||||||
|
KC2CPIC,
|
||||||
|
KGROUPPIC,
|
||||||
|
KDISCPIC,
|
||||||
|
KC2CVIDEO,
|
||||||
|
KGROUPVIDEO,
|
||||||
|
KC2CPTT,
|
||||||
|
KGROUPPTT,
|
||||||
|
KFEEDCOMMENTPIC,
|
||||||
|
KGUILDFILE,
|
||||||
|
KGUILDPIC,
|
||||||
|
KGUILDPTT,
|
||||||
|
KGUILDVIDEO
|
||||||
|
}
|
||||||
|
export interface CommonFileInfo {
|
||||||
|
bizType: number;
|
||||||
|
chatType: number;
|
||||||
|
elemId: string;
|
||||||
|
favId: string;
|
||||||
|
fileModelId: string;
|
||||||
|
fileName: string;
|
||||||
|
fileSize: string;
|
||||||
|
md5: string;
|
||||||
|
md510m: string;
|
||||||
|
msgId: string;
|
||||||
|
msgTime: string;
|
||||||
|
parent: string;
|
||||||
|
peerUid: string;
|
||||||
|
picThumbPath: Array<string>
|
||||||
|
sha: string;
|
||||||
|
sha3: string;
|
||||||
|
subId: string;
|
||||||
|
uuid: string;
|
||||||
|
}
|
||||||
export interface NodeIKernelRichMediaService {
|
export interface NodeIKernelRichMediaService {
|
||||||
//getVideoPlayUrl(peer, msgId, elemId, videoCodecFormat, VideoRequestWay.KHAND, cb);
|
//getVideoPlayUrl(peer, msgId, elemId, videoCodecFormat, VideoRequestWay.KHAND, cb);
|
||||||
// public enum VideoCodecFormatType {
|
// public enum VideoCodecFormatType {
|
||||||
@@ -46,7 +90,7 @@ export interface NodeIKernelRichMediaService {
|
|||||||
}
|
}
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
getRichMediaFileDir(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
getRichMediaFileDir(elementType: number, downType: number, isTemp: boolean): unknown;
|
||||||
|
|
||||||
// this.senderUid = "";
|
// this.senderUid = "";
|
||||||
// this.peerUid = "";
|
// this.peerUid = "";
|
||||||
@@ -65,16 +109,43 @@ export interface NodeIKernelRichMediaService {
|
|||||||
// this.elem = msgElement;
|
// this.elem = msgElement;
|
||||||
// this.useHttps = num;
|
// this.useHttps = num;
|
||||||
|
|
||||||
getVideoPlayUrlInVisit(arg: unknown): unknown;
|
getVideoPlayUrlInVisit(arg: {
|
||||||
|
downloadType: number,
|
||||||
|
thumbSize: number,
|
||||||
|
msgId: string,
|
||||||
|
msgRandom: string,
|
||||||
|
msgSeq: string,
|
||||||
|
msgTime: string,
|
||||||
|
chatType: number,
|
||||||
|
senderUid: string,
|
||||||
|
peerUid: string,
|
||||||
|
guildId: string,
|
||||||
|
ele: MessageElement,
|
||||||
|
useHttps: boolean
|
||||||
|
}): Promise<unknown>;
|
||||||
|
|
||||||
isFileExpired(arg: unknown): unknown;
|
//arg双端number
|
||||||
|
isFileExpired(arg: number): unknown;
|
||||||
|
|
||||||
deleteGroupFolder(GroupCode: string, FolderId: string): Promise<GeneralCallResult & { groupFileCommonResult: { retCode: number, retMsg: string, clientWording: string } }>;
|
deleteGroupFolder(GroupCode: string, FolderId: string): Promise<GeneralCallResult & { groupFileCommonResult: { retCode: number, retMsg: string, clientWording: string } }>;
|
||||||
|
|
||||||
//参数与getVideoPlayUrlInVisit一样
|
//参数与getVideoPlayUrlInVisit一样
|
||||||
downloadRichMediaInVisit(arg: unknown): unknown;
|
downloadRichMediaInVisit(arg: {
|
||||||
|
downloadType: number,
|
||||||
downloadFileForModelId(peer: Peer, arg: unknown[], arg3: string): unknown;
|
thumbSize: number,
|
||||||
|
msgId: string,
|
||||||
|
msgRandom: string,
|
||||||
|
msgSeq: string,
|
||||||
|
msgTime: string,
|
||||||
|
chatType: number,
|
||||||
|
senderUid: string,
|
||||||
|
peerUid: string,
|
||||||
|
guildId: string,
|
||||||
|
ele: MessageElement,
|
||||||
|
useHttps: boolean
|
||||||
|
}): unknown;
|
||||||
|
//arg3为“”
|
||||||
|
downloadFileForModelId(peer: Peer, ModelId: string[], arg3: string): unknown;
|
||||||
//第三个参数 Array<Type>
|
//第三个参数 Array<Type>
|
||||||
// this.fileId = "";
|
// this.fileId = "";
|
||||||
// this.fileName = "";
|
// this.fileName = "";
|
||||||
@@ -83,15 +154,20 @@ export interface NodeIKernelRichMediaService {
|
|||||||
// this.fileSize = j2;
|
// this.fileSize = j2;
|
||||||
// this.fileModelId = j3;
|
// this.fileModelId = j3;
|
||||||
|
|
||||||
downloadFileForFileUuid(peer: Peer, arg1: string, arg3: unknown[]): unknown;
|
downloadFileForFileUuid(peer: Peer, uuid: string, arg3: {
|
||||||
|
fileId: string,
|
||||||
|
fileName: string,
|
||||||
|
fileSize: string,
|
||||||
|
fileModelId: string
|
||||||
|
}[]): Promise<unknown>;
|
||||||
|
|
||||||
downloadFileByUrlList(arg1: unknown, arg2: unknown): unknown;
|
downloadFileByUrlList(fileDownloadTyp: UrlFileDownloadType, urlList: Array<string>): unknown;
|
||||||
|
|
||||||
downloadFileForFileInfo(arg1: unknown, arg2: unknown): unknown;
|
downloadFileForFileInfo(fileInfo: CommonFileInfo[], savePath: string): unknown;
|
||||||
|
|
||||||
createGroupFolder(GroupCode: string, FolderName: string): Promise<GeneralCallResult & { resultWithGroupItem: { result: any, groupItem: Array<any> } }>
|
createGroupFolder(GroupCode: string, FolderName: string): Promise<GeneralCallResult & { resultWithGroupItem: { result: any, groupItem: Array<any> } }>
|
||||||
|
|
||||||
downloadFile(arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown): unknown;
|
downloadFile(commonFile: CommonFileInfo, arg2: unknown, arg3: unknown, savePath: string): unknown;
|
||||||
|
|
||||||
createGroupFolder(arg1: unknown, arg2: unknown): unknown;
|
createGroupFolder(arg1: unknown, arg2: unknown): unknown;
|
||||||
|
|
||||||
@@ -168,13 +244,25 @@ export interface NodeIKernelRichMediaService {
|
|||||||
|
|
||||||
cancelSearcheGroupFile(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
cancelSearcheGroupFile(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
||||||
|
|
||||||
onlyDownloadFile(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
onlyDownloadFile(peer: Peer, arg2: unknown, arg3: Array<{
|
||||||
|
fileId: string,
|
||||||
|
fileName: string,
|
||||||
|
fileSize: string,
|
||||||
|
fileModelId: string
|
||||||
|
}
|
||||||
|
>): unknown;
|
||||||
|
|
||||||
onlyUploadFile(arg1: unknown, arg2: unknown): unknown;
|
onlyUploadFile(arg1: unknown, arg2: unknown): unknown;
|
||||||
|
|
||||||
isExtraLargePic(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
isExtraLargePic(arg1: unknown, arg2: unknown, arg3: unknown): unknown;
|
||||||
|
|
||||||
uploadRMFileWithoutMsg(arg: unknown): unknown;
|
uploadRMFileWithoutMsg(arg: {
|
||||||
|
bizType: RMBizTypeEnum,
|
||||||
|
filePath: string,
|
||||||
|
peerUid: string,
|
||||||
|
transferId: string
|
||||||
|
useNTV2: string
|
||||||
|
}): Promise<unknown>;
|
||||||
|
|
||||||
isNull(): boolean;
|
isNull(): boolean;
|
||||||
}
|
}
|
@@ -1,79 +1,129 @@
|
|||||||
|
import { ChatType } from "../entities";
|
||||||
|
|
||||||
export interface NodeIKernelSearchService {
|
export interface NodeIKernelSearchService {
|
||||||
addKernelSearchListenerr(...args: any[]): unknown;// needs 1 arguments
|
addKernelSearchListener(...args: any[]): unknown;// needs 1 arguments
|
||||||
|
|
||||||
removeKernelSearchListenerr(...args: any[]): unknown;// needs 1 arguments
|
removeKernelSearchListener(...args: any[]): unknown;// needs 1 arguments
|
||||||
|
|
||||||
searchStrangerr(...args: any[]): unknown;// needs 3 arguments
|
searchStranger(...args: any[]): unknown;// needs 3 arguments
|
||||||
|
|
||||||
searchGroupr(...args: any[]): unknown;// needs 1 arguments
|
searchGroup(...args: any[]): unknown;// needs 1 arguments
|
||||||
|
|
||||||
searchLocalInfor(...args: any[]): unknown;// needs 2 arguments
|
searchLocalInfo(keywords: string, unknown: number/*4*/): unknown;
|
||||||
|
|
||||||
cancelSearchLocalInfor(...args: any[]): unknown;// needs 3 arguments
|
cancelSearchLocalInfo(...args: any[]): unknown;// needs 3 arguments
|
||||||
|
|
||||||
searchBuddyChatInfor(...args: any[]): unknown;// needs 2 arguments
|
searchBuddyChatInfo(...args: any[]): unknown;// needs 2 arguments
|
||||||
|
|
||||||
searchMoreBuddyChatInfor(...args: any[]): unknown;// needs 1 arguments
|
searchMoreBuddyChatInfo(...args: any[]): unknown;// needs 1 arguments
|
||||||
|
|
||||||
cancelSearchBuddyChatInfor(...args: any[]): unknown;// needs 3 arguments
|
cancelSearchBuddyChatInfo(...args: any[]): unknown;// needs 3 arguments
|
||||||
|
|
||||||
searchContactr(...args: any[]): unknown;// needs 2 arguments
|
searchContact(...args: any[]): unknown;// needs 2 arguments
|
||||||
|
|
||||||
searchMoreContactr(...args: any[]): unknown;// needs 1 arguments
|
searchMoreContact(...args: any[]): unknown;// needs 1 arguments
|
||||||
|
|
||||||
cancelSearchContactr(...args: any[]): unknown;// needs 3 arguments
|
cancelSearchContact(...args: any[]): unknown;// needs 3 arguments
|
||||||
|
|
||||||
searchGroupChatInfor(...args: any[]): unknown;// needs 3 arguments
|
searchGroupChatInfo(...args: any[]): unknown;// needs 3 arguments
|
||||||
|
|
||||||
resetSearchGroupChatInfoSortTyper(...args: any[]): unknown;// needs 3 arguments
|
resetSearchGroupChatInfoSortType(...args: any[]): unknown;// needs 3 arguments
|
||||||
|
|
||||||
resetSearchGroupChatInfoFilterMembersr(...args: any[]): unknown;// needs 3 arguments
|
resetSearchGroupChatInfoFilterMembers(...args: any[]): unknown;// needs 3 arguments
|
||||||
|
|
||||||
searchMoreGroupChatInfor(...args: any[]): unknown;// needs 1 arguments
|
searchMoreGroupChatInfo(...args: any[]): unknown;// needs 1 arguments
|
||||||
|
|
||||||
cancelSearchGroupChatInfor(...args: any[]): unknown;// needs 3 arguments
|
cancelSearchGroupChatInfo(...args: any[]): unknown;// needs 3 arguments
|
||||||
|
|
||||||
searchChatsWithKeywordsr(...args: any[]): unknown;// needs 3 arguments
|
searchChatsWithKeywords(...args: any[]): unknown;// needs 3 arguments
|
||||||
|
|
||||||
searchMoreChatsWithKeywordsr(...args: any[]): unknown;// needs 1 arguments
|
searchMoreChatsWithKeywords(...args: any[]): unknown;// needs 1 arguments
|
||||||
|
|
||||||
cancelSearchChatsWithKeywordsr(...args: any[]): unknown;// needs 3 arguments
|
cancelSearchChatsWithKeywords(...args: any[]): unknown;// needs 3 arguments
|
||||||
|
|
||||||
searchChatMsgsr(...args: any[]): unknown;// needs 2 arguments
|
searchChatMsgs(...args: any[]): unknown;// needs 2 arguments
|
||||||
|
|
||||||
searchMoreChatMsgsr(...args: any[]): unknown;// needs 1 arguments
|
searchMoreChatMsgs(...args: any[]): unknown;// needs 1 arguments
|
||||||
|
|
||||||
cancelSearchChatMsgsr(...args: any[]): unknown;// needs 3 arguments
|
cancelSearchChatMsgs(...args: any[]): unknown;// needs 3 arguments
|
||||||
|
|
||||||
searchMsgWithKeywordsr(...args: any[]): unknown;// needs 2 arguments
|
searchMsgWithKeywords(...args: any[]): unknown;// needs 2 arguments
|
||||||
|
|
||||||
searchMoreMsgWithKeywordsr(...args: any[]): unknown;// needs 1 arguments
|
searchMoreMsgWithKeywords(...args: any[]): unknown;// needs 1 arguments
|
||||||
|
|
||||||
cancelSearchMsgWithKeywords(...args: any[]): unknown;// needs 3 arguments
|
cancelSearchMsgWithKeywords(...args: any[]): unknown;// needs 3 arguments
|
||||||
|
|
||||||
searchFileWithKeywords(keywords: string[], source: number): Promise<unknown>;// needs 2 arguments
|
searchFileWithKeywords(keywords: string[], source: number): Promise<string>;// needs 2 arguments
|
||||||
|
|
||||||
searchMoreFileWithKeywordsr(...args: any[]): unknown;// needs 1 arguments
|
searchMoreFileWithKeywords(...args: any[]): unknown;// needs 1 arguments
|
||||||
|
|
||||||
cancelSearchFileWithKeywordsr(...args: any[]): unknown;// needs 3 arguments
|
cancelSearchFileWithKeywords(...args: any[]): unknown;// needs 3 arguments
|
||||||
|
|
||||||
searchAtMeChatsr(...args: any[]): unknown;// needs 3 arguments
|
searchAtMeChats(...args: any[]): unknown;// needs 3 arguments
|
||||||
|
|
||||||
searchMoreAtMeChatsr(...args: any[]): unknown;// needs 1 arguments
|
searchMoreAtMeChats(...args: any[]): unknown;// needs 1 arguments
|
||||||
|
|
||||||
cancelSearchAtMeChatsr(...args: any[]): unknown;// needs 3 arguments
|
cancelSearchAtMeChats(...args: any[]): unknown;// needs 3 arguments
|
||||||
|
|
||||||
searchChatAtMeMsgsr(...args: any[]): unknown;// needs 1 arguments
|
searchChatAtMeMsgs(...args: any[]): unknown;// needs 1 arguments
|
||||||
|
|
||||||
searchMoreChatAtMeMsgsr(...args: any[]): unknown;// needs 1 arguments
|
searchMoreChatAtMeMsgs(...args: any[]): unknown;// needs 1 arguments
|
||||||
|
|
||||||
cancelSearchChatAtMeMsgsr(...args: any[]): unknown;// needs 3 arguments
|
cancelSearchChatAtMeMsgs(...args: any[]): unknown;// needs 3 arguments
|
||||||
|
|
||||||
addSearchHistoryr(...args: any[]): unknown;// needs 1 arguments
|
addSearchHistory(param: {
|
||||||
|
type: number,//4
|
||||||
|
contactList: [],
|
||||||
|
id: number,//-1
|
||||||
|
groupInfos: [],
|
||||||
|
msgs: [],
|
||||||
|
fileInfos: [
|
||||||
|
{
|
||||||
|
chatType: ChatType,
|
||||||
|
buddyChatInfo: Array<{ category_name: string, peerUid: string, peerUin: string, remark: string }>,
|
||||||
|
discussChatInfo: [],
|
||||||
|
groupChatInfo: Array<
|
||||||
|
{
|
||||||
|
groupCode: string,
|
||||||
|
isConf: boolean,
|
||||||
|
hasModifyConfGroupFace: boolean,
|
||||||
|
hasModifyConfGroupName: boolean,
|
||||||
|
groupName: string,
|
||||||
|
remark: string
|
||||||
|
}>
|
||||||
|
,
|
||||||
|
dataLineChatInfo: [],
|
||||||
|
tmpChatInfo: [],
|
||||||
|
msgId: string,
|
||||||
|
msgSeq: string,
|
||||||
|
msgTime: string,
|
||||||
|
senderUid: string,
|
||||||
|
senderNick: string,
|
||||||
|
senderRemark: string,
|
||||||
|
senderCard: string,
|
||||||
|
elemId: string,
|
||||||
|
elemType: string,//3
|
||||||
|
fileSize: string,
|
||||||
|
filePath: string,
|
||||||
|
fileName: string,
|
||||||
|
hits: Array<
|
||||||
|
{
|
||||||
|
start: 12,
|
||||||
|
end: 14
|
||||||
|
}
|
||||||
|
>
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
removeSearchHistoryr(...args: any[]): unknown;// needs 1 arguments
|
}): Promise<{
|
||||||
|
result: number,
|
||||||
|
errMsg: string,
|
||||||
|
id?: number
|
||||||
|
}>;
|
||||||
|
|
||||||
searchCacher(...args: any[]): unknown;// needs 3 arguments
|
removeSearchHistory(...args: any[]): unknown;// needs 1 arguments
|
||||||
|
|
||||||
clearSearchCacher(...args: any[]): unknown;// needs 1 arguments
|
searchCache(...args: any[]): unknown;// needs 3 arguments
|
||||||
|
|
||||||
|
clearSearchCache(...args: any[]): unknown;// needs 1 arguments
|
||||||
}
|
}
|
||||||
|
14
src/core/src/services/NodeIkernelTestPerformanceService.ts
Normal file
14
src/core/src/services/NodeIkernelTestPerformanceService.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { MessageElement, Peer } from "../entities";
|
||||||
|
|
||||||
|
export interface NodeIkernelTestPerformanceService {
|
||||||
|
insertMsg(MsgParam: {
|
||||||
|
peer: Peer
|
||||||
|
msgTime: string
|
||||||
|
msgId: string
|
||||||
|
msgSeq: string
|
||||||
|
batchNums: number
|
||||||
|
timesPerBatch: number
|
||||||
|
numPerTime: number
|
||||||
|
}, msg: Array<MessageElement>): Promise<unknown>;
|
||||||
|
|
||||||
|
}
|
@@ -41,6 +41,7 @@ import { NodeIKernelSearchService } from './services/NodeIKernelSearchService';
|
|||||||
import { NodeIKernelCollectionService } from './services/NodeIKernelCollectionService';
|
import { NodeIKernelCollectionService } from './services/NodeIKernelCollectionService';
|
||||||
import { NodeIKernelRecentContactService } from './services/NodeIKernelRecentContactService';
|
import { NodeIKernelRecentContactService } from './services/NodeIKernelRecentContactService';
|
||||||
import { NodeIKernelMSFService } from './services/NodeIKernelMSFService';
|
import { NodeIKernelMSFService } from './services/NodeIKernelMSFService';
|
||||||
|
import { NodeIkernelTestPerformanceService } from './services/NodeIkernelTestPerformanceService';
|
||||||
|
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
@@ -210,7 +211,7 @@ export interface NodeIQQNTWrapperSession {
|
|||||||
|
|
||||||
getSkinService(): unknown;
|
getSkinService(): unknown;
|
||||||
|
|
||||||
getTestPerformanceService(): unknown;
|
getTestPerformanceService(): NodeIkernelTestPerformanceService;
|
||||||
|
|
||||||
getQQPlayService(): unknown;
|
getQQPlayService(): unknown;
|
||||||
|
|
||||||
|
21
src/onebot11/action/extends/FetchCustomFace.ts
Normal file
21
src/onebot11/action/extends/FetchCustomFace.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||||
|
import BaseAction from '../BaseAction';
|
||||||
|
import { ActionName } from '../types';
|
||||||
|
import { NTQQMsgApi } from '@/core/apis';
|
||||||
|
const SchemaData = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
count: { type: 'number' },
|
||||||
|
}
|
||||||
|
} as const satisfies JSONSchema;
|
||||||
|
|
||||||
|
type Payload = FromSchema<typeof SchemaData>;
|
||||||
|
|
||||||
|
export class FetchCustomFace extends BaseAction<Payload, string[]> {
|
||||||
|
actionName = ActionName.FetchCustomFace;
|
||||||
|
PayloadSchema = SchemaData;
|
||||||
|
protected async _handle(payload: Payload) {
|
||||||
|
const ret = await NTQQMsgApi.fetchFavEmojiList(payload.count || 48);
|
||||||
|
return ret.emojiInfoList.map(e => e.url);
|
||||||
|
}
|
||||||
|
}
|
@@ -5,7 +5,7 @@ import { log, logDebug } from '@/common/utils/log';
|
|||||||
import { sleep } from '@/common/utils/helper';
|
import { sleep } from '@/common/utils/helper';
|
||||||
import { uri2local } from '@/common/utils/file';
|
import { uri2local } from '@/common/utils/file';
|
||||||
import { ActionName, BaseCheckResult } from '../types';
|
import { ActionName, BaseCheckResult } from '../types';
|
||||||
import { FileElement, RawMessage, VideoElement } from '@/core/entities';
|
import { ChatType, FileElement, Peer, RawMessage, VideoElement } from '@/core/entities';
|
||||||
import { NTQQFileApi, NTQQMsgApi } from '@/core/apis';
|
import { NTQQFileApi, NTQQMsgApi } from '@/core/apis';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||||
import Ajv from 'ajv';
|
import Ajv from 'ajv';
|
||||||
@@ -45,6 +45,44 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
|
|||||||
return { id: element.elementId, element: element.fileElement };
|
return { id: element.elementId, element: element.fileElement };
|
||||||
}
|
}
|
||||||
protected async _handle(payload: GetFilePayload): Promise<GetFileResponse> {
|
protected async _handle(payload: GetFilePayload): Promise<GetFileResponse> {
|
||||||
|
const { enableLocalFile2Url } = ob11Config;
|
||||||
|
const NTSearchNameResult = (await NTQQFileApi.searchfile([payload.file])).resultItems;
|
||||||
|
if (NTSearchNameResult.length !== 0) {
|
||||||
|
const MsgId = NTSearchNameResult[0].msgId;
|
||||||
|
let peer: Peer | undefined = undefined;
|
||||||
|
if (NTSearchNameResult[0].chatType == ChatType.group) {
|
||||||
|
peer = { chatType: ChatType.group, peerUid: NTSearchNameResult[0].groupChatInfo[0].groupCode };
|
||||||
|
}
|
||||||
|
if (!peer) {
|
||||||
|
throw new Error('chattype not support');
|
||||||
|
}
|
||||||
|
const msgList: RawMessage[] = (await NTQQMsgApi.getMsgsByMsgId(peer, [MsgId]))?.msgList;
|
||||||
|
if (!msgList || msgList.length == 0) {
|
||||||
|
throw new Error('msg not found');
|
||||||
|
}
|
||||||
|
const msg = msgList[0];
|
||||||
|
const file = msg.elements.filter(e => e.elementType == NTSearchNameResult[0].elemType);
|
||||||
|
if (file.length == 0) {
|
||||||
|
throw new Error('file not found');
|
||||||
|
}
|
||||||
|
const downloadPath = await NTQQFileApi.downloadMedia(msg.msgId, msg.chatType, msg.peerUid, file[0].elementId, '', '');
|
||||||
|
const res: GetFileResponse = {
|
||||||
|
file: downloadPath,
|
||||||
|
url: downloadPath,
|
||||||
|
file_size: NTSearchNameResult[0].fileSize.toString(),
|
||||||
|
file_name: NTSearchNameResult[0].fileName
|
||||||
|
};
|
||||||
|
if (enableLocalFile2Url) {
|
||||||
|
try {
|
||||||
|
res.base64 = await fs.readFile(downloadPath, 'base64');
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error('文件下载失败. ' + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//不手动删除?文件持久化了
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
//下面逻辑是有UUID的情况
|
||||||
throw new Error('file not found');
|
throw new Error('file not found');
|
||||||
// let cache = await dbUtil.getFileCacheByName(payload.file);
|
// let cache = await dbUtil.getFileCacheByName(payload.file);
|
||||||
// if (!cache) {
|
// if (!cache) {
|
||||||
|
@@ -18,7 +18,7 @@ const SchemaData = {
|
|||||||
message_seq: { type: 'number' },
|
message_seq: { type: 'number' },
|
||||||
count: { type: 'number' }
|
count: { type: 'number' }
|
||||||
},
|
},
|
||||||
required: ['group_id', 'message_seq', 'count']
|
required: ['group_id']
|
||||||
} as const satisfies JSONSchema;
|
} as const satisfies JSONSchema;
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = FromSchema<typeof SchemaData>;
|
||||||
@@ -31,13 +31,17 @@ export default class GoCQHTTPGetGroupMsgHistory extends BaseAction<Payload, Resp
|
|||||||
if (!group) {
|
if (!group) {
|
||||||
throw `群${payload.group_id}不存在`;
|
throw `群${payload.group_id}不存在`;
|
||||||
}
|
}
|
||||||
const startMsgId = (await MessageUnique.getMsgIdAndPeerByShortId(payload.message_seq))?.MsgId || '0';
|
let targetMsgShortId, count = parseInt(payload.count?.toString() ?? '20');
|
||||||
// log("startMsgId", startMsgId)
|
const peer = {
|
||||||
const historyResult = (await NTQQMsgApi.getMsgHistory({
|
|
||||||
chatType: ChatType.group,
|
chatType: ChatType.group,
|
||||||
peerUid: group.groupCode
|
peerUid: group.groupCode
|
||||||
}, startMsgId, parseInt(payload.count?.toString()) || 20));
|
};
|
||||||
//logDebug(historyResult);
|
if (!payload.message_seq) {
|
||||||
|
const latestMsgId = (await NTQQMsgApi.getLastestMsgByUids(peer)).msgList[0].msgId;
|
||||||
|
targetMsgShortId = await MessageUnique.createMsg(peer, latestMsgId || '0');
|
||||||
|
}
|
||||||
|
const startMsgId = (await MessageUnique.getMsgIdAndPeerByShortId(targetMsgShortId ?? (payload.message_seq ?? 0)))?.MsgId || '0';
|
||||||
|
const historyResult = (await NTQQMsgApi.getMsgHistory(peer, startMsgId, count));
|
||||||
const msgList = historyResult.msgList;
|
const msgList = historyResult.msgList;
|
||||||
await Promise.all(msgList.map(async msg => {
|
await Promise.all(msgList.map(async msg => {
|
||||||
msg.id = await MessageUnique.createMsg({ guildId: '', chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId);
|
msg.id = await MessageUnique.createMsg({ guildId: '', chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId);
|
||||||
|
51
src/onebot11/action/go-cqhttp/UploadPrivareFile.ts
Normal file
51
src/onebot11/action/go-cqhttp/UploadPrivareFile.ts
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import BaseAction from '../BaseAction';
|
||||||
|
import { getGroup } from '@/core/data';
|
||||||
|
import { ActionName } from '../types';
|
||||||
|
import { SendMsgElementConstructor } from '@/core/entities/constructor';
|
||||||
|
import { ChatType, Peer, SendFileElement } from '@/core/entities';
|
||||||
|
import fs from 'fs';
|
||||||
|
import { SendMsg, sendMsg } from '@/onebot11/action/msg/SendMsg';
|
||||||
|
import { uri2local } from '@/common/utils/file';
|
||||||
|
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||||
|
import { NTQQFriendApi, NTQQUserApi } from '@/core';
|
||||||
|
const SchemaData = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
user_id: { type: ['number', 'string'] },
|
||||||
|
file: { type: 'string' },
|
||||||
|
name: { type: 'string' }
|
||||||
|
},
|
||||||
|
required: ['user_id', 'file', 'name']
|
||||||
|
} as const satisfies JSONSchema;
|
||||||
|
|
||||||
|
type Payload = FromSchema<typeof SchemaData>;
|
||||||
|
|
||||||
|
export default class GoCQHTTPUploadPrivateFile extends BaseAction<Payload, null> {
|
||||||
|
actionName = ActionName.GOCQHTTP_UploadPrivateFile;
|
||||||
|
PayloadSchema = SchemaData;
|
||||||
|
async getPeer(payload: Payload): Promise<Peer> {
|
||||||
|
if (payload.user_id) {
|
||||||
|
const peerUid = await NTQQUserApi.getUidByUin(payload.user_id.toString());
|
||||||
|
if (!peerUid) {
|
||||||
|
throw `私聊${payload.user_id}不存在`;
|
||||||
|
}
|
||||||
|
const isBuddy = await NTQQFriendApi.isBuddy(peerUid);
|
||||||
|
return { chatType: isBuddy ? ChatType.friend : ChatType.temp, peerUid };
|
||||||
|
}
|
||||||
|
throw '缺少参数 user_id';
|
||||||
|
}
|
||||||
|
protected async _handle(payload: Payload): Promise<null> {
|
||||||
|
const peer = await this.getPeer(payload);
|
||||||
|
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 sendMsg(peer, [sendFileEle], [], true);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@@ -59,9 +59,9 @@ class GetGroupMemberInfo extends BaseAction<Payload, OB11GroupMember> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let LastestMsgList = await NTQQGroupApi.getLastestMsg(payload.group_id.toString(), [payload.user_id.toString()]);
|
const LastestMsgList = await NTQQGroupApi.getLastestMsg(payload.group_id.toString(), [payload.user_id.toString()]);
|
||||||
if (LastestMsgList?.msgList?.length && LastestMsgList?.msgList?.length > 0) {
|
if (LastestMsgList?.msgList?.length && LastestMsgList?.msgList?.length > 0) {
|
||||||
let last_send_time = LastestMsgList.msgList[0].msgTime;
|
const last_send_time = LastestMsgList.msgList[0].msgTime;
|
||||||
if (last_send_time && last_send_time != '0' && last_send_time != '') {
|
if (last_send_time && last_send_time != '0' && last_send_time != '') {
|
||||||
retMember.last_sent_time = parseInt(last_send_time);
|
retMember.last_sent_time = parseInt(last_send_time);
|
||||||
retMember.join_time = Math.round(Date.now() / 1000);//兜底数据 防止群管乱杀
|
retMember.join_time = Math.round(Date.now() / 1000);//兜底数据 防止群管乱杀
|
||||||
|
@@ -39,7 +39,7 @@ class GetGroupMemberList extends BaseAction<Payload, OB11GroupMember[]> {
|
|||||||
|
|
||||||
const MemberMap: Map<number, OB11GroupMember> = new Map<number, OB11GroupMember>();
|
const MemberMap: Map<number, OB11GroupMember> = new Map<number, OB11GroupMember>();
|
||||||
// 转为Map 方便索引
|
// 转为Map 方便索引
|
||||||
let date = Math.round(Date.now() / 1000);
|
const date = Math.round(Date.now() / 1000);
|
||||||
for (let i = 0, len = _groupMembers.length; i < len; i++) {
|
for (let i = 0, len = _groupMembers.length; i < len; i++) {
|
||||||
// 保证基础数据有这个 同时避免群管插件过于依赖这个杀了
|
// 保证基础数据有这个 同时避免群管插件过于依赖这个杀了
|
||||||
_groupMembers[i].join_time = date;
|
_groupMembers[i].join_time = date;
|
||||||
@@ -65,7 +65,7 @@ class GetGroupMemberList extends BaseAction<Payload, OB11GroupMember[]> {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const DateMap = await NTQQGroupApi.getGroupMemberLastestSendTimeCache(payload.group_id.toString());//开始从本地拉取
|
const DateMap = await NTQQGroupApi.getGroupMemberLastestSendTimeCache(payload.group_id.toString());//开始从本地拉取
|
||||||
for (let DateUin of DateMap.keys()) {
|
for (const DateUin of DateMap.keys()) {
|
||||||
const MemberData = MemberMap.get(parseInt(DateUin));
|
const MemberData = MemberMap.get(parseInt(DateUin));
|
||||||
if (MemberData) {
|
if (MemberData) {
|
||||||
MemberData.last_sent_time = parseInt(DateMap.get(DateUin)!);
|
MemberData.last_sent_time = parseInt(DateMap.get(DateUin)!);
|
||||||
|
@@ -75,6 +75,8 @@ import SetEssenceMsg from './group/SetEssenceMsg';
|
|||||||
import GetRecentContact from './user/GetRecentContact';
|
import GetRecentContact from './user/GetRecentContact';
|
||||||
import { GetProfileLike } from './extends/GetProfileLike';
|
import { GetProfileLike } from './extends/GetProfileLike';
|
||||||
import SetGroupHeader from './extends/SetGroupHeader';
|
import SetGroupHeader from './extends/SetGroupHeader';
|
||||||
|
import { FetchCustomFace } from './extends/FetchCustomFace';
|
||||||
|
import GoCQHTTPUploadPrivateFile from './go-cqhttp/UploadPrivareFile';
|
||||||
|
|
||||||
export const actionHandlers = [
|
export const actionHandlers = [
|
||||||
new RebootNormal(),
|
new RebootNormal(),
|
||||||
@@ -156,7 +158,9 @@ export const actionHandlers = [
|
|||||||
new GetRecentContact(),
|
new GetRecentContact(),
|
||||||
new MarkAllMsgAsRead(),
|
new MarkAllMsgAsRead(),
|
||||||
new GetProfileLike(),
|
new GetProfileLike(),
|
||||||
new SetGroupHeader()
|
new SetGroupHeader(),
|
||||||
|
new FetchCustomFace(),
|
||||||
|
new GoCQHTTPUploadPrivateFile()
|
||||||
];
|
];
|
||||||
|
|
||||||
function initActionMap() {
|
function initActionMap() {
|
||||||
|
@@ -12,7 +12,7 @@ import {
|
|||||||
SignMusicWrapper
|
SignMusicWrapper
|
||||||
} from '@/core';
|
} from '@/core';
|
||||||
import { getGroupMember } from '@/core/data';
|
import { getGroupMember } from '@/core/data';
|
||||||
import { logDebug, logError } from '@/common/utils/log';
|
import { logDebug, logError, logWarn } from '@/common/utils/log';
|
||||||
import { uri2local } from '@/common/utils/file';
|
import { uri2local } from '@/common/utils/file';
|
||||||
import { ob11Config } from '@/onebot11/config';
|
import { ob11Config } from '@/onebot11/config';
|
||||||
import { RequestUtil } from '@/common/utils/request';
|
import { RequestUtil } from '@/common/utils/request';
|
||||||
@@ -30,26 +30,6 @@ async function handleOb11FileLikeMessage(
|
|||||||
) {
|
) {
|
||||||
const uri = file;
|
const uri = file;
|
||||||
|
|
||||||
// const cache = await dbUtil.getFileCacheByName(file);
|
|
||||||
// if (cache) {
|
|
||||||
// if (fs.existsSync(cache.path)) {
|
|
||||||
// uri = 'file://' + cache.path;
|
|
||||||
// } else if (cache.url) {
|
|
||||||
// uri = cache.url;
|
|
||||||
// } else {
|
|
||||||
// const fileMsgPeer = MessageUnique.getPeerByMsgId(cache.msgId);
|
|
||||||
// if (fileMsgPeer) {
|
|
||||||
// cache.path = await NTQQFileApi.downloadMedia(
|
|
||||||
// fileMsgPeer.MsgId, fileMsgPeer.Peer.chatType, fileMsgPeer.Peer.peerUid,
|
|
||||||
// cache.elementId, '', ''
|
|
||||||
// );
|
|
||||||
// uri = 'file://' + cache.path;
|
|
||||||
// dbUtil.updateFileCache(cache);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// logDebug('找到文件缓存', uri);
|
|
||||||
// }
|
|
||||||
|
|
||||||
const { path, isLocal, fileName, errMsg } = (await uri2local(uri));
|
const { path, isLocal, fileName, errMsg } = (await uri2local(uri));
|
||||||
|
|
||||||
if (errMsg) {
|
if (errMsg) {
|
||||||
@@ -85,9 +65,12 @@ const _handlers: {
|
|||||||
SendMsgElementConstructor.at(atQQ, atMember.uid, AtType.atUser, atMember.cardName || atMember.nick) :
|
SendMsgElementConstructor.at(atQQ, atMember.uid, AtType.atUser, atMember.cardName || atMember.nick) :
|
||||||
undefined;
|
undefined;
|
||||||
},
|
},
|
||||||
|
|
||||||
[OB11MessageDataType.reply]: async ({ data: { id } }) => {
|
[OB11MessageDataType.reply]: async ({ data: { id } }) => {
|
||||||
const replyMsgM = MessageUnique.getMsgIdAndPeerByShortId(parseInt(id));
|
const replyMsgM = MessageUnique.getMsgIdAndPeerByShortId(parseInt(id));
|
||||||
|
if (!replyMsgM) {
|
||||||
|
logWarn('回复消息不存在', id);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
const replyMsg = (await NTQQMsgApi.getMsgsByMsgId(replyMsgM?.Peer!, [replyMsgM?.MsgId!])).msgList[0];
|
const replyMsg = (await NTQQMsgApi.getMsgsByMsgId(replyMsgM?.Peer!, [replyMsgM?.MsgId!])).msgList[0];
|
||||||
return replyMsg ?
|
return replyMsg ?
|
||||||
SendMsgElementConstructor.reply(replyMsg.msgSeq, replyMsg.msgId, replyMsg.senderUin!, replyMsg.senderUin!) :
|
SendMsgElementConstructor.reply(replyMsg.msgSeq, replyMsg.msgId, replyMsg.senderUin!, replyMsg.senderUin!) :
|
||||||
@@ -230,7 +213,7 @@ export default async function createSendElements(
|
|||||||
ignoreTypes: OB11MessageDataType[] = []
|
ignoreTypes: OB11MessageDataType[] = []
|
||||||
) {
|
) {
|
||||||
const deleteAfterSentFiles: string[] = [];
|
const deleteAfterSentFiles: string[] = [];
|
||||||
let callResultList: Array<Promise<SendMessageElement | undefined>> = [];
|
const callResultList: Array<Promise<SendMessageElement | undefined>> = [];
|
||||||
for (const sendMsg of messageData) {
|
for (const sendMsg of messageData) {
|
||||||
if (ignoreTypes.includes(sendMsg.type)) {
|
if (ignoreTypes.includes(sendMsg.type)) {
|
||||||
continue;
|
continue;
|
||||||
@@ -241,7 +224,7 @@ export default async function createSendElements(
|
|||||||
)?.catch(undefined);
|
)?.catch(undefined);
|
||||||
callResultList.push(callResult);
|
callResultList.push(callResult);
|
||||||
}
|
}
|
||||||
let ret = await Promise.all(callResultList);
|
const ret = await Promise.all(callResultList);
|
||||||
const sendElements: SendMessageElement[] = ret.filter(ele => ele) as SendMessageElement[];
|
const sendElements: SendMessageElement[] = ret.filter(ele => ele) as SendMessageElement[];
|
||||||
return { sendElements, deleteAfterSentFiles };
|
return { sendElements, deleteAfterSentFiles };
|
||||||
}
|
}
|
||||||
|
@@ -40,7 +40,7 @@ export async function sendMsg(peer: Peer, sendElements: SendMessageElement[], de
|
|||||||
throw ('消息体无法解析, 请检查是否发送了不支持的消息类型');
|
throw ('消息体无法解析, 请检查是否发送了不支持的消息类型');
|
||||||
}
|
}
|
||||||
let totalSize = 0;
|
let totalSize = 0;
|
||||||
let timeout = 5000;
|
let timeout = 10000;
|
||||||
try {
|
try {
|
||||||
for (const fileElement of sendElements) {
|
for (const fileElement of sendElements) {
|
||||||
if (fileElement.elementType === ElementType.PTT) {
|
if (fileElement.elementType === ElementType.PTT) {
|
||||||
@@ -59,7 +59,7 @@ export async function sendMsg(peer: Peer, sendElements: SendMessageElement[], de
|
|||||||
//且 PredictTime ((totalSize / 1024 / 512) * 1000)不等于Nan
|
//且 PredictTime ((totalSize / 1024 / 512) * 1000)不等于Nan
|
||||||
const PredictTime = totalSize / 1024 / 256 * 1000;
|
const PredictTime = totalSize / 1024 / 256 * 1000;
|
||||||
if (!Number.isNaN(PredictTime)) {
|
if (!Number.isNaN(PredictTime)) {
|
||||||
timeout += PredictTime;// 5S Basic Timeout + PredictTime( For File 512kb/s )
|
timeout += PredictTime;// 10S Basic Timeout + PredictTime( For File 512kb/s )
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError('发送消息计算预计时间异常', e);
|
logError('发送消息计算预计时间异常', e);
|
||||||
|
@@ -7,8 +7,8 @@ import { MessageUnique } from '@/common/utils/MessageUnique';
|
|||||||
const SchemaData = {
|
const SchemaData = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
message_id: { type: ['string','number'] },
|
message_id: { type: ['string', 'number'] },
|
||||||
emoji_id: { type: ['string','number'] }
|
emoji_id: { type: ['string', 'number'] }
|
||||||
},
|
},
|
||||||
required: ['message_id', 'emoji_id']
|
required: ['message_id', 'emoji_id']
|
||||||
} as const satisfies JSONSchema;
|
} as const satisfies JSONSchema;
|
||||||
@@ -23,10 +23,13 @@ export class SetMsgEmojiLike extends BaseAction<Payload, any> {
|
|||||||
if (!msg) {
|
if (!msg) {
|
||||||
throw new Error('msg not found');
|
throw new Error('msg not found');
|
||||||
}
|
}
|
||||||
if (!payload.emoji_id){
|
if (!payload.emoji_id) {
|
||||||
throw new Error('emojiId not found');
|
throw new Error('emojiId not found');
|
||||||
}
|
}
|
||||||
const msgSeq = (await NTQQMsgApi.getMsgsByMsgId(msg.Peer, [msg.MsgId])).msgList[0].msgSeq;
|
const msgData = (await NTQQMsgApi.getMsgsByMsgId(msg.Peer, [msg.MsgId])).msgList;
|
||||||
return await NTQQMsgApi.setEmojiLike(msg.Peer, msgSeq, payload.emoji_id.toString(), true);
|
if (!msgData || msgData.length == 0 || !msgData[0].msgSeq) {
|
||||||
|
throw new Error('find msg by msgid error');
|
||||||
|
}
|
||||||
|
return await NTQQMsgApi.setEmojiLike(msg.Peer, msgData[0].msgSeq, payload.emoji_id.toString(), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -99,5 +99,7 @@ export enum ActionName {
|
|||||||
GetRecentContact = 'get_recent_contact',
|
GetRecentContact = 'get_recent_contact',
|
||||||
_MarkAllMsgAsRead = '_mark_all_as_read',
|
_MarkAllMsgAsRead = '_mark_all_as_read',
|
||||||
GetProfileLike = 'get_profile_like',
|
GetProfileLike = 'get_profile_like',
|
||||||
SetGroupHeader = "set_group_head"
|
SetGroupHeader = 'set_group_head',
|
||||||
|
FetchCustomFace = 'fetch_custom_face',
|
||||||
|
GOCQHTTP_UploadPrivateFile = 'upload_private_file'
|
||||||
}
|
}
|
||||||
|
@@ -42,7 +42,7 @@ export interface OB11Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Config extends ConfigBase<OB11Config> implements OB11Config {
|
class Config extends ConfigBase<OB11Config> implements OB11Config {
|
||||||
name: string = 'onebot11'
|
name: string = 'onebot11';
|
||||||
http = {
|
http = {
|
||||||
enable: false,
|
enable: false,
|
||||||
host: '',
|
host: '',
|
||||||
|
@@ -12,18 +12,19 @@ import {
|
|||||||
import {
|
import {
|
||||||
AtType,
|
AtType,
|
||||||
ChatType,
|
ChatType,
|
||||||
ElementType, FaceIndex,
|
FaceIndex,
|
||||||
Friend,
|
Friend,
|
||||||
GrayTipElementSubType,
|
GrayTipElementSubType,
|
||||||
Group,
|
Group,
|
||||||
GroupMember,
|
GroupMember,
|
||||||
IMAGE_HTTP_HOST, IMAGE_HTTP_HOST_NT, mFaceCache,
|
mFaceCache,
|
||||||
Peer,
|
Peer,
|
||||||
RawMessage,
|
RawMessage,
|
||||||
SelfInfo,
|
SelfInfo,
|
||||||
Sex,
|
Sex,
|
||||||
TipGroupElementType,
|
TipGroupElementType,
|
||||||
User
|
User,
|
||||||
|
VideoElement
|
||||||
} from '@/core/entities';
|
} from '@/core/entities';
|
||||||
import { EventType } from './event/OB11BaseEvent';
|
import { EventType } from './event/OB11BaseEvent';
|
||||||
import { encodeCQCode } from './cqcode';
|
import { encodeCQCode } from './cqcode';
|
||||||
@@ -33,7 +34,7 @@ import { OB11GroupUploadNoticeEvent } from './event/notice/OB11GroupUploadNotice
|
|||||||
import { OB11GroupNoticeEvent } from './event/notice/OB11GroupNoticeEvent';
|
import { OB11GroupNoticeEvent } from './event/notice/OB11GroupNoticeEvent';
|
||||||
|
|
||||||
import { calcQQLevel } from '../common/utils/qqlevel';
|
import { calcQQLevel } from '../common/utils/qqlevel';
|
||||||
import { log, logDebug, logError } from '../common/utils/log';
|
import { log, logDebug, logError, logWarn } from '../common/utils/log';
|
||||||
import { sleep } from '../common/utils/helper';
|
import { sleep } from '../common/utils/helper';
|
||||||
import { OB11GroupTitleEvent } from './event/notice/OB11GroupTitleEvent';
|
import { OB11GroupTitleEvent } from './event/notice/OB11GroupTitleEvent';
|
||||||
import { OB11GroupCardEvent } from './event/notice/OB11GroupCardEvent';
|
import { OB11GroupCardEvent } from './event/notice/OB11GroupCardEvent';
|
||||||
@@ -75,7 +76,12 @@ export class OB11Constructor {
|
|||||||
if (msg.chatType == ChatType.group) {
|
if (msg.chatType == ChatType.group) {
|
||||||
resMsg.sub_type = 'normal'; // 这里go-cqhttp是group,而onebot11标准是normal, 蛋疼
|
resMsg.sub_type = 'normal'; // 这里go-cqhttp是group,而onebot11标准是normal, 蛋疼
|
||||||
resMsg.group_id = parseInt(msg.peerUin);
|
resMsg.group_id = parseInt(msg.peerUin);
|
||||||
const member = await getGroupMember(msg.peerUin, msg.senderUin!);
|
let member = await getGroupMember(msg.peerUin, msg.senderUin!);
|
||||||
|
if (!member) {
|
||||||
|
//直接去QQNative取
|
||||||
|
const memberList = await NTQQGroupApi.getGroupMembers(msg.peerUin);
|
||||||
|
member = memberList.get(msg.senderUin!);
|
||||||
|
}
|
||||||
if (member) {
|
if (member) {
|
||||||
resMsg.sender.role = OB11Constructor.groupMemberRole(member.role);
|
resMsg.sender.role = OB11Constructor.groupMemberRole(member.role);
|
||||||
resMsg.sender.nickname = member.nick;
|
resMsg.sender.nickname = member.nick;
|
||||||
@@ -134,29 +140,30 @@ export class OB11Constructor {
|
|||||||
}
|
}
|
||||||
else if (element.replyElement) {
|
else if (element.replyElement) {
|
||||||
message_data['type'] = 'reply';
|
message_data['type'] = 'reply';
|
||||||
// log("收到回复消息", element.replyElement.replayMsgSeq)
|
//log("收到回复消息", element.replyElement);
|
||||||
try {
|
try {
|
||||||
let replyMsg = await NTQQMsgApi.getMsgsBySeqAndCount(
|
//做这么多都是因为NC速度太快 可能nt还没有写入数据库
|
||||||
{
|
//const records = msg.records.find(msgRecord => msgRecord.msgId === element.replyElement.sourceMsgIdInRecords);
|
||||||
|
const peer = {
|
||||||
chatType: msg.chatType,
|
chatType: msg.chatType,
|
||||||
peerUid: msg.peerUid,
|
peerUid: msg.peerUid,
|
||||||
guildId: '',
|
guildId: '',
|
||||||
},
|
};
|
||||||
element.replyElement.replayMsgSeq,
|
let replyMsg: RawMessage | undefined;
|
||||||
1,
|
|
||||||
true,
|
replyMsg = (await NTQQMsgApi.getMsgsBySeqAndCount({ peerUid: msg.peerUid, guildId: '', chatType: msg.chatType }, element.replyElement.replayMsgSeq, 1, true, true)).msgList[0];
|
||||||
true
|
if (!replyMsg || element.replyElement.replayMsgSeq !== replyMsg.msgSeq) {
|
||||||
);
|
replyMsg = (await NTQQMsgApi.getSingleMsg(peer, element.replyElement.replayMsgSeq)).msgList[0];
|
||||||
// console.log(JSON.stringify(retData, null, 2));
|
|
||||||
// const replyMsg = await NTQQMsgApi.getMsgsBySeqAndCount({ peerUid: msg.peerUid, guildId: '', chatType: msg.chatType }, element.replyElement.replayMsgSeq, 1, true, true);
|
|
||||||
if (replyMsg) {
|
|
||||||
message_data['data']['id'] = MessageUnique.createMsg({ peerUid: msg.peerUid, guildId: '', chatType: msg.chatType }, replyMsg.msgList[0].msgId)?.toString();
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
continue;
|
if (!replyMsg || element.replyElement.replayMsgSeq !== replyMsg.msgSeq) {
|
||||||
|
throw new Error('回复消息消息验证失败');
|
||||||
}
|
}
|
||||||
|
message_data['data']['id'] = MessageUnique.createMsg({ peerUid: msg.peerUid, guildId: '', chatType: msg.chatType }, replyMsg.msgId)?.toString();
|
||||||
//log("找到回复消息", message_data['data']['id'], replyMsg.msgList[0].msgId)
|
//log("找到回复消息", message_data['data']['id'], replyMsg.msgList[0].msgId)
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
|
message_data['type'] = "unknown";
|
||||||
|
message_data['data'] = undefined;
|
||||||
logError('获取不到引用的消息', e.stack, element.replyElement.replayMsgSeq);
|
logError('获取不到引用的消息', e.stack, element.replyElement.replayMsgSeq);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,9 +172,8 @@ export class OB11Constructor {
|
|||||||
message_data['type'] = 'image';
|
message_data['type'] = 'image';
|
||||||
// message_data["data"]["file"] = element.picElement.sourcePath
|
// message_data["data"]["file"] = element.picElement.sourcePath
|
||||||
message_data['data']['file'] = element.picElement.fileName;
|
message_data['data']['file'] = element.picElement.fileName;
|
||||||
message_data['subType'] = element.picElement.picSubType;
|
message_data['data']['subType'] = element.picElement.picSubType;
|
||||||
// message_data["data"]["path"] = element.picElement.sourcePath
|
// message_data["data"]["path"] = element.picElement.sourcePath
|
||||||
// let currentRKey = "CAQSKAB6JWENi5LMk0kc62l8Pm3Jn1dsLZHyRLAnNmHGoZ3y_gDZPqZt-64"
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
message_data['data']['url'] = await NTQQFileApi.getImageUrl(element.picElement);
|
message_data['data']['url'] = await NTQQFileApi.getImageUrl(element.picElement);
|
||||||
@@ -177,50 +183,82 @@ export class OB11Constructor {
|
|||||||
//console.log(message_data['data']['url'])
|
//console.log(message_data['data']['url'])
|
||||||
// message_data["data"]["file_id"] = element.picElement.fileUuid
|
// message_data["data"]["file_id"] = element.picElement.fileUuid
|
||||||
message_data['data']['file_size'] = element.picElement.fileSize;
|
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) {
|
else if (element.fileElement) {
|
||||||
const videoOrFileElement = element.videoElement || element.fileElement;
|
|
||||||
const ob11MessageDataType = element.videoElement ? OB11MessageDataType.video : OB11MessageDataType.file;
|
const FileElement = element.fileElement;
|
||||||
const videoDownUrl = element.videoElement ? await NTQQFileApi.getVideoUrl(msg, element) : videoOrFileElement.filePath;
|
message_data['type'] = OB11MessageDataType.file;
|
||||||
message_data['type'] = ob11MessageDataType;
|
message_data['data']['file'] = FileElement.fileName;
|
||||||
message_data['data']['file'] = videoOrFileElement.fileName;
|
message_data['data']['path'] = FileElement.filePath;
|
||||||
|
message_data['data']['url'] = FileElement.filePath;
|
||||||
|
message_data['data']['file_id'] = FileElement.fileUuid;
|
||||||
|
message_data['data']['file_size'] = FileElement.fileSize;
|
||||||
|
await NTQQFileApi.addFileCache({
|
||||||
|
peerUid: msg.peerUid,
|
||||||
|
chatType: msg.chatType,
|
||||||
|
guildId: '',
|
||||||
|
},
|
||||||
|
msg.msgId,
|
||||||
|
msg.msgSeq,
|
||||||
|
msg.senderUid,
|
||||||
|
element.elementId,
|
||||||
|
element.elementType.toString(),
|
||||||
|
FileElement.fileSize,
|
||||||
|
FileElement.fileName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (element.videoElement) {
|
||||||
|
const videoElement: VideoElement = element.videoElement;
|
||||||
|
//读取视频链接并兜底
|
||||||
|
let videoUrl;//Array
|
||||||
|
try {
|
||||||
|
videoUrl = await NTQQFileApi.getVideoUrl({
|
||||||
|
chatType: msg.chatType,
|
||||||
|
peerUid: msg.peerUid,
|
||||||
|
guildId: '0'
|
||||||
|
}, msg.msgId, element.elementId);
|
||||||
|
} catch (error) {
|
||||||
|
videoUrl = undefined;
|
||||||
|
}
|
||||||
|
//读取在线URL
|
||||||
|
let videoDownUrl = undefined;
|
||||||
|
|
||||||
|
if (videoUrl) {
|
||||||
|
const videoDownUrlTemp = videoUrl.find((url) => { if (url.url) { return true; } return false; });
|
||||||
|
if (videoDownUrlTemp) {
|
||||||
|
videoDownUrl = videoDownUrlTemp.url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//开始兜底
|
||||||
|
if (!videoDownUrl) {
|
||||||
|
videoDownUrl = videoElement.filePath;
|
||||||
|
}
|
||||||
|
message_data['type'] = OB11MessageDataType.video;
|
||||||
|
message_data['data']['file'] = videoElement.fileName;
|
||||||
message_data['data']['path'] = videoDownUrl;
|
message_data['data']['path'] = videoDownUrl;
|
||||||
message_data['data']['url'] = videoDownUrl;
|
message_data['data']['url'] = videoDownUrl;
|
||||||
message_data['data']['file_id'] = videoOrFileElement.fileUuid;
|
message_data['data']['file_id'] = videoElement.fileUuid;
|
||||||
message_data['data']['file_size'] = videoOrFileElement.fileSize;
|
message_data['data']['file_size'] = videoElement.fileSize;
|
||||||
if (!element.videoElement) {
|
|
||||||
// dbUtil.addFileCache({
|
await NTQQFileApi.addFileCache({
|
||||||
// msgId: msg.msgId,
|
peerUid: msg.peerUid,
|
||||||
// name: videoOrFileElement.fileName,
|
chatType: msg.chatType,
|
||||||
// path: videoOrFileElement.filePath,
|
guildId: '',
|
||||||
// size: parseInt(videoOrFileElement.fileSize || '0'),
|
},
|
||||||
// uuid: videoOrFileElement.fileUuid || '',
|
msg.msgId,
|
||||||
// url: '',
|
msg.msgSeq,
|
||||||
// element: element.videoElement || element.fileElement,
|
msg.senderUid,
|
||||||
// elementType: element.videoElement ? ElementType.VIDEO : ElementType.FILE,
|
element.elementId,
|
||||||
// elementId: element.elementId
|
element.elementType.toString(),
|
||||||
// }).then();
|
videoElement.fileSize || '0',
|
||||||
// }
|
videoElement.fileName
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
else if (element.pttElement) {
|
else if (element.pttElement) {
|
||||||
message_data['type'] = OB11MessageDataType.voice;
|
message_data['type'] = OB11MessageDataType.voice;
|
||||||
message_data['data']['file'] = element.pttElement.fileName;
|
message_data['data']['file'] = element.pttElement.fileName;
|
||||||
message_data['data']['path'] = element.pttElement.filePath;
|
message_data['data']['path'] = element.pttElement.filePath;
|
||||||
// message_data["data"]["file_id"] = element.pttElement.fileUuid
|
message_data['data']['file_id'] = element.pttElement.fileUuid;
|
||||||
message_data['data']['file_size'] = element.pttElement.fileSize;
|
message_data['data']['file_size'] = element.pttElement.fileSize;
|
||||||
// dbUtil.addFileCache({
|
// dbUtil.addFileCache({
|
||||||
// name: element.pttElement.fileName,
|
// name: element.pttElement.fileName,
|
||||||
@@ -233,7 +271,20 @@ export class OB11Constructor {
|
|||||||
// elementType: ElementType.PTT,
|
// elementType: ElementType.PTT,
|
||||||
// elementId: element.elementId
|
// elementId: element.elementId
|
||||||
// }).then();
|
// }).then();
|
||||||
|
await NTQQFileApi.addFileCache({
|
||||||
|
peerUid: msg.peerUid,
|
||||||
|
chatType: msg.chatType,
|
||||||
|
guildId: '',
|
||||||
|
},
|
||||||
|
msg.msgId,
|
||||||
|
msg.msgSeq,
|
||||||
|
msg.senderUid,
|
||||||
|
element.elementId,
|
||||||
|
element.elementType.toString(),
|
||||||
|
element.pttElement.fileSize || '0',
|
||||||
|
element.pttElement.fileUuid || ''
|
||||||
|
);
|
||||||
|
//以uuid作为文件名
|
||||||
}
|
}
|
||||||
else if (element.arkElement) {
|
else if (element.arkElement) {
|
||||||
message_data['type'] = OB11MessageDataType.json;
|
message_data['type'] = OB11MessageDataType.json;
|
||||||
@@ -279,6 +330,7 @@ export class OB11Constructor {
|
|||||||
}
|
}
|
||||||
if (message_data.type !== 'unknown' && message_data.data) {
|
if (message_data.type !== 'unknown' && message_data.data) {
|
||||||
const cqCode = encodeCQCode(message_data);
|
const cqCode = encodeCQCode(message_data);
|
||||||
|
|
||||||
if (messagePostFormat === 'string') {
|
if (messagePostFormat === 'string') {
|
||||||
(resMsg.message as string) += cqCode;
|
(resMsg.message as string) += cqCode;
|
||||||
}
|
}
|
||||||
|
@@ -66,10 +66,10 @@ export function encodeCQCode(data: OB11MessageData) {
|
|||||||
|
|
||||||
let result = '[CQ:' + data.type;
|
let result = '[CQ:' + data.type;
|
||||||
for (const name in data.data) {
|
for (const name in data.data) {
|
||||||
const value = data.data[name];
|
let value = data.data[name];
|
||||||
try {
|
try {
|
||||||
// Check if the value can be converted to a string
|
// Check if the value can be converted to a string
|
||||||
value.toString();
|
value = value.toString();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// If it can't be converted, skip this name-value pair
|
// If it can't be converted, skip this name-value pair
|
||||||
// console.warn(`Skipping problematic name-value pair. Name: ${name}, Value: ${value}`);
|
// console.warn(`Skipping problematic name-value pair. Name: ${name}, Value: ${value}`);
|
||||||
|
@@ -41,7 +41,7 @@ export interface LineDevice {
|
|||||||
device_name: string;
|
device_name: string;
|
||||||
device_kind: string;
|
device_kind: string;
|
||||||
}
|
}
|
||||||
export let DeviceList = new Array<LineDevice>();
|
export const DeviceList = new Array<LineDevice>();
|
||||||
|
|
||||||
//peer->cached(boolen)
|
//peer->cached(boolen)
|
||||||
// const PokeCache = new Map<string, boolean>();
|
// const PokeCache = new Map<string, boolean>();
|
||||||
@@ -240,16 +240,25 @@ export class NapCatOnebot11 {
|
|||||||
};
|
};
|
||||||
msgListener.onMsgInfoListUpdate = (msgList) => {
|
msgListener.onMsgInfoListUpdate = (msgList) => {
|
||||||
this.postRecallMsg(msgList).then().catch(logError);
|
this.postRecallMsg(msgList).then().catch(logError);
|
||||||
};
|
for (const msg of msgList.filter(e => e.senderUin == selfInfo.uin)) {
|
||||||
msgListener.onAddSendMsg = (msg) => {
|
// console.log(msg);
|
||||||
|
if (msg.sendStatus !== 2) {
|
||||||
|
//完成后再post
|
||||||
|
return;
|
||||||
|
}
|
||||||
OB11Constructor.message(msg).then((_msg) => {
|
OB11Constructor.message(msg).then((_msg) => {
|
||||||
_msg.target_id = parseInt(msg.peerUin);
|
_msg.target_id = parseInt(msg.peerUin);
|
||||||
logMessage(_msg as OB11Message).then().catch(logError);
|
|
||||||
}).catch(logError);
|
|
||||||
if (ob11Config.reportSelfMessage) {
|
if (ob11Config.reportSelfMessage) {
|
||||||
msg.id = MessageUnique.createMsg({ chatType: msg.chatType, peerUid: msg.peerUid, guildId: '' }, msg.msgId);
|
msg.id = MessageUnique.createMsg({ chatType: msg.chatType, peerUid: msg.peerUid, guildId: '' }, msg.msgId);
|
||||||
this.postReceiveMsg([msg]).then().catch(logError);
|
this.postReceiveMsg([msg]).then().catch(logError);
|
||||||
|
} else {
|
||||||
|
logMessage(_msg as OB11Message).then().catch(logError);
|
||||||
}
|
}
|
||||||
|
}).catch(logError);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
msgListener.onAddSendMsg = (msg) => {
|
||||||
|
|
||||||
};
|
};
|
||||||
napCatCore.addListener(msgListener);
|
napCatCore.addListener(msgListener);
|
||||||
logDebug('ob11 msg listener added');
|
logDebug('ob11 msg listener added');
|
||||||
@@ -276,7 +285,7 @@ export class NapCatOnebot11 {
|
|||||||
// }
|
// }
|
||||||
groupListener.onGroupNotifiesUpdated = async (doubt, notifies) => {
|
groupListener.onGroupNotifiesUpdated = async (doubt, notifies) => {
|
||||||
//console.log('ob11 onGroupNotifiesUpdated', notifies[0]);
|
//console.log('ob11 onGroupNotifiesUpdated', notifies[0]);
|
||||||
if (![GroupNotifyTypes.ADMIN_SET, GroupNotifyTypes.ADMIN_UNSET, GroupNotifyTypes.ADMIN_UNSET_OTHER].includes(notifies[0].type)) {
|
if (![GroupNotifyTypes.INVITE_ME, GroupNotifyTypes.ADMIN_SET, GroupNotifyTypes.ADMIN_UNSET, GroupNotifyTypes.ADMIN_UNSET_OTHER].includes(notifies[0].type)) {
|
||||||
this.postGroupNotifies(notifies).then().catch(e => logError('postGroupNotifies error: ', e));
|
this.postGroupNotifies(notifies).then().catch(e => logError('postGroupNotifies error: ', e));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -323,11 +332,12 @@ export class NapCatOnebot11 {
|
|||||||
const isPrivilege = role === 3 || role === 4;
|
const isPrivilege = role === 3 || role === 4;
|
||||||
for (const member of members.values()) {
|
for (const member of members.values()) {
|
||||||
//console.log(member?.isDelete, role, isPrivilege);
|
//console.log(member?.isDelete, role, isPrivilege);
|
||||||
if (member?.isDelete && !isPrivilege && selfInfo.uin !== member.uin) {
|
// Develop Mlikiowa Taged: 暂时屏蔽这个方案 考虑onMemberListChange
|
||||||
log('[群聊] 群组 ', groupCode, ' 成员' + member.uin + '退出');
|
// if (member?.isDelete && !isPrivilege && selfInfo.uin !== member.uin) {
|
||||||
const groupDecreaseEvent = new OB11GroupDecreaseEvent(parseInt(groupCode), parseInt(member.uin), 0, 'leave');// 不知道怎么出去的
|
// log('[群聊] 群组 ', groupCode, ' 成员' + member.uin + '退出');
|
||||||
postOB11Event(groupDecreaseEvent, true);
|
// const groupDecreaseEvent = new OB11GroupDecreaseEvent(parseInt(groupCode), parseInt(member.uin), 0, 'leave');// 不知道怎么出去的
|
||||||
}
|
// postOB11Event(groupDecreaseEvent, true);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
groupListener.onJoinGroupNotify = (...notify) => {
|
groupListener.onJoinGroupNotify = (...notify) => {
|
||||||
@@ -415,7 +425,7 @@ export class NapCatOnebot11 {
|
|||||||
if (check_http_ws_equal(NewOb11) || check_http_ws_equal(OldConfig)) {
|
if (check_http_ws_equal(NewOb11) || check_http_ws_equal(OldConfig)) {
|
||||||
// http与ws共站 需要同步重启
|
// http与ws共站 需要同步重启
|
||||||
if (isHttpChanged || isWsChanged) {
|
if (isHttpChanged || isWsChanged) {
|
||||||
log("http与ws进行热重载")
|
log('http与ws进行热重载');
|
||||||
ob11WebsocketServer.stop();
|
ob11WebsocketServer.stop();
|
||||||
ob11HTTPServer.stop();
|
ob11HTTPServer.stop();
|
||||||
if (NewOb11.http.enable) {
|
if (NewOb11.http.enable) {
|
||||||
@@ -432,7 +442,7 @@ export class NapCatOnebot11 {
|
|||||||
} else {
|
} else {
|
||||||
// http重启逻辑
|
// http重启逻辑
|
||||||
if (isHttpChanged) {
|
if (isHttpChanged) {
|
||||||
log("http进行热重载")
|
log('http进行热重载');
|
||||||
ob11HTTPServer.stop();
|
ob11HTTPServer.stop();
|
||||||
if (NewOb11.http.enable) {
|
if (NewOb11.http.enable) {
|
||||||
ob11HTTPServer.start(NewOb11.http.port, NewOb11.http.host);
|
ob11HTTPServer.start(NewOb11.http.port, NewOb11.http.host);
|
||||||
@@ -441,7 +451,7 @@ export class NapCatOnebot11 {
|
|||||||
|
|
||||||
// ws重启逻辑
|
// ws重启逻辑
|
||||||
if (isWsChanged) {
|
if (isWsChanged) {
|
||||||
log("ws进行热重载")
|
log('ws进行热重载');
|
||||||
ob11WebsocketServer.stop();
|
ob11WebsocketServer.stop();
|
||||||
if (NewOb11.ws.enable) {
|
if (NewOb11.ws.enable) {
|
||||||
ob11WebsocketServer.start(NewOb11.ws.port, NewOb11.ws.host);
|
ob11WebsocketServer.start(NewOb11.ws.port, NewOb11.ws.host);
|
||||||
@@ -451,7 +461,7 @@ export class NapCatOnebot11 {
|
|||||||
|
|
||||||
// 反向ws重启逻辑
|
// 反向ws重启逻辑
|
||||||
if (isWsReverseChanged) {
|
if (isWsReverseChanged) {
|
||||||
log("反向ws进行热重载")
|
log('反向ws进行热重载');
|
||||||
ob11ReverseWebsockets.stop();
|
ob11ReverseWebsockets.stop();
|
||||||
if (NewOb11.reverseWs.enable) {
|
if (NewOb11.reverseWs.enable) {
|
||||||
ob11ReverseWebsockets.start();
|
ob11ReverseWebsockets.start();
|
||||||
@@ -514,7 +524,8 @@ export class NapCatOnebot11 {
|
|||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
logError('获取群通知的成员信息失败', notify, e.stack.toString());
|
logError('获取群通知的成员信息失败', notify, e.stack.toString());
|
||||||
}
|
}
|
||||||
} else if ([GroupNotifyTypes.JOIN_REQUEST].includes(notify.type)) {
|
//notify.status == 1 表示未处理 2表示处理完成
|
||||||
|
} else if ([GroupNotifyTypes.JOIN_REQUEST].includes(notify.type) && notify.status == 1) {
|
||||||
logDebug('有加群请求');
|
logDebug('有加群请求');
|
||||||
const groupRequestEvent = new OB11GroupRequestEvent();
|
const groupRequestEvent = new OB11GroupRequestEvent();
|
||||||
groupRequestEvent.group_id = parseInt(notify.group.groupCode);
|
groupRequestEvent.group_id = parseInt(notify.group.groupCode);
|
||||||
|
@@ -1 +1 @@
|
|||||||
export const version = '1.6.7';
|
export const version = '1.7.2';
|
||||||
|
@@ -27,18 +27,19 @@ export async function InitWebUi() {
|
|||||||
}
|
}
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
// 初始服务
|
// 初始服务
|
||||||
app.all('/', (_req, res) => {
|
// WebUI只在config.prefix所示路径上提供服务,可配合Nginx挂载到子目录中
|
||||||
|
app.all(config.prefix + '/', (_req, res) => {
|
||||||
res.json({
|
res.json({
|
||||||
msg: 'NapCat WebAPI is now running!',
|
msg: 'NapCat WebAPI is now running!',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// 配置静态文件服务,提供./static目录下的文件服务,访问路径为/webui
|
// 配置静态文件服务,提供./static目录下的文件服务,访问路径为/webui
|
||||||
app.use('/webui', express.static(resolve(__dirname, './static')));
|
app.use(config.prefix + '/webui', express.static(resolve(__dirname, './static')));
|
||||||
//挂载API接口
|
//挂载API接口
|
||||||
app.use('/api', ALLRouter);
|
app.use(config.prefix + '/api', ALLRouter);
|
||||||
app.listen(config.port, async () => {
|
app.listen(config.port, config.host, async () => {
|
||||||
log(`[NapCat] [WebUi] Current WebUi is running at IP:${config.port}`);
|
log(`[NapCat] [WebUi] Current WebUi is running at http://${config.host}:${config.port}${config.prefix}`);
|
||||||
|
log(`[NapCat] [WebUi] Login URL is http://${config.host}:${config.port}${config.prefix}/webui`);
|
||||||
log(`[NapCat] [WebUi] Login Token is ${config.token}`);
|
log(`[NapCat] [WebUi] Login Token is ${config.token}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
@@ -12,7 +12,33 @@ const __dirname = dirname(__filename);
|
|||||||
// 限制尝试端口的次数,避免死循环
|
// 限制尝试端口的次数,避免死循环
|
||||||
const MAX_PORT_TRY = 100;
|
const MAX_PORT_TRY = 100;
|
||||||
|
|
||||||
async function tryUsePort(port: number, tryCount: number = 0): Promise<number> {
|
async function tryUseHost(host: string): Promise<string> {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
try {
|
||||||
|
const server = net.createServer();
|
||||||
|
server.on('listening', () => {
|
||||||
|
server.close();
|
||||||
|
resolve(host);
|
||||||
|
});
|
||||||
|
|
||||||
|
server.on('error', (err: any) => {
|
||||||
|
if (err.code === 'EADDRNOTAVAIL') {
|
||||||
|
reject('主机地址验证失败,可能为非本机地址');
|
||||||
|
} else {
|
||||||
|
reject(`遇到错误: ${err.code}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 尝试监听 让系统随机分配一个端口
|
||||||
|
server.listen(0, host);
|
||||||
|
} catch (error) {
|
||||||
|
// 这里捕获到的错误应该是启动服务器时的同步错误
|
||||||
|
reject(`服务器启动时发生错误: ${error}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function tryUsePort(port: number, host: string, tryCount: number = 0): Promise<number> {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
const server = net.createServer();
|
const server = net.createServer();
|
||||||
@@ -25,7 +51,7 @@ async function tryUsePort(port: number, tryCount: number = 0): Promise<number> {
|
|||||||
if (err.code === 'EADDRINUSE') {
|
if (err.code === 'EADDRINUSE') {
|
||||||
if (tryCount < MAX_PORT_TRY) {
|
if (tryCount < MAX_PORT_TRY) {
|
||||||
// 使用循环代替递归
|
// 使用循环代替递归
|
||||||
resolve(tryUsePort(port + 1, tryCount + 1));
|
resolve(tryUsePort(port + 1, host, tryCount + 1));
|
||||||
} else {
|
} else {
|
||||||
reject(`端口尝试失败,达到最大尝试次数: ${MAX_PORT_TRY}`);
|
reject(`端口尝试失败,达到最大尝试次数: ${MAX_PORT_TRY}`);
|
||||||
}
|
}
|
||||||
@@ -35,7 +61,7 @@ async function tryUsePort(port: number, tryCount: number = 0): Promise<number> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 尝试监听端口
|
// 尝试监听端口
|
||||||
server.listen(port);
|
server.listen(port, host);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 这里捕获到的错误应该是启动服务器时的同步错误
|
// 这里捕获到的错误应该是启动服务器时的同步错误
|
||||||
reject(`服务器启动时发生错误: ${error}`);
|
reject(`服务器启动时发生错误: ${error}`);
|
||||||
@@ -44,44 +70,73 @@ async function tryUsePort(port: number, tryCount: number = 0): Promise<number> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface WebUiConfigType {
|
export interface WebUiConfigType {
|
||||||
|
host: string;
|
||||||
port: number;
|
port: number;
|
||||||
|
prefix: string;
|
||||||
token: string;
|
token: string;
|
||||||
loginRate: number
|
loginRate: number
|
||||||
}
|
}
|
||||||
// 读取当前目录下名为 webui.json 的配置文件,如果不存在则创建初始化配置文件
|
// 读取当前目录下名为 webui.json 的配置文件,如果不存在则创建初始化配置文件
|
||||||
class WebUiConfigWrapper {
|
class WebUiConfigWrapper {
|
||||||
WebUiConfigData: WebUiConfigType | undefined = undefined;
|
WebUiConfigData: WebUiConfigType | undefined = undefined;
|
||||||
|
private applyDefaults<T>(obj: Partial<T>, defaults: T): T {
|
||||||
|
return { ...defaults, ...obj };
|
||||||
|
}
|
||||||
async GetWebUIConfig(): Promise<WebUiConfigType> {
|
async GetWebUIConfig(): Promise<WebUiConfigType> {
|
||||||
if (this.WebUiConfigData) {
|
if (this.WebUiConfigData) {
|
||||||
return this.WebUiConfigData;
|
return this.WebUiConfigData;
|
||||||
}
|
}
|
||||||
try {
|
const defaultconfig: WebUiConfigType = {
|
||||||
const configPath = resolve(__dirname, './config/webui.json');
|
host: '0.0.0.0',
|
||||||
const config: WebUiConfigType = {
|
|
||||||
port: 6099,
|
port: 6099,
|
||||||
token: Math.random().toString(36).slice(2),//生成随机密码
|
prefix: '',
|
||||||
|
token: '', // 默认先填空,空密码无法登录
|
||||||
loginRate: 3
|
loginRate: 3
|
||||||
};
|
};
|
||||||
|
try {
|
||||||
|
defaultconfig.token = Math.random().toString(36).slice(2); //生成随机密码
|
||||||
|
} catch (e) {
|
||||||
|
logError('随机密码生成失败', e);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const configPath = resolve(__dirname, './config/webui.json');
|
||||||
|
|
||||||
if (!existsSync(configPath)) {
|
if (!existsSync(configPath)) {
|
||||||
writeFileSync(configPath, JSON.stringify(config, null, 4));
|
writeFileSync(configPath, JSON.stringify(defaultconfig, null, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileContent = readFileSync(configPath, 'utf-8');
|
const fileContent = readFileSync(configPath, 'utf-8');
|
||||||
const parsedConfig = JSON.parse(fileContent) as WebUiConfigType;
|
// 更新配置字段后新增字段可能会缺失,同步一下
|
||||||
|
const parsedConfig = this.applyDefaults(JSON.parse(fileContent) as Partial<WebUiConfigType>, defaultconfig);
|
||||||
|
|
||||||
|
if (!parsedConfig.prefix.startsWith('/')) parsedConfig.prefix = '/' + parsedConfig.prefix;
|
||||||
|
if (parsedConfig.prefix.endsWith('/')) parsedConfig.prefix = parsedConfig.prefix.slice(0, -1);
|
||||||
|
// 配置已经被操作过了,还是回写一下吧,不然新配置不会出现在配置文件里
|
||||||
|
writeFileSync(configPath, JSON.stringify(parsedConfig, null, 4));
|
||||||
|
// 不希望回写的配置放后面
|
||||||
|
|
||||||
|
// 查询主机地址是否可用
|
||||||
|
const [host_err, host] = await tryUseHost(parsedConfig.host).then(data => [null, data as string]).catch(err => [err, null]);
|
||||||
|
if (host_err) {
|
||||||
|
logError('host不可用', host_err);
|
||||||
|
parsedConfig.port = 0; // 设置为0,禁用WebUI
|
||||||
|
} else {
|
||||||
|
parsedConfig.host = host;
|
||||||
// 修正端口占用情况
|
// 修正端口占用情况
|
||||||
const [err, data] = await tryUsePort(parsedConfig.port).then(data => [null, data as number]).catch(err => [err, null]);
|
const [port_err, port] = await tryUsePort(parsedConfig.port, parsedConfig.host).then(data => [null, data as number]).catch(err => [err, null]);
|
||||||
parsedConfig.port = data;
|
if (port_err) {
|
||||||
if (err) {
|
logError('port不可用', port_err);
|
||||||
//一般没那么离谱 如果真有这么离谱 考虑下 向外抛出异常
|
parsedConfig.port = 0; // 设置为0,禁用WebUI
|
||||||
|
} else {
|
||||||
|
parsedConfig.port = port;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.WebUiConfigData = parsedConfig;
|
this.WebUiConfigData = parsedConfig;
|
||||||
return this.WebUiConfigData;
|
return this.WebUiConfigData;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError('读取配置文件失败', e);
|
logError('读取配置文件失败', e);
|
||||||
}
|
}
|
||||||
return {} as WebUiConfigType; // 理论上这行代码到不了,为了保持函数完整性而保留
|
return defaultconfig; // 理论上这行代码到不了,到了只能返回默认配置了
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export const WebUiConfig = new WebUiConfigWrapper();
|
export const WebUiConfig = new WebUiConfigWrapper();
|
@@ -15,7 +15,7 @@ async function onSettingWindowCreated(view: Element) {
|
|||||||
} else if (configKey.length === 3) {
|
} else if (configKey.length === 3) {
|
||||||
ob11Config[configKey[1]][configKey[2]] = value;
|
ob11Config[configKey[1]][configKey[2]] = value;
|
||||||
}
|
}
|
||||||
OB11ConfigWrapper.SetOB11Config(ob11Config);
|
// OB11ConfigWrapper.SetOB11Config(ob11Config); // 只有当点保存时才下发配置,而不是在修改值后立即下发
|
||||||
};
|
};
|
||||||
|
|
||||||
const parser = new DOMParser();
|
const parser = new DOMParser();
|
||||||
@@ -29,7 +29,7 @@ async function onSettingWindowCreated(view: Element) {
|
|||||||
SettingItem(
|
SettingItem(
|
||||||
'<span id="napcat-update-title">Napcat</span>',
|
'<span id="napcat-update-title">Napcat</span>',
|
||||||
undefined,
|
undefined,
|
||||||
SettingButton('V1.6.8', 'napcat-update-button', 'secondary')
|
SettingButton('V1.7.2', 'napcat-update-button', 'secondary')
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
SettingList([
|
SettingList([
|
||||||
@@ -192,7 +192,7 @@ async function onSettingWindowCreated(view: Element) {
|
|||||||
|
|
||||||
// 外链按钮
|
// 外链按钮
|
||||||
doc.querySelector('#open-github')?.addEventListener('click', () => {
|
doc.querySelector('#open-github')?.addEventListener('click', () => {
|
||||||
window.open('https://napneko.github.io/', '_blank');
|
window.open('https://github.com/NapNeko/NapCatQQ', '_blank');
|
||||||
});
|
});
|
||||||
doc.querySelector('#open-telegram')?.addEventListener('click', () => {
|
doc.querySelector('#open-telegram')?.addEventListener('click', () => {
|
||||||
window.open('https://t.me/+nLZEnpne-pQ1OWFl');
|
window.open('https://t.me/+nLZEnpne-pQ1OWFl');
|
||||||
@@ -201,7 +201,7 @@ async function onSettingWindowCreated(view: Element) {
|
|||||||
window.open('https://qm.qq.com/q/bDnHRG38aI');
|
window.open('https://qm.qq.com/q/bDnHRG38aI');
|
||||||
});
|
});
|
||||||
doc.querySelector('#open-docs')?.addEventListener('click', () => {
|
doc.querySelector('#open-docs')?.addEventListener('click', () => {
|
||||||
window.open('https://github.com/NapNeko/NapCatQQ');
|
window.open('https://napneko.github.io/', '_blank');
|
||||||
});
|
});
|
||||||
// 生成反向地址列表
|
// 生成反向地址列表
|
||||||
const buildHostListItem = (
|
const buildHostListItem = (
|
||||||
|
@@ -38,7 +38,7 @@ class WebUiApiOB11ConfigWrapper {
|
|||||||
this.retCredential = Credential;
|
this.retCredential = Credential;
|
||||||
}
|
}
|
||||||
async GetOB11Config(): Promise<OB11Config> {
|
async GetOB11Config(): Promise<OB11Config> {
|
||||||
const ConfigResponse = await fetch('/api/OB11Config/GetConfig', {
|
const ConfigResponse = await fetch('../api/OB11Config/GetConfig', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: 'Bearer ' + this.retCredential,
|
Authorization: 'Bearer ' + this.retCredential,
|
||||||
@@ -54,7 +54,7 @@ class WebUiApiOB11ConfigWrapper {
|
|||||||
return {} as OB11Config;
|
return {} as OB11Config;
|
||||||
}
|
}
|
||||||
async SetOB11Config(config: OB11Config): Promise<boolean> {
|
async SetOB11Config(config: OB11Config): Promise<boolean> {
|
||||||
const ConfigResponse = await fetch('/api/OB11Config/SetConfig', {
|
const ConfigResponse = await fetch('../api/OB11Config/SetConfig', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: 'Bearer ' + this.retCredential,
|
Authorization: 'Bearer ' + this.retCredential,
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
|
"host": "0.0.0.0",
|
||||||
"port": 6099,
|
"port": 6099,
|
||||||
|
"prefix": "",
|
||||||
"token": "random",
|
"token": "random",
|
||||||
"loginRate": 3
|
"loginRate": 3
|
||||||
|
|
||||||
|
@@ -160,7 +160,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
async function GetQQLoginQrcode(retCredential) {
|
async function GetQQLoginQrcode(retCredential) {
|
||||||
let QQLoginResponse = await fetch('/api/QQLogin/GetQQLoginQrcode', {
|
let QQLoginResponse = await fetch('../api/QQLogin/GetQQLoginQrcode', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': "Bearer " + retCredential,
|
'Authorization': "Bearer " + retCredential,
|
||||||
@@ -180,7 +180,7 @@
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
async function CheckQQLoginStatus(retCredential) {
|
async function CheckQQLoginStatus(retCredential) {
|
||||||
let QQLoginResponse = await fetch('/api/QQLogin/CheckLoginStatus', {
|
let QQLoginResponse = await fetch('../api/QQLogin/CheckLoginStatus', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': "Bearer " + retCredential,
|
'Authorization': "Bearer " + retCredential,
|
||||||
@@ -200,7 +200,7 @@
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
async function GetQQQucickLoginList(retCredential) {
|
async function GetQQQucickLoginList(retCredential) {
|
||||||
let QQLoginResponse = await fetch('/api/QQLogin/GetQuickLoginList', {
|
let QQLoginResponse = await fetch('../api/QQLogin/GetQuickLoginList', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': "Bearer " + retCredential,
|
'Authorization': "Bearer " + retCredential,
|
||||||
@@ -216,7 +216,7 @@
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
async function SetQuickLogin(uin, retCredential) {
|
async function SetQuickLogin(uin, retCredential) {
|
||||||
let QQLoginResponse = await fetch('/api/QQLogin/SetQuickLogin', {
|
let QQLoginResponse = await fetch('../api/QQLogin/SetQuickLogin', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': "Bearer " + retCredential,
|
'Authorization': "Bearer " + retCredential,
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
const SettingList = (items, title, isCollapsible = false, direction = "column") => {
|
const SettingList = (items, title, isCollapsible = false, direction = "column") => {
|
||||||
return `<setting-section ${title && !isCollapsible ? `data-title="${title}"` : ""}>
|
return `<setting-section ${""}>
|
||||||
<setting-panel>
|
<setting-panel>
|
||||||
<setting-list ${direction ? `data-direction="${direction}"` : ""} ${isCollapsible ? "is-collapsible" : ""} ${title && isCollapsible ? `data-title="${title}"` : ""}>
|
<setting-list ${direction ? `data-direction="${direction}"` : ""} ${isCollapsible ? "is-collapsible" : ""} ${""}>
|
||||||
${items.join("")}
|
${items.join("")}
|
||||||
</setting-list>
|
</setting-list>
|
||||||
</setting-panel>
|
</setting-panel>
|
||||||
@@ -66,16 +66,13 @@ window.customElements.define(
|
|||||||
window[`${isHidden ? "remove" : "add"}EventListener`]("pointerdown", windowPointerDown);
|
window[`${isHidden ? "remove" : "add"}EventListener`]("pointerdown", windowPointerDown);
|
||||||
};
|
};
|
||||||
const windowPointerDown = ({ target }) => {
|
const windowPointerDown = ({ target }) => {
|
||||||
if (!this.contains(target))
|
if (!this.contains(target)) buttonClick();
|
||||||
buttonClick();
|
|
||||||
};
|
};
|
||||||
this._button.addEventListener("click", buttonClick);
|
this._button.addEventListener("click", buttonClick);
|
||||||
this._context.addEventListener("click", ({ target }) => {
|
this._context.addEventListener("click", ({ target }) => {
|
||||||
if (target.tagName !== "SETTING-OPTION")
|
if (target.tagName !== "SETTING-OPTION") return;
|
||||||
return;
|
|
||||||
buttonClick();
|
buttonClick();
|
||||||
if (target.hasAttribute("is-selected"))
|
if (target.hasAttribute("is-selected")) return;
|
||||||
return;
|
|
||||||
this.querySelectorAll("setting-option[is-selected]").forEach((dom) => dom.toggleAttribute("is-selected"));
|
this.querySelectorAll("setting-option[is-selected]").forEach((dom) => dom.toggleAttribute("is-selected"));
|
||||||
target.toggleAttribute("is-selected");
|
target.toggleAttribute("is-selected");
|
||||||
this._text.value = target.textContent;
|
this._text.value = target.textContent;
|
||||||
@@ -95,9 +92,9 @@ window.customElements.define(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
const SettingSelect = (items, configKey, configValue) => {
|
const SettingSelect = (items, configKey, configValue) => {
|
||||||
return `<ob-setting-select ${configKey ? `data-config-key="${configKey}"` : ""}>
|
return `<ob-setting-select ${`data-config-key="${configKey}"` }>
|
||||||
${items.map((e, i) => {
|
${items.map((e, i) => {
|
||||||
return SettingOption(e.text, e.value, configKey && configValue ? configValue === e.value : i === 0);
|
return SettingOption(e.text, e.value, configValue ? configValue === e.value : i === 0);
|
||||||
}).join("")}
|
}).join("")}
|
||||||
</ob-setting-select>`;
|
</ob-setting-select>`;
|
||||||
};
|
};
|
||||||
@@ -108,7 +105,7 @@ class WebUiApiOB11ConfigWrapper {
|
|||||||
this.retCredential = Credential;
|
this.retCredential = Credential;
|
||||||
}
|
}
|
||||||
async GetOB11Config() {
|
async GetOB11Config() {
|
||||||
const ConfigResponse = await fetch("/api/OB11Config/GetConfig", {
|
const ConfigResponse = await fetch("../api/OB11Config/GetConfig", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: "Bearer " + this.retCredential,
|
Authorization: "Bearer " + this.retCredential,
|
||||||
@@ -124,7 +121,7 @@ class WebUiApiOB11ConfigWrapper {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
async SetOB11Config(config) {
|
async SetOB11Config(config) {
|
||||||
const ConfigResponse = await fetch("/api/OB11Config/SetConfig", {
|
const ConfigResponse = await fetch("../api/OB11Config/SetConfig", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: "Bearer " + this.retCredential,
|
Authorization: "Bearer " + this.retCredential,
|
||||||
@@ -154,7 +151,6 @@ async function onSettingWindowCreated(view) {
|
|||||||
} else if (configKey.length === 3) {
|
} else if (configKey.length === 3) {
|
||||||
ob11Config[configKey[1]][configKey[2]] = value;
|
ob11Config[configKey[1]][configKey[2]] = value;
|
||||||
}
|
}
|
||||||
OB11ConfigWrapper.SetOB11Config(ob11Config);
|
|
||||||
};
|
};
|
||||||
const parser = new DOMParser();
|
const parser = new DOMParser();
|
||||||
const doc = parser.parseFromString(
|
const doc = parser.parseFromString(
|
||||||
@@ -167,7 +163,7 @@ async function onSettingWindowCreated(view) {
|
|||||||
SettingItem(
|
SettingItem(
|
||||||
'<span id="napcat-update-title">Napcat</span>',
|
'<span id="napcat-update-title">Napcat</span>',
|
||||||
void 0,
|
void 0,
|
||||||
SettingButton("V1.6.8", "napcat-update-button", "secondary")
|
SettingButton("V1.7.2", "napcat-update-button", "secondary")
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
SettingList([
|
SettingList([
|
||||||
@@ -326,7 +322,7 @@ async function onSettingWindowCreated(view) {
|
|||||||
"text/html"
|
"text/html"
|
||||||
);
|
);
|
||||||
doc.querySelector("#open-github")?.addEventListener("click", () => {
|
doc.querySelector("#open-github")?.addEventListener("click", () => {
|
||||||
window.open("https://napneko.github.io/", "_blank");
|
window.open("https://github.com/NapNeko/NapCatQQ", "_blank");
|
||||||
});
|
});
|
||||||
doc.querySelector("#open-telegram")?.addEventListener("click", () => {
|
doc.querySelector("#open-telegram")?.addEventListener("click", () => {
|
||||||
window.open("https://t.me/+nLZEnpne-pQ1OWFl");
|
window.open("https://t.me/+nLZEnpne-pQ1OWFl");
|
||||||
@@ -335,7 +331,7 @@ async function onSettingWindowCreated(view) {
|
|||||||
window.open("https://qm.qq.com/q/bDnHRG38aI");
|
window.open("https://qm.qq.com/q/bDnHRG38aI");
|
||||||
});
|
});
|
||||||
doc.querySelector("#open-docs")?.addEventListener("click", () => {
|
doc.querySelector("#open-docs")?.addEventListener("click", () => {
|
||||||
window.open("https://github.com/NapNeko/NapCatQQ");
|
window.open("https://napneko.github.io/", "_blank");
|
||||||
});
|
});
|
||||||
const buildHostListItem = (type, host, index, inputAttrs = {}) => {
|
const buildHostListItem = (type, host, index, inputAttrs = {}) => {
|
||||||
const dom = {
|
const dom = {
|
||||||
@@ -431,19 +427,15 @@ async function onSettingWindowCreated(view) {
|
|||||||
dom.addEventListener("click", () => {
|
dom.addEventListener("click", () => {
|
||||||
const active = dom.getAttribute("is-active") == void 0;
|
const active = dom.getAttribute("is-active") == void 0;
|
||||||
setOB11Config(dom.dataset.configKey, active);
|
setOB11Config(dom.dataset.configKey, active);
|
||||||
if (active)
|
if (active) dom.setAttribute("is-active", "");
|
||||||
dom.setAttribute("is-active", "");
|
else dom.removeAttribute("is-active");
|
||||||
else
|
|
||||||
dom.removeAttribute("is-active");
|
|
||||||
if (!isEmpty(dom.dataset.controlDisplayId)) {
|
if (!isEmpty(dom.dataset.controlDisplayId)) {
|
||||||
const displayDom = document.querySelector(
|
const displayDom = document.querySelector(
|
||||||
//@ts-expect-error 等待修复
|
//@ts-expect-error 等待修复
|
||||||
`#${dom.dataset.controlDisplayId}`
|
`#${dom.dataset.controlDisplayId}`
|
||||||
);
|
);
|
||||||
if (active)
|
if (active) displayDom?.removeAttribute("is-hidden");
|
||||||
displayDom?.removeAttribute("is-hidden");
|
else displayDom?.setAttribute("is-hidden", "");
|
||||||
else
|
|
||||||
displayDom?.setAttribute("is-hidden", "");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<script>
|
<script>
|
||||||
async function CheckQQLoginStatus(retCredential) {
|
async function CheckQQLoginStatus(retCredential) {
|
||||||
let QQLoginResponse = await fetch('/api/QQLogin/CheckLoginStatus', {
|
let QQLoginResponse = await fetch('../api/QQLogin/CheckLoginStatus', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': "Bearer " + retCredential,
|
'Authorization': "Bearer " + retCredential,
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
async function CheckWebUiLogined(retCredential) {
|
async function CheckWebUiLogined(retCredential) {
|
||||||
let LoginResponse = await fetch('/api/auth/check', {
|
let LoginResponse = await fetch('../api/auth/check', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': "Bearer " + retCredential,
|
'Authorization': "Bearer " + retCredential,
|
||||||
|
@@ -86,7 +86,7 @@
|
|||||||
let data = "";
|
let data = "";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let loginResponse = await fetch('/api/auth/login', {
|
let loginResponse = await fetch('../api/auth/login', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
@@ -99,7 +99,7 @@
|
|||||||
//登录成功
|
//登录成功
|
||||||
let retCredential = loginResponseJson.data.Credential;
|
let retCredential = loginResponseJson.data.Credential;
|
||||||
localStorage.setItem('auth', retCredential);
|
localStorage.setItem('auth', retCredential);
|
||||||
let QQLoginResponse = await fetch('/api/QQLogin/CheckLoginStatus', {
|
let QQLoginResponse = await fetch('../api/QQLogin/CheckLoginStatus', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': "Bearer " + retCredential,
|
'Authorization': "Bearer " + retCredential,
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
describe('MessageUniqueWrapper', () => {
|
describe('MessageUniqueWrapper', () => {
|
||||||
let messageUniqueWrapper: MessageUniqueWrapper;
|
let messageUniqueWrapper: MessageUniqueWrapper;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
messageUniqueWrapper = new MessageUniqueWrapper();
|
messageUniqueWrapper = new MessageUniqueWrapper();
|
||||||
});
|
});
|
||||||
|
@@ -26,9 +26,9 @@ if (process.env.NAPCAT_BUILDSYS == 'linux') {
|
|||||||
} else if (process.env.NAPCAT_BUILDSYS == 'win32') {
|
} else if (process.env.NAPCAT_BUILDSYS == 'win32') {
|
||||||
if (process.env.NAPCAT_BUILDARCH == 'x64') {
|
if (process.env.NAPCAT_BUILDARCH == 'x64') {
|
||||||
}
|
}
|
||||||
startScripts = ['./script/napcat.ps1', './script/napcat.bat', './script/napcat-utf8.bat', './script/napcat-utf8.ps1', './script/napcat-log.ps1', './script/NapCat.164.bat', './script/napcat-9912.ps1', './script/napcat-9912-utf8.ps1', './script/napcat-9912.bat', './script/napcat-9912-utf8.bat'];
|
startScripts = ['./script/dbghelp.dll', './script/BootWay05.ps1', './script/napcat-9912.ps1', './script/napcat-9912-utf8.ps1', './script/napcat-9912.bat', './script/napcat-9912-utf8.bat'];
|
||||||
} else {
|
} else {
|
||||||
startScripts = ['./script/napcat.sh', './script/napcat.ps1', './script/napcat.bat', './script/napcat-utf8.bat', './script/napcat-utf8.ps1', './script/napcat-log.ps1', './script/napcat-9912.ps1', './script/napcat-9912-utf8.ps1', './script/napcat-9912.bat', './script/napcat-9912-utf8.bat'];
|
startScripts = ['./script/dbghelp.dll', './script/BootWay05.ps1', './script/napcat.sh', './script/napcat.ps1', './script/napcat.bat', './script/napcat-utf8.bat', './script/napcat-utf8.ps1', './script/napcat-log.ps1', './script/napcat-9912.ps1', './script/napcat-9912-utf8.ps1', './script/napcat-9912.bat', './script/napcat-9912-utf8.bat'];
|
||||||
}
|
}
|
||||||
|
|
||||||
const baseConfigPlugin: PluginOption[] = [
|
const baseConfigPlugin: PluginOption[] = [
|
||||||
|
Reference in New Issue
Block a user