mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
51 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5e0b3b2f35 | ||
![]() |
6829fad5bd | ||
![]() |
7af0d9e87b | ||
![]() |
c089ebea99 | ||
![]() |
d2a2c1c39c | ||
![]() |
ce9b09e8d1 | ||
![]() |
2f6dfe51f5 | ||
![]() |
bd227cd0b8 | ||
![]() |
96003724ab | ||
![]() |
6a08b15095 | ||
![]() |
dab0f9ab45 | ||
![]() |
e733a6b69a | ||
![]() |
9aca98bf13 | ||
![]() |
b7c95e53dc | ||
![]() |
f762c450ca | ||
![]() |
d58bbe53da | ||
![]() |
f32edd8af7 | ||
![]() |
c747a86e5b | ||
![]() |
abfda0dd58 | ||
![]() |
f66d7b11a8 | ||
![]() |
f425c9478e | ||
![]() |
756dea71fc | ||
![]() |
71a6c4ccc5 | ||
![]() |
ae2f4777ec | ||
![]() |
dcd9b8168a | ||
![]() |
4bb03ae5ba | ||
![]() |
8bd6f8397b | ||
![]() |
096e52d93e | ||
![]() |
037065291d | ||
![]() |
4cf52e1b13 | ||
![]() |
21b228552d | ||
![]() |
76b404cdd8 | ||
![]() |
937c594ff7 | ||
![]() |
b463140de7 | ||
![]() |
f518fb9214 | ||
![]() |
1092831718 | ||
![]() |
6b377416da | ||
![]() |
8f5baa47ec | ||
![]() |
5494ff0553 | ||
![]() |
7a4805b464 | ||
![]() |
8435375810 | ||
![]() |
c893ec6030 | ||
![]() |
e8bf6fa0a6 | ||
![]() |
f228129c19 | ||
![]() |
cbf98ffb89 | ||
![]() |
f6067b002f | ||
![]() |
636d1103e3 | ||
![]() |
bede517f7e | ||
![]() |
16e4891b7d | ||
![]() |
3bcd79fbb7 | ||
![]() |
aacf6c2917 |
3
.github/workflows/build.yml
vendored
3
.github/workflows/build.yml
vendored
@@ -1,5 +1,8 @@
|
|||||||
name: "Build Action"
|
name: "Build Action"
|
||||||
on:
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions: write-all
|
permissions: write-all
|
||||||
|
30
README.md
30
README.md
@@ -5,18 +5,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
---
|
---
|
||||||
## 欢迎回来
|
## 欢迎回家
|
||||||
NapCatQQ (aka 猫猫框架) 是现代化的基于 NTQQ 的 Bot 协议端实现
|
NapCatQQ 是现代化的基于 NTQQ 的 Bot 协议端实现
|
||||||
|
|
||||||
## 猫猫技能
|
## 碎碎叨叨
|
||||||
- [x] **启动方式**:支持以无头、LiteLoader 插件、仅 QQ GUI 三种方式启动
|
- [x] **安装简单**:就算是笨蛋也能使用
|
||||||
- [x] **覆盖平台**: 覆盖 Windows / Linux (可选 Docker) / Android Termux / MacOS
|
- [x] **性能友好**:就算是低内存也能使用
|
||||||
- [x] **安装简单**: 支持一键脚本/程序自动部署/镜像部署等多种覆盖范围
|
- [x] **接口丰富**:就算是没有也能使用
|
||||||
- [x] **超低占用**:无头模式占用资源极低,适合在服务器上运行
|
- [x] **稳定好用**:就算是被捉也能使用
|
||||||
- [x] **超多接口**:实现大部分 OneBot 和 go-cqhttp 接口,超多扩展 API
|
|
||||||
- [x] **远程管理**:自带 WebUI 支持,远程管理更加便捷
|
|
||||||
|
|
||||||
## 使用猫猫
|
## 使用框架
|
||||||
|
|
||||||
可前往 [Release](https://github.com/NapNeko/NapCatQQ/releases/) 页面下载最新版本
|
可前往 [Release](https://github.com/NapNeko/NapCatQQ/releases/) 页面下载最新版本
|
||||||
|
|
||||||
@@ -38,19 +36,15 @@ NapCatQQ (aka 猫猫框架) 是现代化的基于 NTQQ 的 Bot 协议端实现
|
|||||||
## 回家旅途
|
## 回家旅途
|
||||||
[QQ Group](https://qm.qq.com/q/VfjAq5HIMS)
|
[QQ Group](https://qm.qq.com/q/VfjAq5HIMS)
|
||||||
|
|
||||||
[Telegram Link](https://t.me/+nLZEnpne-pQ1OWFl)
|
## 感谢他们
|
||||||
|
|
||||||
## 猫猫朋友
|
|
||||||
感谢 [LLOneBot](https://github.com/LLOneBot/LLOneBot)
|
感谢 [LLOneBot](https://github.com/LLOneBot/LLOneBot)
|
||||||
|
|
||||||
感谢 [Lagrange](https://github.com/LagrangeDev/Lagrange.Core) 对本项目的大力支持
|
感谢 [Lagrange](https://github.com/LagrangeDev/Lagrange.Core) 对本项目的大力支持 参考部分代码 已获授权
|
||||||
|
|
||||||
不过最最重要的 还是需要感谢屏幕前的你哦~
|
不过最最重要的 还是需要感谢屏幕前的你哦~
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 约法三章
|
## 开源附加
|
||||||
> [!CAUTION]\
|
|
||||||
> **请不要在 QQ 官方群聊和任何影响力较大的简中互联网平台(包括但不限于: 哔哩哔哩,微博,知乎,抖音等)发布和讨论*任何*与本项目存在相关性的信息**
|
|
||||||
|
|
||||||
任何使用本仓库代码的地方,都应当严格遵守[本仓库开源许可](./LICENSE)。**此外,禁止任何项目未经授权二次分发或基于 NapCat 代码开发。**
|
任何使用本仓库代码的地方,都应当严格遵守[本仓库开源许可](./LICENSE)。**此外,禁止任何项目未经仓库主作者授权二次分发或基于 NapCat 代码开发。**
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
"name": "NapCatQQ",
|
"name": "NapCatQQ",
|
||||||
"slug": "NapCat.Framework",
|
"slug": "NapCat.Framework",
|
||||||
"description": "高性能的 OneBot 11 协议实现",
|
"description": "高性能的 OneBot 11 协议实现",
|
||||||
"version": "3.6.17",
|
"version": "4.0.0",
|
||||||
"icon": "./logo.png",
|
"icon": "./logo.png",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
"name": "napcat",
|
"name": "napcat",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "3.6.17",
|
"version": "4.0.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:framework": "vite build --mode framework",
|
"build:framework": "vite build --mode framework",
|
||||||
"build:shell": "vite build --mode shell",
|
"build:shell": "vite build --mode shell",
|
||||||
@@ -48,9 +48,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": "^5.0.0",
|
"express": "^5.0.0",
|
||||||
"fluent-ffmpeg": "^2.1.2",
|
|
||||||
"qrcode-terminal": "^0.12.0",
|
|
||||||
"silk-wasm": "^3.6.1",
|
"silk-wasm": "^3.6.1",
|
||||||
"ws": "^8.18.0"
|
"ws": "^8.18.0",
|
||||||
|
"qrcode-terminal": "^0.12.0",
|
||||||
|
"fluent-ffmpeg": "^2.1.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -21,9 +21,9 @@ type FuncKeys<T> = Extract<
|
|||||||
export type ListenerClassBase = Record<string, string>;
|
export type ListenerClassBase = Record<string, string>;
|
||||||
|
|
||||||
export class NTEventWrapper {
|
export class NTEventWrapper {
|
||||||
private WrapperSession: NodeIQQNTWrapperSession | undefined; //WrapperSession
|
private readonly WrapperSession: NodeIQQNTWrapperSession | undefined; //WrapperSession
|
||||||
private listenerManager: Map<string, ListenerClassBase> = new Map<string, ListenerClassBase>(); //ListenerName-Unique -> Listener实例
|
private readonly listenerManager: Map<string, ListenerClassBase> = new Map<string, ListenerClassBase>(); //ListenerName-Unique -> Listener实例
|
||||||
private EventTask = new Map<string, Map<string, Map<string, InternalMapKey>>>(); //tasks ListenerMainName -> ListenerSubName-> uuid -> {timeout,createtime,func}
|
private readonly EventTask = new Map<string, Map<string, Map<string, InternalMapKey>>>(); //tasks ListenerMainName -> ListenerSubName-> uuid -> {timeout,createtime,func}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
wrapperSession: NodeIQQNTWrapperSession,
|
wrapperSession: NodeIQQNTWrapperSession,
|
||||||
@@ -120,9 +120,9 @@ export class NTEventWrapper {
|
|||||||
ListenerType extends (...args: any) => any = EnsureFunc<ListenerNamingMapping[Listener][ListenerMethod]>,
|
ListenerType extends (...args: any) => any = EnsureFunc<ListenerNamingMapping[Listener][ListenerMethod]>,
|
||||||
>(
|
>(
|
||||||
listenerAndMethod: `${Listener}/${ListenerMethod}`,
|
listenerAndMethod: `${Listener}/${ListenerMethod}`,
|
||||||
|
checker: (...args: Parameters<ListenerType>) => boolean,
|
||||||
waitTimes = 1,
|
waitTimes = 1,
|
||||||
timeout = 5000,
|
timeout = 5000,
|
||||||
checker: (...args: Parameters<ListenerType>) => boolean,
|
|
||||||
) {
|
) {
|
||||||
return new Promise<Parameters<ListenerType>>((resolve, reject) => {
|
return new Promise<Parameters<ListenerType>>((resolve, reject) => {
|
||||||
const ListenerNameList = listenerAndMethod.split('/');
|
const ListenerNameList = listenerAndMethod.split('/');
|
||||||
@@ -181,14 +181,12 @@ export class NTEventWrapper {
|
|||||||
callbackTimesToWait = 1,
|
callbackTimesToWait = 1,
|
||||||
timeout = 5000,
|
timeout = 5000,
|
||||||
) {
|
) {
|
||||||
return new Promise<[EventRet: Awaited<ReturnType<EventType>>, ...Parameters<ListenerType>]>(
|
|
||||||
async (resolve, reject) => {
|
|
||||||
const id = randomUUID();
|
const id = randomUUID();
|
||||||
let complete = 0;
|
let complete = 0;
|
||||||
let retData: Parameters<ListenerType> | undefined = undefined;
|
let retData: Parameters<ListenerType> | undefined = undefined;
|
||||||
let retEvent: any = {};
|
let retEvent: any = {};
|
||||||
|
|
||||||
function sendDataCallback() {
|
function sendDataCallback(resolve: any, reject: any) {
|
||||||
if (complete == 0) {
|
if (complete == 0) {
|
||||||
reject(
|
reject(
|
||||||
new Error(
|
new Error(
|
||||||
@@ -210,7 +208,9 @@ export class NTEventWrapper {
|
|||||||
const ListenerMainName = ListenerNameList[0];
|
const ListenerMainName = ListenerNameList[0];
|
||||||
const ListenerSubName = ListenerNameList[1];
|
const ListenerSubName = ListenerNameList[1];
|
||||||
|
|
||||||
const timeoutRef = setTimeout(sendDataCallback, timeout);
|
return new Promise<[EventRet: Awaited<ReturnType<EventType>>, ...Parameters<ListenerType>]>(
|
||||||
|
(resolve, reject) => {
|
||||||
|
const timeoutRef = setTimeout(() => sendDataCallback(resolve, reject), timeout);
|
||||||
|
|
||||||
const eventCallback = {
|
const eventCallback = {
|
||||||
timeout: timeout,
|
timeout: timeout,
|
||||||
@@ -221,7 +221,7 @@ export class NTEventWrapper {
|
|||||||
retData = args as Parameters<ListenerType>;
|
retData = args as Parameters<ListenerType>;
|
||||||
if (complete >= callbackTimesToWait) {
|
if (complete >= callbackTimesToWait) {
|
||||||
clearTimeout(timeoutRef);
|
clearTimeout(timeoutRef);
|
||||||
sendDataCallback();
|
sendDataCallback(resolve, reject);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -233,8 +233,10 @@ export class NTEventWrapper {
|
|||||||
}
|
}
|
||||||
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallback);
|
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallback);
|
||||||
this.createListenerFunction(ListenerMainName);
|
this.createListenerFunction(ListenerMainName);
|
||||||
const eventFunction = this.createEventFunction(serviceAndMethod);
|
|
||||||
retEvent = await eventFunction!(...(args));
|
this.createEventFunction(serviceAndMethod)!(...(args))
|
||||||
|
.then((eventResult: any) => {
|
||||||
|
retEvent = eventResult;
|
||||||
if (!checkerEvent(retEvent) && timeoutRef.hasRef()) {
|
if (!checkerEvent(retEvent) && timeoutRef.hasRef()) {
|
||||||
clearTimeout(timeoutRef);
|
clearTimeout(timeoutRef);
|
||||||
reject(
|
reject(
|
||||||
@@ -249,7 +251,8 @@ export class NTEventWrapper {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.catch(reject);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -54,11 +54,7 @@ export class ForwardMsgBuilder {
|
|||||||
const id = crypto.randomUUID();
|
const id = crypto.randomUUID();
|
||||||
const isGroupMsg = msg.some(m => m.isGroupMsg);
|
const isGroupMsg = msg.some(m => m.isGroupMsg);
|
||||||
if (!source) {
|
if (!source) {
|
||||||
source = isGroupMsg ? "群聊的聊天记录" :
|
source = isGroupMsg ? "群聊的聊天记录" : msg.map(m => m.senderName).filter((v, i, a) => a.indexOf(v) === i).slice(0, 4).join('和') + '的聊天记录';
|
||||||
msg.length
|
|
||||||
? Array.from(new Set(msg.slice(0, 4).map(m => m.senderName)))
|
|
||||||
.join('和') + '的聊天记录'
|
|
||||||
: '聊天记录';
|
|
||||||
}
|
}
|
||||||
if (!news) {
|
if (!news) {
|
||||||
news = msg.length === 0 ? [{
|
news = msg.length === 0 ? [{
|
||||||
@@ -111,7 +107,7 @@ export class ForwardMsgBuilder {
|
|||||||
senderName: msg.senderName,
|
senderName: msg.senderName,
|
||||||
isGroupMsg: msg.groupId !== undefined,
|
isGroupMsg: msg.groupId !== undefined,
|
||||||
msg: msg.msg.map(m => ({
|
msg: msg.msg.map(m => ({
|
||||||
preview: m.valid? m.toPreview() : "[该消息类型暂不支持查看]",
|
preview: m.valid ? m.toPreview() : "[该消息类型暂不支持查看]",
|
||||||
}))
|
}))
|
||||||
})), source, news, summary, prompt);
|
})), source, news, summary, prompt);
|
||||||
}
|
}
|
||||||
|
@@ -74,6 +74,12 @@ export class LogWrapper {
|
|||||||
}
|
}
|
||||||
files.forEach(file => {
|
files.forEach(file => {
|
||||||
const filePath = path.join(logDir, file);
|
const filePath = path.join(logDir, file);
|
||||||
|
this.deleteOldLogFile(filePath, oneWeekAgo);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private deleteOldLogFile(filePath: string, oneWeekAgo: number) {
|
||||||
fs.stat(filePath, (err, stats) => {
|
fs.stat(filePath, (err, stats) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
this.logger.error('Failed to get file stats', err);
|
this.logger.error('Failed to get file stats', err);
|
||||||
@@ -83,18 +89,16 @@ export class LogWrapper {
|
|||||||
fs.unlink(filePath, err => {
|
fs.unlink(filePath, err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err.code === 'ENOENT') {
|
if (err.code === 'ENOENT') {
|
||||||
this.logger.warn(`File already deleted: ${file}`);
|
this.logger.warn(`File already deleted: ${filePath}`);
|
||||||
} else {
|
} else {
|
||||||
this.logger.error('Failed to delete old log file', err);
|
this.logger.error('Failed to delete old log file', err);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.logger.info(`Deleted old log file: ${file}`);
|
this.logger.info(`Deleted old log file: ${filePath}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setFileAndConsoleLogLevel(fileLogLevel: LogLevel, consoleLogLevel: LogLevel) {
|
setFileAndConsoleLogLevel(fileLogLevel: LogLevel, consoleLogLevel: LogLevel) {
|
||||||
@@ -198,7 +202,7 @@ export function rawMessageToText(msg: RawMessage, recursiveLevel = 0): string {
|
|||||||
tokens.push(`群聊 [${msg.peerName}(${msg.peerUin})]`);
|
tokens.push(`群聊 [${msg.peerName}(${msg.peerUin})]`);
|
||||||
}
|
}
|
||||||
if (msg.senderUin !== '0') {
|
if (msg.senderUin !== '0') {
|
||||||
tokens.push(`[${msg.sendMemberName || msg.sendRemarkName || msg.sendNickName}(${msg.senderUin})]`);
|
tokens.push(`[${msg.sendMemberName ?? msg.sendRemarkName ?? msg.sendNickName}(${msg.senderUin})]`);
|
||||||
}
|
}
|
||||||
} else if (msg.chatType == ChatType.KCHATTYPEDATALINE) {
|
} else if (msg.chatType == ChatType.KCHATTYPEDATALINE) {
|
||||||
tokens.push('移动设备');
|
tokens.push('移动设备');
|
||||||
@@ -206,28 +210,20 @@ export function rawMessageToText(msg: RawMessage, recursiveLevel = 0): string {
|
|||||||
tokens.push(`临时消息 (${msg.peerUin})`);
|
tokens.push(`临时消息 (${msg.peerUin})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function msgElementToText(element: MessageElement) {
|
for (const element of msg.elements) {
|
||||||
if (element.textElement) {
|
tokens.push(msgElementToText(element, msg, recursiveLevel));
|
||||||
if (element.textElement.atType === AtType.notAt) {
|
|
||||||
const originalContentLines = element.textElement.content.split('\n');
|
|
||||||
return `${originalContentLines[0]}${originalContentLines.length > 1 ? ' ...' : ''}`;
|
|
||||||
} else if (element.textElement.atType === AtType.atAll) {
|
|
||||||
return `@全体成员`;
|
|
||||||
} else if (element.textElement.atType === AtType.atUser) {
|
|
||||||
return `${element.textElement.content} (${element.textElement.atUid})`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return tokens.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
function msgElementToText(element: MessageElement, msg: RawMessage, recursiveLevel: number): string {
|
||||||
|
if (element.textElement) {
|
||||||
|
return textElementToText(element.textElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element.replyElement) {
|
if (element.replyElement) {
|
||||||
const recordMsgOrNull = msg.records.find(
|
return replyElementToText(element.replyElement, msg, recursiveLevel);
|
||||||
record => element.replyElement!.sourceMsgIdInRecords === record.msgId,
|
|
||||||
);
|
|
||||||
return `[回复消息 ${recordMsgOrNull &&
|
|
||||||
recordMsgOrNull.peerUin != '284840486' && recordMsgOrNull.peerUin != '1094950020'
|
|
||||||
?
|
|
||||||
rawMessageToText(recordMsgOrNull, recursiveLevel + 1) :
|
|
||||||
`未找到消息记录 (MsgId = ${element.replyElement.sourceMsgIdInRecords})`
|
|
||||||
}]`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element.picElement) {
|
if (element.picElement) {
|
||||||
@@ -271,11 +267,28 @@ export function rawMessageToText(msg: RawMessage, recursiveLevel = 0): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return `[未实现 (ElementType = ${element.elementType})]`;
|
return `[未实现 (ElementType = ${element.elementType})]`;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const element of msg.elements) {
|
function textElementToText(textElement: any): string {
|
||||||
tokens.push(msgElementToText(element));
|
if (textElement.atType === AtType.notAt) {
|
||||||
}
|
const originalContentLines = textElement.content.split('\n');
|
||||||
|
return `${originalContentLines[0]}${originalContentLines.length > 1 ? ' ...' : ''}`;
|
||||||
return tokens.join(' ');
|
} else if (textElement.atType === AtType.atAll) {
|
||||||
|
return `@全体成员`;
|
||||||
|
} else if (textElement.atType === AtType.atUser) {
|
||||||
|
return `${textElement.content} (${textElement.atUid})`;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function replyElementToText(replyElement: any, msg: RawMessage, recursiveLevel: number): string {
|
||||||
|
const recordMsgOrNull = msg.records.find(
|
||||||
|
record => replyElement.sourceMsgIdInRecords === record.msgId,
|
||||||
|
);
|
||||||
|
return `[回复消息 ${recordMsgOrNull &&
|
||||||
|
recordMsgOrNull.peerUin != '284840486' && recordMsgOrNull.peerUin != '1094950020'
|
||||||
|
?
|
||||||
|
rawMessageToText(recordMsgOrNull, recursiveLevel + 1) :
|
||||||
|
`未找到消息记录 (MsgId = ${replyElement.sourceMsgIdInRecords})`
|
||||||
|
}]`;
|
||||||
}
|
}
|
@@ -30,4 +30,13 @@ export class LRUCache<K, V> {
|
|||||||
}
|
}
|
||||||
this.cache.set(key, value);
|
this.cache.set(key, value);
|
||||||
}
|
}
|
||||||
|
public resetCapacity(newCapacity: number): void {
|
||||||
|
this.capacity = newCapacity;
|
||||||
|
while (this.cache.size > this.capacity) {
|
||||||
|
const firstKey = this.cache.keys().next().value;
|
||||||
|
if (firstKey !== undefined) {
|
||||||
|
this.cache.delete(firstKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@@ -2,8 +2,8 @@ import { Peer } from '@/core';
|
|||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
|
|
||||||
export class LimitedHashTable<K, V> {
|
export class LimitedHashTable<K, V> {
|
||||||
private keyToValue: Map<K, V> = new Map();
|
private readonly keyToValue: Map<K, V> = new Map();
|
||||||
private valueToKey: Map<V, K> = new Map();
|
private readonly valueToKey: Map<V, K> = new Map();
|
||||||
private maxSize: number;
|
private maxSize: number;
|
||||||
|
|
||||||
constructor(maxSize: number) {
|
constructor(maxSize: number) {
|
||||||
@@ -75,8 +75,8 @@ export class LimitedHashTable<K, V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MessageUniqueWrapper {
|
class MessageUniqueWrapper {
|
||||||
private msgDataMap: LimitedHashTable<string, number>;
|
private readonly msgDataMap: LimitedHashTable<string, number>;
|
||||||
private msgIdMap: LimitedHashTable<string, number>;
|
private readonly msgIdMap: LimitedHashTable<string, number>;
|
||||||
|
|
||||||
constructor(maxMap: number = 1000) {
|
constructor(maxMap: number = 1000) {
|
||||||
this.msgIdMap = new LimitedHashTable<string, number>(maxMap);
|
this.msgIdMap = new LimitedHashTable<string, number>(maxMap);
|
||||||
|
@@ -8,34 +8,40 @@ export class RequestUtil {
|
|||||||
const client = url.startsWith('https') ? https : http;
|
const client = url.startsWith('https') ? https : http;
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const req = client.get(url, (res) => {
|
const req = client.get(url, (res) => {
|
||||||
let cookies: { [key: string]: string } = {};
|
const cookies: { [key: string]: string } = {};
|
||||||
const handleRedirect = (res: http.IncomingMessage) => {
|
|
||||||
//console.log(res.headers.location);
|
res.on('data', () => { }); // Necessary to consume the stream
|
||||||
|
res.on('end', () => {
|
||||||
|
this.handleRedirect(res, url, cookies)
|
||||||
|
.then(resolve)
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.headers['set-cookie']) {
|
||||||
|
this.extractCookies(res.headers['set-cookie'], cookies);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on('error', (error: Error) => {
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async handleRedirect(res: http.IncomingMessage, url: string, cookies: { [key: string]: string }): Promise<{ [key: string]: string }> {
|
||||||
if (res.statusCode === 301 || res.statusCode === 302) {
|
if (res.statusCode === 301 || res.statusCode === 302) {
|
||||||
if (res.headers.location) {
|
if (res.headers.location) {
|
||||||
const redirectUrl = new URL(res.headers.location, url);
|
const redirectUrl = new URL(res.headers.location, url);
|
||||||
RequestUtil.HttpsGetCookies(redirectUrl.href).then((redirectCookies) => {
|
const redirectCookies = await this.HttpsGetCookies(redirectUrl.href);
|
||||||
// 合并重定向过程中的cookies
|
// 合并重定向过程中的cookies
|
||||||
cookies = { ...cookies, ...redirectCookies };
|
return { ...cookies, ...redirectCookies };
|
||||||
resolve(cookies);
|
|
||||||
}).catch((err) => {
|
|
||||||
reject(err);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
resolve(cookies);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
resolve(cookies);
|
|
||||||
}
|
}
|
||||||
};
|
return cookies;
|
||||||
res.on('data', () => {
|
}
|
||||||
}); // Necessary to consume the stream
|
|
||||||
res.on('end', () => {
|
private static extractCookies(setCookieHeaders: string[], cookies: { [key: string]: string }) {
|
||||||
handleRedirect(res);
|
setCookieHeaders.forEach((cookie) => {
|
||||||
});
|
|
||||||
if (res.headers['set-cookie']) {
|
|
||||||
//console.log(res.headers['set-cookie']);
|
|
||||||
res.headers['set-cookie'].forEach((cookie) => {
|
|
||||||
const parts = cookie.split(';')[0].split('=');
|
const parts = cookie.split(';')[0].split('=');
|
||||||
const key = parts[0];
|
const key = parts[0];
|
||||||
const value = parts[1];
|
const value = parts[1];
|
||||||
@@ -44,13 +50,6 @@ export class RequestUtil {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
req.on('error', (error: any) => {
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 请求和回复都是JSON data传原始内容 自动编码json
|
// 请求和回复都是JSON data传原始内容 自动编码json
|
||||||
static async HttpGetJson<T>(url: string, method: string = 'GET', data?: any, headers: {
|
static async HttpGetJson<T>(url: string, method: string = 'GET', data?: any, headers: {
|
||||||
@@ -88,13 +87,13 @@ export class RequestUtil {
|
|||||||
} else {
|
} else {
|
||||||
reject(new Error(`Unexpected status code: ${res.statusCode}`));
|
reject(new Error(`Unexpected status code: ${res.statusCode}`));
|
||||||
}
|
}
|
||||||
} catch (parseError) {
|
} catch (parseError: unknown) {
|
||||||
reject(parseError);
|
reject(new Error((parseError as Error).message));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
req.on('error', (error: any) => {
|
req.on('error', (error: Error) => {
|
||||||
reject(error);
|
reject(error);
|
||||||
});
|
});
|
||||||
if (method === 'POST' || method === 'PUT' || method === 'PATCH') {
|
if (method === 'POST' || method === 'PUT' || method === 'PATCH') {
|
||||||
@@ -133,62 +132,4 @@ export class RequestUtil {
|
|||||||
Buffer.from(footer, 'utf8'),
|
Buffer.from(footer, 'utf8'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async uploadImageForOpenPlatform(filePath: string, cookies: string): Promise<string> {
|
|
||||||
return new Promise(async (resolve, reject) => {
|
|
||||||
type retType = { retcode: number, result?: { url: string } };
|
|
||||||
try {
|
|
||||||
const options = {
|
|
||||||
hostname: 'cgi.connect.qq.com',
|
|
||||||
port: 443,
|
|
||||||
path: '/qqconnectopen/upload_share_image',
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Referer': 'https://cgi.connect.qq.com',
|
|
||||||
'Cookie': cookies,
|
|
||||||
'Accept': '*/*',
|
|
||||||
'Connection': 'keep-alive',
|
|
||||||
'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const req = https.request(options, async (res) => {
|
|
||||||
let responseBody = '';
|
|
||||||
|
|
||||||
res.on('data', (chunk: string | Buffer) => {
|
|
||||||
responseBody += chunk.toString();
|
|
||||||
});
|
|
||||||
|
|
||||||
res.on('end', () => {
|
|
||||||
try {
|
|
||||||
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
|
||||||
const responseJson = JSON.parse(responseBody) as retType;
|
|
||||||
resolve(responseJson.result!.url!);
|
|
||||||
} else {
|
|
||||||
reject(new Error(`Unexpected status code: ${res.statusCode}`));
|
|
||||||
}
|
|
||||||
} catch (parseError) {
|
|
||||||
reject(parseError);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
req.on('error', (error) => {
|
|
||||||
reject(error);
|
|
||||||
console.log('Error during upload:', error);
|
|
||||||
});
|
|
||||||
|
|
||||||
const body = await RequestUtil.createFormData('WebKitFormBoundary7MA4YWxkTrZu0gW', filePath);
|
|
||||||
// req.setHeader('Content-Length', Buffer.byteLength(body));
|
|
||||||
// console.log(`Prepared data size: ${Buffer.byteLength(body)} bytes`);
|
|
||||||
req.write(body);
|
|
||||||
req.end();
|
|
||||||
return;
|
|
||||||
} catch (error) {
|
|
||||||
reject(error);
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -1 +1 @@
|
|||||||
export const napCatVersion = '3.6.17';
|
export const napCatVersion = '4.0.0';
|
||||||
|
@@ -20,7 +20,7 @@ export async function getVideoInfo(filePath: string, logger: LogWrapper) {
|
|||||||
ffmpeg.setFfmpegPath(ffmpegPath);
|
ffmpeg.setFfmpegPath(ffmpegPath);
|
||||||
ffmpeg(filePath).ffprobe((err: any, metadata: ffmpeg.FfprobeData) => {
|
ffmpeg(filePath).ffprobe((err: any, metadata: ffmpeg.FfprobeData) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err);
|
reject(new Error('无法获取视频信息。'));
|
||||||
} else {
|
} else {
|
||||||
const videoStream = metadata.streams.find((s: FfprobeStream) => s.codec_type === 'video');
|
const videoStream = metadata.streams.find((s: FfprobeStream) => s.codec_type === 'video');
|
||||||
if (videoStream) {
|
if (videoStream) {
|
||||||
|
@@ -6,8 +6,10 @@ export class NodeIDependsAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMSFSsoError(args: unknown) {
|
onMSFSsoError(args: unknown) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getGroupCode(args: unknown) {
|
getGroupCode(args: unknown) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -357,16 +357,14 @@ export class NTQQFileApi {
|
|||||||
|
|
||||||
async getImageSize(filePath: string): Promise<ISizeCalculationResult> {
|
async getImageSize(filePath: string): Promise<ISizeCalculationResult> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
imageSize(filePath, (err, dimensions) => {
|
imageSize(filePath, (err: Error | null, dimensions) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err);
|
reject(new Error(err.message));
|
||||||
} else {
|
} else if (!dimensions) {
|
||||||
if (!dimensions) {
|
|
||||||
reject(new Error('获取图片尺寸失败'));
|
reject(new Error('获取图片尺寸失败'));
|
||||||
} else {
|
} else {
|
||||||
resolve(dimensions);
|
resolve(dimensions);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -408,26 +406,31 @@ export class NTQQFileApi {
|
|||||||
return fileData.filePath!;
|
return fileData.filePath!;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getImageUrl(element: PicElement) {
|
async getImageUrl(element: PicElement): Promise<string> {
|
||||||
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;
|
||||||
|
|
||||||
if (url) {
|
if (url) {
|
||||||
const parsedUrl = new URL(IMAGE_HTTP_HOST + url);
|
const parsedUrl = new URL(IMAGE_HTTP_HOST + url);
|
||||||
const urlRkey = parsedUrl.searchParams.get('rkey');
|
const rkeyData = await this.getRkeyData();
|
||||||
const imageAppid = parsedUrl.searchParams.get('appid');
|
return this.getImageUrlFromParsedUrl(parsedUrl, rkeyData);
|
||||||
const isNTV2 = imageAppid && ['1406', '1407'].includes(imageAppid);
|
}
|
||||||
const imageFileId = parsedUrl.searchParams.get('fileid');
|
|
||||||
|
|
||||||
|
return this.getImageUrlFromMd5(fileMd5, md5HexStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getRkeyData() {
|
||||||
const rkeyData = {
|
const rkeyData = {
|
||||||
private_rkey: 'CAQSKAB6JWENi5LM_xp9vumLbuThJSaYf-yzMrbZsuq7Uz2qEc3Rbib9LP4',
|
private_rkey: 'CAQSKAB6JWENi5LM_xp9vumLbuThJSaYf-yzMrbZsuq7Uz2qEc3Rbib9LP4',
|
||||||
group_rkey: 'CAQSKAB6JWENi5LM_xp9vumLbuThJSaYf-yzMrbZsuq7Uz2qffcqm614gds',
|
group_rkey: 'CAQSKAB6JWENi5LM_xp9vumLbuThJSaYf-yzMrbZsuq7Uz2qffcqm614gds',
|
||||||
online_rkey: false
|
online_rkey: false
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (this.core.apis.PacketApi.available) {
|
if (this.core.apis.PacketApi.available) {
|
||||||
const rkey_expired_private = !this.packetRkey || this.packetRkey[0].time + Number(this.packetRkey[0].ttl) < Date.now() / 1000;
|
const rkey_expired_private = !this.packetRkey || this.packetRkey[0].time + Number(this.packetRkey[0].ttl) < Date.now() / 1000;
|
||||||
@@ -455,23 +458,35 @@ export class NTQQFileApi {
|
|||||||
this.context.logger.logError.bind(this.context.logger)('获取rkey失败 Fallback Old Mode', e);
|
this.context.logger.logError.bind(this.context.logger)('获取rkey失败 Fallback Old Mode', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return rkeyData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getImageUrlFromParsedUrl(parsedUrl: URL, rkeyData: any): string {
|
||||||
|
const urlRkey = parsedUrl.searchParams.get('rkey');
|
||||||
|
const imageAppid = parsedUrl.searchParams.get('appid');
|
||||||
|
const isNTV2 = imageAppid && ['1406', '1407'].includes(imageAppid);
|
||||||
|
const imageFileId = parsedUrl.searchParams.get('fileid');
|
||||||
|
|
||||||
if (isNTV2 && urlRkey) {
|
if (isNTV2 && urlRkey) {
|
||||||
return IMAGE_HTTP_HOST_NT + urlRkey;
|
return IMAGE_HTTP_HOST_NT + urlRkey;
|
||||||
} else if (isNTV2 && rkeyData.online_rkey) {
|
} else if (isNTV2 && rkeyData.online_rkey) {
|
||||||
const rkey = imageAppid === '1406' ? rkeyData.private_rkey : rkeyData.group_rkey;
|
const rkey = imageAppid === '1406' ? rkeyData.private_rkey : rkeyData.group_rkey;
|
||||||
return IMAGE_HTTP_HOST_NT + url + `&rkey=${rkey}`;
|
return IMAGE_HTTP_HOST_NT + parsedUrl.pathname + `&rkey=${rkey}`;
|
||||||
} else if (isNTV2 && imageFileId) {
|
} else if (isNTV2 && imageFileId) {
|
||||||
const rkey = imageAppid === '1406' ? rkeyData.private_rkey : rkeyData.group_rkey;
|
const rkey = imageAppid === '1406' ? rkeyData.private_rkey : rkeyData.group_rkey;
|
||||||
return IMAGE_HTTP_HOST + `/download?appid=${imageAppid}&fileid=${imageFileId}&rkey=${rkey}`;
|
return IMAGE_HTTP_HOST + `/download?appid=${imageAppid}&fileid=${imageFileId}&rkey=${rkey}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
//到这里说明可能是旧客户端
|
|
||||||
|
private getImageUrlFromMd5(fileMd5: string | undefined, md5HexStr: string | undefined): string {
|
||||||
if (fileMd5 || md5HexStr) {
|
if (fileMd5 || md5HexStr) {
|
||||||
return `${IMAGE_HTTP_HOST}/gchatpic_new/0/0-0-${(fileMd5 ?? md5HexStr)!.toUpperCase()}/0`;
|
return `${IMAGE_HTTP_HOST}/gchatpic_new/0/0-0-${(fileMd5 ?? md5HexStr)!.toUpperCase()}/0`;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.context.logger.logDebug('图片url获取失败', element);
|
this.context.logger.logDebug('图片url获取失败', { fileMd5, md5HexStr });
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,7 +15,7 @@ export class NTQQFriendApi {
|
|||||||
}
|
}
|
||||||
async getBuddyV2SimpleInfoMap(refresh = false) {
|
async getBuddyV2SimpleInfoMap(refresh = false) {
|
||||||
const buddyService = this.context.session.getBuddyService();
|
const buddyService = this.context.session.getBuddyService();
|
||||||
const buddyListV2 = refresh ? await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL) : await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL);
|
const buddyListV2 = await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL);
|
||||||
const uids = buddyListV2.data.flatMap(item => item.buddyUids);
|
const uids = buddyListV2.data.flatMap(item => item.buddyUids);
|
||||||
return await this.core.eventWrapper.callNoListenerEvent(
|
return await this.core.eventWrapper.callNoListenerEvent(
|
||||||
'NodeIKernelProfileService/getCoreAndBaseInfo',
|
'NodeIKernelProfileService/getCoreAndBaseInfo',
|
||||||
@@ -41,14 +41,10 @@ export class NTQQFriendApi {
|
|||||||
tempBothDel: tempBothDel
|
tempBothDel: tempBothDel
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
async getBuddyV2ExWithCate(refresh = false) {
|
async getBuddyV2ExWithCate() {
|
||||||
const categoryMap: Map<string, any> = new Map();
|
|
||||||
const buddyService = this.context.session.getBuddyService();
|
const buddyService = this.context.session.getBuddyService();
|
||||||
const buddyListV2 = refresh ? (await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL)).data : (await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL)).data;
|
const buddyListV2 = (await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL)).data;
|
||||||
const uids = buddyListV2.flatMap(item => {
|
const uids = buddyListV2.flatMap(item => {
|
||||||
item.buddyUids.forEach(uid => {
|
|
||||||
categoryMap.set(uid, { categoryId: item.categoryId, categoryName: item.categroyName });
|
|
||||||
});
|
|
||||||
return item.buddyUids;
|
return item.buddyUids;
|
||||||
});
|
});
|
||||||
const data = await this.core.eventWrapper.callNoListenerEvent(
|
const data = await this.core.eventWrapper.callNoListenerEvent(
|
||||||
|
@@ -25,9 +25,10 @@ export class NTQQGroupApi {
|
|||||||
constructor(context: InstanceContext, core: NapCatCore) {
|
constructor(context: InstanceContext, core: NapCatCore) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.core = core;
|
this.core = core;
|
||||||
this.initCache().then().catch(context.logger.logError.bind(context.logger));
|
|
||||||
}
|
}
|
||||||
|
async initApi() {
|
||||||
|
this.initCache().then().catch(this.context.logger.logError.bind(this.context.logger));
|
||||||
|
}
|
||||||
async initCache() {
|
async initCache() {
|
||||||
this.groups = await this.getGroups();
|
this.groups = await this.getGroups();
|
||||||
for (const group of this.groups) {
|
for (const group of this.groups) {
|
||||||
@@ -54,7 +55,7 @@ export class NTQQGroupApi {
|
|||||||
}, pskey);
|
}, pskey);
|
||||||
}
|
}
|
||||||
async getGroupShutUpMemberList(groupCode: string) {
|
async getGroupShutUpMemberList(groupCode: string) {
|
||||||
const data = this.core.eventWrapper.registerListen('NodeIKernelGroupListener/onShutUpMemberListChanged', 1, 1000, (group_id) => group_id === groupCode);
|
const data = this.core.eventWrapper.registerListen('NodeIKernelGroupListener/onShutUpMemberListChanged', (group_id) => group_id === groupCode, 1, 1000);
|
||||||
this.context.session.getGroupService().getGroupShutUpMemberList(groupCode);
|
this.context.session.getGroupService().getGroupShutUpMemberList(groupCode);
|
||||||
return (await data)[1];
|
return (await data)[1];
|
||||||
}
|
}
|
||||||
@@ -258,9 +259,9 @@ export class NTQQGroupApi {
|
|||||||
async getGroupMemberV2(GroupCode: string, uid: string, forced = false) {
|
async getGroupMemberV2(GroupCode: string, uid: string, forced = false) {
|
||||||
const Listener = this.core.eventWrapper.registerListen(
|
const Listener = this.core.eventWrapper.registerListen(
|
||||||
'NodeIKernelGroupListener/onMemberInfoChange',
|
'NodeIKernelGroupListener/onMemberInfoChange',
|
||||||
|
(params, _, members) => params === GroupCode && members.size > 0,
|
||||||
1,
|
1,
|
||||||
forced ? 5000 : 250,
|
forced ? 5000 : 250,
|
||||||
(params, _, members) => params === GroupCode && members.size > 0,
|
|
||||||
);
|
);
|
||||||
const retData = await (
|
const retData = await (
|
||||||
this.core.eventWrapper
|
this.core.eventWrapper
|
||||||
@@ -318,13 +319,13 @@ export class NTQQGroupApi {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
async tryGetGroupMembersV2(modeListener = false, groupQQ: string, num = 30, timeout = 100): Promise<{
|
async tryGetGroupMembersV2(groupQQ: string, modeListener = false, num = 30, timeout = 100): Promise<{
|
||||||
infos: Map<string, GroupMember>;
|
infos: Map<string, GroupMember>;
|
||||||
finish: boolean;
|
finish: boolean;
|
||||||
hasNext: boolean | undefined;
|
hasNext: boolean | undefined;
|
||||||
}> {
|
}> {
|
||||||
const sceneId = this.context.session.getGroupService().createMemberListScene(groupQQ, 'groupMemberList_MainWindow_1');
|
const sceneId = this.context.session.getGroupService().createMemberListScene(groupQQ, 'groupMemberList_MainWindow_1');
|
||||||
const once = this.core.eventWrapper.registerListen('NodeIKernelGroupListener/onMemberListChange', 0, timeout, (params) => params.sceneId === sceneId)
|
const once = this.core.eventWrapper.registerListen('NodeIKernelGroupListener/onMemberListChange', (params) => params.sceneId === sceneId, 0, timeout)
|
||||||
.catch(() => { });
|
.catch(() => { });
|
||||||
const result = await this.context.session.getGroupService().getNextMemberList(sceneId, undefined, num);
|
const result = await this.context.session.getGroupService().getNextMemberList(sceneId, undefined, num);
|
||||||
if (result.errCode !== 0) {
|
if (result.errCode !== 0) {
|
||||||
@@ -352,7 +353,7 @@ export class NTQQGroupApi {
|
|||||||
listenerMode: boolean;
|
listenerMode: boolean;
|
||||||
}> {
|
}> {
|
||||||
const sceneId = this.context.session.getGroupService().createMemberListScene(groupQQ, 'groupMemberList_MainWindow_1');
|
const sceneId = this.context.session.getGroupService().createMemberListScene(groupQQ, 'groupMemberList_MainWindow_1');
|
||||||
const once = this.core.eventWrapper.registerListen('NodeIKernelGroupListener/onMemberListChange', 0, timeout, (params) => params.sceneId === sceneId)
|
const once = this.core.eventWrapper.registerListen('NodeIKernelGroupListener/onMemberListChange', (params) => params.sceneId === sceneId, 0, timeout)
|
||||||
.catch(() => { });
|
.catch(() => { });
|
||||||
const result = await this.context.session.getGroupService().getNextMemberList(sceneId, undefined, num);
|
const result = await this.context.session.getGroupService().getNextMemberList(sceneId, undefined, num);
|
||||||
if (result.errCode !== 0) {
|
if (result.errCode !== 0) {
|
||||||
@@ -371,7 +372,7 @@ export class NTQQGroupApi {
|
|||||||
infos: new Map([...(resMode2?.infos ?? []), ...result.result.infos]),
|
infos: new Map([...(resMode2?.infos ?? []), ...result.result.infos]),
|
||||||
finish: result.result.finish,
|
finish: result.result.finish,
|
||||||
hasNext: resMode2?.hasNext,
|
hasNext: resMode2?.hasNext,
|
||||||
listenerMode: resMode2?.hasNext !== undefined ? true : false
|
listenerMode: resMode2?.hasNext !== undefined
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4,5 +4,4 @@ export * from './group';
|
|||||||
export * from './msg';
|
export * from './msg';
|
||||||
export * from './user';
|
export * from './user';
|
||||||
export * from './webapi';
|
export * from './webapi';
|
||||||
export * from './sign';
|
|
||||||
export * from './system';
|
export * from './system';
|
@@ -144,7 +144,7 @@ export class NTQQMsgApi {
|
|||||||
params,
|
params,
|
||||||
],
|
],
|
||||||
() => true,
|
() => true,
|
||||||
() => true, // Todo: 应当通过 groupFileListResult 判断
|
() => true, // 应当通过 groupFileListResult 判断
|
||||||
1,
|
1,
|
||||||
5000,
|
5000,
|
||||||
);
|
);
|
||||||
@@ -194,7 +194,7 @@ export class NTQQMsgApi {
|
|||||||
async sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
|
async sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
|
||||||
//唉?!我有个想法
|
//唉?!我有个想法
|
||||||
if (peer.chatType === ChatType.KCHATTYPETEMPC2CFROMGROUP && peer.guildId && peer.guildId !== '') {
|
if (peer.chatType === ChatType.KCHATTYPETEMPC2CFROMGROUP && peer.guildId && peer.guildId !== '') {
|
||||||
const member = await this.core.apis.GroupApi.getGroupMember(peer.guildId, peer.peerUid!);
|
const member = await this.core.apis.GroupApi.getGroupMember(peer.guildId, peer.peerUid);
|
||||||
if (member) {
|
if (member) {
|
||||||
await this.PrepareTempChat(peer.peerUid, peer.guildId, member.nick);
|
await this.PrepareTempChat(peer.peerUid, peer.guildId, member.nick);
|
||||||
}
|
}
|
||||||
|
@@ -26,14 +26,15 @@ export class NTQQPacketApi {
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
this.core = core;
|
this.core = core;
|
||||||
this.logger = core.context.logger;
|
this.logger = core.context.logger;
|
||||||
this.InitSendPacket(this.context.basicInfoWrapper.getFullQQVesion())
|
}
|
||||||
|
async initApi() {
|
||||||
|
await this.InitSendPacket(this.context.basicInfoWrapper.getFullQQVesion())
|
||||||
.then()
|
.then()
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
this.logger.logError.bind(this.core.context.logger);
|
this.logger.logError.bind(this.core.context.logger);
|
||||||
this.errStack.push(err);
|
this.errStack.push(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get available(): boolean {
|
get available(): boolean {
|
||||||
return this.pkt?.available ?? false;
|
return this.pkt?.available ?? false;
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
import { RequestUtil } from '@/common/request';
|
|
||||||
import { MiniAppLuaJsonType } from '@/core';
|
|
||||||
import { InstanceContext, NapCatCore } from '..';
|
import { InstanceContext, NapCatCore } from '..';
|
||||||
|
|
||||||
export class NTQQMusicSignApi {
|
export class NTQQMusicSignApi {
|
||||||
@@ -10,210 +8,6 @@ export class NTQQMusicSignApi {
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
this.core = core;
|
this.core = core;
|
||||||
}
|
}
|
||||||
|
|
||||||
async signMiniApp(CardData: MiniAppLuaJsonType) {
|
|
||||||
// {
|
|
||||||
// "app": "com.tencent.miniapp.lua",
|
|
||||||
// "bizsrc": "tianxuan.imgJumpArk",
|
|
||||||
// "view": "miniapp",
|
|
||||||
// "prompt": "hi! 这里有我的日常故事,只想讲给你听",
|
|
||||||
// "config": {
|
|
||||||
// "type": "normal",
|
|
||||||
// "forward": 1,
|
|
||||||
// "autosize": 0
|
|
||||||
// },
|
|
||||||
// "meta": {
|
|
||||||
// "miniapp": {
|
|
||||||
// "title": "hi! 这里有我的日常故事,只想讲给你听",
|
|
||||||
// "preview": "https:\/\/tianquan.gtimg.cn\/qqAIAgent\/item\/7\/square.png",
|
|
||||||
// "jumpUrl": "https:\/\/club.vip.qq.com\/transfer?open_kuikly_info=%7B%22version%22%3A%20%221%22%2C%22src_type%22%3A%20%22web%22%2C%22kr_turbo_display%22%3A%20%221%22%2C%22page_name%22%3A%20%22vas_ai_persona_moments%22%2C%22bundle_name%22%3A%20%22vas_ai_persona_moments%22%7D&page_name=vas_ai_persona_moments&enteranceId=share&robot_uin=3889008584",
|
|
||||||
// "tag": "QQ智能体",
|
|
||||||
// "tagIcon": "https:\/\/tianquan.gtimg.cn\/shoal\/qqAIAgent\/3e9d70c9-d98c-45b8-80b4-79d82971b514.png",
|
|
||||||
// "source": "QQ智能体",
|
|
||||||
// "sourcelogo": "https:\/\/tianquan.gtimg.cn\/shoal\/qqAIAgent\/3e9d70c9-d98c-45b8-80b4-79d82971b514.png"
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// token : function(url,skey){
|
|
||||||
// var str = skey || cookie('skey') || cookie('rv2') || '',
|
|
||||||
// hash = 5381;
|
|
||||||
// if(url){
|
|
||||||
// var hostname = uri(url).hostname;
|
|
||||||
// if(hostname.indexOf('qun.qq.com') > -1 || (hostname.indexOf('qzone.qq.com') > -1 && hostname.indexOf('qun.qzone.qq.com') === -1)){
|
|
||||||
// str = cookie('p_skey') || str;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// for(var i = 0, len = str.length; i < len; ++i){
|
|
||||||
// hash += (hash << 5) + str.charAt(i).charCodeAt();
|
|
||||||
// }
|
|
||||||
// return hash & 0x7fffffff;
|
|
||||||
// },
|
|
||||||
//
|
|
||||||
|
|
||||||
// function signToken(skey: string) {
|
|
||||||
// let hash = 5381;
|
|
||||||
// for (let i = 0, len = skey.length; i < len; ++i) {
|
|
||||||
// hash += (hash << 5) + skey.charCodeAt(i);
|
|
||||||
// }
|
|
||||||
// return hash & 0x7fffffff;
|
|
||||||
// }
|
|
||||||
const signCard = {
|
|
||||||
'app': 'com.tencent.miniapp.lua',
|
|
||||||
'bizsrc': 'tianxuan.imgJumpArk',
|
|
||||||
'view': 'miniapp',
|
|
||||||
'prompt': CardData.prompt,
|
|
||||||
'config': {
|
|
||||||
'type': 'normal',
|
|
||||||
'forward': 1,
|
|
||||||
'autosize': 0,
|
|
||||||
},
|
|
||||||
'meta': {
|
|
||||||
'miniapp': {
|
|
||||||
'title': CardData.title,
|
|
||||||
'preview': (CardData.preview as string).replace(/\\/g, '\\/\\/'),
|
|
||||||
'jumpUrl': (CardData.jumpUrl as string).replace(/\\/g, '\\/\\/'),
|
|
||||||
'tag': CardData.tag,
|
|
||||||
'tagIcon': (CardData.tagIcon as string).replace(/\\/g, '\\/\\/'),
|
|
||||||
'source': CardData.source,
|
|
||||||
'sourcelogo': (CardData.sourcelogo as string).replace(/\\/g, '\\/\\/'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
// let signCard = {
|
|
||||||
// "app": "com.tencent.eventshare.lua",
|
|
||||||
// "prompt": "Bot Test",
|
|
||||||
// "bizsrc": "tianxuan.business",
|
|
||||||
// "meta": {
|
|
||||||
// "eventshare": {
|
|
||||||
// "button1URL": "https://www.bilibili.com",
|
|
||||||
// "button1disable": false,
|
|
||||||
// "button1title": "点我前往",
|
|
||||||
// "button2URL": "",
|
|
||||||
// "button2disable": false,
|
|
||||||
// "button2title": "",
|
|
||||||
// "buttonNum": 1,
|
|
||||||
// "jumpURL": "https://www.bilibili.com",
|
|
||||||
// "preview": "https://tianquan.gtimg.cn/shoal/card/9930bc4e-4a92-4da3-814f-8094a2421d9c.png",
|
|
||||||
// "tag": "QQ集卡",
|
|
||||||
// "tagIcon": "https://tianquan.gtimg.cn/shoal/card/c034854b-102d-40be-a545-5ca90a7c49c9.png",
|
|
||||||
// "title": "Bot Test"
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// "config": {
|
|
||||||
// "autosize": 0,
|
|
||||||
// "collect": 0,
|
|
||||||
// "ctime": 1716568575,
|
|
||||||
// "forward": 1,
|
|
||||||
// "height": 336,
|
|
||||||
// "reply": 0,
|
|
||||||
// "round": 1,
|
|
||||||
// "type": "normal",
|
|
||||||
// "width": 263
|
|
||||||
// },
|
|
||||||
// "view": "eventshare",
|
|
||||||
// "ver": "0.0.0.1"
|
|
||||||
// };
|
|
||||||
const data = (await this.core.apis.UserApi.getQzoneCookies());
|
|
||||||
const Bkn = this.core.apis.WebApi.getBknFromCookie(data.p_skey);
|
|
||||||
|
|
||||||
const CookieValue = 'p_skey=' + data.p_skey + '; skey=' + data.skey + '; p_uin=o' + this.core.selfInfo.uin + '; uin=o' + this.core.selfInfo.uin;
|
|
||||||
|
|
||||||
const signurl = 'https://h5.qzone.qq.com/v2/vip/tx/trpc/ark-share/GenNewSignedArk?g_tk=' + Bkn + '&ark=' + encodeURIComponent(JSON.stringify(signCard));
|
|
||||||
let signed_ark = '';
|
|
||||||
try {
|
|
||||||
const retData = await RequestUtil.HttpGetJson<{
|
|
||||||
code: number,
|
|
||||||
data: { signed_ark: string }
|
|
||||||
}>(signurl, 'GET', undefined, { Cookie: CookieValue });
|
|
||||||
//logDebug('MiniApp JSON 消息生成成功', retData);
|
|
||||||
signed_ark = retData.data.signed_ark;
|
|
||||||
} catch (error) {
|
|
||||||
this.context.logger.logDebug('MiniApp JSON 消息生成失败', error);
|
|
||||||
}
|
|
||||||
return signed_ark;
|
|
||||||
}
|
|
||||||
|
|
||||||
async signInternal(songname: string, singer: string, cover: string, songmid: string, songmusic: string) {
|
|
||||||
//curl -X POST 'https://mqq.reader.qq.com/api/mqq/share/card?accessToken&_csrfToken&source=c0003' -H 'Content-Type: application/json' -H 'Cookie: uin=o10086' -d '{"app":"com.tencent.qqreader.share","config":{"ctime":1718634110,"forward":1,"token":"9a63343c32d5a16bcde653eb97faa25d","type":"normal"},"extra":{"app_type":1,"appid":100497308,"msg_seq":14386738075403815000.0,"uin":1733139081},"meta":{"music":{"action":"","android_pkg_name":"","app_type":1,"appid":100497308,"ctime":1718634110,"desc":"周杰伦","jumpUrl":"https://i.y.qq.com/v8/playsong.html?songmid=0039MnYb0qxYhV&type=0","musicUrl":"http://ws.stream.qqmusic.qq.com/http://isure6.stream.qqmusic.qq.com/M800002202B43Cq4V4.mp3?fromtag=810033622&guid=br_xzg&trace=23fe7bcbe2336bbf&uin=553&vkey=CF0F5CE8B0FA16F3001F8A88D877A217EB5E4F00BDCEF1021EB6C48969CA33C6303987AEECE9CC840122DD2F917A59D6130D8A8CA4577C87","preview":"https://y.qq.com/music/photo_new/T002R800x800M000000MkMni19ClKG.jpg","cover":"https://y.qq.com/music/photo_new/T002R800x800M000000MkMni19ClKG.jpg","sourceMsgId":"0","source_icon":"https://p.qpic.cn/qqconnect/0/app_100497308_1626060999/100?max-age=2592000&t=0","source_url":"","tag":"QQ音乐","title":"晴天","uin":10086}},"prompt":"[分享]晴天","ver":"0.0.0.1","view":"music"}'
|
|
||||||
const signurl = 'https://mqq.reader.qq.com/api/mqq/share/card?accessToken&_csrfToken&source=c0003';
|
|
||||||
//let = "https://y.qq.com/music/photo_new/T002R800x800M000000MkMni19ClKG.jpg";
|
|
||||||
const signCard = {
|
|
||||||
app: 'com.tencent.qqreader.share',
|
|
||||||
config: {
|
|
||||||
ctime: 1718634110,
|
|
||||||
forward: 1,
|
|
||||||
token: '9a63343c32d5a16bcde653eb97faa25d',
|
|
||||||
type: 'normal',
|
|
||||||
},
|
|
||||||
extra: {
|
|
||||||
app_type: 1,
|
|
||||||
appid: 100497308,
|
|
||||||
msg_seq: 14386738075403815000,
|
|
||||||
uin: 1733139081,
|
|
||||||
},
|
|
||||||
meta: {
|
|
||||||
music: {
|
|
||||||
action: '',
|
|
||||||
android_pkg_name: '',
|
|
||||||
app_type: 1,
|
|
||||||
appid: 100497308,
|
|
||||||
ctime: 1718634110,
|
|
||||||
desc: singer,
|
|
||||||
jumpUrl: 'https://i.y.qq.com/v8/playsong.html?songmid=' + songmid + '&type=0',
|
|
||||||
musicUrl: songmusic,
|
|
||||||
preview: cover,
|
|
||||||
cover: cover,
|
|
||||||
sourceMsgId: '0',
|
|
||||||
source_icon: 'https://p.qpic.cn/qqconnect/0/app_100497308_1626060999/100?max-age=2592000&t=0',
|
|
||||||
source_url: '',
|
|
||||||
tag: 'QQ音乐',
|
|
||||||
title: songname,
|
|
||||||
uin: 10086,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
prompt: '[分享]' + songname,
|
|
||||||
ver: '0.0.0.1',
|
|
||||||
view: 'music',
|
|
||||||
};
|
|
||||||
//console.log(JSON.stringify(signCard, null, 2));
|
|
||||||
const data = await RequestUtil.HttpGetJson<{ code: number, data: { arkResult: string } }>
|
|
||||||
(signurl, 'POST', signCard, { 'Cookie': 'uin=o10086', 'Content-Type': 'application/json' });
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
//注意处理错误
|
|
||||||
async signWay03(id: string = '', mid: string = '') {
|
|
||||||
let signedMid;
|
|
||||||
if (mid == '') {
|
|
||||||
const MusicInfo = await RequestUtil.HttpGetJson<{
|
|
||||||
songinfo?: {
|
|
||||||
data?: {
|
|
||||||
track_info: {
|
|
||||||
mid: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}>(
|
|
||||||
'https://u.y.qq.com/cgi-bin/musicu.fcg?format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq.json&needNewCode=0&data={"comm":{"ct":24,"cv":0},"songinfo":{"method":"get_song_detail_yqq","param":{"song_type":0,"song_mid":"","song_id":' + id + '},"module":"music.pf_song_detail_svr"}}',
|
|
||||||
'GET',
|
|
||||||
undefined,
|
|
||||||
);
|
|
||||||
signedMid = MusicInfo.songinfo?.data?.track_info.mid;
|
|
||||||
}
|
|
||||||
//第三方接口 存在速率限制 现在勉强用
|
|
||||||
const MusicReal = await RequestUtil.HttpGetJson<{
|
|
||||||
code: number,
|
|
||||||
data?: {
|
|
||||||
name: string,
|
|
||||||
singer: string,
|
|
||||||
url: string,
|
|
||||||
cover: string
|
|
||||||
}
|
|
||||||
}>('https://api.leafone.cn/api/qqmusic?id=' + signedMid + '&type=8', 'GET');
|
|
||||||
//console.log(MusicReal);
|
|
||||||
return { ...MusicReal.data, mid: signedMid };
|
|
||||||
}
|
|
||||||
//转换外域名为 https://qq.ugcimg.cn/v1/cpqcbu4b8870i61bde6k7cbmjgejq8mr3in82qir4qi7ielffv5slv8ck8g42novtmev26i233ujtuab6tvu2l2sjgtupfr389191v00s1j5oh5325j5eqi40774jv1i/khovifoh7jrqd6eahoiv7koh8o
|
//转换外域名为 https://qq.ugcimg.cn/v1/cpqcbu4b8870i61bde6k7cbmjgejq8mr3in82qir4qi7ielffv5slv8ck8g42novtmev26i233ujtuab6tvu2l2sjgtupfr389191v00s1j5oh5325j5eqi40774jv1i/khovifoh7jrqd6eahoiv7koh8o
|
||||||
//https://cgi.connect.qq.com/qqconnectopen/openapi/change_image_url?url=https://th.bing.com/th?id=OSK.b8ed36f1fb1889de6dc84fd81c187773&w=46&h=46&c=11&rs=1&qlt=80&o=6&dpr=2&pid=SANGAM
|
//https://cgi.connect.qq.com/qqconnectopen/openapi/change_image_url?url=https://th.bing.com/th?id=OSK.b8ed36f1fb1889de6dc84fd81c187773&w=46&h=46&c=11&rs=1&qlt=80&o=6&dpr=2&pid=SANGAM
|
||||||
|
|
||||||
@@ -227,10 +21,5 @@ export class NTQQMusicSignApi {
|
|||||||
//https://y.gtimg.cn/music/photo_new/T002R800x800M000000y5gq7449K9I.jpg?max_age=2592000
|
//https://y.gtimg.cn/music/photo_new/T002R800x800M000000y5gq7449K9I.jpg?max_age=2592000
|
||||||
|
|
||||||
//还有一处公告上传可以上传高质量图片 持久为qq域名
|
//还有一处公告上传可以上传高质量图片 持久为qq域名
|
||||||
async SignMusicWrapper(id: string = '') {
|
|
||||||
const MusicInfo = await this.signWay03(id)!;
|
|
||||||
return await this.signInternal(MusicInfo.name!, MusicInfo.singer!, MusicInfo.cover!, MusicInfo.mid!, 'https://ws.stream.qqmusic.qq.com/' + MusicInfo.url!);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -212,15 +212,13 @@ export class NTQQWebApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getGroupHonorInfo(groupCode: string, getType: WebHonorType) {
|
private async getDataInternal(cookieObject: any, groupCode: string, type: number) {
|
||||||
const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com');
|
|
||||||
const getDataInternal = async (Internal_groupCode: string, Internal_type: number) => {
|
|
||||||
let resJson;
|
let resJson;
|
||||||
try {
|
try {
|
||||||
const res = await RequestUtil.HttpGetText(
|
const res = await RequestUtil.HttpGetText(
|
||||||
`https://qun.qq.com/interactive/honorlist?${new URLSearchParams({
|
`https://qun.qq.com/interactive/honorlist?${new URLSearchParams({
|
||||||
gc: Internal_groupCode,
|
gc: groupCode,
|
||||||
type: Internal_type.toString(),
|
type: type.toString(),
|
||||||
}).toString()}`,
|
}).toString()}`,
|
||||||
'GET',
|
'GET',
|
||||||
'',
|
'',
|
||||||
@@ -230,90 +228,49 @@ export class NTQQWebApi {
|
|||||||
if (match) {
|
if (match) {
|
||||||
resJson = JSON.parse(match[1].trim());
|
resJson = JSON.parse(match[1].trim());
|
||||||
}
|
}
|
||||||
if (Internal_type === 1) {
|
return type === 1 ? resJson?.talkativeList : resJson?.actorList;
|
||||||
return resJson?.talkativeList;
|
|
||||||
} else {
|
|
||||||
return resJson?.actorList;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.context.logger.logDebug('获取当前群荣耀失败', e);
|
this.context.logger.logDebug('获取当前群荣耀失败', e);
|
||||||
}
|
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getHonorList(cookieObject: any, groupCode: string, type: number) {
|
||||||
|
const data = await this.getDataInternal(cookieObject, groupCode, type);
|
||||||
|
if (!data) {
|
||||||
|
this.context.logger.logError(`获取类型 ${type} 的荣誉信息失败`);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return data.map((item: any) => ({
|
||||||
|
user_id: item?.uin,
|
||||||
|
nickname: item?.name,
|
||||||
|
avatar: item?.avatar,
|
||||||
|
description: item?.desc,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
async getGroupHonorInfo(groupCode: string, getType: WebHonorType) {
|
||||||
|
const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com');
|
||||||
const HonorInfo: any = { group_id: groupCode };
|
const HonorInfo: any = { group_id: groupCode };
|
||||||
|
|
||||||
if (getType === WebHonorType.TALKATIVE || getType === WebHonorType.ALL) {
|
if (getType === WebHonorType.TALKATIVE || getType === WebHonorType.ALL) {
|
||||||
const RetInternal = await getDataInternal(groupCode, 1);
|
const talkativeList = await this.getHonorList(cookieObject, groupCode, 1);
|
||||||
if (RetInternal) {
|
if (talkativeList.length > 0) {
|
||||||
HonorInfo.current_talkative = {
|
HonorInfo.current_talkative = talkativeList[0];
|
||||||
user_id: RetInternal[0]?.uin,
|
HonorInfo.talkative_list = talkativeList;
|
||||||
avatar: RetInternal[0]?.avatar,
|
|
||||||
nickname: RetInternal[0]?.name,
|
|
||||||
day_count: 0,
|
|
||||||
description: RetInternal[0]?.desc,
|
|
||||||
};
|
|
||||||
HonorInfo.talkative_list = [];
|
|
||||||
for (const talkative_ele of RetInternal) {
|
|
||||||
HonorInfo.talkative_list.push({
|
|
||||||
user_id: talkative_ele?.uin,
|
|
||||||
avatar: talkative_ele?.avatar,
|
|
||||||
description: talkative_ele?.desc,
|
|
||||||
day_count: 0,
|
|
||||||
nickname: talkative_ele?.name,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.context.logger.logError.bind(this.context.logger)('获取龙王信息失败');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getType === WebHonorType.PERFORMER || getType === WebHonorType.ALL) {
|
if (getType === WebHonorType.PERFORMER || getType === WebHonorType.ALL) {
|
||||||
const RetInternal = await getDataInternal(groupCode, 2);
|
HonorInfo.performer_list = await this.getHonorList(cookieObject, groupCode, 2);
|
||||||
if (RetInternal) {
|
|
||||||
HonorInfo.performer_list = [];
|
|
||||||
for (const performer_ele of RetInternal) {
|
|
||||||
HonorInfo.performer_list.push({
|
|
||||||
user_id: performer_ele?.uin,
|
|
||||||
nickname: performer_ele?.name,
|
|
||||||
avatar: performer_ele?.avatar,
|
|
||||||
description: performer_ele?.desc,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.context.logger.logError.bind(this.context.logger)('获取群聊之火失败');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getType === WebHonorType.LEGEND || getType === WebHonorType.ALL) {
|
if (getType === WebHonorType.LEGEND || getType === WebHonorType.ALL) {
|
||||||
const RetInternal = await getDataInternal(groupCode, 3);
|
HonorInfo.legend_list = await this.getHonorList(cookieObject, groupCode, 3);
|
||||||
if (RetInternal) {
|
|
||||||
HonorInfo.legend_list = [];
|
|
||||||
for (const legend_ele of RetInternal) {
|
|
||||||
HonorInfo.legend_list.push({
|
|
||||||
user_id: legend_ele?.uin,
|
|
||||||
nickname: legend_ele?.name,
|
|
||||||
avatar: legend_ele?.avatar,
|
|
||||||
desc: legend_ele?.description,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.context.logger.logError.bind(this.context.logger)('获取群聊炽焰失败');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getType === WebHonorType.EMOTION || getType === WebHonorType.ALL) {
|
if (getType === WebHonorType.EMOTION || getType === WebHonorType.ALL) {
|
||||||
const RetInternal = await getDataInternal(groupCode, 6);
|
HonorInfo.emotion_list = await this.getHonorList(cookieObject, groupCode, 6);
|
||||||
if (RetInternal) {
|
|
||||||
HonorInfo.emotion_list = [];
|
|
||||||
for (const emotion_ele of RetInternal) {
|
|
||||||
HonorInfo.emotion_list.push({
|
|
||||||
user_id: emotion_ele.uin,
|
|
||||||
nickname: emotion_ele.name,
|
|
||||||
avatar: emotion_ele.avatar,
|
|
||||||
desc: emotion_ele.description,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.context.logger.logError.bind(this.context.logger)('获取快乐源泉失败');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 冒尖小春笋好像已经被tx扬了 R.I.P.
|
// 冒尖小春笋好像已经被tx扬了 R.I.P.
|
||||||
|
@@ -23,7 +23,7 @@ export interface ChatCacheList {
|
|||||||
export interface ChatCacheListItem {
|
export interface ChatCacheListItem {
|
||||||
chatType: ChatType;
|
chatType: ChatType;
|
||||||
basicChatCacheInfo: ChatCacheListItemBasic;
|
basicChatCacheInfo: ChatCacheListItemBasic;
|
||||||
guildChatCacheInfo: unknown[]; // TODO: 没用过频道所以不知道这里边的详细内容
|
guildChatCacheInfo: unknown[]; // work: 没用过频道所以不知道这里边的详细内容
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ChatCacheListItemBasic {
|
export interface ChatCacheListItemBasic {
|
||||||
|
@@ -117,7 +117,7 @@ export enum GroupMemberRole {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface GroupMember {
|
export interface GroupMember {
|
||||||
memberRealLevel: string | undefined;
|
memberRealLevel: number | undefined;
|
||||||
memberSpecialTitle?: string;
|
memberSpecialTitle?: string;
|
||||||
avatarPath: string;
|
avatarPath: string;
|
||||||
cardName: string;
|
cardName: string;
|
||||||
|
@@ -175,8 +175,8 @@ export interface SimpleInfo {
|
|||||||
status: UserStatus | null;
|
status: UserStatus | null;
|
||||||
vasInfo: VasInfo | null;
|
vasInfo: VasInfo | null;
|
||||||
relationFlags: RelationFlags | null;
|
relationFlags: RelationFlags | null;
|
||||||
otherFlags: any | null;
|
otherFlags: any;
|
||||||
intimate: any | null;
|
intimate: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FriendV2 = SimpleInfo;
|
export type FriendV2 = SimpleInfo;
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
// TODO: further refactor in NapCat.Packet v2
|
// work:further refactor in NapCat.Packet v2
|
||||||
import { NapProtoMsg, ProtoField, ScalarType } from "@napneko/nap-proto-core";
|
import { NapProtoMsg, ProtoField, ScalarType } from "@napneko/nap-proto-core";
|
||||||
|
|
||||||
const LikeDetail = {
|
const LikeDetail = {
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
// TODO: further refactor in NapCat.Packet v2
|
// work:further refactor in NapCat.Packet v2
|
||||||
import { NapProtoMsg, ProtoField, ScalarType } from "@napneko/nap-proto-core";
|
import { NapProtoMsg, ProtoField, ScalarType } from "@napneko/nap-proto-core";
|
||||||
|
|
||||||
const BodyInner = {
|
const BodyInner = {
|
||||||
|
@@ -84,11 +84,10 @@ export function getMajorPath(QQVersion: string): string {
|
|||||||
}
|
}
|
||||||
export class NapCatCore {
|
export class NapCatCore {
|
||||||
readonly context: InstanceContext;
|
readonly context: InstanceContext;
|
||||||
readonly apis: StableNTApiWrapper;
|
|
||||||
readonly eventWrapper: NTEventWrapper;
|
readonly eventWrapper: NTEventWrapper;
|
||||||
// readonly eventChannel: NTEventChannel;
|
NapCatDataPath: string = '';
|
||||||
NapCatDataPath: string;
|
NapCatTempPath: string = '';
|
||||||
NapCatTempPath: string;
|
apis: StableNTApiWrapper;
|
||||||
// runtime info, not readonly
|
// runtime info, not readonly
|
||||||
selfInfo: SelfInfo;
|
selfInfo: SelfInfo;
|
||||||
util: NodeQQNTWrapperUtil;
|
util: NodeQQNTWrapperUtil;
|
||||||
@@ -112,6 +111,8 @@ export class NapCatCore {
|
|||||||
UserApi: new NTQQUserApi(this.context, this),
|
UserApi: new NTQQUserApi(this.context, this),
|
||||||
GroupApi: new NTQQGroupApi(this.context, this),
|
GroupApi: new NTQQGroupApi(this.context, this),
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
async initCore() {
|
||||||
this.NapCatDataPath = path.join(this.dataPath, 'NapCat');
|
this.NapCatDataPath = path.join(this.dataPath, 'NapCat');
|
||||||
fs.mkdirSync(this.NapCatDataPath, { recursive: true });
|
fs.mkdirSync(this.NapCatDataPath, { recursive: true });
|
||||||
this.NapCatTempPath = path.join(this.NapCatDataPath, 'temp');
|
this.NapCatTempPath = path.join(this.NapCatDataPath, 'temp');
|
||||||
@@ -119,7 +120,13 @@ export class NapCatCore {
|
|||||||
if (!fs.existsSync(this.NapCatTempPath)) {
|
if (!fs.existsSync(this.NapCatTempPath)) {
|
||||||
fs.mkdirSync(this.NapCatTempPath, { recursive: true });
|
fs.mkdirSync(this.NapCatTempPath, { recursive: true });
|
||||||
}
|
}
|
||||||
|
//遍历this.apis[i].initApi 如果存在该函数进行async 调用
|
||||||
|
for (const apiKey in this.apis) {
|
||||||
|
const api = this.apis[apiKey as keyof StableNTApiWrapper];
|
||||||
|
if ('initApi' in api && typeof api.initApi === 'function') {
|
||||||
|
await api.initApi();
|
||||||
|
}
|
||||||
|
}
|
||||||
this.initNapCatCoreListeners().then().catch(this.context.logger.logError.bind(this.context.logger));
|
this.initNapCatCoreListeners().then().catch(this.context.logger.logError.bind(this.context.logger));
|
||||||
|
|
||||||
this.context.logger.setFileLogEnabled(
|
this.context.logger.setFileLogEnabled(
|
||||||
@@ -133,7 +140,6 @@ export class NapCatCore {
|
|||||||
this.configLoader.configData.consoleLogLevel as LogLevel,
|
this.configLoader.configData.consoleLogLevel as LogLevel,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get dataPath(): string {
|
get dataPath(): string {
|
||||||
let result = this.context.wrapper.NodeQQNTWrapperUtil.getNTUserDataInfoConfig();
|
let result = this.context.wrapper.NodeQQNTWrapperUtil.getNTUserDataInfoConfig();
|
||||||
if (!result) {
|
if (!result) {
|
||||||
@@ -204,7 +210,7 @@ export class NapCatCore {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
groupListener.onMemberListChange = (arg) => {
|
groupListener.onMemberListChange = (arg) => {
|
||||||
// todo: 应该加一个内部自己维护的成员变动callback,用于判断成员变化通知
|
// work:应该加一个内部自己维护的成员变动callback,用于判断成员变化通知
|
||||||
const groupCode = arg.sceneId.split('_')[0];
|
const groupCode = arg.sceneId.split('_')[0];
|
||||||
if (this.apis.GroupApi.groupMemberCache.has(groupCode)) {
|
if (this.apis.GroupApi.groupMemberCache.has(groupCode)) {
|
||||||
const existMembers = this.apis.GroupApi.groupMemberCache.get(groupCode)!;
|
const existMembers = this.apis.GroupApi.groupMemberCache.get(groupCode)!;
|
||||||
@@ -214,7 +220,7 @@ export class NapCatCore {
|
|||||||
if (existMember) {
|
if (existMember) {
|
||||||
Object.assign(existMember, member);
|
Object.assign(existMember, member);
|
||||||
} else {
|
} else {
|
||||||
existMembers!.set(uid, member);
|
existMembers.set(uid, member);
|
||||||
}
|
}
|
||||||
//移除成员
|
//移除成员
|
||||||
if (member.isDelete) {
|
if (member.isDelete) {
|
||||||
|
@@ -3,57 +3,57 @@ import { BuddyCategoryType, FriendRequestNotify } from '@/core/entities';
|
|||||||
export type OnBuddyChangeParams = BuddyCategoryType[];
|
export type OnBuddyChangeParams = BuddyCategoryType[];
|
||||||
|
|
||||||
export class NodeIKernelBuddyListener {
|
export class NodeIKernelBuddyListener {
|
||||||
onBuddyListChangedV2(arg: unknown): void {
|
onBuddyListChangedV2(arg: unknown): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onAddBuddyNeedVerify(arg: unknown) {
|
onAddBuddyNeedVerify(arg: unknown): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onAddMeSettingChanged(arg: unknown) {
|
onAddMeSettingChanged(arg: unknown): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onAvatarUrlUpdated(arg: unknown) {
|
onAvatarUrlUpdated(arg: unknown): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onBlockChanged(arg: unknown) {
|
onBlockChanged(arg: unknown): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onBuddyDetailInfoChange(arg: unknown) {
|
onBuddyDetailInfoChange(arg: unknown): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onBuddyInfoChange(arg: unknown) {
|
onBuddyInfoChange(arg: unknown): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onBuddyListChange(arg: OnBuddyChangeParams): void {
|
onBuddyListChange(arg: OnBuddyChangeParams): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onBuddyRemarkUpdated(arg: unknown): void {
|
onBuddyRemarkUpdated(arg: unknown): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onBuddyReqChange(arg: FriendRequestNotify): void {
|
onBuddyReqChange(arg: FriendRequestNotify): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onBuddyReqUnreadCntChange(arg: unknown): void {
|
onBuddyReqUnreadCntChange(arg: unknown): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onCheckBuddySettingResult(arg: unknown): void {
|
onCheckBuddySettingResult(arg: unknown): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onDelBatchBuddyInfos(arg: unknown): void {
|
onDelBatchBuddyInfos(arg: unknown): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onDoubtBuddyReqChange(arg: unknown): void {
|
onDoubtBuddyReqChange(arg: unknown): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onDoubtBuddyReqUnreadNumChange(arg: unknown): void {
|
onDoubtBuddyReqUnreadNumChange(arg: unknown): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onNickUpdated(arg: unknown): void {
|
onNickUpdated(arg: unknown): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onSmartInfos(arg: unknown): void {
|
onSmartInfos(arg: unknown): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onSpacePermissionInfos(arg: unknown): void {
|
onSpacePermissionInfos(arg: unknown): any {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -7,19 +7,19 @@ export class NodeIKernelFileAssistantListener {
|
|||||||
fileSpeed: number,
|
fileSpeed: number,
|
||||||
thumbPath: string | null,
|
thumbPath: string | null,
|
||||||
filePath: string | null,
|
filePath: string | null,
|
||||||
}) {
|
}): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onSessionListChanged(...args: unknown[]) {
|
onSessionListChanged(...args: unknown[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onSessionChanged(...args: unknown[]) {
|
onSessionChanged(...args: unknown[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onFileListChanged(...args: unknown[]) {
|
onFileListChanged(...args: unknown[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onFileSearch(searchResult: SearchResultWrapper) {
|
onFileSearch(searchResult: SearchResultWrapper): any {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,70 +1,70 @@
|
|||||||
import { DataSource, Group, GroupListUpdateType, GroupMember, GroupNotify, ShutUpGroupMember } from '@/core/entities';
|
import { DataSource, Group, GroupListUpdateType, GroupMember, GroupNotify, ShutUpGroupMember } from '@/core/entities';
|
||||||
|
|
||||||
export class NodeIKernelGroupListener {
|
export class NodeIKernelGroupListener {
|
||||||
onGroupListInited(listEmpty: boolean): void { }
|
onGroupListInited(listEmpty: boolean): any { }
|
||||||
// 发现于Win 9.9.9 23159
|
// 发现于Win 9.9.9 23159
|
||||||
onGroupMemberLevelInfoChange(...args: unknown[]): void {
|
onGroupMemberLevelInfoChange(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onGetGroupBulletinListResult(...args: unknown[]) {
|
onGetGroupBulletinListResult(...args: unknown[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupAllInfoChange(...args: unknown[]) {
|
onGroupAllInfoChange(...args: unknown[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupBulletinChange(...args: unknown[]) {
|
onGroupBulletinChange(...args: unknown[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupBulletinRemindNotify(...args: unknown[]) {
|
onGroupBulletinRemindNotify(...args: unknown[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupArkInviteStateResult(...args: unknown[]) {
|
onGroupArkInviteStateResult(...args: unknown[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupBulletinRichMediaDownloadComplete(...args: unknown[]) {
|
onGroupBulletinRichMediaDownloadComplete(...args: unknown[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupConfMemberChange(...args: unknown[]) {
|
onGroupConfMemberChange(...args: unknown[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupDetailInfoChange(...args: unknown[]) {
|
onGroupDetailInfoChange(...args: unknown[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupExtListUpdate(...args: unknown[]) {
|
onGroupExtListUpdate(...args: unknown[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupFirstBulletinNotify(...args: unknown[]) {
|
onGroupFirstBulletinNotify(...args: unknown[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupListUpdate(updateType: GroupListUpdateType, groupList: Group[]) {
|
onGroupListUpdate(updateType: GroupListUpdateType, groupList: Group[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupNotifiesUpdated(dboubt: boolean, notifies: GroupNotify[]) {
|
onGroupNotifiesUpdated(dboubt: boolean, notifies: GroupNotify[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupBulletinRichMediaProgressUpdate(...args: unknown[]) {
|
onGroupBulletinRichMediaProgressUpdate(...args: unknown[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupNotifiesUnreadCountUpdated(...args: unknown[]) {
|
onGroupNotifiesUnreadCountUpdated(...args: unknown[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupSingleScreenNotifies(doubt: boolean, seq: string, notifies: GroupNotify[]) {
|
onGroupSingleScreenNotifies(doubt: boolean, seq: string, notifies: GroupNotify[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupsMsgMaskResult(...args: unknown[]) {
|
onGroupsMsgMaskResult(...args: unknown[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupStatisticInfoChange(...args: unknown[]) {
|
onGroupStatisticInfoChange(...args: unknown[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onJoinGroupNotify(...args: unknown[]) {
|
onJoinGroupNotify(...args: unknown[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onJoinGroupNoVerifyFlag(...args: unknown[]) {
|
onJoinGroupNoVerifyFlag(...args: unknown[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onMemberInfoChange(groupCode: string, dateSource: DataSource, members: Map<string, GroupMember>) {
|
onMemberInfoChange(groupCode: string, dateSource: DataSource, members: Map<string, GroupMember>): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onMemberListChange(arg: {
|
onMemberListChange(arg: {
|
||||||
@@ -74,12 +74,12 @@ export class NodeIKernelGroupListener {
|
|||||||
hasPrev: boolean,
|
hasPrev: boolean,
|
||||||
hasNext: boolean,
|
hasNext: boolean,
|
||||||
hasRobot: boolean
|
hasRobot: boolean
|
||||||
}) {
|
}): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onSearchMemberChange(...args: unknown[]) {
|
onSearchMemberChange(...args: unknown[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onShutUpMemberListChanged(groupCode: string, members: Array<ShutUpGroupMember>) {
|
onShutUpMemberListChanged(groupCode: string, members: Array<ShutUpGroupMember>): any {
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,57 +1,57 @@
|
|||||||
export class NodeIKernelLoginListener {
|
export class NodeIKernelLoginListener {
|
||||||
onLoginConnected(...args: any[]): void {
|
onLoginConnected(...args: any[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoginDisConnected(...args: any[]): void {
|
onLoginDisConnected(...args: any[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoginConnecting(...args: any[]): void {
|
onLoginConnecting(...args: any[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onQRCodeGetPicture(arg: { pngBase64QrcodeData: string, qrcodeUrl: string }): void {
|
onQRCodeGetPicture(arg: { pngBase64QrcodeData: string, qrcodeUrl: string }): any {
|
||||||
// let base64Data: string = arg.pngBase64QrcodeData
|
// let base64Data: string = arg.pngBase64QrcodeData
|
||||||
// base64Data = base64Data.split("data:image/png;base64,")[1]
|
// base64Data = base64Data.split("data:image/png;base64,")[1]
|
||||||
// let buffer = Buffer.from(base64Data, 'base64')
|
// let buffer = Buffer.from(base64Data, 'base64')
|
||||||
// console.log("onQRCodeGetPicture", arg);
|
// console.log("onQRCodeGetPicture", arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
onQRCodeLoginPollingStarted(...args: any[]): void {
|
onQRCodeLoginPollingStarted(...args: any[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onQRCodeSessionUserScaned(...args: any[]): void {
|
onQRCodeSessionUserScaned(...args: any[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onQRCodeLoginSucceed(arg: QRCodeLoginSucceedResult): void {
|
onQRCodeLoginSucceed(arg: QRCodeLoginSucceedResult): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onQRCodeSessionFailed(...args: any[]): void {
|
onQRCodeSessionFailed(...args: any[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoginFailed(...args: any[]): void {
|
onLoginFailed(...args: any[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onLogoutSucceed(...args: any[]): void {
|
onLogoutSucceed(...args: any[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onLogoutFailed(...args: any[]): void {
|
onLogoutFailed(...args: any[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onUserLoggedIn(...args: any[]): void {
|
onUserLoggedIn(...args: any[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onQRCodeSessionQuickLoginFailed(...args: any[]): void {
|
onQRCodeSessionQuickLoginFailed(...args: any[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onPasswordLoginFailed(...args: any[]): void {
|
onPasswordLoginFailed(...args: any[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
OnConfirmUnusualDeviceFailed(...args: any[]): void {
|
OnConfirmUnusualDeviceFailed(...args: any[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onQQLoginNumLimited(...args: any[]): void {
|
onQQLoginNumLimited(...args: any[]): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoginState(...args: any[]): void {
|
onLoginState(...args: any[]): any {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -20,8 +20,8 @@ export interface OnRichMediaDownloadCompleteParams {
|
|||||||
fileSrvErrCode: string,
|
fileSrvErrCode: string,
|
||||||
clientMsg: string,
|
clientMsg: string,
|
||||||
businessId: number,
|
businessId: number,
|
||||||
userTotalSpacePerDay: unknown | null,
|
userTotalSpacePerDay: unknown,
|
||||||
userUsedSpacePerDay: unknown | null
|
userUsedSpacePerDay: unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GroupFileInfoUpdateParamType {
|
export interface GroupFileInfoUpdateParamType {
|
||||||
@@ -94,108 +94,108 @@ export interface TempOnRecvParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class NodeIKernelMsgListener {
|
export class NodeIKernelMsgListener {
|
||||||
onAddSendMsg(msgRecord: RawMessage) {
|
onAddSendMsg(msgRecord: RawMessage): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onBroadcastHelperDownloadComplete(broadcastHelperTransNotifyInfo: unknown) {
|
onBroadcastHelperDownloadComplete(broadcastHelperTransNotifyInfo: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onBroadcastHelperProgressUpdate(broadcastHelperTransNotifyInfo: unknown) {
|
onBroadcastHelperProgressUpdate(broadcastHelperTransNotifyInfo: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onChannelFreqLimitInfoUpdate(contact: unknown, z: unknown, freqLimitInfo: unknown) {
|
onChannelFreqLimitInfoUpdate(contact: unknown, z: unknown, freqLimitInfo: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onContactUnreadCntUpdate(hashMap: unknown) {
|
onContactUnreadCntUpdate(hashMap: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onCustomWithdrawConfigUpdate(customWithdrawConfig: unknown) {
|
onCustomWithdrawConfigUpdate(customWithdrawConfig: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onDraftUpdate(contact: unknown, arrayList: unknown, j2: unknown) {
|
onDraftUpdate(contact: unknown, arrayList: unknown, j2: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onEmojiDownloadComplete(emojiNotifyInfo: unknown) {
|
onEmojiDownloadComplete(emojiNotifyInfo: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onEmojiResourceUpdate(emojiResourceInfo: unknown) {
|
onEmojiResourceUpdate(emojiResourceInfo: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown) {
|
onFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onFileMsgCome(arrayList: unknown) {
|
onFileMsgCome(arrayList: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onFirstViewDirectMsgUpdate(firstViewDirectMsgNotifyInfo: unknown) {
|
onFirstViewDirectMsgUpdate(firstViewDirectMsgNotifyInfo: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onFirstViewGroupGuildMapping(arrayList: unknown) {
|
onFirstViewGroupGuildMapping(arrayList: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onGrabPasswordRedBag(i2: unknown, str: unknown, i3: unknown, recvdOrder: unknown, msgRecord: unknown) {
|
onGrabPasswordRedBag(i2: unknown, str: unknown, i3: unknown, recvdOrder: unknown, msgRecord: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupFileInfoAdd(groupItem: unknown) {
|
onGroupFileInfoAdd(groupItem: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupFileInfoUpdate(groupFileListResult: GroupFileInfoUpdateParamType) {
|
onGroupFileInfoUpdate(groupFileListResult: GroupFileInfoUpdateParamType): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupGuildUpdate(groupGuildNotifyInfo: unknown) {
|
onGroupGuildUpdate(groupGuildNotifyInfo: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
onGroupTransferInfoAdd(groupItem: unknown) {
|
onGroupTransferInfoAdd(groupItem: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupTransferInfoUpdate(groupFileListResult: unknown) {
|
onGroupTransferInfoUpdate(groupFileListResult: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onGuildInteractiveUpdate(guildInteractiveNotificationItem: unknown) {
|
onGuildInteractiveUpdate(guildInteractiveNotificationItem: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onGuildMsgAbFlagChanged(guildMsgAbFlag: unknown) {
|
onGuildMsgAbFlagChanged(guildMsgAbFlag: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onGuildNotificationAbstractUpdate(guildNotificationAbstractInfo: unknown) {
|
onGuildNotificationAbstractUpdate(guildNotificationAbstractInfo: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onHitCsRelatedEmojiResult(downloadRelateEmojiResultInfo: unknown) {
|
onHitCsRelatedEmojiResult(downloadRelateEmojiResultInfo: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onHitEmojiKeywordResult(hitRelatedEmojiWordsResult: unknown) {
|
onHitEmojiKeywordResult(hitRelatedEmojiWordsResult: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onHitRelatedEmojiResult(relatedWordEmojiInfo: unknown) {
|
onHitRelatedEmojiResult(relatedWordEmojiInfo: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onImportOldDbProgressUpdate(importOldDbMsgNotifyInfo: unknown) {
|
onImportOldDbProgressUpdate(importOldDbMsgNotifyInfo: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,176 +208,176 @@ export class NodeIKernelMsgListener {
|
|||||||
statusText: string;
|
statusText: string;
|
||||||
timestamp: string;
|
timestamp: string;
|
||||||
toUin: string;
|
toUin: string;
|
||||||
}) {
|
}): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onKickedOffLine(kickedInfo: KickedOffLineInfo) {
|
onKickedOffLine(kickedInfo: KickedOffLineInfo): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onLineDev(arrayList: unknown) {
|
onLineDev(arrayList: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onLogLevelChanged(j2: unknown) {
|
onLogLevelChanged(j2: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMsgAbstractUpdate(arrayList: unknown) {
|
onMsgAbstractUpdate(arrayList: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMsgBoxChanged(arrayList: unknown) {
|
onMsgBoxChanged(arrayList: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMsgDelete(contact: unknown, arrayList: unknown) {
|
onMsgDelete(contact: unknown, arrayList: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMsgEventListUpdate(hashMap: unknown) {
|
onMsgEventListUpdate(hashMap: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMsgInfoListAdd(arrayList: unknown) {
|
onMsgInfoListAdd(arrayList: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMsgInfoListUpdate(msgList: RawMessage[]) {
|
onMsgInfoListUpdate(msgList: RawMessage[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMsgQRCodeStatusChanged(i2: unknown) {
|
onMsgQRCodeStatusChanged(i2: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMsgRecall(i2: unknown, str: unknown, j2: unknown) {
|
onMsgRecall(i2: unknown, str: unknown, j2: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMsgSecurityNotify(msgRecord: unknown) {
|
onMsgSecurityNotify(msgRecord: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMsgSettingUpdate(msgSetting: unknown) {
|
onMsgSettingUpdate(msgSetting: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onNtFirstViewMsgSyncEnd() {
|
onNtFirstViewMsgSyncEnd(): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onNtMsgSyncEnd() {
|
onNtMsgSyncEnd(): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onNtMsgSyncStart() {
|
onNtMsgSyncStart(): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onReadFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown) {
|
onReadFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onRecvGroupGuildFlag(i2: unknown) {
|
onRecvGroupGuildFlag(i2: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onRecvMsg(arrayList: RawMessage[]) {
|
onRecvMsg(arrayList: RawMessage[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onRecvMsgSvrRspTransInfo(j2: unknown, contact: unknown, i2: unknown, i3: unknown, str: unknown, bArr: unknown) {
|
onRecvMsgSvrRspTransInfo(j2: unknown, contact: unknown, i2: unknown, i3: unknown, str: unknown, bArr: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onRecvOnlineFileMsg(arrayList: unknown) {
|
onRecvOnlineFileMsg(arrayList: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onRecvS2CMsg(arrayList: unknown) {
|
onRecvS2CMsg(arrayList: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onRecvSysMsg(arrayList: Array<number>) {
|
onRecvSysMsg(arrayList: Array<number>): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onRecvUDCFlag(i2: unknown) {
|
onRecvUDCFlag(i2: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onRichMediaDownloadComplete(fileTransNotifyInfo: OnRichMediaDownloadCompleteParams) {
|
onRichMediaDownloadComplete(fileTransNotifyInfo: OnRichMediaDownloadCompleteParams): any {
|
||||||
}
|
}
|
||||||
|
|
||||||
onRichMediaProgerssUpdate(fileTransNotifyInfo: unknown) {
|
onRichMediaProgerssUpdate(fileTransNotifyInfo: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onRichMediaUploadComplete(fileTransNotifyInfo: unknown) {
|
onRichMediaUploadComplete(fileTransNotifyInfo: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onSearchGroupFileInfoUpdate(searchGroupFileResult: unknown) {
|
onSearchGroupFileInfoUpdate(searchGroupFileResult: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onSendMsgError(j2: unknown, contact: unknown, i2: unknown, str: unknown) {
|
onSendMsgError(j2: unknown, contact: unknown, i2: unknown, str: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onSysMsgNotification(i2: unknown, j2: unknown, j3: unknown, arrayList: unknown) {
|
onSysMsgNotification(i2: unknown, j2: unknown, j3: unknown, arrayList: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onTempChatInfoUpdate(tempChatInfo: TempOnRecvParams) {
|
onTempChatInfoUpdate(tempChatInfo: TempOnRecvParams): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onUnreadCntAfterFirstView(hashMap: unknown) {
|
onUnreadCntAfterFirstView(hashMap: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onUnreadCntUpdate(hashMap: unknown) {
|
onUnreadCntUpdate(hashMap: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onUserChannelTabStatusChanged(z: unknown) {
|
onUserChannelTabStatusChanged(z: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onUserOnlineStatusChanged(z: unknown) {
|
onUserOnlineStatusChanged(z: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onUserTabStatusChanged(arrayList: unknown) {
|
onUserTabStatusChanged(arrayList: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onlineStatusBigIconDownloadPush(i2: unknown, j2: unknown, str: unknown) {
|
onlineStatusBigIconDownloadPush(i2: unknown, j2: unknown, str: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onlineStatusSmallIconDownloadPush(i2: unknown, j2: unknown, str: unknown) {
|
onlineStatusSmallIconDownloadPush(i2: unknown, j2: unknown, str: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 第一次发现于Linux
|
// 第一次发现于Linux
|
||||||
onUserSecQualityChanged(...args: unknown[]) {
|
onUserSecQualityChanged(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMsgWithRichLinkInfoUpdate(...args: unknown[]) {
|
onMsgWithRichLinkInfoUpdate(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onRedTouchChanged(...args: unknown[]) {
|
onRedTouchChanged(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 第一次发现于Win 9.9.9-23159
|
// 第一次发现于Win 9.9.9-23159
|
||||||
onBroadcastHelperProgerssUpdate(...args: unknown[]) {
|
onBroadcastHelperProgerssUpdate(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,67 +5,67 @@ export class NodeIKernelProfileListener {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onProfileSimpleChanged(...args: unknown[]) {
|
onProfileSimpleChanged(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onProfileDetailInfoChanged(profile: User) {
|
onProfileDetailInfoChanged(profile: User): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onStatusUpdate(...args: unknown[]) {
|
onStatusUpdate(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onSelfStatusChanged(...args: unknown[]) {
|
onSelfStatusChanged(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onStrangerRemarkChanged(...args: unknown[]) {
|
onStrangerRemarkChanged(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMemberListChange(...args: unknown[]) {
|
onMemberListChange(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMemberInfoChange(...args: unknown[]) {
|
onMemberInfoChange(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupListUpdate(...args: unknown[]) {
|
onGroupListUpdate(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupAllInfoChange(...args: unknown[]) {
|
onGroupAllInfoChange(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupDetailInfoChange(...args: unknown[]) {
|
onGroupDetailInfoChange(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupConfMemberChange(...args: unknown[]) {
|
onGroupConfMemberChange(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupExtListUpdate(...args: unknown[]) {
|
onGroupExtListUpdate(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupNotifiesUpdated(...args: unknown[]) {
|
onGroupNotifiesUpdated(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupNotifiesUnreadCountUpdated(...args: unknown[]) {
|
onGroupNotifiesUnreadCountUpdated(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupMemberLevelInfoChange(...args: unknown[]) {
|
onGroupMemberLevelInfoChange(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupBulletinChange(...args: unknown[]) {
|
onGroupBulletinChange(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,25 +1,25 @@
|
|||||||
export class NodeIKernelRecentContactListener {
|
export class NodeIKernelRecentContactListener {
|
||||||
onDeletedContactsNotify(...args: unknown[]) {
|
onDeletedContactsNotify(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onRecentContactNotification(msgList: any, arg0: { msgListUnreadCnt: string }, arg1: number) {
|
onRecentContactNotification(msgList: any, arg0: { msgListUnreadCnt: string }, arg1: number): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMsgUnreadCountUpdate(...args: unknown[]) {
|
onMsgUnreadCountUpdate(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onGuildDisplayRecentContactListChanged(...args: unknown[]) {
|
onGuildDisplayRecentContactListChanged(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onRecentContactListChanged(...args: unknown[]) {
|
onRecentContactListChanged(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onRecentContactListChangedVer2(...args: unknown[]) {
|
onRecentContactListChangedVer2(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,13 +1,13 @@
|
|||||||
export class NodeIKernelRobotListener {
|
export class NodeIKernelRobotListener {
|
||||||
onRobotFriendListChanged(...args: unknown[]) {
|
onRobotFriendListChanged(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onRobotListChanged(...args: unknown[]) {
|
onRobotListChanged(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onRobotProfileChanged(...args: unknown[]) {
|
onRobotProfileChanged(...args: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -57,7 +57,7 @@ export interface GroupSearchResult {
|
|||||||
}
|
}
|
||||||
export interface NodeIKernelSearchListener {
|
export interface NodeIKernelSearchListener {
|
||||||
|
|
||||||
onSearchGroupResult(params: GroupSearchResult): void;
|
onSearchGroupResult(params: GroupSearchResult): any;
|
||||||
|
|
||||||
onSearchFileKeywordsResult(params: {
|
onSearchFileKeywordsResult(params: {
|
||||||
searchId: string,
|
searchId: string,
|
||||||
@@ -93,5 +93,5 @@ export interface NodeIKernelSearchListener {
|
|||||||
end: number
|
end: number
|
||||||
}[]
|
}[]
|
||||||
}[]
|
}[]
|
||||||
}): void;
|
}): any;
|
||||||
}
|
}
|
||||||
|
@@ -1,25 +1,25 @@
|
|||||||
export class NodeIKernelSessionListener {
|
export class NodeIKernelSessionListener {
|
||||||
onNTSessionCreate(args: unknown) {
|
onNTSessionCreate(args: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onGProSessionCreate(args: unknown) {
|
onGProSessionCreate(args: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onSessionInitComplete(args: unknown) {
|
onSessionInitComplete(args: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onOpentelemetryInit(args: unknown) {
|
onOpentelemetryInit(args: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onUserOnlineResult(args: unknown) {
|
onUserOnlineResult(args: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onGetSelfTinyId(args: unknown) {
|
onGetSelfTinyId(args: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,21 +1,21 @@
|
|||||||
export class NodeIKernelStorageCleanListener {
|
export class NodeIKernelStorageCleanListener {
|
||||||
onCleanCacheProgressChanged(args: unknown) {
|
onCleanCacheProgressChanged(args: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onScanCacheProgressChanged(args: unknown) {
|
onScanCacheProgressChanged(args: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onCleanCacheStorageChanged(args: unknown) {
|
onCleanCacheStorageChanged(args: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onFinishScan(args: unknown) {
|
onFinishScan(args: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onChatCleanDone(args: unknown) {
|
onChatCleanDone(args: unknown): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,2 +1,5 @@
|
|||||||
export class NodeIKernelTicketListener {
|
export class NodeIKernelTicketListener {
|
||||||
|
listener(): any {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
export class NodeIO3MiscListener {
|
export class NodeIO3MiscListener {
|
||||||
getOnAmgomDataPiece(...arg: unknown[]) {
|
getOnAmgomDataPiece(...arg: unknown[]): any {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -16,8 +16,8 @@ export interface NativePacketExportType {
|
|||||||
|
|
||||||
export class NativePacketClient extends IPacketClient {
|
export class NativePacketClient extends IPacketClient {
|
||||||
private readonly supportedPlatforms = ['win32.x64', 'linux.x64', 'linux.arm64', 'darwin.x64', 'darwin.arm64'];
|
private readonly supportedPlatforms = ['win32.x64', 'linux.x64', 'linux.arm64', 'darwin.x64', 'darwin.arm64'];
|
||||||
private MoeHooExport: { exports: NativePacketExportType } = { exports: {} };
|
private readonly MoeHooExport: { exports: NativePacketExportType } = { exports: {} };
|
||||||
private sendEvent = new LRUCache<number, string>(500); // seq->trace_id
|
private readonly sendEvent = new LRUCache<number, string>(500); // seq->trace_id
|
||||||
|
|
||||||
constructor(context: PacketContext, logStack: LogStack) {
|
constructor(context: PacketContext, logStack: LogStack) {
|
||||||
super(context, logStack);
|
super(context, logStack);
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
import { Data, WebSocket } from "ws";
|
import { Data, WebSocket, ErrorEvent } from "ws";
|
||||||
import { IPacketClient, RecvPacket } from "@/core/packet/client/baseClient";
|
import { IPacketClient, RecvPacket } from "@/core/packet/client/baseClient";
|
||||||
import { PacketContext } from "@/core/packet/context/packetContext";
|
import { PacketContext } from "@/core/packet/context/packetContext";
|
||||||
import { LogStack } from "@/core/packet/context/clientContext";
|
import { LogStack } from "@/core/packet/context/clientContext";
|
||||||
|
|
||||||
export class wsPacketClient extends IPacketClient {
|
export class WsPacketClient extends IPacketClient {
|
||||||
private websocket: WebSocket | null = null;
|
private websocket: WebSocket | null = null;
|
||||||
private reconnectAttempts: number = 0;
|
private reconnectAttempts: number = 0;
|
||||||
private readonly maxReconnectAttempts: number = 60; // 现在暂时不可配置
|
private readonly maxReconnectAttempts: number = 60; // 现在暂时不可配置
|
||||||
@@ -85,11 +85,11 @@ export class wsPacketClient extends IPacketClient {
|
|||||||
this.websocket.onmessage = (event) => this.handleMessage(event.data).catch(err => {
|
this.websocket.onmessage = (event) => this.handleMessage(event.data).catch(err => {
|
||||||
this.context.logger.error(`处理消息时出错: ${err}`);
|
this.context.logger.error(`处理消息时出错: ${err}`);
|
||||||
});
|
});
|
||||||
this.websocket.onerror = (error) => {
|
this.websocket.onerror = (event: ErrorEvent) => {
|
||||||
this.available = false;
|
this.available = false;
|
||||||
this.context.logger.error(`WebSocket 出错: ${error.message}`);
|
this.context.logger.error(`WebSocket 出错: ${event.message}`);
|
||||||
this.websocket?.close();
|
this.websocket?.close();
|
||||||
reject(error);
|
reject(new Error(`WebSocket 出错: ${event.message}`));
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -24,7 +24,7 @@ export class PacketClientSession {
|
|||||||
return this.context.operation;
|
return this.context.operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: global message element adapter (?
|
// work: global message element adapter (?
|
||||||
get msgConverter() {
|
get msgConverter() {
|
||||||
return this.context.msgConverter;
|
return this.context.msgConverter;
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { PacketContext } from "@/core/packet/context/packetContext";
|
import { PacketContext } from "@/core/packet/context/packetContext";
|
||||||
import { IPacketClient } from "@/core/packet/client/baseClient";
|
import { IPacketClient } from "@/core/packet/client/baseClient";
|
||||||
import { NativePacketClient } from "@/core/packet/client/nativeClient";
|
import { NativePacketClient } from "@/core/packet/client/nativeClient";
|
||||||
import { wsPacketClient } from "@/core/packet/client/wsClient";
|
import { WsPacketClient } from "@/core/packet/client/wsClient";
|
||||||
import { OidbPacket } from "@/core/packet/transformer/base";
|
import { OidbPacket } from "@/core/packet/transformer/base";
|
||||||
import { PacketLogger } from "@/core/packet/context/loggerContext";
|
import { PacketLogger } from "@/core/packet/context/loggerContext";
|
||||||
|
|
||||||
@@ -11,12 +11,12 @@ type clientPriority = {
|
|||||||
|
|
||||||
const clientPriority: clientPriority = {
|
const clientPriority: clientPriority = {
|
||||||
10: (context: PacketContext, logStack: LogStack) => new NativePacketClient(context, logStack),
|
10: (context: PacketContext, logStack: LogStack) => new NativePacketClient(context, logStack),
|
||||||
1: (context: PacketContext, logStack: LogStack) => new wsPacketClient(context, logStack),
|
1: (context: PacketContext, logStack: LogStack) => new WsPacketClient(context, logStack),
|
||||||
};
|
};
|
||||||
|
|
||||||
export class LogStack {
|
export class LogStack {
|
||||||
private stack: string[] = [];
|
private stack: string[] = [];
|
||||||
private logger: PacketLogger;
|
private readonly logger: PacketLogger;
|
||||||
|
|
||||||
constructor(logger: PacketLogger) {
|
constructor(logger: PacketLogger) {
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
@@ -88,7 +88,7 @@ export class PacketClientContext {
|
|||||||
break;
|
break;
|
||||||
case "frida":
|
case "frida":
|
||||||
this.context.logger.info("[Core] [Packet] 使用指定的 FridaPacketClient 作为后端");
|
this.context.logger.info("[Core] [Packet] 使用指定的 FridaPacketClient 作为后端");
|
||||||
client = new wsPacketClient(this.context, this.logStack);
|
client = new WsPacketClient(this.context, this.logStack);
|
||||||
break;
|
break;
|
||||||
case "auto":
|
case "auto":
|
||||||
case undefined:
|
case undefined:
|
||||||
@@ -98,9 +98,12 @@ export class PacketClientContext {
|
|||||||
this.context.logger.error(`未知的PacketBackend ${prefer},请检查配置文件!`);
|
this.context.logger.error(`未知的PacketBackend ${prefer},请检查配置文件!`);
|
||||||
client = null;
|
client = null;
|
||||||
}
|
}
|
||||||
if (!(client && client.check())) {
|
if (!client?.check()) {
|
||||||
throw new Error("[Core] [Packet] 无可用的后端,NapCat.Packet将不会加载!");
|
throw new Error("[Core] [Packet] 无可用的后端,NapCat.Packet将不会加载!");
|
||||||
}
|
}
|
||||||
|
if (!client) {
|
||||||
|
throw new Error("[Core] [Packet] 后端异常,NapCat.Packet将不会加载!");
|
||||||
|
}
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { LogLevel, LogWrapper } from "@/common/log";
|
import { LogLevel, LogWrapper } from "@/common/log";
|
||||||
import { PacketContext } from "@/core/packet/context/packetContext";
|
import { PacketContext } from "@/core/packet/context/packetContext";
|
||||||
|
|
||||||
// TODO: check bind?
|
// work: check bind?
|
||||||
export class PacketLogger {
|
export class PacketLogger {
|
||||||
private readonly napLogger: LogWrapper;
|
private readonly napLogger: LogWrapper;
|
||||||
|
|
||||||
|
@@ -15,7 +15,7 @@ import { NapProtoDecodeStructType, NapProtoEncodeStructType } from "@napneko/nap
|
|||||||
import { IndexNode, MsgInfo } from "@/core/packet/transformer/proto";
|
import { IndexNode, MsgInfo } from "@/core/packet/transformer/proto";
|
||||||
|
|
||||||
export class PacketOperationContext {
|
export class PacketOperationContext {
|
||||||
private context: PacketContext;
|
private readonly context: PacketContext;
|
||||||
constructor(context: PacketContext) {
|
constructor(context: PacketContext) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
@@ -65,35 +65,22 @@ export class PacketOperationContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async UploadResources(msg: PacketMsg[], groupUin: number = 0) {
|
async UploadResources(msg: PacketMsg[], groupUin: number = 0) {
|
||||||
const reqList = [];
|
const chatType = groupUin ? ChatType.KCHATTYPEGROUP : ChatType.KCHATTYPEC2C;
|
||||||
for (const m of msg) {
|
const peerUid = groupUin ? String(groupUin) : this.context.napcore.basicInfo.uid;
|
||||||
for (const e of m.msg) {
|
const reqList = msg.flatMap(m =>
|
||||||
|
m.msg.map(e => {
|
||||||
if (e instanceof PacketMsgPicElement) {
|
if (e instanceof PacketMsgPicElement) {
|
||||||
reqList.push(this.context.highway.uploadImage({
|
return this.context.highway.uploadImage({ chatType, peerUid }, e);
|
||||||
chatType: groupUin ? ChatType.KCHATTYPEGROUP : ChatType.KCHATTYPEC2C,
|
} else if (e instanceof PacketMsgVideoElement) {
|
||||||
peerUid: groupUin ? String(groupUin) : this.context.napcore.basicInfo.uid
|
return this.context.highway.uploadVideo({ chatType, peerUid }, e);
|
||||||
}, e));
|
} else if (e instanceof PacketMsgPttElement) {
|
||||||
}
|
return this.context.highway.uploadPtt({ chatType, peerUid }, e);
|
||||||
if (e instanceof PacketMsgVideoElement) {
|
} else if (e instanceof PacketMsgFileElement) {
|
||||||
reqList.push(this.context.highway.uploadVideo({
|
return this.context.highway.uploadFile({ chatType, peerUid }, e);
|
||||||
chatType: groupUin ? ChatType.KCHATTYPEGROUP : ChatType.KCHATTYPEC2C,
|
|
||||||
peerUid: groupUin ? String(groupUin) : this.context.napcore.basicInfo.uid
|
|
||||||
}, e));
|
|
||||||
}
|
|
||||||
if (e instanceof PacketMsgPttElement) {
|
|
||||||
reqList.push(this.context.highway.uploadPtt({
|
|
||||||
chatType: groupUin ? ChatType.KCHATTYPEGROUP : ChatType.KCHATTYPEC2C,
|
|
||||||
peerUid: groupUin ? String(groupUin) : this.context.napcore.basicInfo.uid
|
|
||||||
}, e));
|
|
||||||
}
|
|
||||||
if (e instanceof PacketMsgFileElement) {
|
|
||||||
reqList.push(this.context.highway.uploadFile({
|
|
||||||
chatType: groupUin ? ChatType.KCHATTYPEGROUP : ChatType.KCHATTYPEC2C,
|
|
||||||
peerUid: groupUin ? String(groupUin) : this.context.napcore.basicInfo.uid
|
|
||||||
}, e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
}).filter(Boolean)
|
||||||
|
);
|
||||||
const res = await Promise.allSettled(reqList);
|
const res = await Promise.allSettled(reqList);
|
||||||
this.context.logger.info(`上传资源${res.length}个,失败${res.filter(r => r.status === 'rejected').length}个`);
|
this.context.logger.info(`上传资源${res.length}个,失败${res.filter(r => r.status === 'rejected').length}个`);
|
||||||
res.forEach((result, index) => {
|
res.forEach((result, index) => {
|
||||||
|
@@ -33,7 +33,7 @@ export interface PacketHighwaySig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class PacketHighwayContext {
|
export class PacketHighwayContext {
|
||||||
private context: PacketContext;
|
private readonly context: PacketContext;
|
||||||
protected sig: PacketHighwaySig;
|
protected sig: PacketHighwaySig;
|
||||||
protected logger: PacketLogger;
|
protected logger: PacketLogger;
|
||||||
protected hwClient: PacketHighwayClient;
|
protected hwClient: PacketHighwayClient;
|
||||||
@@ -223,12 +223,12 @@ export class PacketHighwayContext {
|
|||||||
msgInfoBody: preRespData.upload.msgInfo.msgInfoBody,
|
msgInfoBody: preRespData.upload.msgInfo.msgInfoBody,
|
||||||
blockSize: BlockSize,
|
blockSize: BlockSize,
|
||||||
hash: {
|
hash: {
|
||||||
fileSha1: await calculateSha1StreamBytes(video.filePath!)
|
fileSha1: await calculateSha1StreamBytes(video.filePath)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await this.hwClient.upload(
|
await this.hwClient.upload(
|
||||||
1005,
|
1005,
|
||||||
fs.createReadStream(video.filePath!, { highWaterMark: BlockSize }),
|
fs.createReadStream(video.filePath, { highWaterMark: BlockSize }),
|
||||||
+video.fileSize!,
|
+video.fileSize!,
|
||||||
md5,
|
md5,
|
||||||
extend
|
extend
|
||||||
@@ -256,7 +256,7 @@ export class PacketHighwayContext {
|
|||||||
});
|
});
|
||||||
await this.hwClient.upload(
|
await this.hwClient.upload(
|
||||||
1006,
|
1006,
|
||||||
fs.createReadStream(video.thumbPath!, { highWaterMark: BlockSize }),
|
fs.createReadStream(video.thumbPath, { highWaterMark: BlockSize }),
|
||||||
+video.thumbSize!,
|
+video.thumbSize!,
|
||||||
md5,
|
md5,
|
||||||
extend
|
extend
|
||||||
@@ -288,12 +288,12 @@ export class PacketHighwayContext {
|
|||||||
msgInfoBody: preRespData.upload.msgInfo.msgInfoBody,
|
msgInfoBody: preRespData.upload.msgInfo.msgInfoBody,
|
||||||
blockSize: BlockSize,
|
blockSize: BlockSize,
|
||||||
hash: {
|
hash: {
|
||||||
fileSha1: await calculateSha1StreamBytes(video.filePath!)
|
fileSha1: await calculateSha1StreamBytes(video.filePath)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await this.hwClient.upload(
|
await this.hwClient.upload(
|
||||||
1001,
|
1001,
|
||||||
fs.createReadStream(video.filePath!, { highWaterMark: BlockSize }),
|
fs.createReadStream(video.filePath, { highWaterMark: BlockSize }),
|
||||||
+video.fileSize!,
|
+video.fileSize!,
|
||||||
md5,
|
md5,
|
||||||
extend
|
extend
|
||||||
@@ -321,7 +321,7 @@ export class PacketHighwayContext {
|
|||||||
});
|
});
|
||||||
await this.hwClient.upload(
|
await this.hwClient.upload(
|
||||||
1002,
|
1002,
|
||||||
fs.createReadStream(video.thumbPath!, { highWaterMark: BlockSize }),
|
fs.createReadStream(video.thumbPath, { highWaterMark: BlockSize }),
|
||||||
+video.thumbSize!,
|
+video.thumbSize!,
|
||||||
md5,
|
md5,
|
||||||
extend
|
extend
|
||||||
|
@@ -64,11 +64,11 @@ export class HighwayHttpUploader extends IHighwayUploader {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
req.write(frame);
|
req.write(frame);
|
||||||
req.on('error', (error) => {
|
req.on('error', (error: Error) => {
|
||||||
reject(error);
|
reject(error);
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error: unknown) {
|
||||||
reject(error);
|
reject(new Error((error as Error).message));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -7,12 +7,12 @@ export const int32ip2str = (ip: number) => {
|
|||||||
return [ip & 0xff, (ip & 0xff00) >> 8, (ip & 0xff0000) >> 16, ((ip & 0xff000000) >> 24) & 0xff].join('.');
|
return [ip & 0xff, (ip & 0xff00) >> 8, (ip & 0xff0000) >> 16, ((ip & 0xff000000) >> 24) & 0xff].join('.');
|
||||||
};
|
};
|
||||||
|
|
||||||
export const oidbIpv4s2HighwayIpv4s = (ipv4s: NapProtoEncodeStructType<typeof proto.IPv4>[]): NapProtoEncodeStructType<typeof proto.NTHighwayIPv4>[] =>{
|
export const oidbIpv4s2HighwayIpv4s = (ipv4s: NapProtoEncodeStructType<typeof proto.IPv4>[]): NapProtoEncodeStructType<typeof proto.NTHighwayIPv4>[] => {
|
||||||
return ipv4s.map((ip) => {
|
return ipv4s.map((ip) => {
|
||||||
return {
|
return {
|
||||||
domain: {
|
domain: {
|
||||||
isEnable: true,
|
isEnable: true,
|
||||||
ip: int32ip2str(ip.outIP!),
|
ip: int32ip2str(ip.outIP ?? 0),
|
||||||
},
|
},
|
||||||
port: ip.outPort!
|
port: ip.outPort!
|
||||||
} as NapProtoEncodeStructType<typeof proto.NTHighwayIPv4>;
|
} as NapProtoEncodeStructType<typeof proto.NTHighwayIPv4>;
|
||||||
|
@@ -16,7 +16,7 @@ export class PacketMsgBuilder {
|
|||||||
return element.map((node): NapProtoEncodeStructType<typeof PushMsgBody> => {
|
return element.map((node): NapProtoEncodeStructType<typeof PushMsgBody> => {
|
||||||
const avatar = `https://q.qlogo.cn/headimg_dl?dst_uin=${node.senderUin}&spec=640&img_type=jpg`;
|
const avatar = `https://q.qlogo.cn/headimg_dl?dst_uin=${node.senderUin}&spec=640&img_type=jpg`;
|
||||||
const msgContent = node.msg.reduceRight((acc: undefined | Uint8Array, msg: IPacketMsgElement<PacketSendMsgElement>) => {
|
const msgContent = node.msg.reduceRight((acc: undefined | Uint8Array, msg: IPacketMsgElement<PacketSendMsgElement>) => {
|
||||||
return acc !== undefined ? acc : msg.buildContent();
|
return acc ?? msg.buildContent();
|
||||||
}, undefined);
|
}, undefined);
|
||||||
const msgElement = node.msg.flatMap(msg => msg.buildElement() ?? []);
|
const msgElement = node.msg.flatMap(msg => msg.buildElement() ?? []);
|
||||||
if (!msgContent && !msgElement.length) {
|
if (!msgContent && !msgElement.length) {
|
||||||
|
@@ -76,13 +76,13 @@ export type rawMsgWithSendMsg = {
|
|||||||
msg: PacketSendMsgElement[]
|
msg: PacketSendMsgElement[]
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: make it become adapter?
|
// work:make it become adapter?
|
||||||
export class PacketMsgConverter {
|
export class PacketMsgConverter {
|
||||||
private isValidElementType(type: ElementType): type is keyof ElementToPacketMsgConverters {
|
private isValidElementType(type: ElementType): type is keyof ElementToPacketMsgConverters {
|
||||||
return SupportedElementTypes.includes(type);
|
return SupportedElementTypes.includes(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
private rawToPacketMsgConverters: ElementToPacketMsgConverters = {
|
private readonly rawToPacketMsgConverters: ElementToPacketMsgConverters = {
|
||||||
[ElementType.TEXT]: (element) => {
|
[ElementType.TEXT]: (element) => {
|
||||||
if (element.textElement?.atType) {
|
if (element.textElement?.atType) {
|
||||||
return new PacketMsgAtElement(element as SendTextElement);
|
return new PacketMsgAtElement(element as SendTextElement);
|
||||||
@@ -116,7 +116,7 @@ export class PacketMsgConverter {
|
|||||||
[ElementType.MARKDOWN]: (element) => {
|
[ElementType.MARKDOWN]: (element) => {
|
||||||
return new PacketMsgMarkDownElement(element as SendMarkdownElement);
|
return new PacketMsgMarkDownElement(element as SendMarkdownElement);
|
||||||
},
|
},
|
||||||
// TODO: check this logic, move it in arkElement?
|
// work:check this logic, move it in arkElement?
|
||||||
[ElementType.STRUCTLONGMSG]: (element) => {
|
[ElementType.STRUCTLONGMSG]: (element) => {
|
||||||
return new PacketMultiMsgElement(element as SendStructLongMsgElement);
|
return new PacketMultiMsgElement(element as SendStructLongMsgElement);
|
||||||
}
|
}
|
||||||
|
@@ -32,7 +32,7 @@ import { ForwardMsgBuilder } from "@/common/forward-msg-builder";
|
|||||||
import { PacketMsg, PacketSendMsgElement } from "@/core/packet/message/message";
|
import { PacketMsg, PacketSendMsgElement } from "@/core/packet/message/message";
|
||||||
|
|
||||||
// raw <-> packet
|
// raw <-> packet
|
||||||
// TODO: SendStructLongMsgElement
|
// work:SendStructLongMsgElement
|
||||||
export abstract class IPacketMsgElement<T extends PacketSendMsgElement> {
|
export abstract class IPacketMsgElement<T extends PacketSendMsgElement> {
|
||||||
protected constructor(rawElement: T) {
|
protected constructor(rawElement: T) {
|
||||||
}
|
}
|
||||||
@@ -118,7 +118,7 @@ export class PacketMsgReplyElement extends IPacketMsgElement<SendReplyElement> {
|
|||||||
this.targetUin = +(element.replyElement.senderUin ?? 0);
|
this.targetUin = +(element.replyElement.senderUin ?? 0);
|
||||||
this.targetUid = element.replyElement.senderUidStr ?? '';
|
this.targetUid = element.replyElement.senderUidStr ?? '';
|
||||||
this.time = +(element.replyElement.replyMsgTime ?? 0);
|
this.time = +(element.replyElement.replyMsgTime ?? 0);
|
||||||
this.elems = []; // TODO: in replyElement.sourceMsgTextElems
|
this.elems = []; // work:in replyElement.sourceMsgTextElems
|
||||||
}
|
}
|
||||||
|
|
||||||
get isGroupReply(): boolean {
|
get isGroupReply(): boolean {
|
||||||
@@ -131,7 +131,7 @@ export class PacketMsgReplyElement extends IPacketMsgElement<SendReplyElement> {
|
|||||||
origSeqs: [this.isGroupReply ? this.messageClientSeq : this.messageSeq],
|
origSeqs: [this.isGroupReply ? this.messageClientSeq : this.messageSeq],
|
||||||
senderUin: BigInt(this.targetUin),
|
senderUin: BigInt(this.targetUin),
|
||||||
time: this.time,
|
time: this.time,
|
||||||
elems: [], // TODO: in replyElement.sourceMsgTextElems
|
elems: [], // work:in replyElement.sourceMsgTextElems
|
||||||
pbReserve: {
|
pbReserve: {
|
||||||
messageId: this.messageId,
|
messageId: this.messageId,
|
||||||
},
|
},
|
||||||
@@ -346,9 +346,9 @@ export class PacketMsgPttElement extends IPacketMsgElement<SendPttElement> {
|
|||||||
constructor(element: SendPttElement) {
|
constructor(element: SendPttElement) {
|
||||||
super(element);
|
super(element);
|
||||||
this.filePath = element.pttElement.filePath;
|
this.filePath = element.pttElement.filePath;
|
||||||
this.fileSize = +element.pttElement.fileSize; // TODO: cc
|
this.fileSize = +element.pttElement.fileSize; // work:cc
|
||||||
this.fileMd5 = element.pttElement.md5HexStr;
|
this.fileMd5 = element.pttElement.md5HexStr;
|
||||||
this.fileDuration = Math.round(element.pttElement.duration); // TODO: cc
|
this.fileDuration = Math.round(element.pttElement.duration); // work:cc
|
||||||
}
|
}
|
||||||
|
|
||||||
get valid(): boolean {
|
get valid(): boolean {
|
||||||
|
@@ -25,7 +25,7 @@ class DownloadOfflineFile extends PacketTransformer<typeof proto.OidbSvcTrpcTcp0
|
|||||||
return OidbBase.build(0xE37, 800, body, false, false);
|
return OidbBase.build(0xE37, 800, body, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: check
|
// work:check
|
||||||
parse(data: Buffer) {
|
parse(data: Buffer) {
|
||||||
const oidbBody = OidbBase.parse(data).body;
|
const oidbBody = OidbBase.parse(data).body;
|
||||||
return new NapProtoMsg(proto.OidbSvcTrpcTcp0XE37Response).decode(oidbBody);
|
return new NapProtoMsg(proto.OidbSvcTrpcTcp0XE37Response).decode(oidbBody);
|
||||||
|
@@ -16,7 +16,7 @@ class FetchSessionKey extends PacketTransformer<typeof proto.HttpConn0x6ff_501Re
|
|||||||
field4: 1,
|
field4: 1,
|
||||||
field6: 3,
|
field6: 3,
|
||||||
serviceTypes: [1, 5, 10, 21],
|
serviceTypes: [1, 5, 10, 21],
|
||||||
// tgt: "", // TODO: do we really need tgt? seems not
|
// tgt: "", // work:do we really need tgt? seems not
|
||||||
field9: 2,
|
field9: 2,
|
||||||
field10: 9,
|
field10: 9,
|
||||||
field11: 8,
|
field11: 8,
|
||||||
|
@@ -16,7 +16,7 @@ class UploadGroupFile extends PacketTransformer<typeof proto.OidbSvcTrpcTcp0x6D6
|
|||||||
appId: 4,
|
appId: 4,
|
||||||
busId: 102,
|
busId: 102,
|
||||||
entrance: 6,
|
entrance: 6,
|
||||||
targetDirectory: '/', // TODO:
|
targetDirectory: '/', // work:
|
||||||
fileName: file.fileName,
|
fileName: file.fileName,
|
||||||
localDirectory: `/${file.fileName}`,
|
localDirectory: `/${file.fileName}`,
|
||||||
fileSize: BigInt(file.fileSize),
|
fileSize: BigInt(file.fileSize),
|
||||||
|
@@ -40,7 +40,7 @@ class UploadGroupImage extends PacketTransformer<typeof proto.NTV2RichMediaResp>
|
|||||||
fileName: img.name,
|
fileName: img.name,
|
||||||
type: {
|
type: {
|
||||||
type: 1,
|
type: 1,
|
||||||
picFormat: img.picType, //TODO: extend NapCat imgType /cc @MliKiowa
|
picFormat: img.picType, //work:extend NapCat imgType /cc @MliKiowa
|
||||||
videoFormat: 0,
|
videoFormat: 0,
|
||||||
voiceFormat: 0,
|
voiceFormat: 0,
|
||||||
},
|
},
|
||||||
@@ -59,7 +59,7 @@ class UploadGroupImage extends PacketTransformer<typeof proto.NTV2RichMediaResp>
|
|||||||
extBizInfo: {
|
extBizInfo: {
|
||||||
pic: {
|
pic: {
|
||||||
bytesPbReserveTroop: Buffer.from("0800180020004200500062009201009a0100a2010c080012001800200028003a00", 'hex'),
|
bytesPbReserveTroop: Buffer.from("0800180020004200500062009201009a0100a2010c080012001800200028003a00", 'hex'),
|
||||||
textSummary: "Nya~", // TODO:
|
textSummary: "Nya~", // work:
|
||||||
},
|
},
|
||||||
video: {
|
video: {
|
||||||
bytesPbReserve: Buffer.alloc(0),
|
bytesPbReserve: Buffer.alloc(0),
|
||||||
|
@@ -40,7 +40,7 @@ class UploadPrivateImage extends PacketTransformer<typeof proto.NTV2RichMediaRes
|
|||||||
fileName: img.name,
|
fileName: img.name,
|
||||||
type: {
|
type: {
|
||||||
type: 1,
|
type: 1,
|
||||||
picFormat: img.picType, //TODO: extend NapCat imgType /cc @MliKiowa
|
picFormat: img.picType, //work:extend NapCat imgType /cc @MliKiowa
|
||||||
videoFormat: 0,
|
videoFormat: 0,
|
||||||
voiceFormat: 0,
|
voiceFormat: 0,
|
||||||
},
|
},
|
||||||
@@ -59,7 +59,7 @@ class UploadPrivateImage extends PacketTransformer<typeof proto.NTV2RichMediaRes
|
|||||||
extBizInfo: {
|
extBizInfo: {
|
||||||
pic: {
|
pic: {
|
||||||
bytesPbReserveTroop: Buffer.from("0800180020004200500062009201009a0100a2010c080012001800200028003a00", 'hex'),
|
bytesPbReserveTroop: Buffer.from("0800180020004200500062009201009a0100a2010c080012001800200028003a00", 'hex'),
|
||||||
textSummary: "Nya~", // TODO:
|
textSummary: "Nya~", // work:
|
||||||
},
|
},
|
||||||
video: {
|
video: {
|
||||||
bytesPbReserve: Buffer.alloc(0),
|
bytesPbReserve: Buffer.alloc(0),
|
||||||
|
@@ -5,17 +5,17 @@ import * as fs from 'fs';
|
|||||||
import { CalculateStreamBytesTransform } from "@/core/packet/utils/crypto/sha1StreamBytesTransform";
|
import { CalculateStreamBytesTransform } from "@/core/packet/utils/crypto/sha1StreamBytesTransform";
|
||||||
|
|
||||||
function sha1Stream(readable: stream.Readable) {
|
function sha1Stream(readable: stream.Readable) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise<Buffer>((resolve, reject) => {
|
||||||
readable.on('error', reject);
|
readable.on('error', reject);
|
||||||
readable.pipe(crypto.createHash('sha1').on('error', reject).on('data', resolve));
|
readable.pipe(crypto.createHash('sha1').on('error', reject).on('data', resolve));
|
||||||
}) as Promise<Buffer>;
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function md5Stream(readable: stream.Readable) {
|
function md5Stream(readable: stream.Readable) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise<Buffer>((resolve, reject) => {
|
||||||
readable.on('error', reject);
|
readable.on('error', reject);
|
||||||
readable.pipe(crypto.createHash('md5').on('error', reject).on('data', resolve));
|
readable.pipe(crypto.createHash('md5').on('error', reject).on('data', resolve));
|
||||||
}) as Promise<Buffer>;
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateSha1(filePath: string): Promise<Buffer> {
|
export function calculateSha1(filePath: string): Promise<Buffer> {
|
||||||
@@ -39,7 +39,7 @@ export function calculateSha1StreamBytes(filePath: string): Promise<Buffer[]> {
|
|||||||
calculateStreamBytes.on('end', () => {
|
calculateStreamBytes.on('end', () => {
|
||||||
resolve(byteArrayList);
|
resolve(byteArrayList);
|
||||||
});
|
});
|
||||||
calculateStreamBytes.on('error', (err) => {
|
calculateStreamBytes.on('error', (err: Error) => {
|
||||||
reject(err);
|
reject(err);
|
||||||
});
|
});
|
||||||
readable.pipe(calculateStreamBytes);
|
readable.pipe(calculateStreamBytes);
|
||||||
|
@@ -45,11 +45,17 @@ export class Sha1Stream {
|
|||||||
let e = this._state[4];
|
let e = this._state[4];
|
||||||
|
|
||||||
for (let i = 0; i < 80; i++) {
|
for (let i = 0; i < 80; i++) {
|
||||||
const [f, k] = (i < 20) ? [(b & c) | ((~b) & d), 0x5A827999] :
|
let temp;
|
||||||
(i < 40) ? [b ^ c ^ d, 0x6ED9EBA1] :
|
if (i < 20) {
|
||||||
(i < 60) ? [(b & c) | (b & d) | (c & d), 0x8F1BBCDC] :
|
temp = ((b & c) | (~b & d)) + 0x5A827999;
|
||||||
[b ^ c ^ d, 0xCA62C1D6];
|
} else if (i < 40) {
|
||||||
const temp = (this.rotateLeft(a, 5) + f + k + e + w[i]) >>> 0;
|
temp = (b ^ c ^ d) + 0x6ED9EBA1;
|
||||||
|
} else if (i < 60) {
|
||||||
|
temp = ((b & c) | (b & d) | (c & d)) + 0x8F1BBCDC;
|
||||||
|
} else {
|
||||||
|
temp = (b ^ c ^ d) + 0xCA62C1D6;
|
||||||
|
}
|
||||||
|
temp += ((this.rotateLeft(a, 5) + e + w[i]) >>> 0);
|
||||||
e = d;
|
e = d;
|
||||||
d = c;
|
d = c;
|
||||||
c = this.rotateLeft(b, 30) >>> 0;
|
c = this.rotateLeft(b, 30) >>> 0;
|
||||||
|
@@ -3,7 +3,7 @@ import { Sha1Stream } from "@/core/packet/utils/crypto/sha1Stream";
|
|||||||
|
|
||||||
export class CalculateStreamBytesTransform extends stream.Transform {
|
export class CalculateStreamBytesTransform extends stream.Transform {
|
||||||
private readonly blockSize = 1024 * 1024;
|
private readonly blockSize = 1024 * 1024;
|
||||||
private sha1: Sha1Stream;
|
private readonly sha1: Sha1Stream;
|
||||||
private buffer: Buffer;
|
private buffer: Buffer;
|
||||||
private bytesRead: number;
|
private bytesRead: number;
|
||||||
private readonly byteArrayList: Buffer[];
|
private readonly byteArrayList: Buffer[];
|
||||||
|
@@ -9,10 +9,10 @@ import {
|
|||||||
type MiniAppTemplateNameList = "bili" | "weibo";
|
type MiniAppTemplateNameList = "bili" | "weibo";
|
||||||
|
|
||||||
export abstract class MiniAppInfo {
|
export abstract class MiniAppInfo {
|
||||||
static sdkId: string = "V1_PC_MINISDK_99.99.99_1_APP_A";
|
static readonly sdkId: string = "V1_PC_MINISDK_99.99.99_1_APP_A";
|
||||||
template: MiniAppReqTemplateParams;
|
template: MiniAppReqTemplateParams;
|
||||||
|
|
||||||
private static appMap = new Map<MiniAppTemplateNameList, MiniAppInfo>();
|
private static readonly appMap = new Map<MiniAppTemplateNameList, MiniAppInfo>();
|
||||||
|
|
||||||
protected constructor(template: MiniAppReqTemplateParams) {
|
protected constructor(template: MiniAppReqTemplateParams) {
|
||||||
this.template = template;
|
this.template = template;
|
||||||
@@ -22,7 +22,7 @@ export abstract class MiniAppInfo {
|
|||||||
return this.appMap.get(name);
|
return this.appMap.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Bili = new class extends MiniAppInfo {
|
static readonly Bili = new class extends MiniAppInfo {
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
sdkId: MiniAppInfo.sdkId,
|
sdkId: MiniAppInfo.sdkId,
|
||||||
@@ -40,7 +40,7 @@ export abstract class MiniAppInfo {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static WeiBo = new class extends MiniAppInfo {
|
static readonly WeiBo = new class extends MiniAppInfo {
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
sdkId: MiniAppInfo.sdkId,
|
sdkId: MiniAppInfo.sdkId,
|
||||||
|
@@ -89,7 +89,7 @@ export interface NodeIKernelGroupService {
|
|||||||
|
|
||||||
isEssenceMsg(req: { groupCode: string, msgRandom: number, msgSeq: number }): Promise<unknown>;
|
isEssenceMsg(req: { groupCode: string, msgRandom: number, msgSeq: number }): Promise<unknown>;
|
||||||
|
|
||||||
queryCachedEssenceMsg(req: { groupCode: string, msgRandom: number, msgSeq: number }): Promise<unknown>;
|
queryCachedEssenceMsg(req: { groupCode: string, msgRandom: number, msgSeq: number }): Promise<{ items: Array<unknown> }>;
|
||||||
|
|
||||||
fetchGroupEssenceList(req: {
|
fetchGroupEssenceList(req: {
|
||||||
groupCode: string,
|
groupCode: string,
|
||||||
|
@@ -29,10 +29,7 @@ import { NodeIKernelECDHService } from './services/NodeIKernelECDHService';
|
|||||||
import { NodeIO3MiscService } from './services/NodeIO3MiscService';
|
import { NodeIO3MiscService } from './services/NodeIO3MiscService';
|
||||||
|
|
||||||
export interface NodeQQNTWrapperUtil {
|
export interface NodeQQNTWrapperUtil {
|
||||||
get(): unknown;
|
get(): NodeQQNTWrapperUtil;
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
|
||||||
new(): NodeQQNTWrapperUtil;
|
|
||||||
|
|
||||||
getNTUserDataInfoConfig(): string;
|
getNTUserDataInfoConfig(): string;
|
||||||
|
|
||||||
|
@@ -55,11 +55,12 @@ export async function NCoreInitFramework(
|
|||||||
// await sleep(2500);
|
// await sleep(2500);
|
||||||
// 初始化 NapCatFramework
|
// 初始化 NapCatFramework
|
||||||
const loaderObject = new NapCatFramework(wrapper, session, logger, loginService, selfInfo, basicInfoWrapper, pathWrapper);
|
const loaderObject = new NapCatFramework(wrapper, session, logger, loginService, selfInfo, basicInfoWrapper, pathWrapper);
|
||||||
|
await loaderObject.core.initCore();
|
||||||
|
|
||||||
//启动WebUi
|
//启动WebUi
|
||||||
InitWebUi(logger, pathWrapper).then().catch(logger.logError.bind(logger));
|
InitWebUi(logger, pathWrapper).then().catch(logger.logError.bind(logger));
|
||||||
//初始化LLNC的Onebot实现
|
//初始化LLNC的Onebot实现
|
||||||
new NapCatOneBot11Adapter(loaderObject.core, loaderObject.context, pathWrapper);
|
await new NapCatOneBot11Adapter(loaderObject.core, loaderObject.context, pathWrapper).InitOneBot();
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NapCatFramework {
|
export class NapCatFramework {
|
||||||
|
BIN
src/native/external/MoeHoo.win32.node
vendored
BIN
src/native/external/MoeHoo.win32.node
vendored
Binary file not shown.
@@ -1,40 +0,0 @@
|
|||||||
import { constants } from "node:os";
|
|
||||||
import path from "path";
|
|
||||||
import { dlopen } from "process";
|
|
||||||
import fs from "fs";
|
|
||||||
export class Native {
|
|
||||||
platform: string;
|
|
||||||
supportedPlatforms = [''];
|
|
||||||
MoeHooExport: any = { exports: {} };
|
|
||||||
recallHookEnabled: boolean = false;
|
|
||||||
inited = true;
|
|
||||||
constructor(nodePath: string, platform: string = process.platform) {
|
|
||||||
this.platform = platform;
|
|
||||||
try {
|
|
||||||
if (!this.supportedPlatforms.includes(this.platform)) {
|
|
||||||
throw new Error(`Platform ${this.platform} is not supported`);
|
|
||||||
}
|
|
||||||
const nativeNode = path.join(nodePath, './native/MoeHoo.win32.node');
|
|
||||||
if (fs.existsSync(nativeNode)) {
|
|
||||||
dlopen(this.MoeHooExport, nativeNode, constants.dlopen.RTLD_LAZY);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
this.inited = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
isSetReCallEnabled(): boolean {
|
|
||||||
return this.recallHookEnabled && this.inited;
|
|
||||||
}
|
|
||||||
registerRecallCallback(callback: (hex: string) => any): void {
|
|
||||||
try {
|
|
||||||
if (!this.inited) throw new Error('Native Not Init');
|
|
||||||
if (this.MoeHooExport.exports?.registMsgPush) {
|
|
||||||
this.MoeHooExport.exports.registMsgPush(callback);
|
|
||||||
this.recallHookEnabled = true;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
this.recallHookEnabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -29,7 +29,7 @@ abstract class BaseAction<PayloadType, ReturnDataType> {
|
|||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
valid: false,
|
valid: false,
|
||||||
message: errorMessages.join('\n') as string || '未知错误',
|
message: errorMessages.join('\n') ?? '未知错误',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
@@ -6,7 +6,7 @@ export class GetFriendWithCategory extends BaseAction<void, any> {
|
|||||||
actionName = ActionName.GetFriendsWithCategory;
|
actionName = ActionName.GetFriendsWithCategory;
|
||||||
|
|
||||||
async _handle(payload: void) {
|
async _handle(payload: void) {
|
||||||
return (await this.core.apis.FriendApi.getBuddyV2ExWithCate(true)).map(category => ({
|
return (await this.core.apis.FriendApi.getBuddyV2ExWithCate()).map(category => ({
|
||||||
...category,
|
...category,
|
||||||
buddyList: OB11Entities.friendsV2(category.buddyList),
|
buddyList: OB11Entities.friendsV2(category.buddyList),
|
||||||
}));
|
}));
|
||||||
|
@@ -60,7 +60,7 @@ export class GetMiniAppArk extends GetPacketStatusDepends<Payload, {
|
|||||||
if (payload.type) {
|
if (payload.type) {
|
||||||
reqParam = MiniAppInfoHelper.generateReq(customParams, MiniAppInfo.get(payload.type)!.template);
|
reqParam = MiniAppInfoHelper.generateReq(customParams, MiniAppInfo.get(payload.type)!.template);
|
||||||
} else {
|
} else {
|
||||||
const { appId, scene, iconUrl, templateType, businessType, verType, shareType, versionId, withShareTicket } = payload as Required<Payload>;
|
const { appId, scene, iconUrl, templateType, businessType, verType, shareType, versionId, withShareTicket } = payload;
|
||||||
reqParam = MiniAppInfoHelper.generateReq(
|
reqParam = MiniAppInfoHelper.generateReq(
|
||||||
customParams,
|
customParams,
|
||||||
{
|
{
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import BaseAction from '../BaseAction';
|
import BaseAction from '../BaseAction';
|
||||||
import { ActionName, BaseCheckResult } from '../types';
|
import { ActionName } from '../types';
|
||||||
|
|
||||||
interface Payload {
|
interface Payload {
|
||||||
start: number,
|
start: number,
|
||||||
@@ -13,9 +13,9 @@ export class GetProfileLike extends BaseAction<Payload, any> {
|
|||||||
const start = payload.start ? Number(payload.start) : 0;
|
const start = payload.start ? Number(payload.start) : 0;
|
||||||
const count = payload.count ? Number(payload.count) : 10;
|
const count = payload.count ? Number(payload.count) : 10;
|
||||||
const ret = await this.core.apis.UserApi.getProfileLike(this.core.selfInfo.uid, start, count);
|
const ret = await this.core.apis.UserApi.getProfileLike(this.core.selfInfo.uid, start, count);
|
||||||
const listdata: any[] = ret.info.userLikeInfos[0].voteInfo.userInfos;
|
const listdata = ret.info.userLikeInfos[0].voteInfo.userInfos;
|
||||||
for (let i = 0; i < listdata.length; i++) {
|
for (const item of listdata) {
|
||||||
listdata[i].uin = parseInt((await this.core.apis.UserApi.getUinByUidV2(listdata[i].uid)) || '');
|
item.uin = parseInt((await this.core.apis.UserApi.getUinByUidV2(item.uid)) || '');
|
||||||
}
|
}
|
||||||
return ret.info.userLikeInfos[0].voteInfo;
|
return ret.info.userLikeInfos[0].voteInfo;
|
||||||
}
|
}
|
||||||
|
@@ -21,7 +21,7 @@ export class OCRImage extends BaseAction<Payload, any> {
|
|||||||
async _handle(payload: Payload) {
|
async _handle(payload: Payload) {
|
||||||
const { path, success } = (await uri2local(this.core.NapCatTempPath, payload.image));
|
const { path, success } = (await uri2local(this.core.NapCatTempPath, payload.image));
|
||||||
if (!success) {
|
if (!success) {
|
||||||
throw `OCR ${payload.image}失败,image字段可能格式不正确`;
|
throw new Error(`OCR ${payload.image}失败,image字段可能格式不正确`);
|
||||||
}
|
}
|
||||||
if (path) {
|
if (path) {
|
||||||
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃,需要提前判断
|
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃,需要提前判断
|
||||||
@@ -29,12 +29,12 @@ export class OCRImage extends BaseAction<Payload, any> {
|
|||||||
fs.unlink(path, () => { });
|
fs.unlink(path, () => { });
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
throw `OCR ${payload.file}失败`;
|
throw new Error(`OCR ${payload.file}失败`);
|
||||||
}
|
}
|
||||||
return ret.result;
|
return ret.result;
|
||||||
}
|
}
|
||||||
fs.unlink(path, () => { });
|
fs.unlink(path, () => { });
|
||||||
throw `OCR ${payload.file}失败,文件可能不存在`;
|
throw new Error(`OCR ${payload.file}失败,文件可能不存在`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||||
import BaseAction from '../BaseAction';
|
import BaseAction from '../BaseAction';
|
||||||
import { ActionName, BaseCheckResult } from '../types';
|
import { ActionName } from '../types';
|
||||||
import { ChatType, Peer } from '@/core';
|
import { ChatType } from '@/core';
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
@@ -9,7 +9,7 @@ const SchemaData = {
|
|||||||
event_type: { type: 'number' },
|
event_type: { type: 'number' },
|
||||||
user_id: { type: ['number', 'string'] },
|
user_id: { type: ['number', 'string'] },
|
||||||
},
|
},
|
||||||
required: ['event_type','user_id'],
|
required: ['event_type', 'user_id'],
|
||||||
} as const satisfies JSONSchema;
|
} as const satisfies JSONSchema;
|
||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = FromSchema<typeof SchemaData>;
|
||||||
|
@@ -26,7 +26,7 @@ export default class SetAvatar extends BaseAction<Payload, null> {
|
|||||||
async _handle(payload: Payload): Promise<null> {
|
async _handle(payload: Payload): Promise<null> {
|
||||||
const { path, success } = (await uri2local(this.core.NapCatTempPath, payload.file));
|
const { path, success } = (await uri2local(this.core.NapCatTempPath, payload.file));
|
||||||
if (!success) {
|
if (!success) {
|
||||||
throw `头像${payload.file}设置失败,file字段可能格式不正确`;
|
throw new Error(`头像${payload.file}设置失败,file字段可能格式不正确`);
|
||||||
}
|
}
|
||||||
if (path) {
|
if (path) {
|
||||||
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃,需要提前判断
|
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃,需要提前判断
|
||||||
@@ -35,18 +35,18 @@ export default class SetAvatar extends BaseAction<Payload, null> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
throw `头像${payload.file}设置失败,api无返回`;
|
throw new Error(`头像${payload.file}设置失败,api无返回`);
|
||||||
}
|
}
|
||||||
// log(`头像设置返回:${JSON.stringify(ret)}`)
|
// log(`头像设置返回:${JSON.stringify(ret)}`)
|
||||||
if (ret.result as number == 1004022) {
|
if (ret.result as number == 1004022) {
|
||||||
throw `头像${payload.file}设置失败,文件可能不是图片格式`;
|
throw new Error(`头像${payload.file}设置失败,文件可能不是图片格式`);
|
||||||
} else if (ret.result != 0) {
|
} else if (ret.result != 0) {
|
||||||
throw `头像${payload.file}设置失败,未知的错误,${ret.result}:${ret.errMsg}`;
|
throw new Error(`头像${payload.file}设置失败,未知的错误,${ret.result}:${ret.errMsg}`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fs.unlink(path, () => { });
|
fs.unlink(path, () => { });
|
||||||
|
|
||||||
throw `头像${payload.file}设置失败,无法获取头像,文件可能不存在`;
|
throw new Error(`头像${payload.file}设置失败,无法获取头像,文件可能不存在`);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@@ -61,7 +61,7 @@ export class GoCQHTTPGetForwardMsgAction extends BaseAction<Payload, any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const rootMsgId = MessageUnique.getShortIdByMsgId(msgId);
|
const rootMsgId = MessageUnique.getShortIdByMsgId(msgId);
|
||||||
const rootMsg = MessageUnique.getMsgIdAndPeerByShortId(rootMsgId || parseInt(msgId));
|
const rootMsg = MessageUnique.getMsgIdAndPeerByShortId(rootMsgId ?? +msgId);
|
||||||
if (!rootMsg) {
|
if (!rootMsg) {
|
||||||
throw new Error('msg not found');
|
throw new Error('msg not found');
|
||||||
}
|
}
|
||||||
|
@@ -31,14 +31,14 @@ export default class GetFriendMsgHistory extends BaseAction<Payload, Response> {
|
|||||||
const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
||||||
const MsgCount = +(payload.count ?? 20);
|
const MsgCount = +(payload.count ?? 20);
|
||||||
const isReverseOrder = typeof payload.reverseOrder === 'string' ? payload.reverseOrder === 'true' : !!payload.reverseOrder;
|
const isReverseOrder = typeof payload.reverseOrder === 'string' ? payload.reverseOrder === 'true' : !!payload.reverseOrder;
|
||||||
if (!uid) throw `记录${payload.user_id}不存在`;
|
if (!uid) throw new Error(`记录${payload.user_id}不存在`);
|
||||||
const friend = await this.core.apis.FriendApi.isBuddy(uid);
|
const friend = await this.core.apis.FriendApi.isBuddy(uid);
|
||||||
const peer = { chatType: friend ? ChatType.KCHATTYPEC2C : ChatType.KCHATTYPETEMPC2CFROMGROUP, peerUid: uid };
|
const peer = { chatType: friend ? ChatType.KCHATTYPEC2C : ChatType.KCHATTYPETEMPC2CFROMGROUP, peerUid: uid };
|
||||||
const hasMessageSeq = !payload.message_seq ? !!payload.message_seq : !(payload.message_seq?.toString() === '' || payload.message_seq?.toString() === '0');
|
const hasMessageSeq = !payload.message_seq ? !!payload.message_seq : !(payload.message_seq?.toString() === '' || payload.message_seq?.toString() === '0');
|
||||||
const startMsgId = hasMessageSeq ? (MessageUnique.getMsgIdAndPeerByShortId(+payload.message_seq!)?.MsgId ?? payload.message_seq!.toString()) : '0';
|
const startMsgId = hasMessageSeq ? (MessageUnique.getMsgIdAndPeerByShortId(+payload.message_seq!)?.MsgId ?? payload.message_seq!.toString()) : '0';
|
||||||
const msgList = hasMessageSeq ?
|
const msgList = hasMessageSeq ?
|
||||||
(await this.core.apis.MsgApi.getMsgHistory(peer, startMsgId, MsgCount)).msgList : (await this.core.apis.MsgApi.getAioFirstViewLatestMsgs(peer, MsgCount)).msgList;
|
(await this.core.apis.MsgApi.getMsgHistory(peer, startMsgId, MsgCount)).msgList : (await this.core.apis.MsgApi.getAioFirstViewLatestMsgs(peer, MsgCount)).msgList;
|
||||||
if (msgList.length === 0) throw `消息${payload.message_seq}不存在`;
|
if (msgList.length === 0) throw new Error(`消息${payload.message_seq}不存在`);
|
||||||
//翻转消息
|
//翻转消息
|
||||||
if (isReverseOrder) msgList.reverse();
|
if (isReverseOrder) msgList.reverse();
|
||||||
//转换序号
|
//转换序号
|
||||||
|
@@ -15,7 +15,7 @@ type Payload = FromSchema<typeof SchemaData>;
|
|||||||
export class GetGroupFileSystemInfo extends BaseAction<Payload, {
|
export class GetGroupFileSystemInfo extends BaseAction<Payload, {
|
||||||
file_count: number,
|
file_count: number,
|
||||||
limit_count: number, // unimplemented
|
limit_count: number, // unimplemented
|
||||||
used_space: number, // todo: unimplemented, but can be implemented later
|
used_space: number, // work:unimplemented, but can be implemented later
|
||||||
total_space: number, // unimplemented, 10 GB by default
|
total_space: number, // unimplemented, 10 GB by default
|
||||||
}> {
|
}> {
|
||||||
actionName = ActionName.GoCQHTTP_GetGroupFileSystemInfo;
|
actionName = ActionName.GoCQHTTP_GetGroupFileSystemInfo;
|
||||||
|
@@ -36,7 +36,7 @@ export default class GoCQHTTPGetGroupMsgHistory extends BaseAction<Payload, Resp
|
|||||||
const startMsgId = hasMessageSeq ? (MessageUnique.getMsgIdAndPeerByShortId(+payload.message_seq!)?.MsgId ?? payload.message_seq!.toString()) : '0';
|
const startMsgId = hasMessageSeq ? (MessageUnique.getMsgIdAndPeerByShortId(+payload.message_seq!)?.MsgId ?? payload.message_seq!.toString()) : '0';
|
||||||
const msgList = hasMessageSeq ?
|
const msgList = hasMessageSeq ?
|
||||||
(await this.core.apis.MsgApi.getMsgHistory(peer, startMsgId, MsgCount)).msgList : (await this.core.apis.MsgApi.getAioFirstViewLatestMsgs(peer, MsgCount)).msgList;
|
(await this.core.apis.MsgApi.getMsgHistory(peer, startMsgId, MsgCount)).msgList : (await this.core.apis.MsgApi.getAioFirstViewLatestMsgs(peer, MsgCount)).msgList;
|
||||||
if (msgList.length === 0) throw `消息${payload.message_seq}不存在`;
|
if (msgList.length === 0) throw new Error(`消息${payload.message_seq}不存在`);
|
||||||
//翻转消息
|
//翻转消息
|
||||||
if (isReverseOrder) msgList.reverse();
|
if (isReverseOrder) msgList.reverse();
|
||||||
//转换序号
|
//转换序号
|
||||||
|
@@ -34,15 +34,15 @@ export class SendGroupNotice extends BaseAction<Payload, null> {
|
|||||||
success,
|
success,
|
||||||
} = (await uri2local(this.core.NapCatTempPath, payload.image));
|
} = (await uri2local(this.core.NapCatTempPath, payload.image));
|
||||||
if (!success) {
|
if (!success) {
|
||||||
throw `群公告${payload.image}设置失败,image字段可能格式不正确`;
|
throw new Error(`群公告${payload.image}设置失败,image字段可能格式不正确`);
|
||||||
}
|
}
|
||||||
if (!path) {
|
if (!path) {
|
||||||
throw `群公告${payload.image}设置失败,获取资源失败`;
|
throw new Error(`群公告${payload.image}设置失败,获取资源失败`);
|
||||||
}
|
}
|
||||||
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃,需要提前判断
|
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃,需要提前判断
|
||||||
const ImageUploadResult = await this.core.apis.GroupApi.uploadGroupBulletinPic(payload.group_id.toString(), path);
|
const ImageUploadResult = await this.core.apis.GroupApi.uploadGroupBulletinPic(payload.group_id.toString(), path);
|
||||||
if (ImageUploadResult.errCode != 0) {
|
if (ImageUploadResult.errCode != 0) {
|
||||||
throw `群公告${payload.image}设置失败,图片上传失败`;
|
throw new Error(`群公告${payload.image}设置失败,图片上传失败`);
|
||||||
}
|
}
|
||||||
|
|
||||||
unlink(path, () => {
|
unlink(path, () => {
|
||||||
|
@@ -27,24 +27,24 @@ export default class SetGroupPortrait extends BaseAction<Payload, any> {
|
|||||||
async _handle(payload: Payload): Promise<any> {
|
async _handle(payload: Payload): Promise<any> {
|
||||||
const { path, success } = (await uri2local(this.core.NapCatTempPath, payload.file));
|
const { path, success } = (await uri2local(this.core.NapCatTempPath, payload.file));
|
||||||
if (!success) {
|
if (!success) {
|
||||||
throw `头像${payload.file}设置失败,file字段可能格式不正确`;
|
throw new Error(`头像${payload.file}设置失败,file字段可能格式不正确`);
|
||||||
}
|
}
|
||||||
if (path) {
|
if (path) {
|
||||||
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃,需要提前判断
|
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃,需要提前判断
|
||||||
const ret = await this.core.apis.GroupApi.setGroupAvatar(payload.group_id.toString(), path);
|
const ret = await this.core.apis.GroupApi.setGroupAvatar(payload.group_id.toString(), path);
|
||||||
fs.unlink(path, () => { });
|
fs.unlink(path, () => { });
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
throw `头像${payload.file}设置失败,api无返回`;
|
throw new Error(`头像${payload.file}设置失败,api无返回`);
|
||||||
}
|
}
|
||||||
if (ret.result as number == 1004022) {
|
if (ret.result as number == 1004022) {
|
||||||
throw `头像${payload.file}设置失败,文件可能不是图片格式或权限不足`;
|
throw new Error(`头像${payload.file}设置失败,文件可能不是图片格式或权限不足`);
|
||||||
} else if (ret.result != 0) {
|
} else if (ret.result != 0) {
|
||||||
throw `头像${payload.file}设置失败,未知的错误,${ret.result}:${ret.errMsg}`;
|
throw new Error(`头像${payload.file}设置失败,未知的错误,${ret.result}:${ret.errMsg}`);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
} else {
|
} else {
|
||||||
fs.unlink(path, () => {});
|
fs.unlink(path, () => { });
|
||||||
throw `头像${payload.file}设置失败,无法获取头像,文件可能不存在`;
|
throw new Error(`头像${payload.file}设置失败,无法获取头像,文件可能不存在`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -14,7 +14,7 @@ const SchemaData = {
|
|||||||
|
|
||||||
type Payload = FromSchema<typeof SchemaData>;
|
type Payload = FromSchema<typeof SchemaData>;
|
||||||
|
|
||||||
export class SetQQProfile extends BaseAction<Payload, any | null> {
|
export class SetQQProfile extends BaseAction<Payload, any> {
|
||||||
actionName = ActionName.SetQQProfile;
|
actionName = ActionName.SetQQProfile;
|
||||||
payloadSchema = SchemaData;
|
payloadSchema = SchemaData;
|
||||||
|
|
||||||
|
@@ -27,7 +27,7 @@ export default class GoCQHTTPUploadPrivateFile extends BaseAction<Payload, null>
|
|||||||
if (payload.user_id) {
|
if (payload.user_id) {
|
||||||
const peerUid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
const peerUid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
||||||
if (!peerUid) {
|
if (!peerUid) {
|
||||||
throw `私聊${payload.user_id}不存在`;
|
throw new Error( `私聊${payload.user_id}不存在`);
|
||||||
}
|
}
|
||||||
const isBuddy = await this.core.apis.FriendApi.isBuddy(peerUid);
|
const isBuddy = await this.core.apis.FriendApi.isBuddy(peerUid);
|
||||||
return { chatType: isBuddy ? ChatType.KCHATTYPEC2C : ChatType.KCHATTYPETEMPC2CFROMGROUP, peerUid };
|
return { chatType: isBuddy ? ChatType.KCHATTYPEC2C : ChatType.KCHATTYPETEMPC2CFROMGROUP, peerUid };
|
||||||
|
@@ -3,7 +3,6 @@ import { OB11Entities } from '@/onebot/entities';
|
|||||||
import BaseAction from '../BaseAction';
|
import BaseAction from '../BaseAction';
|
||||||
import { ActionName } from '../types';
|
import { ActionName } from '../types';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||||
import { GroupMember } from '@/core';
|
|
||||||
|
|
||||||
const SchemaData = {
|
const SchemaData = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
@@ -44,7 +43,7 @@ class GetGroupMemberInfo extends BaseAction<Payload, OB11GroupMember> {
|
|||||||
} else {
|
} else {
|
||||||
this.core.context.logger.logDebug(`获取群成员详细信息失败, 只能返回基础信息`);
|
this.core.context.logger.logDebug(`获取群成员详细信息失败, 只能返回基础信息`);
|
||||||
}
|
}
|
||||||
return OB11Entities.groupMember(payload.group_id.toString(), member as GroupMember);
|
return OB11Entities.groupMember(payload.group_id.toString(), member);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
import { OB11Group } from '@/onebot';
|
|
||||||
import BaseAction from '../BaseAction';
|
import BaseAction from '../BaseAction';
|
||||||
import { ActionName } from '../types';
|
import { ActionName } from '../types';
|
||||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||||
|
@@ -26,7 +26,7 @@ export class SendGroupAiRecord extends GetPacketStatusDepends<Payload, {
|
|||||||
async _handle(payload: Payload) {
|
async _handle(payload: Payload) {
|
||||||
const rawRsp = await this.core.apis.PacketApi.pkt.operation.GetAiVoice(+payload.group_id, payload.character, payload.text, AIVoiceChatType.Sound);
|
const rawRsp = await this.core.apis.PacketApi.pkt.operation.GetAiVoice(+payload.group_id, payload.character, payload.text, AIVoiceChatType.Sound);
|
||||||
const url = await this.core.apis.PacketApi.pkt.operation.GetGroupPttUrl(+payload.group_id, rawRsp.msgInfoBody[0].index);
|
const url = await this.core.apis.PacketApi.pkt.operation.GetGroupPttUrl(+payload.group_id, rawRsp.msgInfoBody[0].index);
|
||||||
const { path, fileName, errMsg, success } = (await uri2local(this.core.NapCatTempPath, url));
|
const { path, errMsg, success } = (await uri2local(this.core.NapCatTempPath, url));
|
||||||
if (!success) {
|
if (!success) {
|
||||||
throw new Error(errMsg);
|
throw new Error(errMsg);
|
||||||
}
|
}
|
||||||
|
@@ -28,7 +28,7 @@ class GetMsg extends BaseAction<Payload, OB11Message> {
|
|||||||
throw Error('参数message_id不能为空');
|
throw Error('参数message_id不能为空');
|
||||||
}
|
}
|
||||||
const MsgShortId = MessageUnique.getShortIdByMsgId(payload.message_id.toString());
|
const MsgShortId = MessageUnique.getShortIdByMsgId(payload.message_id.toString());
|
||||||
const msgIdWithPeer = MessageUnique.getMsgIdAndPeerByShortId(MsgShortId || parseInt(payload.message_id.toString()));
|
const msgIdWithPeer = MessageUnique.getMsgIdAndPeerByShortId(MsgShortId ?? +payload.message_id);
|
||||||
if (!msgIdWithPeer) {
|
if (!msgIdWithPeer) {
|
||||||
throw new Error('消息不存在');
|
throw new Error('消息不存在');
|
||||||
}
|
}
|
||||||
|
@@ -30,7 +30,7 @@ class MarkMsgAsRead extends BaseAction<PlayloadType, null> {
|
|||||||
if (payload.user_id) {
|
if (payload.user_id) {
|
||||||
const peerUid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
const peerUid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
||||||
if (!peerUid) {
|
if (!peerUid) {
|
||||||
throw `私聊${payload.user_id}不存在`;
|
throw new Error( `私聊${payload.user_id}不存在`);
|
||||||
}
|
}
|
||||||
const isBuddy = await this.core.apis.FriendApi.isBuddy(peerUid);
|
const isBuddy = await this.core.apis.FriendApi.isBuddy(peerUid);
|
||||||
return { chatType: isBuddy ? ChatType.KCHATTYPEC2C : ChatType.KCHATTYPETEMPC2CFROMGROUP, peerUid };
|
return { chatType: isBuddy ? ChatType.KCHATTYPEC2C : ChatType.KCHATTYPETEMPC2CFROMGROUP, peerUid };
|
||||||
|
@@ -68,7 +68,7 @@ export async function createContext(core: NapCatCore, payload: OB11PostContext,
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
chatType: ChatType.KCHATTYPEC2C,
|
chatType: ChatType.KCHATTYPEC2C,
|
||||||
peerUid: Uid!,
|
peerUid: Uid,
|
||||||
guildId: '',
|
guildId: '',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -133,7 +133,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
guildId: '',
|
guildId: '',
|
||||||
peerUid: peer.peerUid,
|
peerUid: peer.peerUid,
|
||||||
chatType: peer.chatType,
|
chatType: peer.chatType,
|
||||||
}, (returnMsgAndResId.message)!.msgId);
|
}, (returnMsgAndResId.message).msgId);
|
||||||
return { message_id: msgShortId!, res_id: returnMsgAndResId.res_id };
|
return { message_id: msgShortId!, res_id: returnMsgAndResId.res_id };
|
||||||
} else if (returnMsgAndResId.res_id && !returnMsgAndResId.message) {
|
} else if (returnMsgAndResId.res_id && !returnMsgAndResId.message) {
|
||||||
throw Error(`发送转发消息(res_id:${returnMsgAndResId.res_id} 失败`);
|
throw Error(`发送转发消息(res_id:${returnMsgAndResId.res_id} 失败`);
|
||||||
@@ -150,7 +150,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
const { sendElements, deleteAfterSentFiles } = await this.obContext.apis.MsgApi
|
const { sendElements, deleteAfterSentFiles } = await this.obContext.apis.MsgApi
|
||||||
.createSendElements(messages, peer);
|
.createSendElements(messages, peer);
|
||||||
const returnMsg = await this.obContext.apis.MsgApi.sendMsgWithOb11UniqueId(peer, sendElements, deleteAfterSentFiles);
|
const returnMsg = await this.obContext.apis.MsgApi.sendMsgWithOb11UniqueId(peer, sendElements, deleteAfterSentFiles);
|
||||||
return { message_id: returnMsg!.id! };
|
return { message_id: returnMsg.id! };
|
||||||
}
|
}
|
||||||
|
|
||||||
private async uploadForwardedNodesPacket(msgPeer: Peer, messageNodes: OB11MessageNode[], source?: string, news?: {
|
private async uploadForwardedNodesPacket(msgPeer: Peer, messageNodes: OB11MessageNode[], source?: string, news?: {
|
||||||
@@ -175,7 +175,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
|
|
||||||
if (getSpecialMsgNum({ message: OB11Data }, OB11MessageDataType.node)) {
|
if (getSpecialMsgNum({ message: OB11Data }, OB11MessageDataType.node)) {
|
||||||
const uploadReturnData = await this.uploadForwardedNodesPacket(msgPeer, OB11Data as OB11MessageNode[], node.data.source, node.data.news, node.data.summary, node.data.prompt, {
|
const uploadReturnData = await this.uploadForwardedNodesPacket(msgPeer, OB11Data as OB11MessageNode[], node.data.source, node.data.news, node.data.summary, node.data.prompt, {
|
||||||
user_id: (node.data.user_id || node.data.uin)?.toString() ?? parentMeta?.user_id ?? this.core.selfInfo.uin,
|
user_id: (node.data.user_id ?? node.data.uin)?.toString() ?? parentMeta?.user_id ?? this.core.selfInfo.uin,
|
||||||
nickname: (node.data.nickname || node.data.name) ?? parentMeta?.nickname ?? "QQ用户",
|
nickname: (node.data.nickname || node.data.name) ?? parentMeta?.nickname ?? "QQ用户",
|
||||||
}, dp + 1);
|
}, dp + 1);
|
||||||
sendElements = uploadReturnData?.finallySendElements ? [uploadReturnData.finallySendElements] : [];
|
sendElements = uploadReturnData?.finallySendElements ? [uploadReturnData.finallySendElements] : [];
|
||||||
@@ -185,7 +185,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const packetMsgElements: rawMsgWithSendMsg = {
|
const packetMsgElements: rawMsgWithSendMsg = {
|
||||||
senderUin: Number((node.data.user_id || node.data.uin) ?? parentMeta?.user_id) || +this.core.selfInfo.uin,
|
senderUin: Number((node.data.user_id ?? node.data.uin) ?? parentMeta?.user_id) || +this.core.selfInfo.uin,
|
||||||
senderName: (node.data.nickname || node.data.name) ?? parentMeta?.nickname ?? "QQ用户",
|
senderName: (node.data.nickname || node.data.name) ?? parentMeta?.nickname ?? "QQ用户",
|
||||||
groupId: msgPeer.chatType === ChatType.KCHATTYPEGROUP ? +msgPeer.peerUid : undefined,
|
groupId: msgPeer.chatType === ChatType.KCHATTYPEGROUP ? +msgPeer.peerUid : undefined,
|
||||||
time: Number(node.data.time) || Date.now(),
|
time: Number(node.data.time) || Date.now(),
|
||||||
@@ -194,7 +194,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
logger.logDebug(`handleForwardedNodesPacket[SendRaw] 开始转换 ${stringifyWithBigInt(packetMsgElements)}`);
|
logger.logDebug(`handleForwardedNodesPacket[SendRaw] 开始转换 ${stringifyWithBigInt(packetMsgElements)}`);
|
||||||
const transformedMsg = this.core.apis.PacketApi.pkt.msgConverter.rawMsgWithSendMsgToPacketMsg(packetMsgElements);
|
const transformedMsg = this.core.apis.PacketApi.pkt.msgConverter.rawMsgWithSendMsgToPacketMsg(packetMsgElements);
|
||||||
logger.logDebug(`handleForwardedNodesPacket[SendRaw] 转换为 ${stringifyWithBigInt(transformedMsg)}`);
|
logger.logDebug(`handleForwardedNodesPacket[SendRaw] 转换为 ${stringifyWithBigInt(transformedMsg)}`);
|
||||||
packetMsg.push(transformedMsg!);
|
packetMsg.push(transformedMsg);
|
||||||
} else if (node.data.id) {
|
} else if (node.data.id) {
|
||||||
const id = node.data.id;
|
const id = node.data.id;
|
||||||
const nodeMsg = MessageUnique.getMsgIdAndPeerByShortId(+id) || MessageUnique.getPeerByMsgId(id);
|
const nodeMsg = MessageUnique.getMsgIdAndPeerByShortId(+id) || MessageUnique.getPeerByMsgId(id);
|
||||||
@@ -207,7 +207,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
await this.core.apis.FileApi.downloadRawMsgMedia([msg]);
|
await this.core.apis.FileApi.downloadRawMsgMedia([msg]);
|
||||||
const transformedMsg = this.core.apis.PacketApi.pkt.msgConverter.rawMsgToPacketMsg(msg, msgPeer);
|
const transformedMsg = this.core.apis.PacketApi.pkt.msgConverter.rawMsgToPacketMsg(msg, msgPeer);
|
||||||
logger.logDebug(`handleForwardedNodesPacket[PureRaw] 转换为 ${stringifyWithBigInt(transformedMsg)}`);
|
logger.logDebug(`handleForwardedNodesPacket[PureRaw] 转换为 ${stringifyWithBigInt(transformedMsg)}`);
|
||||||
packetMsg.push(transformedMsg!);
|
packetMsg.push(transformedMsg);
|
||||||
} else {
|
} else {
|
||||||
logger.logDebug(`handleForwardedNodesPacket 跳过元素 ${stringifyWithBigInt(node)}`);
|
logger.logDebug(`handleForwardedNodesPacket 跳过元素 ${stringifyWithBigInt(node)}`);
|
||||||
}
|
}
|
||||||
|
@@ -7,7 +7,7 @@ export abstract class GetPacketStatusDepends<PT, RT> extends BaseAction<PT, RT>
|
|||||||
|
|
||||||
protected async check(payload: PT): Promise<BaseCheckResult>{
|
protected async check(payload: PT): Promise<BaseCheckResult>{
|
||||||
if (!this.core.apis.PacketApi.available) {
|
if (!this.core.apis.PacketApi.available) {
|
||||||
// TODO: add error stack?
|
// work:add error stack?
|
||||||
return {
|
return {
|
||||||
valid: false,
|
valid: false,
|
||||||
message: "packetBackend不可用,请参照文档 https://napneko.github.io/config/advanced 和启动日志检查packetBackend状态或进行配置!" +
|
message: "packetBackend不可用,请参照文档 https://napneko.github.io/config/advanced 和启动日志检查packetBackend状态或进行配置!" +
|
||||||
|
@@ -18,13 +18,11 @@ export default class SendLike extends BaseAction<Payload, null> {
|
|||||||
payloadSchema = SchemaData;
|
payloadSchema = SchemaData;
|
||||||
|
|
||||||
async _handle(payload: Payload): Promise<null> {
|
async _handle(payload: Payload): Promise<null> {
|
||||||
//logDebug('点赞参数', payload);
|
|
||||||
const qq = payload.user_id.toString();
|
const qq = payload.user_id.toString();
|
||||||
const uid: string = await this.core.apis.UserApi.getUidByUinV2(qq) || '';
|
const uid: string = await this.core.apis.UserApi.getUidByUinV2(qq) ?? '';
|
||||||
const result = await this.core.apis.UserApi.like(uid, parseInt(payload.times?.toString()) || 1);
|
const result = await this.core.apis.UserApi.like(uid, parseInt(payload.times?.toString()) || 1);
|
||||||
//logDebug('点赞结果', result);
|
|
||||||
if (result.result !== 0) {
|
if (result.result !== 0) {
|
||||||
throw `点赞失败 ${result.errMsg}`;
|
throw new Error(`点赞失败 ${result.errMsg}`);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@@ -40,7 +40,7 @@ export class OneBotGroupApi {
|
|||||||
if (msg.senderUin && msg.senderUin !== '0') {
|
if (msg.senderUin && msg.senderUin !== '0') {
|
||||||
const member = await this.core.apis.GroupApi.getGroupMember(msg.peerUid, msg.senderUin);
|
const member = await this.core.apis.GroupApi.getGroupMember(msg.peerUid, msg.senderUin);
|
||||||
if (member && member.cardName !== msg.sendMemberName) {
|
if (member && member.cardName !== msg.sendMemberName) {
|
||||||
const newCardName = msg.sendMemberName || '';
|
const newCardName = msg.sendMemberName ?? '';
|
||||||
const event = new OB11GroupCardEvent(this.core, parseInt(msg.peerUid), parseInt(msg.senderUin), newCardName, member.cardName);
|
const event = new OB11GroupCardEvent(this.core, parseInt(msg.peerUid), parseInt(msg.senderUin), newCardName, member.cardName);
|
||||||
member.cardName = newCardName;
|
member.cardName = newCardName;
|
||||||
return event;
|
return event;
|
||||||
@@ -48,7 +48,7 @@ export class OneBotGroupApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const element of msg.elements) {
|
for (const element of msg.elements) {
|
||||||
if (element.grayTipElement && element.grayTipElement.groupElement) {
|
if (element.grayTipElement?.groupElement) {
|
||||||
const groupElement = element.grayTipElement.groupElement;
|
const groupElement = element.grayTipElement.groupElement;
|
||||||
if (groupElement.type == TipGroupElementType.memberIncrease) {
|
if (groupElement.type == TipGroupElementType.memberIncrease) {
|
||||||
const MemberIncreaseEvent = await this.obContext.apis.GroupApi.parseGroupMemberIncreaseEvent(msg.peerUid, element.grayTipElement);
|
const MemberIncreaseEvent = await this.obContext.apis.GroupApi.parseGroupMemberIncreaseEvent(msg.peerUid, element.grayTipElement);
|
||||||
@@ -83,7 +83,7 @@ export class OneBotGroupApi {
|
|||||||
url: pathToFileURL(element.fileElement.filePath).href,
|
url: pathToFileURL(element.fileElement.filePath).href,
|
||||||
name: element.fileElement.fileName,
|
name: element.fileElement.fileName,
|
||||||
size: parseInt(element.fileElement.fileSize),
|
size: parseInt(element.fileElement.fileSize),
|
||||||
busid: element.fileElement.fileBizId || 0,
|
busid: element.fileElement.fileBizId ?? 0,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -109,8 +109,8 @@ export class OneBotGroupApi {
|
|||||||
return new OB11GroupPokeEvent(
|
return new OB11GroupPokeEvent(
|
||||||
this.core,
|
this.core,
|
||||||
parseInt(msg.peerUid),
|
parseInt(msg.peerUid),
|
||||||
parseInt((await this.core.apis.UserApi.getUinByUidV2(poke_uid[0].uid))!),
|
+await this.core.apis.UserApi.getUinByUidV2(poke_uid[0].uid),
|
||||||
parseInt((await this.core.apis.UserApi.getUinByUidV2(poke_uid[1].uid))!),
|
+await this.core.apis.UserApi.getUinByUidV2(poke_uid[1].uid),
|
||||||
pokedetail,
|
pokedetail,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -165,13 +165,13 @@ export class OneBotGroupApi {
|
|||||||
async parseGroupBanEvent(GroupCode: string, grayTipElement: GrayTipElement) {
|
async parseGroupBanEvent(GroupCode: string, grayTipElement: GrayTipElement) {
|
||||||
const groupElement = grayTipElement?.groupElement;
|
const groupElement = grayTipElement?.groupElement;
|
||||||
if (!groupElement?.shutUp) return undefined;
|
if (!groupElement?.shutUp) return undefined;
|
||||||
const memberUid = groupElement.shutUp!.member.uid;
|
const memberUid = groupElement.shutUp.member.uid;
|
||||||
const adminUid = groupElement.shutUp!.admin.uid;
|
const adminUid = groupElement.shutUp.admin.uid;
|
||||||
let memberUin: string;
|
let memberUin: string;
|
||||||
let duration = parseInt(groupElement.shutUp!.duration);
|
let duration = parseInt(groupElement.shutUp.duration);
|
||||||
const subType: 'ban' | 'lift_ban' = duration > 0 ? 'ban' : 'lift_ban';
|
const subType: 'ban' | 'lift_ban' = duration > 0 ? 'ban' : 'lift_ban';
|
||||||
if (memberUid) {
|
if (memberUid) {
|
||||||
memberUin = (await this.core.apis.GroupApi.getGroupMember(GroupCode, memberUid))?.uin || '';
|
memberUin = (await this.core.apis.GroupApi.getGroupMember(GroupCode, memberUid))?.uin ?? '';
|
||||||
} else {
|
} else {
|
||||||
memberUin = '0'; // 0表示全员禁言
|
memberUin = '0'; // 0表示全员禁言
|
||||||
if (duration > 0) {
|
if (duration > 0) {
|
||||||
@@ -225,7 +225,7 @@ export class OneBotGroupApi {
|
|||||||
const memberUin = member?.uin;
|
const memberUin = member?.uin;
|
||||||
const adminMember = await this.core.apis.GroupApi.getGroupMember(GroupCode, groupElement.adminUid);
|
const adminMember = await this.core.apis.GroupApi.getGroupMember(GroupCode, groupElement.adminUid);
|
||||||
if (memberUin) {
|
if (memberUin) {
|
||||||
const operatorUin = adminMember?.uin || memberUin;
|
const operatorUin = adminMember?.uin ?? memberUin;
|
||||||
return new OB11GroupIncreaseEvent(
|
return new OB11GroupIncreaseEvent(
|
||||||
this.core,
|
this.core,
|
||||||
parseInt(GroupCode),
|
parseInt(GroupCode),
|
||||||
@@ -240,7 +240,7 @@ export class OneBotGroupApi {
|
|||||||
async parseGroupKickEvent(GroupCode: string, grayTipElement: GrayTipElement) {
|
async parseGroupKickEvent(GroupCode: string, grayTipElement: GrayTipElement) {
|
||||||
const groupElement = grayTipElement?.groupElement;
|
const groupElement = grayTipElement?.groupElement;
|
||||||
if (!groupElement) return undefined;
|
if (!groupElement) return undefined;
|
||||||
const adminUin = (await this.core.apis.GroupApi.getGroupMember(GroupCode, groupElement.adminUid))?.uin || (await this.core.apis.UserApi.getUidByUinV2(groupElement.adminUid));
|
const adminUin = (await this.core.apis.GroupApi.getGroupMember(GroupCode, groupElement.adminUid))?.uin ?? (await this.core.apis.UserApi.getUidByUinV2(groupElement.adminUid));
|
||||||
if (adminUin) {
|
if (adminUin) {
|
||||||
return new OB11GroupDecreaseEvent(
|
return new OB11GroupDecreaseEvent(
|
||||||
this.core,
|
this.core,
|
||||||
|
@@ -187,6 +187,7 @@ export class OneBotMsgApi {
|
|||||||
url: url,
|
url: url,
|
||||||
key: _.key,
|
key: _.key,
|
||||||
emoji_id: _.emojiId,
|
emoji_id: _.emojiId,
|
||||||
|
emoji_package_id: _.emojiPackageId,
|
||||||
file_unique: _.key
|
file_unique: _.key
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -699,16 +700,16 @@ export class OneBotMsgApi {
|
|||||||
//跳过空消息
|
//跳过空消息
|
||||||
const resMsg: OB11Message = {
|
const resMsg: OB11Message = {
|
||||||
self_id: parseInt(this.core.selfInfo.uin),
|
self_id: parseInt(this.core.selfInfo.uin),
|
||||||
user_id: parseInt(msg.senderUin!),
|
user_id: parseInt(msg.senderUin),
|
||||||
time: parseInt(msg.msgTime) || Date.now(),
|
time: parseInt(msg.msgTime) || Date.now(),
|
||||||
message_id: msg.id!,
|
message_id: msg.id!,
|
||||||
message_seq: msg.id!,
|
message_seq: msg.id!,
|
||||||
real_id: msg.id!,
|
real_id: msg.id!,
|
||||||
message_type: msg.chatType == ChatType.KCHATTYPEGROUP ? 'group' : 'private',
|
message_type: msg.chatType == ChatType.KCHATTYPEGROUP ? 'group' : 'private',
|
||||||
sender: {
|
sender: {
|
||||||
user_id: parseInt(msg.senderUin || '0'),
|
user_id: +(msg.senderUin ?? 0),
|
||||||
nickname: msg.sendNickName,
|
nickname: msg.sendNickName,
|
||||||
card: msg.sendMemberName || '',
|
card: msg.sendMemberName ?? '',
|
||||||
},
|
},
|
||||||
raw_message: '',
|
raw_message: '',
|
||||||
font: 14,
|
font: 14,
|
||||||
|
@@ -25,7 +25,7 @@ export class OB11Entities {
|
|||||||
user_id: parseInt(rawFriend.coreInfo.uin),
|
user_id: parseInt(rawFriend.coreInfo.uin),
|
||||||
nickname: rawFriend.coreInfo.nick,
|
nickname: rawFriend.coreInfo.nick,
|
||||||
remark: rawFriend.coreInfo.remark ?? rawFriend.coreInfo.nick,
|
remark: rawFriend.coreInfo.remark ?? rawFriend.coreInfo.nick,
|
||||||
sex: this.sex(rawFriend.baseInfo.sex!),
|
sex: this.sex(rawFriend.baseInfo.sex),
|
||||||
level: 0,
|
level: 0,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,7 @@ export class OB11Entities {
|
|||||||
sex: OB11Entities.sex(member.sex!),
|
sex: OB11Entities.sex(member.sex!),
|
||||||
age: member.age ?? 0,
|
age: member.age ?? 0,
|
||||||
area: '',
|
area: '',
|
||||||
level: member.memberRealLevel ?? '0',
|
level: member.memberRealLevel?.toString() ?? '0',
|
||||||
qq_level: member.qqLevel && calcQQLevel(member.qqLevel) || 0,
|
qq_level: member.qqLevel && calcQQLevel(member.qqLevel) || 0,
|
||||||
join_time: +member.joinTime,
|
join_time: +member.joinTime,
|
||||||
last_sent_time: +member.lastSpeakTime,
|
last_sent_time: +member.lastSpeakTime,
|
||||||
@@ -76,7 +76,7 @@ export class OB11Entities {
|
|||||||
is_robot: member.isRobot,
|
is_robot: member.isRobot,
|
||||||
shut_up_timestamp: member.shutUpTime,
|
shut_up_timestamp: member.shutUpTime,
|
||||||
role: OB11Entities.groupMemberRole(member.role),
|
role: OB11Entities.groupMemberRole(member.role),
|
||||||
title: member.memberSpecialTitle || '',
|
title: member.memberSpecialTitle ?? '',
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -11,11 +11,11 @@ export class OB11HeartbeatEvent extends OB11BaseMetaEvent {
|
|||||||
status: HeartbeatStatus;
|
status: HeartbeatStatus;
|
||||||
interval: number;
|
interval: number;
|
||||||
|
|
||||||
public constructor(core: NapCatCore, interval: number, isOnline: boolean | undefined, isGood: boolean) {
|
public constructor(core: NapCatCore, interval: number, isOnline: boolean, isGood: boolean) {
|
||||||
super(core);
|
super(core);
|
||||||
this.interval = interval;
|
this.interval = interval;
|
||||||
this.status = {
|
this.status = {
|
||||||
online: isOnline && true,
|
online: isOnline,
|
||||||
good: isGood,
|
good: isGood,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -5,7 +5,7 @@ export type GroupDecreaseSubType = 'leave' | 'kick' | 'kick_me';
|
|||||||
|
|
||||||
export class OB11GroupDecreaseEvent extends OB11GroupNoticeEvent {
|
export class OB11GroupDecreaseEvent extends OB11GroupNoticeEvent {
|
||||||
notice_type = 'group_decrease';
|
notice_type = 'group_decrease';
|
||||||
sub_type: GroupDecreaseSubType = 'leave'; // TODO: 实现其他几种子类型的识别 ("leave" | "kick" | "kick_me")
|
sub_type: GroupDecreaseSubType = 'leave'; // work:实现其他几种子类型的识别 ("leave" | "kick" | "kick_me")
|
||||||
operator_id: number;
|
operator_id: number;
|
||||||
|
|
||||||
constructor(core: NapCatCore, groupId: number, userId: number, operatorId: number, subType: GroupDecreaseSubType = 'leave') {
|
constructor(core: NapCatCore, groupId: number, userId: number, operatorId: number, subType: GroupDecreaseSubType = 'leave') {
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import { OB11BaseNoticeEvent } from './OB11BaseNoticeEvent';
|
import { OB11BaseNoticeEvent } from './OB11BaseNoticeEvent';
|
||||||
import { NapCatCore } from '@/core';
|
import { NapCatCore } from '@/core';
|
||||||
|
|
||||||
//输入状态事件 初步完成 Mlikio wa Todo 需要做一些过滤
|
//work: 输入状态事件 初步完成 Mlikiowa 需要做一些过滤
|
||||||
export class OB11InputStatusEvent extends OB11BaseNoticeEvent {
|
export class OB11InputStatusEvent extends OB11BaseNoticeEvent {
|
||||||
notice_type = 'notify';
|
notice_type = 'notify';
|
||||||
sub_type = 'input_status';
|
sub_type = 'input_status';
|
||||||
|
@@ -25,7 +25,7 @@ export class OB11GroupPokeEvent extends OB11PokeEvent {
|
|||||||
raw_info: any;
|
raw_info: any;
|
||||||
|
|
||||||
//raw_message nb等框架标准为string
|
//raw_message nb等框架标准为string
|
||||||
constructor(core: NapCatCore, group_id: number, user_id: number = 0, target_id: number = 0, raw_message: any) {
|
constructor(core: NapCatCore, group_id: number, user_id: number, target_id: number, raw_message: any) {
|
||||||
super(core);
|
super(core);
|
||||||
this.group_id = group_id;
|
this.group_id = group_id;
|
||||||
this.target_id = target_id;
|
this.target_id = target_id;
|
||||||
|
@@ -6,7 +6,6 @@ import {
|
|||||||
GroupNotifyMsgStatus,
|
GroupNotifyMsgStatus,
|
||||||
GroupNotifyMsgType,
|
GroupNotifyMsgType,
|
||||||
InstanceContext,
|
InstanceContext,
|
||||||
MsgSourceType,
|
|
||||||
NapCatCore,
|
NapCatCore,
|
||||||
NodeIKernelBuddyListener,
|
NodeIKernelBuddyListener,
|
||||||
NodeIKernelGroupListener,
|
NodeIKernelGroupListener,
|
||||||
@@ -45,8 +44,6 @@ import { OB11FriendRecallNoticeEvent } from '@/onebot/event/notice/OB11FriendRec
|
|||||||
import { OB11GroupRecallNoticeEvent } from '@/onebot/event/notice/OB11GroupRecallNoticeEvent';
|
import { OB11GroupRecallNoticeEvent } from '@/onebot/event/notice/OB11GroupRecallNoticeEvent';
|
||||||
import { LRUCache } from '@/common/lru-cache';
|
import { LRUCache } from '@/common/lru-cache';
|
||||||
import { NodeIKernelRecentContactListener } from '@/core/listeners/NodeIKernelRecentContactListener';
|
import { NodeIKernelRecentContactListener } from '@/core/listeners/NodeIKernelRecentContactListener';
|
||||||
import { Native } from '@/native';
|
|
||||||
import { decodeMessage, decodeRecallGroup } from "@/core/helper/adaptSysMessageDecoder";
|
|
||||||
import { BotOfflineEvent } from './event/notice/BotOfflineEvent';
|
import { BotOfflineEvent } from './event/notice/BotOfflineEvent';
|
||||||
|
|
||||||
//OneBot实现类
|
//OneBot实现类
|
||||||
@@ -58,8 +55,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
apis: StableOneBotApiWrapper;
|
apis: StableOneBotApiWrapper;
|
||||||
networkManager: OB11NetworkManager;
|
networkManager: OB11NetworkManager;
|
||||||
actions: ActionMap;
|
actions: ActionMap;
|
||||||
nativeCore: Native | undefined;
|
private readonly bootTime = Date.now() / 1000;
|
||||||
private bootTime = Date.now() / 1000;
|
|
||||||
recallMsgCache = new LRUCache<string, RawMessage>(100);
|
recallMsgCache = new LRUCache<string, RawMessage>(100);
|
||||||
|
|
||||||
constructor(core: NapCatCore, context: InstanceContext, pathWrapper: NapCatPathWrapper) {
|
constructor(core: NapCatCore, context: InstanceContext, pathWrapper: NapCatPathWrapper) {
|
||||||
@@ -75,41 +71,8 @@ export class NapCatOneBot11Adapter {
|
|||||||
};
|
};
|
||||||
this.actions = createActionMap(this, core);
|
this.actions = createActionMap(this, core);
|
||||||
this.networkManager = new OB11NetworkManager();
|
this.networkManager = new OB11NetworkManager();
|
||||||
// this.registerNative(core, context).catch(e => this.context.logger.logWarn.bind(this.context.logger)('初始化Native失败', e)).then();
|
}
|
||||||
this.InitOneBot()
|
|
||||||
.catch(e => this.context.logger.logError.bind(this.context.logger)('初始化OneBot失败', e));
|
|
||||||
|
|
||||||
}
|
|
||||||
async registerNative(core: NapCatCore, context: InstanceContext) {
|
|
||||||
try {
|
|
||||||
this.nativeCore = new Native(context.pathWrapper.binaryPath);
|
|
||||||
if (!this.nativeCore.inited) throw new Error('Native Not Init');
|
|
||||||
// this.nativeCore.registerRecallCallback(async (hex: string) => {
|
|
||||||
// try {
|
|
||||||
// const data = decodeMessage(Buffer.from(hex, 'hex'));
|
|
||||||
// //data.MsgHead.BodyInner.MsgType SubType
|
|
||||||
// const bodyInner = data.msgHead?.bodyInner;
|
|
||||||
// //context.logger.log("[appNative] Parse MsgType:" + bodyInner.msgType + " / SubType:" + bodyInner.subType);
|
|
||||||
// if (bodyInner && bodyInner.msgType == 732 && bodyInner.subType == 17 && data?.msgHead?.noifyData?.innerData) {
|
|
||||||
// const RecallData = Buffer.from(data?.msgHead?.noifyData?.innerData);
|
|
||||||
// //跳过 4字节 群号 + 不知道的1字节 +2字节 长度
|
|
||||||
// const uid = RecallData.readUint32BE();
|
|
||||||
// const buffer = Buffer.from(RecallData.toString('hex').slice(14), 'hex');
|
|
||||||
// const seq: number = decodeRecallGroup(buffer).recallDetails.subDetail.msgSeq;
|
|
||||||
// const peer: Peer = { chatType: ChatType.KCHATTYPEGROUP, peerUid: uid.toString() };
|
|
||||||
// context.logger.log("[Native] 群消息撤回 Peer: " + uid.toString() + " / MsgSeq:" + seq);
|
|
||||||
// const msgs = await core.apis.MsgApi.queryMsgsWithFilterExWithSeq(peer, seq.toString());
|
|
||||||
// this.recallMsgCache.put(msgs.msgList[0].msgId, msgs.msgList[0]);
|
|
||||||
// }
|
|
||||||
// } catch (error: any) {
|
|
||||||
// context.logger.logWarn("[Native] Error:", (error as Error).message, ' HEX:', hex);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
} catch (error) {
|
|
||||||
context.logger.logWarn("[Native] Error:", (error as Error).message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async InitOneBot() {
|
async InitOneBot() {
|
||||||
const selfInfo = this.core.selfInfo;
|
const selfInfo = this.core.selfInfo;
|
||||||
const ob11Config = this.configLoader.configData;
|
const ob11Config = this.configLoader.configData;
|
||||||
@@ -211,8 +174,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
} else {
|
} else {
|
||||||
await this.networkManager.closeAdapterByPredicate(adapter => adapter instanceof OB11ActiveHttpAdapter);
|
await this.networkManager.closeAdapterByPredicate(adapter => adapter instanceof OB11ActiveHttpAdapter);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (now.http.enablePost) {
|
||||||
if (now.http.enablePost) {
|
|
||||||
const { added, removed } = this.findDifference<string>(prev.http.postUrls, now.http.postUrls);
|
const { added, removed } = this.findDifference<string>(prev.http.postUrls, now.http.postUrls);
|
||||||
await this.networkManager.closeAdapterByPredicate(
|
await this.networkManager.closeAdapterByPredicate(
|
||||||
adapter => adapter instanceof OB11ActiveHttpAdapter && removed.includes(adapter.url),
|
adapter => adapter instanceof OB11ActiveHttpAdapter && removed.includes(adapter.url),
|
||||||
@@ -223,7 +185,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// check difference in passive websocket (Ws)
|
// check difference in passive websocket (Ws)
|
||||||
if (prev.ws.enable !== now.ws.enable) {
|
if (prev.ws.enable !== now.ws.enable) {
|
||||||
@@ -251,8 +213,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
adapter => adapter instanceof OB11ActiveWebSocketAdapter,
|
adapter => adapter instanceof OB11ActiveWebSocketAdapter,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (now.reverseWs.enable) {
|
||||||
if (now.reverseWs.enable) {
|
|
||||||
const { added, removed } = this.findDifference<string>(prev.reverseWs.urls, now.reverseWs.urls);
|
const { added, removed } = this.findDifference<string>(prev.reverseWs.urls, now.reverseWs.urls);
|
||||||
await this.networkManager.closeAdapterByPredicate(
|
await this.networkManager.closeAdapterByPredicate(
|
||||||
adapter => adapter instanceof OB11ActiveWebSocketAdapter && removed.includes(adapter.url),
|
adapter => adapter instanceof OB11ActiveWebSocketAdapter && removed.includes(adapter.url),
|
||||||
@@ -263,7 +224,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private findDifference<T>(prev: T[], now: T[]): { added: T[], removed: T[] } {
|
private findDifference<T>(prev: T[], now: T[]): { added: T[], removed: T[] } {
|
||||||
@@ -305,10 +266,8 @@ export class NapCatOneBot11Adapter {
|
|||||||
},
|
},
|
||||||
m.msgId,
|
m.msgId,
|
||||||
);
|
);
|
||||||
// if (m.sourceType == MsgSourceType.K_DOWN_SOURCETYPE_AIOINNER) {
|
|
||||||
await this.emitMsg(m)
|
await this.emitMsg(m)
|
||||||
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理消息失败', e));
|
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理消息失败', e));
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -368,7 +327,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
const requesterUin = await this.core.apis.UserApi.getUinByUidV2(req.friendUid);
|
const requesterUin = await this.core.apis.UserApi.getUinByUidV2(req.friendUid);
|
||||||
await this.networkManager.emitEvent(new OB11FriendRequestEvent(
|
await this.networkManager.emitEvent(new OB11FriendRequestEvent(
|
||||||
this.core,
|
this.core,
|
||||||
parseInt(requesterUin!),
|
+requesterUin,
|
||||||
req.extWords,
|
req.extWords,
|
||||||
req.friendUid + '|' + req.reqTime,
|
req.friendUid + '|' + req.reqTime,
|
||||||
));
|
));
|
||||||
@@ -432,7 +391,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
}
|
}
|
||||||
} else if (notify.type == GroupNotifyMsgType.MEMBER_LEAVE_NOTIFY_ADMIN || notify.type == GroupNotifyMsgType.KICK_MEMBER_NOTIFY_ADMIN) {
|
} else if (notify.type == GroupNotifyMsgType.MEMBER_LEAVE_NOTIFY_ADMIN || notify.type == GroupNotifyMsgType.KICK_MEMBER_NOTIFY_ADMIN) {
|
||||||
this.context.logger.logDebug('有成员退出通知', notify);
|
this.context.logger.logDebug('有成员退出通知', notify);
|
||||||
const member1Uin = (await this.core.apis.UserApi.getUinByUidV2(notify.user1.uid))!;
|
const member1Uin = (await this.core.apis.UserApi.getUinByUidV2(notify.user1.uid));
|
||||||
let operatorId = member1Uin;
|
let operatorId = member1Uin;
|
||||||
let subType: GroupDecreaseSubType = 'leave';
|
let subType: GroupDecreaseSubType = 'leave';
|
||||||
if (notify.user2.uid) {
|
if (notify.user2.uid) {
|
||||||
@@ -458,7 +417,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
].includes(notify.type) && notify.status == GroupNotifyMsgStatus.KUNHANDLE) {
|
].includes(notify.type) && notify.status == GroupNotifyMsgStatus.KUNHANDLE) {
|
||||||
this.context.logger.logDebug('有加群请求');
|
this.context.logger.logDebug('有加群请求');
|
||||||
try {
|
try {
|
||||||
let requestUin = (await this.core.apis.UserApi.getUinByUidV2(notify.user1.uid))!;
|
let requestUin = (await this.core.apis.UserApi.getUinByUidV2(notify.user1.uid));
|
||||||
if (isNaN(parseInt(requestUin))) {
|
if (isNaN(parseInt(requestUin))) {
|
||||||
requestUin = (await this.core.apis.UserApi.getUserDetailInfo(notify.user1.uid)).uin;
|
requestUin = (await this.core.apis.UserApi.getUserDetailInfo(notify.user1.uid)).uin;
|
||||||
}
|
}
|
||||||
@@ -540,10 +499,9 @@ export class NapCatOneBot11Adapter {
|
|||||||
this.context.logger.logDebug('转化为 OB11Message', ob11Msg);
|
this.context.logger.logDebug('转化为 OB11Message', ob11Msg);
|
||||||
if (debug) {
|
if (debug) {
|
||||||
ob11Msg.raw = message;
|
ob11Msg.raw = message;
|
||||||
} else {
|
} else if (ob11Msg.message.length === 0) {
|
||||||
if (ob11Msg.message.length === 0) {
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const isSelfMsg = ob11Msg.user_id.toString() == this.core.selfInfo.uin;
|
const isSelfMsg = ob11Msg.user_id.toString() == this.core.selfInfo.uin;
|
||||||
if (isSelfMsg && !reportSelfMessage) {
|
if (isSelfMsg && !reportSelfMessage) {
|
||||||
@@ -603,7 +561,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
for (const message of msgList) {
|
for (const message of msgList) {
|
||||||
// log("message update", message.sendStatus, message.msgId, message.msgSeq)
|
// log("message update", message.sendStatus, message.msgId, message.msgSeq)
|
||||||
const peer: Peer = { chatType: message.chatType, peerUid: message.peerUid, guildId: '' };
|
const peer: Peer = { chatType: message.chatType, peerUid: message.peerUid, guildId: '' };
|
||||||
if (message.recallTime != '0' && !cache.get(message.msgId)) { //todo: 这个判断方法不太好,应该使用灰色消息元素来判断?
|
if (message.recallTime != '0' && !cache.get(message.msgId)) { //work:这个判断方法不太好,应该使用灰色消息元素来判断?
|
||||||
cache.put(message.msgId, true);
|
cache.put(message.msgId, true);
|
||||||
// 撤回消息上报
|
// 撤回消息上报
|
||||||
let oriMessageId = MessageUnique.getShortIdByMsgId(message.msgId);
|
let oriMessageId = MessageUnique.getShortIdByMsgId(message.msgId);
|
||||||
@@ -613,7 +571,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
if (message.chatType == ChatType.KCHATTYPEC2C) {
|
if (message.chatType == ChatType.KCHATTYPEC2C) {
|
||||||
const friendRecallEvent = new OB11FriendRecallNoticeEvent(
|
const friendRecallEvent = new OB11FriendRecallNoticeEvent(
|
||||||
this.core,
|
this.core,
|
||||||
parseInt(message!.senderUin),
|
+message.senderUin,
|
||||||
oriMessageId,
|
oriMessageId,
|
||||||
);
|
);
|
||||||
this.networkManager.emitEvent(friendRecallEvent)
|
this.networkManager.emitEvent(friendRecallEvent)
|
||||||
@@ -624,13 +582,13 @@ export class NapCatOneBot11Adapter {
|
|||||||
const operatorUid = element.grayTipElement?.revokeElement.operatorUid;
|
const operatorUid = element.grayTipElement?.revokeElement.operatorUid;
|
||||||
if (!operatorUid) return;
|
if (!operatorUid) return;
|
||||||
const operator = await this.core.apis.GroupApi.getGroupMember(message.peerUin, operatorUid);
|
const operator = await this.core.apis.GroupApi.getGroupMember(message.peerUin, operatorUid);
|
||||||
operatorId = operator?.uin || message.senderUin;
|
operatorId = operator?.uin ?? message.senderUin;
|
||||||
}
|
}
|
||||||
const groupRecallEvent = new OB11GroupRecallNoticeEvent(
|
const groupRecallEvent = new OB11GroupRecallNoticeEvent(
|
||||||
this.core,
|
this.core,
|
||||||
parseInt(message.peerUin),
|
+message.peerUin,
|
||||||
parseInt(message.senderUin),
|
+message.senderUin,
|
||||||
parseInt(operatorId),
|
+operatorId,
|
||||||
oriMessageId
|
oriMessageId
|
||||||
);
|
);
|
||||||
this.networkManager.emitEvent(groupRecallEvent)
|
this.networkManager.emitEvent(groupRecallEvent)
|
||||||
|
@@ -18,7 +18,7 @@ export class OB11ActiveWebSocketAdapter implements IOB11NetworkAdapter {
|
|||||||
public url: string,
|
public url: string,
|
||||||
public reconnectIntervalInMillis: number,
|
public reconnectIntervalInMillis: number,
|
||||||
public heartbeatIntervalInMillis: number,
|
public heartbeatIntervalInMillis: number,
|
||||||
private token: string,
|
private readonly token: string,
|
||||||
public core: NapCatCore,
|
public core: NapCatCore,
|
||||||
public actions: ActionMap,
|
public actions: ActionMap,
|
||||||
) {
|
) {
|
||||||
@@ -37,7 +37,7 @@ export class OB11ActiveWebSocketAdapter implements IOB11NetworkAdapter {
|
|||||||
}
|
}
|
||||||
this.heartbeatRef = setInterval(() => {
|
this.heartbeatRef = setInterval(() => {
|
||||||
if (this.connection && this.connection.readyState === WebSocket.OPEN) {
|
if (this.connection && this.connection.readyState === WebSocket.OPEN) {
|
||||||
this.connection.send(JSON.stringify(new OB11HeartbeatEvent(this.core, this.heartbeatIntervalInMillis, this.core.selfInfo.online, true)));
|
this.connection.send(JSON.stringify(new OB11HeartbeatEvent(this.core, this.heartbeatIntervalInMillis, this.core.selfInfo.online ?? true, true)));
|
||||||
}
|
}
|
||||||
}, this.heartbeatIntervalInMillis);
|
}, this.heartbeatIntervalInMillis);
|
||||||
await this.tryConnect();
|
await this.tryConnect();
|
||||||
@@ -148,7 +148,6 @@ export class OB11ActiveWebSocketAdapter implements IOB11NetworkAdapter {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const retdata = await action.websocketHandle(receiveData.params, echo ?? '');
|
const retdata = await action.websocketHandle(receiveData.params, echo ?? '');
|
||||||
const packet = Object.assign({}, retdata);
|
this.checkStateAndReply<any>({ ...retdata });
|
||||||
this.checkStateAndReply<any>(packet);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -145,7 +145,7 @@ export class OB11PassiveWebSocketAdapter implements IOB11NetworkAdapter {
|
|||||||
this.wsClientsMutex.runExclusive(async () => {
|
this.wsClientsMutex.runExclusive(async () => {
|
||||||
this.wsClientWithEvent.forEach((wsClient) => {
|
this.wsClientWithEvent.forEach((wsClient) => {
|
||||||
if (wsClient.readyState === WebSocket.OPEN) {
|
if (wsClient.readyState === WebSocket.OPEN) {
|
||||||
wsClient.send(JSON.stringify(new OB11HeartbeatEvent(this.core, this.heartbeatInterval, this.core.selfInfo.online, true)));
|
wsClient.send(JSON.stringify(new OB11HeartbeatEvent(this.core, this.heartbeatInterval, this.core.selfInfo.online ?? true, true)));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -189,8 +189,7 @@ export class OB11PassiveWebSocketAdapter implements IOB11NetworkAdapter {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const retdata = await action.websocketHandle(receiveData.params, echo ?? '');
|
const retdata = await action.websocketHandle(receiveData.params, echo ?? '');
|
||||||
const packet = Object.assign({}, retdata);
|
this.checkStateAndReply<any>({ ...retdata }, wsClient);
|
||||||
this.checkStateAndReply<any>(packet, wsClient);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -34,33 +34,16 @@ program.option('-q, --qq [number]', 'QQ号').parse(process.argv);
|
|||||||
const cmdOptions = program.opts();
|
const cmdOptions = program.opts();
|
||||||
|
|
||||||
// NapCat Shell App ES 入口文件
|
// NapCat Shell App ES 入口文件
|
||||||
export async function NCoreInitShell() {
|
async function handleUncaughtExceptions(logger: LogWrapper) {
|
||||||
console.log('NapCat Shell App Loading...');
|
|
||||||
process.on('uncaughtException', (err) => {
|
process.on('uncaughtException', (err) => {
|
||||||
console.log('[NapCat] [Error] Unhandled Exception:', err.message);
|
logger.logError('[NapCat] [Error] Unhandled Exception:', err.message);
|
||||||
});
|
});
|
||||||
process.on('unhandledRejection', (reason, promise) => {
|
process.on('unhandledRejection', (reason, promise) => {
|
||||||
console.log('[NapCat] [Error] unhandledRejection:', reason);
|
logger.logError('[NapCat] [Error] unhandledRejection:', reason);
|
||||||
});
|
});
|
||||||
const pathWrapper = new NapCatPathWrapper();
|
}
|
||||||
const logger = new LogWrapper(pathWrapper.logsPath);
|
|
||||||
const basicInfoWrapper = new QQBasicInfoWrapper({ logger });
|
|
||||||
const wrapper = loadQQWrapper(basicInfoWrapper.getFullQQVesion());
|
|
||||||
|
|
||||||
const o3Service = wrapper.NodeIO3MiscService.get();
|
function getDataPaths(wrapper: WrapperNodeApi): [string, string] {
|
||||||
o3Service.addO3MiscListener(new NodeIO3MiscListener());
|
|
||||||
|
|
||||||
logger.log(`[NapCat] [Core] NapCat.Core Version: ` + napCatVersion);
|
|
||||||
InitWebUi(logger, pathWrapper).then().catch(logger.logError.bind(logger));
|
|
||||||
|
|
||||||
// from constructor
|
|
||||||
const engine = wrapper.NodeIQQNTWrapperEngine.get();
|
|
||||||
//const util = wrapper.NodeQQNTWrapperUtil.get();
|
|
||||||
const loginService = wrapper.NodeIKernelLoginService.get();
|
|
||||||
|
|
||||||
const session = wrapper.NodeIQQNTWrapperSession.create();
|
|
||||||
// from get dataPath
|
|
||||||
const [dataPath, dataPathGlobal] = (() => {
|
|
||||||
if (os.platform() === 'darwin') {
|
if (os.platform() === 'darwin') {
|
||||||
const userPath = os.homedir();
|
const userPath = os.homedir();
|
||||||
const appDataPath = path.resolve(userPath, './Library/Application Support/QQ');
|
const appDataPath = path.resolve(userPath, './Library/Application Support/QQ');
|
||||||
@@ -73,15 +56,24 @@ export async function NCoreInitShell() {
|
|||||||
}
|
}
|
||||||
const dataPathGlobal = path.resolve(dataPath, './nt_qq/global');
|
const dataPathGlobal = path.resolve(dataPath, './nt_qq/global');
|
||||||
return [dataPath, dataPathGlobal];
|
return [dataPath, dataPathGlobal];
|
||||||
})();
|
}
|
||||||
|
|
||||||
|
function getPlatformType(): PlatformType {
|
||||||
const platformMapping: Partial<Record<NodeJS.Platform, PlatformType>> = {
|
const platformMapping: Partial<Record<NodeJS.Platform, PlatformType>> = {
|
||||||
win32: PlatformType.KWINDOWS,
|
win32: PlatformType.KWINDOWS,
|
||||||
darwin: PlatformType.KMAC,
|
darwin: PlatformType.KMAC,
|
||||||
linux: PlatformType.KLINUX,
|
linux: PlatformType.KLINUX,
|
||||||
};
|
};
|
||||||
const systemPlatform = platformMapping[os.platform()] ?? PlatformType.KWINDOWS;
|
return platformMapping[os.platform()] ?? PlatformType.KWINDOWS;
|
||||||
if (!basicInfoWrapper.QQVersionAppid || !basicInfoWrapper.QQVersionQua) throw new Error('QQVersionAppid or QQVersionQua is not defined');
|
}
|
||||||
// from initConfig
|
|
||||||
|
async function initializeEngine(
|
||||||
|
engine: any,
|
||||||
|
basicInfoWrapper: QQBasicInfoWrapper,
|
||||||
|
dataPathGlobal: string,
|
||||||
|
systemPlatform: PlatformType,
|
||||||
|
systemVersion: string
|
||||||
|
) {
|
||||||
engine.initWithDeskTopConfig(
|
engine.initWithDeskTopConfig(
|
||||||
{
|
{
|
||||||
base_path_prefix: '',
|
base_path_prefix: '',
|
||||||
@@ -98,33 +90,38 @@ export async function NCoreInitShell() {
|
|||||||
},
|
},
|
||||||
new NodeIGlobalAdapter(),
|
new NodeIGlobalAdapter(),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function initializeLoginService(
|
||||||
|
loginService: NodeIKernelLoginService,
|
||||||
|
basicInfoWrapper: QQBasicInfoWrapper,
|
||||||
|
dataPathGlobal: string,
|
||||||
|
systemVersion: string,
|
||||||
|
hostname: string
|
||||||
|
) {
|
||||||
loginService.initConfig({
|
loginService.initConfig({
|
||||||
machineId: '',
|
machineId: '',
|
||||||
appid: basicInfoWrapper.QQVersionAppid,
|
appid: basicInfoWrapper.QQVersionAppid ?? '',
|
||||||
platVer: systemVersion,
|
platVer: systemVersion,
|
||||||
commonPath: dataPathGlobal,
|
commonPath: dataPathGlobal,
|
||||||
clientVer: basicInfoWrapper.getFullQQVesion(),
|
clientVer: basicInfoWrapper.getFullQQVesion(),
|
||||||
hostName: hostname,
|
hostName: hostname,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let quickLoginUin = cmdOptions.qq; // undefined | 'true' | string
|
async function handleLogin(
|
||||||
const historyLoginList = (await loginService.getLoginList()).LocalLoginInfoList;
|
loginService: NodeIKernelLoginService,
|
||||||
if (quickLoginUin == 'true') {
|
logger: LogWrapper,
|
||||||
if (historyLoginList.length > 0) {
|
pathWrapper: NapCatPathWrapper,
|
||||||
quickLoginUin = historyLoginList[0].uin;
|
quickLoginUin: string | undefined,
|
||||||
logger.log(`-q 指令指定使用最近的 QQ ${quickLoginUin} 进行快速登录`);
|
historyLoginList: any[]
|
||||||
} else {
|
): Promise<SelfInfo> {
|
||||||
quickLoginUin = '';
|
return new Promise<SelfInfo>((resolve) => {
|
||||||
}
|
|
||||||
}
|
|
||||||
const dataTimestape = new Date().getTime().toString();
|
|
||||||
o3Service.reportAmgomWeather('login', 'a1', [dataTimestape, '0', '0']);
|
|
||||||
const selfInfo = await new Promise<SelfInfo>((resolve) => {
|
|
||||||
const loginListener = new NodeIKernelLoginListener();
|
const loginListener = new NodeIKernelLoginListener();
|
||||||
let isLogined = false;
|
let isLogined = false;
|
||||||
// from constructor
|
|
||||||
loginListener.onUserLoggedIn = (userid: string) => {
|
loginListener.onUserLoggedIn = (userid: string) => {
|
||||||
logger.logError.bind(logger)(`当前账号(${userid})已登录,无法重复登录`);
|
logger.logError(`当前账号(${userid})已登录,无法重复登录`);
|
||||||
};
|
};
|
||||||
|
|
||||||
loginListener.onQRCodeLoginSucceed = async (loginResult) => {
|
loginListener.onQRCodeLoginSucceed = async (loginResult) => {
|
||||||
@@ -132,13 +129,12 @@ export async function NCoreInitShell() {
|
|||||||
resolve({
|
resolve({
|
||||||
uid: loginResult.uid,
|
uid: loginResult.uid,
|
||||||
uin: loginResult.uin,
|
uin: loginResult.uin,
|
||||||
nick: '', // 获取不到
|
nick: '',
|
||||||
online: true,
|
online: true,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
loginListener.onQRCodeGetPicture = ({ pngBase64QrcodeData, qrcodeUrl }) => {
|
loginListener.onQRCodeGetPicture = ({ pngBase64QrcodeData, qrcodeUrl }) => {
|
||||||
//设置WebuiQrcode
|
|
||||||
WebUiDataRuntime.setQQLoginQrcodeURL(qrcodeUrl);
|
WebUiDataRuntime.setQQLoginQrcodeURL(qrcodeUrl);
|
||||||
|
|
||||||
const realBase64 = pngBase64QrcodeData.replace(/^data:image\/\w+;base64,/, '');
|
const realBase64 = pngBase64QrcodeData.replace(/^data:image\/\w+;base64,/, '');
|
||||||
@@ -157,50 +153,46 @@ export async function NCoreInitShell() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
loginListener.onQRCodeSessionFailed = (errType: number, errCode: number, errMsg: string) => {
|
loginListener.onQRCodeSessionFailed = (errType: number, errCode: number, errMsg: string) => {
|
||||||
if (!isLogined) {
|
if (!isLogined) {
|
||||||
logger.logError.bind(logger)('[Core] [Login] Login Error,ErrCode: ', errCode, ' ErrMsg:', errMsg);
|
logger.logError('[Core] [Login] Login Error,ErrCode: ', errCode, ' ErrMsg:', errMsg);
|
||||||
if (errType == 1 && errCode == 3) {
|
if (errType == 1 && errCode == 3) {
|
||||||
// 二维码过期刷新
|
// 二维码过期刷新
|
||||||
}
|
}
|
||||||
loginService.getQRCodePicture();
|
loginService.getQRCodePicture();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
loginListener.onLoginFailed = (args) => {
|
loginListener.onLoginFailed = (args) => {
|
||||||
logger.logError.bind(logger)('[Core] [Login] Login Error , ErrInfo: ', args);
|
logger.logError('[Core] [Login] Login Error , ErrInfo: ', args);
|
||||||
};
|
};
|
||||||
|
|
||||||
loginService.addKernelLoginListener(proxiedListenerOf(loginListener, logger));
|
loginService.addKernelLoginListener(proxiedListenerOf(loginListener, logger));
|
||||||
const isConnect = loginService.connect();
|
const isConnect = loginService.connect();
|
||||||
if (!isConnect) {
|
if (!isConnect) {
|
||||||
logger.logError.bind(logger)('核心登录服务连接失败!');
|
logger.logError('核心登录服务连接失败!');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.log('核心登录服务连接成功!');
|
logger.log('核心登录服务连接成功!');
|
||||||
// 实现WebUi快速登录
|
|
||||||
loginService.getLoginList().then((res) => {
|
loginService.getLoginList().then((res) => {
|
||||||
// 遍历 res.LocalLoginInfoList[x].isQuickLogin是否可以 res.LocalLoginInfoList[x].uin 转为string 加入string[] 最后遍历完成调用WebUiDataRuntime.setQQQuickLoginList
|
// 遍历 res.LocalLoginInfoList[x].isQuickLogin是否可以 res.LocalLoginInfoList[x].uin 转为string 加入string[] 最后遍历完成调用WebUiDataRuntime.setQQQuickLoginList
|
||||||
WebUiDataRuntime.setQQQuickLoginList(res.LocalLoginInfoList.filter((item) => item.isQuickLogin).map((item) => item.uin.toString()));
|
WebUiDataRuntime.setQQQuickLoginList(res.LocalLoginInfoList.filter((item) => item.isQuickLogin).map((item) => item.uin.toString()));
|
||||||
});
|
});
|
||||||
if (basicInfoWrapper.QQVersionConfig?.curVersion) {
|
|
||||||
loginService.getLoginMiscData('hotUpdateSign').then((res) => {
|
|
||||||
if (res.result === 0) {
|
|
||||||
loginService.setLoginMiscData('hotUpdateSign', res.value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
session.getNodeMiscService().writeVersionToRegistry(basicInfoWrapper.QQVersionConfig?.curVersion);
|
|
||||||
}
|
|
||||||
WebUiDataRuntime.setQuickLoginCall(async (uin: string) => {
|
WebUiDataRuntime.setQuickLoginCall(async (uin: string) => {
|
||||||
return await new Promise((resolve) => {
|
return await new Promise((resolve) => {
|
||||||
if (uin) {
|
if (uin) {
|
||||||
logger.log.bind(logger)('正在快速登录 ', uin);
|
logger.log('正在快速登录 ', uin);
|
||||||
loginService.quickLoginWithUin(uin).then(res => {
|
loginService.quickLoginWithUin(uin).then(res => {
|
||||||
if (res.loginErrorInfo.errMsg) {
|
if (res.loginErrorInfo.errMsg) {
|
||||||
resolve({ result: false, message: res.loginErrorInfo.errMsg });
|
resolve({ result: false, message: res.loginErrorInfo.errMsg });
|
||||||
}
|
}
|
||||||
resolve({ result: true, message: '' });
|
resolve({ result: true, message: '' });
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
logger.logError.bind(logger)(e);
|
logger.logError(e);
|
||||||
resolve({ result: false, message: '快速登录发生错误' });
|
resolve({ result: false, message: '快速登录发生错误' });
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -216,14 +208,14 @@ export async function NCoreInitShell() {
|
|||||||
loginService.quickLoginWithUin(quickLoginUin)
|
loginService.quickLoginWithUin(quickLoginUin)
|
||||||
.then(result => {
|
.then(result => {
|
||||||
if (result.loginErrorInfo.errMsg) {
|
if (result.loginErrorInfo.errMsg) {
|
||||||
logger.logError.bind(logger)('快速登录错误:', result.loginErrorInfo.errMsg);
|
logger.logError('快速登录错误:', result.loginErrorInfo.errMsg);
|
||||||
if (!isLogined) loginService.getQRCodePicture();
|
if (!isLogined) loginService.getQRCodePicture();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch();
|
.catch();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
} else {
|
} else {
|
||||||
logger.logError.bind(logger)('快速登录失败,未找到该 QQ 历史登录记录,将使用二维码登录方式');
|
logger.logError('快速登录失败,未找到该 QQ 历史登录记录,将使用二维码登录方式');
|
||||||
if (!isLogined) loginService.getQRCodePicture();
|
if (!isLogined) loginService.getQRCodePicture();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -237,37 +229,20 @@ export async function NCoreInitShell() {
|
|||||||
loginService.getQRCodePicture();
|
loginService.getQRCodePicture();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// BEFORE LOGGING IN
|
}
|
||||||
const amgomDataPiece = 'eb1fd6ac257461580dc7438eb099f23aae04ca679f4d88f53072dc56e3bb1129';
|
|
||||||
o3Service.setAmgomDataPiece(basicInfoWrapper.QQVersionAppid, new Uint8Array(Buffer.from(amgomDataPiece, 'hex')));
|
|
||||||
// AFTER LOGGING IN
|
|
||||||
//99b15bdb4c984fc69d5aa1feb9aa16xx --> 99b15bdb-4c98-4fc6-9d5a-a1feb9aa16xx
|
|
||||||
//把guid从左向右转换为guid格式 loginService.getMachineGuid()
|
|
||||||
|
|
||||||
let guid = loginService.getMachineGuid();
|
async function initializeSession(
|
||||||
guid = guid.slice(0, 8) + '-' + guid.slice(8, 12) + '-' + guid.slice(12, 16) + '-' + guid.slice(16, 20) + '-' + guid.slice(20);
|
session: NodeIQQNTWrapperSession,
|
||||||
//console.log('guid:', guid);
|
sessionConfig: any,
|
||||||
//NodeIO3MiscService/reportAmgomWeather login a6 [ '1726748166943', '184', '329' ]
|
logger: LogWrapper
|
||||||
o3Service.reportAmgomWeather('login', 'a6', [dataTimestape, '184', '329']);
|
) {
|
||||||
// if(session.getUnitedConfigService()){
|
return new Promise<void>((resolve, reject) => {
|
||||||
// session.getUnitedConfigService().fetchUnitedCommendConfig([]);
|
|
||||||
// }
|
|
||||||
// from initSession
|
|
||||||
await new Promise<void>(async (resolve, reject) => {
|
|
||||||
const sessionConfig = await genSessionConfig(
|
|
||||||
guid,
|
|
||||||
basicInfoWrapper.QQVersionAppid!,
|
|
||||||
basicInfoWrapper.getFullQQVesion(),
|
|
||||||
selfInfo.uin,
|
|
||||||
selfInfo.uid,
|
|
||||||
dataPath,
|
|
||||||
);
|
|
||||||
const sessionListener = new NodeIKernelSessionListener();
|
const sessionListener = new NodeIKernelSessionListener();
|
||||||
sessionListener.onSessionInitComplete = (r: unknown) => {
|
sessionListener.onSessionInitComplete = (r: unknown) => {
|
||||||
if (r === 0) {
|
if (r === 0) {
|
||||||
resolve();
|
resolve();
|
||||||
} else {
|
} else {
|
||||||
reject(r);
|
reject(new Error('登录异常' + r?.toString()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
session.init(
|
session.init(
|
||||||
@@ -278,21 +253,74 @@ export async function NCoreInitShell() {
|
|||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
session.startNT(0);
|
session.startNT(0);
|
||||||
} catch (_) { /* Empty */
|
} catch (_) {
|
||||||
try {
|
try {
|
||||||
session.startNT();
|
session.startNT();
|
||||||
} catch (e) {
|
} catch (e: unknown) {
|
||||||
reject('init failed ' + e);
|
reject(new Error('init failed ' + (e as Error).message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Initialization end!
|
}
|
||||||
|
|
||||||
|
export async function NCoreInitShell() {
|
||||||
|
console.log('NapCat Shell App Loading...');
|
||||||
|
const pathWrapper = new NapCatPathWrapper();
|
||||||
|
const logger = new LogWrapper(pathWrapper.logsPath);
|
||||||
|
handleUncaughtExceptions(logger);
|
||||||
|
|
||||||
|
const basicInfoWrapper = new QQBasicInfoWrapper({ logger });
|
||||||
|
const wrapper = loadQQWrapper(basicInfoWrapper.getFullQQVesion());
|
||||||
|
|
||||||
|
const o3Service = wrapper.NodeIO3MiscService.get();
|
||||||
|
o3Service.addO3MiscListener(new NodeIO3MiscListener());
|
||||||
|
|
||||||
|
logger.log(`[NapCat] [Core] NapCat.Core Version: ` + napCatVersion);
|
||||||
|
InitWebUi(logger, pathWrapper).then().catch(logger.logError.bind(logger));
|
||||||
|
|
||||||
|
const engine = wrapper.NodeIQQNTWrapperEngine.get();
|
||||||
|
const loginService = wrapper.NodeIKernelLoginService.get();
|
||||||
|
const session = wrapper.NodeIQQNTWrapperSession.create();
|
||||||
|
|
||||||
|
const [dataPath, dataPathGlobal] = getDataPaths(wrapper);
|
||||||
|
const systemPlatform = getPlatformType();
|
||||||
|
|
||||||
|
if (!basicInfoWrapper.QQVersionAppid || !basicInfoWrapper.QQVersionQua) throw new Error('QQVersionAppid or QQVersionQua is not defined');
|
||||||
|
|
||||||
|
await initializeEngine(engine, basicInfoWrapper, dataPathGlobal, systemPlatform, systemVersion);
|
||||||
|
await initializeLoginService(loginService, basicInfoWrapper, dataPathGlobal, systemVersion, hostname);
|
||||||
|
|
||||||
|
const quickLoginUin = cmdOptions.qq;
|
||||||
|
const historyLoginList = (await loginService.getLoginList()).LocalLoginInfoList;
|
||||||
|
|
||||||
|
const dataTimestape = new Date().getTime().toString();
|
||||||
|
o3Service.reportAmgomWeather('login', 'a1', [dataTimestape, '0', '0']);
|
||||||
|
|
||||||
|
const selfInfo = await handleLogin(loginService, logger, pathWrapper, quickLoginUin, historyLoginList);
|
||||||
|
|
||||||
|
const amgomDataPiece = 'eb1fd6ac257461580dc7438eb099f23aae04ca679f4d88f53072dc56e3bb1129';
|
||||||
|
o3Service.setAmgomDataPiece(basicInfoWrapper.QQVersionAppid, new Uint8Array(Buffer.from(amgomDataPiece, 'hex')));
|
||||||
|
|
||||||
|
let guid = loginService.getMachineGuid();
|
||||||
|
guid = guid.slice(0, 8) + '-' + guid.slice(8, 12) + '-' + guid.slice(12, 16) + '-' + guid.slice(16, 20) + '-' + guid.slice(20);
|
||||||
|
o3Service.reportAmgomWeather('login', 'a6', [dataTimestape, '184', '329']);
|
||||||
|
|
||||||
|
const sessionConfig = await genSessionConfig(
|
||||||
|
guid,
|
||||||
|
basicInfoWrapper.QQVersionAppid,
|
||||||
|
basicInfoWrapper.getFullQQVesion(),
|
||||||
|
selfInfo.uin,
|
||||||
|
selfInfo.uid,
|
||||||
|
dataPath,
|
||||||
|
);
|
||||||
|
|
||||||
|
await initializeSession(session, sessionConfig, logger);
|
||||||
|
|
||||||
const accountDataPath = path.resolve(dataPath, './NapCat/data');
|
const accountDataPath = path.resolve(dataPath, './NapCat/data');
|
||||||
fs.mkdirSync(dataPath, { recursive: true });
|
fs.mkdirSync(dataPath, { recursive: true });
|
||||||
logger.logDebug('本账号数据/缓存目录:', accountDataPath);
|
logger.logDebug('本账号数据/缓存目录:', accountDataPath);
|
||||||
|
|
||||||
new NapCatShell(
|
await new NapCatShell(
|
||||||
wrapper,
|
wrapper,
|
||||||
session,
|
session,
|
||||||
logger,
|
logger,
|
||||||
@@ -300,9 +328,10 @@ export async function NCoreInitShell() {
|
|||||||
selfInfo,
|
selfInfo,
|
||||||
basicInfoWrapper,
|
basicInfoWrapper,
|
||||||
pathWrapper,
|
pathWrapper,
|
||||||
);
|
).InitNapCat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export class NapCatShell {
|
export class NapCatShell {
|
||||||
readonly core: NapCatCore;
|
readonly core: NapCatCore;
|
||||||
readonly context: InstanceContext;
|
readonly context: InstanceContext;
|
||||||
@@ -327,8 +356,13 @@ export class NapCatShell {
|
|||||||
};
|
};
|
||||||
this.core = new NapCatCore(this.context, selfInfo);
|
this.core = new NapCatCore(this.context, selfInfo);
|
||||||
|
|
||||||
// TODO: complete ob11 adapter initialization logic
|
|
||||||
new NapCatOneBot11Adapter(this.core, this.context, pathWrapper);
|
|
||||||
|
}
|
||||||
|
async InitNapCat() {
|
||||||
|
await this.core.initCore();
|
||||||
|
new NapCatOneBot11Adapter(this.core, this.context, this.context.pathWrapper).InitOneBot()
|
||||||
|
.catch(e => this.context.logger.logError.bind(this.context.logger)('初始化OneBot失败', e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user