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"
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
permissions: write-all
|
||||
|
30
README.md
30
README.md
@@ -5,18 +5,16 @@
|
||||
</div>
|
||||
|
||||
---
|
||||
## 欢迎回来
|
||||
NapCatQQ (aka 猫猫框架) 是现代化的基于 NTQQ 的 Bot 协议端实现
|
||||
## 欢迎回家
|
||||
NapCatQQ 是现代化的基于 NTQQ 的 Bot 协议端实现
|
||||
|
||||
## 猫猫技能
|
||||
- [x] **启动方式**:支持以无头、LiteLoader 插件、仅 QQ GUI 三种方式启动
|
||||
- [x] **覆盖平台**: 覆盖 Windows / Linux (可选 Docker) / Android Termux / MacOS
|
||||
- [x] **安装简单**: 支持一键脚本/程序自动部署/镜像部署等多种覆盖范围
|
||||
- [x] **超低占用**:无头模式占用资源极低,适合在服务器上运行
|
||||
- [x] **超多接口**:实现大部分 OneBot 和 go-cqhttp 接口,超多扩展 API
|
||||
- [x] **远程管理**:自带 WebUI 支持,远程管理更加便捷
|
||||
## 碎碎叨叨
|
||||
- [x] **安装简单**:就算是笨蛋也能使用
|
||||
- [x] **性能友好**:就算是低内存也能使用
|
||||
- [x] **接口丰富**:就算是没有也能使用
|
||||
- [x] **稳定好用**:就算是被捉也能使用
|
||||
|
||||
## 使用猫猫
|
||||
## 使用框架
|
||||
|
||||
可前往 [Release](https://github.com/NapNeko/NapCatQQ/releases/) 页面下载最新版本
|
||||
|
||||
@@ -38,19 +36,15 @@ NapCatQQ (aka 猫猫框架) 是现代化的基于 NTQQ 的 Bot 协议端实现
|
||||
## 回家旅途
|
||||
[QQ Group](https://qm.qq.com/q/VfjAq5HIMS)
|
||||
|
||||
[Telegram Link](https://t.me/+nLZEnpne-pQ1OWFl)
|
||||
|
||||
## 猫猫朋友
|
||||
## 感谢他们
|
||||
感谢 [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",
|
||||
"slug": "NapCat.Framework",
|
||||
"description": "高性能的 OneBot 11 协议实现",
|
||||
"version": "3.6.17",
|
||||
"version": "4.0.0",
|
||||
"icon": "./logo.png",
|
||||
"authors": [
|
||||
{
|
||||
|
@@ -2,7 +2,7 @@
|
||||
"name": "napcat",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "3.6.17",
|
||||
"version": "4.0.0",
|
||||
"scripts": {
|
||||
"build:framework": "vite build --mode framework",
|
||||
"build:shell": "vite build --mode shell",
|
||||
@@ -48,9 +48,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"express": "^5.0.0",
|
||||
"fluent-ffmpeg": "^2.1.2",
|
||||
"qrcode-terminal": "^0.12.0",
|
||||
"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 class NTEventWrapper {
|
||||
private WrapperSession: NodeIQQNTWrapperSession | undefined; //WrapperSession
|
||||
private 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 WrapperSession: NodeIQQNTWrapperSession | undefined; //WrapperSession
|
||||
private readonly listenerManager: Map<string, ListenerClassBase> = new Map<string, ListenerClassBase>(); //ListenerName-Unique -> Listener实例
|
||||
private readonly EventTask = new Map<string, Map<string, Map<string, InternalMapKey>>>(); //tasks ListenerMainName -> ListenerSubName-> uuid -> {timeout,createtime,func}
|
||||
|
||||
constructor(
|
||||
wrapperSession: NodeIQQNTWrapperSession,
|
||||
@@ -120,9 +120,9 @@ export class NTEventWrapper {
|
||||
ListenerType extends (...args: any) => any = EnsureFunc<ListenerNamingMapping[Listener][ListenerMethod]>,
|
||||
>(
|
||||
listenerAndMethod: `${Listener}/${ListenerMethod}`,
|
||||
checker: (...args: Parameters<ListenerType>) => boolean,
|
||||
waitTimes = 1,
|
||||
timeout = 5000,
|
||||
checker: (...args: Parameters<ListenerType>) => boolean,
|
||||
) {
|
||||
return new Promise<Parameters<ListenerType>>((resolve, reject) => {
|
||||
const ListenerNameList = listenerAndMethod.split('/');
|
||||
@@ -181,14 +181,12 @@ export class NTEventWrapper {
|
||||
callbackTimesToWait = 1,
|
||||
timeout = 5000,
|
||||
) {
|
||||
return new Promise<[EventRet: Awaited<ReturnType<EventType>>, ...Parameters<ListenerType>]>(
|
||||
async (resolve, reject) => {
|
||||
const id = randomUUID();
|
||||
let complete = 0;
|
||||
let retData: Parameters<ListenerType> | undefined = undefined;
|
||||
let retEvent: any = {};
|
||||
|
||||
function sendDataCallback() {
|
||||
function sendDataCallback(resolve: any, reject: any) {
|
||||
if (complete == 0) {
|
||||
reject(
|
||||
new Error(
|
||||
@@ -210,7 +208,9 @@ export class NTEventWrapper {
|
||||
const ListenerMainName = ListenerNameList[0];
|
||||
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 = {
|
||||
timeout: timeout,
|
||||
@@ -221,7 +221,7 @@ export class NTEventWrapper {
|
||||
retData = args as Parameters<ListenerType>;
|
||||
if (complete >= callbackTimesToWait) {
|
||||
clearTimeout(timeoutRef);
|
||||
sendDataCallback();
|
||||
sendDataCallback(resolve, reject);
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -233,8 +233,10 @@ export class NTEventWrapper {
|
||||
}
|
||||
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallback);
|
||||
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()) {
|
||||
clearTimeout(timeoutRef);
|
||||
reject(
|
||||
@@ -249,7 +251,8 @@ export class NTEventWrapper {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
})
|
||||
.catch(reject);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@@ -54,11 +54,7 @@ export class ForwardMsgBuilder {
|
||||
const id = crypto.randomUUID();
|
||||
const isGroupMsg = msg.some(m => m.isGroupMsg);
|
||||
if (!source) {
|
||||
source = isGroupMsg ? "群聊的聊天记录" :
|
||||
msg.length
|
||||
? Array.from(new Set(msg.slice(0, 4).map(m => m.senderName)))
|
||||
.join('和') + '的聊天记录'
|
||||
: '聊天记录';
|
||||
source = isGroupMsg ? "群聊的聊天记录" : msg.map(m => m.senderName).filter((v, i, a) => a.indexOf(v) === i).slice(0, 4).join('和') + '的聊天记录';
|
||||
}
|
||||
if (!news) {
|
||||
news = msg.length === 0 ? [{
|
||||
@@ -111,7 +107,7 @@ export class ForwardMsgBuilder {
|
||||
senderName: msg.senderName,
|
||||
isGroupMsg: msg.groupId !== undefined,
|
||||
msg: msg.msg.map(m => ({
|
||||
preview: m.valid? m.toPreview() : "[该消息类型暂不支持查看]",
|
||||
preview: m.valid ? m.toPreview() : "[该消息类型暂不支持查看]",
|
||||
}))
|
||||
})), source, news, summary, prompt);
|
||||
}
|
||||
|
@@ -74,6 +74,12 @@ export class LogWrapper {
|
||||
}
|
||||
files.forEach(file => {
|
||||
const filePath = path.join(logDir, file);
|
||||
this.deleteOldLogFile(filePath, oneWeekAgo);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private deleteOldLogFile(filePath: string, oneWeekAgo: number) {
|
||||
fs.stat(filePath, (err, stats) => {
|
||||
if (err) {
|
||||
this.logger.error('Failed to get file stats', err);
|
||||
@@ -83,18 +89,16 @@ export class LogWrapper {
|
||||
fs.unlink(filePath, err => {
|
||||
if (err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
this.logger.warn(`File already deleted: ${file}`);
|
||||
this.logger.warn(`File already deleted: ${filePath}`);
|
||||
} else {
|
||||
this.logger.error('Failed to delete old log file', err);
|
||||
}
|
||||
} else {
|
||||
this.logger.info(`Deleted old log file: ${file}`);
|
||||
this.logger.info(`Deleted old log file: ${filePath}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
setFileAndConsoleLogLevel(fileLogLevel: LogLevel, consoleLogLevel: LogLevel) {
|
||||
@@ -198,7 +202,7 @@ export function rawMessageToText(msg: RawMessage, recursiveLevel = 0): string {
|
||||
tokens.push(`群聊 [${msg.peerName}(${msg.peerUin})]`);
|
||||
}
|
||||
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) {
|
||||
tokens.push('移动设备');
|
||||
@@ -206,28 +210,20 @@ export function rawMessageToText(msg: RawMessage, recursiveLevel = 0): string {
|
||||
tokens.push(`临时消息 (${msg.peerUin})`);
|
||||
}
|
||||
|
||||
function msgElementToText(element: MessageElement) {
|
||||
if (element.textElement) {
|
||||
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})`;
|
||||
for (const element of msg.elements) {
|
||||
tokens.push(msgElementToText(element, msg, recursiveLevel));
|
||||
}
|
||||
|
||||
return tokens.join(' ');
|
||||
}
|
||||
|
||||
function msgElementToText(element: MessageElement, msg: RawMessage, recursiveLevel: number): string {
|
||||
if (element.textElement) {
|
||||
return textElementToText(element.textElement);
|
||||
}
|
||||
|
||||
if (element.replyElement) {
|
||||
const recordMsgOrNull = msg.records.find(
|
||||
record => element.replyElement!.sourceMsgIdInRecords === record.msgId,
|
||||
);
|
||||
return `[回复消息 ${recordMsgOrNull &&
|
||||
recordMsgOrNull.peerUin != '284840486' && recordMsgOrNull.peerUin != '1094950020'
|
||||
?
|
||||
rawMessageToText(recordMsgOrNull, recursiveLevel + 1) :
|
||||
`未找到消息记录 (MsgId = ${element.replyElement.sourceMsgIdInRecords})`
|
||||
}]`;
|
||||
return replyElementToText(element.replyElement, msg, recursiveLevel);
|
||||
}
|
||||
|
||||
if (element.picElement) {
|
||||
@@ -271,11 +267,28 @@ export function rawMessageToText(msg: RawMessage, recursiveLevel = 0): string {
|
||||
}
|
||||
|
||||
return `[未实现 (ElementType = ${element.elementType})]`;
|
||||
}
|
||||
|
||||
for (const element of msg.elements) {
|
||||
tokens.push(msgElementToText(element));
|
||||
}
|
||||
|
||||
return tokens.join(' ');
|
||||
}
|
||||
|
||||
function textElementToText(textElement: any): string {
|
||||
if (textElement.atType === AtType.notAt) {
|
||||
const originalContentLines = textElement.content.split('\n');
|
||||
return `${originalContentLines[0]}${originalContentLines.length > 1 ? ' ...' : ''}`;
|
||||
} 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);
|
||||
}
|
||||
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';
|
||||
|
||||
export class LimitedHashTable<K, V> {
|
||||
private keyToValue: Map<K, V> = new Map();
|
||||
private valueToKey: Map<V, K> = new Map();
|
||||
private readonly keyToValue: Map<K, V> = new Map();
|
||||
private readonly valueToKey: Map<V, K> = new Map();
|
||||
private maxSize: number;
|
||||
|
||||
constructor(maxSize: number) {
|
||||
@@ -75,8 +75,8 @@ export class LimitedHashTable<K, V> {
|
||||
}
|
||||
|
||||
class MessageUniqueWrapper {
|
||||
private msgDataMap: LimitedHashTable<string, number>;
|
||||
private msgIdMap: LimitedHashTable<string, number>;
|
||||
private readonly msgDataMap: LimitedHashTable<string, number>;
|
||||
private readonly msgIdMap: LimitedHashTable<string, number>;
|
||||
|
||||
constructor(maxMap: number = 1000) {
|
||||
this.msgIdMap = new LimitedHashTable<string, number>(maxMap);
|
||||
|
@@ -8,34 +8,40 @@ export class RequestUtil {
|
||||
const client = url.startsWith('https') ? https : http;
|
||||
return new Promise((resolve, reject) => {
|
||||
const req = client.get(url, (res) => {
|
||||
let cookies: { [key: string]: string } = {};
|
||||
const handleRedirect = (res: http.IncomingMessage) => {
|
||||
//console.log(res.headers.location);
|
||||
const cookies: { [key: string]: string } = {};
|
||||
|
||||
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.headers.location) {
|
||||
const redirectUrl = new URL(res.headers.location, url);
|
||||
RequestUtil.HttpsGetCookies(redirectUrl.href).then((redirectCookies) => {
|
||||
const redirectCookies = await this.HttpsGetCookies(redirectUrl.href);
|
||||
// 合并重定向过程中的cookies
|
||||
cookies = { ...cookies, ...redirectCookies };
|
||||
resolve(cookies);
|
||||
}).catch((err) => {
|
||||
reject(err);
|
||||
});
|
||||
} else {
|
||||
resolve(cookies);
|
||||
return { ...cookies, ...redirectCookies };
|
||||
}
|
||||
} else {
|
||||
resolve(cookies);
|
||||
}
|
||||
};
|
||||
res.on('data', () => {
|
||||
}); // Necessary to consume the stream
|
||||
res.on('end', () => {
|
||||
handleRedirect(res);
|
||||
});
|
||||
if (res.headers['set-cookie']) {
|
||||
//console.log(res.headers['set-cookie']);
|
||||
res.headers['set-cookie'].forEach((cookie) => {
|
||||
return cookies;
|
||||
}
|
||||
|
||||
private static extractCookies(setCookieHeaders: string[], cookies: { [key: string]: string }) {
|
||||
setCookieHeaders.forEach((cookie) => {
|
||||
const parts = cookie.split(';')[0].split('=');
|
||||
const key = parts[0];
|
||||
const value = parts[1];
|
||||
@@ -44,13 +50,6 @@ export class RequestUtil {
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
req.on('error', (error: any) => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 请求和回复都是JSON data传原始内容 自动编码json
|
||||
static async HttpGetJson<T>(url: string, method: string = 'GET', data?: any, headers: {
|
||||
@@ -88,13 +87,13 @@ export class RequestUtil {
|
||||
} else {
|
||||
reject(new Error(`Unexpected status code: ${res.statusCode}`));
|
||||
}
|
||||
} catch (parseError) {
|
||||
reject(parseError);
|
||||
} catch (parseError: unknown) {
|
||||
reject(new Error((parseError as Error).message));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (error: any) => {
|
||||
req.on('error', (error: Error) => {
|
||||
reject(error);
|
||||
});
|
||||
if (method === 'POST' || method === 'PUT' || method === 'PATCH') {
|
||||
@@ -133,62 +132,4 @@ export class RequestUtil {
|
||||
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(filePath).ffprobe((err: any, metadata: ffmpeg.FfprobeData) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
reject(new Error('无法获取视频信息。'));
|
||||
} else {
|
||||
const videoStream = metadata.streams.find((s: FfprobeStream) => s.codec_type === 'video');
|
||||
if (videoStream) {
|
||||
|
@@ -6,8 +6,10 @@ export class NodeIDependsAdapter {
|
||||
}
|
||||
|
||||
onMSFSsoError(args: unknown) {
|
||||
|
||||
}
|
||||
|
||||
getGroupCode(args: unknown) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -357,16 +357,14 @@ export class NTQQFileApi {
|
||||
|
||||
async getImageSize(filePath: string): Promise<ISizeCalculationResult> {
|
||||
return new Promise((resolve, reject) => {
|
||||
imageSize(filePath, (err, dimensions) => {
|
||||
imageSize(filePath, (err: Error | null, dimensions) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
if (!dimensions) {
|
||||
reject(new Error(err.message));
|
||||
} else if (!dimensions) {
|
||||
reject(new Error('获取图片尺寸失败'));
|
||||
} else {
|
||||
resolve(dimensions);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -408,26 +406,31 @@ export class NTQQFileApi {
|
||||
return fileData.filePath!;
|
||||
}
|
||||
|
||||
async getImageUrl(element: PicElement) {
|
||||
async getImageUrl(element: PicElement): Promise<string> {
|
||||
if (!element) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const url: string = element.originImageUrl ?? '';
|
||||
const md5HexStr = element.md5HexStr;
|
||||
const fileMd5 = element.md5HexStr;
|
||||
|
||||
if (url) {
|
||||
const parsedUrl = new URL(IMAGE_HTTP_HOST + url);
|
||||
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');
|
||||
const rkeyData = await this.getRkeyData();
|
||||
return this.getImageUrlFromParsedUrl(parsedUrl, rkeyData);
|
||||
}
|
||||
|
||||
return this.getImageUrlFromMd5(fileMd5, md5HexStr);
|
||||
}
|
||||
|
||||
private async getRkeyData() {
|
||||
const rkeyData = {
|
||||
private_rkey: 'CAQSKAB6JWENi5LM_xp9vumLbuThJSaYf-yzMrbZsuq7Uz2qEc3Rbib9LP4',
|
||||
group_rkey: 'CAQSKAB6JWENi5LM_xp9vumLbuThJSaYf-yzMrbZsuq7Uz2qffcqm614gds',
|
||||
online_rkey: false
|
||||
};
|
||||
|
||||
try {
|
||||
if (this.core.apis.PacketApi.available) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
return IMAGE_HTTP_HOST_NT + urlRkey;
|
||||
} else if (isNTV2 && rkeyData.online_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) {
|
||||
const rkey = imageAppid === '1406' ? rkeyData.private_rkey : rkeyData.group_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) {
|
||||
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 '';
|
||||
}
|
||||
}
|
||||
|
@@ -15,7 +15,7 @@ export class NTQQFriendApi {
|
||||
}
|
||||
async getBuddyV2SimpleInfoMap(refresh = false) {
|
||||
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);
|
||||
return await this.core.eventWrapper.callNoListenerEvent(
|
||||
'NodeIKernelProfileService/getCoreAndBaseInfo',
|
||||
@@ -41,14 +41,10 @@ export class NTQQFriendApi {
|
||||
tempBothDel: tempBothDel
|
||||
});
|
||||
}
|
||||
async getBuddyV2ExWithCate(refresh = false) {
|
||||
const categoryMap: Map<string, any> = new Map();
|
||||
async getBuddyV2ExWithCate() {
|
||||
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 => {
|
||||
item.buddyUids.forEach(uid => {
|
||||
categoryMap.set(uid, { categoryId: item.categoryId, categoryName: item.categroyName });
|
||||
});
|
||||
return item.buddyUids;
|
||||
});
|
||||
const data = await this.core.eventWrapper.callNoListenerEvent(
|
||||
|
@@ -25,9 +25,10 @@ export class NTQQGroupApi {
|
||||
constructor(context: InstanceContext, core: NapCatCore) {
|
||||
this.context = context;
|
||||
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() {
|
||||
this.groups = await this.getGroups();
|
||||
for (const group of this.groups) {
|
||||
@@ -54,7 +55,7 @@ export class NTQQGroupApi {
|
||||
}, pskey);
|
||||
}
|
||||
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);
|
||||
return (await data)[1];
|
||||
}
|
||||
@@ -258,9 +259,9 @@ export class NTQQGroupApi {
|
||||
async getGroupMemberV2(GroupCode: string, uid: string, forced = false) {
|
||||
const Listener = this.core.eventWrapper.registerListen(
|
||||
'NodeIKernelGroupListener/onMemberInfoChange',
|
||||
(params, _, members) => params === GroupCode && members.size > 0,
|
||||
1,
|
||||
forced ? 5000 : 250,
|
||||
(params, _, members) => params === GroupCode && members.size > 0,
|
||||
);
|
||||
const retData = await (
|
||||
this.core.eventWrapper
|
||||
@@ -318,13 +319,13 @@ export class NTQQGroupApi {
|
||||
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>;
|
||||
finish: boolean;
|
||||
hasNext: boolean | undefined;
|
||||
}> {
|
||||
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(() => { });
|
||||
const result = await this.context.session.getGroupService().getNextMemberList(sceneId, undefined, num);
|
||||
if (result.errCode !== 0) {
|
||||
@@ -352,7 +353,7 @@ export class NTQQGroupApi {
|
||||
listenerMode: boolean;
|
||||
}> {
|
||||
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(() => { });
|
||||
const result = await this.context.session.getGroupService().getNextMemberList(sceneId, undefined, num);
|
||||
if (result.errCode !== 0) {
|
||||
@@ -371,7 +372,7 @@ export class NTQQGroupApi {
|
||||
infos: new Map([...(resMode2?.infos ?? []), ...result.result.infos]),
|
||||
finish: result.result.finish,
|
||||
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 './user';
|
||||
export * from './webapi';
|
||||
export * from './sign';
|
||||
export * from './system';
|
@@ -144,7 +144,7 @@ export class NTQQMsgApi {
|
||||
params,
|
||||
],
|
||||
() => true,
|
||||
() => true, // Todo: 应当通过 groupFileListResult 判断
|
||||
() => true, // 应当通过 groupFileListResult 判断
|
||||
1,
|
||||
5000,
|
||||
);
|
||||
@@ -194,7 +194,7 @@ export class NTQQMsgApi {
|
||||
async sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
|
||||
//唉?!我有个想法
|
||||
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) {
|
||||
await this.PrepareTempChat(peer.peerUid, peer.guildId, member.nick);
|
||||
}
|
||||
|
@@ -26,14 +26,15 @@ export class NTQQPacketApi {
|
||||
this.context = context;
|
||||
this.core = core;
|
||||
this.logger = core.context.logger;
|
||||
this.InitSendPacket(this.context.basicInfoWrapper.getFullQQVesion())
|
||||
}
|
||||
async initApi() {
|
||||
await this.InitSendPacket(this.context.basicInfoWrapper.getFullQQVesion())
|
||||
.then()
|
||||
.catch((err) => {
|
||||
this.logger.logError.bind(this.core.context.logger);
|
||||
this.errStack.push(err);
|
||||
});
|
||||
}
|
||||
|
||||
get available(): boolean {
|
||||
return this.pkt?.available ?? false;
|
||||
}
|
||||
|
@@ -1,5 +1,3 @@
|
||||
import { RequestUtil } from '@/common/request';
|
||||
import { MiniAppLuaJsonType } from '@/core';
|
||||
import { InstanceContext, NapCatCore } from '..';
|
||||
|
||||
export class NTQQMusicSignApi {
|
||||
@@ -10,210 +8,6 @@ export class NTQQMusicSignApi {
|
||||
this.context = context;
|
||||
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://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
|
||||
|
||||
//还有一处公告上传可以上传高质量图片 持久为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) {
|
||||
const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com');
|
||||
const getDataInternal = async (Internal_groupCode: string, Internal_type: number) => {
|
||||
private async getDataInternal(cookieObject: any, groupCode: string, type: number) {
|
||||
let resJson;
|
||||
try {
|
||||
const res = await RequestUtil.HttpGetText(
|
||||
`https://qun.qq.com/interactive/honorlist?${new URLSearchParams({
|
||||
gc: Internal_groupCode,
|
||||
type: Internal_type.toString(),
|
||||
gc: groupCode,
|
||||
type: type.toString(),
|
||||
}).toString()}`,
|
||||
'GET',
|
||||
'',
|
||||
@@ -230,90 +228,49 @@ export class NTQQWebApi {
|
||||
if (match) {
|
||||
resJson = JSON.parse(match[1].trim());
|
||||
}
|
||||
if (Internal_type === 1) {
|
||||
return resJson?.talkativeList;
|
||||
} else {
|
||||
return resJson?.actorList;
|
||||
}
|
||||
return type === 1 ? resJson?.talkativeList : resJson?.actorList;
|
||||
} catch (e) {
|
||||
this.context.logger.logDebug('获取当前群荣耀失败', e);
|
||||
}
|
||||
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 };
|
||||
|
||||
if (getType === WebHonorType.TALKATIVE || getType === WebHonorType.ALL) {
|
||||
const RetInternal = await getDataInternal(groupCode, 1);
|
||||
if (RetInternal) {
|
||||
HonorInfo.current_talkative = {
|
||||
user_id: RetInternal[0]?.uin,
|
||||
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)('获取龙王信息失败');
|
||||
const talkativeList = await this.getHonorList(cookieObject, groupCode, 1);
|
||||
if (talkativeList.length > 0) {
|
||||
HonorInfo.current_talkative = talkativeList[0];
|
||||
HonorInfo.talkative_list = talkativeList;
|
||||
}
|
||||
}
|
||||
|
||||
if (getType === WebHonorType.PERFORMER || getType === WebHonorType.ALL) {
|
||||
const RetInternal = await getDataInternal(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)('获取群聊之火失败');
|
||||
}
|
||||
HonorInfo.performer_list = await this.getHonorList(cookieObject, groupCode, 2);
|
||||
}
|
||||
|
||||
if (getType === WebHonorType.LEGEND || getType === WebHonorType.ALL) {
|
||||
const RetInternal = await getDataInternal(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)('获取群聊炽焰失败');
|
||||
}
|
||||
HonorInfo.legend_list = await this.getHonorList(cookieObject, groupCode, 3);
|
||||
}
|
||||
|
||||
if (getType === WebHonorType.EMOTION || getType === WebHonorType.ALL) {
|
||||
const RetInternal = await getDataInternal(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)('获取快乐源泉失败');
|
||||
}
|
||||
HonorInfo.emotion_list = await this.getHonorList(cookieObject, groupCode, 6);
|
||||
}
|
||||
|
||||
// 冒尖小春笋好像已经被tx扬了 R.I.P.
|
||||
|
@@ -23,7 +23,7 @@ export interface ChatCacheList {
|
||||
export interface ChatCacheListItem {
|
||||
chatType: ChatType;
|
||||
basicChatCacheInfo: ChatCacheListItemBasic;
|
||||
guildChatCacheInfo: unknown[]; // TODO: 没用过频道所以不知道这里边的详细内容
|
||||
guildChatCacheInfo: unknown[]; // work: 没用过频道所以不知道这里边的详细内容
|
||||
}
|
||||
|
||||
export interface ChatCacheListItemBasic {
|
||||
|
@@ -117,7 +117,7 @@ export enum GroupMemberRole {
|
||||
}
|
||||
|
||||
export interface GroupMember {
|
||||
memberRealLevel: string | undefined;
|
||||
memberRealLevel: number | undefined;
|
||||
memberSpecialTitle?: string;
|
||||
avatarPath: string;
|
||||
cardName: string;
|
||||
|
@@ -175,8 +175,8 @@ export interface SimpleInfo {
|
||||
status: UserStatus | null;
|
||||
vasInfo: VasInfo | null;
|
||||
relationFlags: RelationFlags | null;
|
||||
otherFlags: any | null;
|
||||
intimate: any | null;
|
||||
otherFlags: any;
|
||||
intimate: any;
|
||||
}
|
||||
|
||||
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";
|
||||
|
||||
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";
|
||||
|
||||
const BodyInner = {
|
||||
|
@@ -84,11 +84,10 @@ export function getMajorPath(QQVersion: string): string {
|
||||
}
|
||||
export class NapCatCore {
|
||||
readonly context: InstanceContext;
|
||||
readonly apis: StableNTApiWrapper;
|
||||
readonly eventWrapper: NTEventWrapper;
|
||||
// readonly eventChannel: NTEventChannel;
|
||||
NapCatDataPath: string;
|
||||
NapCatTempPath: string;
|
||||
NapCatDataPath: string = '';
|
||||
NapCatTempPath: string = '';
|
||||
apis: StableNTApiWrapper;
|
||||
// runtime info, not readonly
|
||||
selfInfo: SelfInfo;
|
||||
util: NodeQQNTWrapperUtil;
|
||||
@@ -112,6 +111,8 @@ export class NapCatCore {
|
||||
UserApi: new NTQQUserApi(this.context, this),
|
||||
GroupApi: new NTQQGroupApi(this.context, this),
|
||||
};
|
||||
}
|
||||
async initCore() {
|
||||
this.NapCatDataPath = path.join(this.dataPath, 'NapCat');
|
||||
fs.mkdirSync(this.NapCatDataPath, { recursive: true });
|
||||
this.NapCatTempPath = path.join(this.NapCatDataPath, 'temp');
|
||||
@@ -119,7 +120,13 @@ export class NapCatCore {
|
||||
if (!fs.existsSync(this.NapCatTempPath)) {
|
||||
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.context.logger.setFileLogEnabled(
|
||||
@@ -133,7 +140,6 @@ export class NapCatCore {
|
||||
this.configLoader.configData.consoleLogLevel as LogLevel,
|
||||
);
|
||||
}
|
||||
|
||||
get dataPath(): string {
|
||||
let result = this.context.wrapper.NodeQQNTWrapperUtil.getNTUserDataInfoConfig();
|
||||
if (!result) {
|
||||
@@ -204,7 +210,7 @@ export class NapCatCore {
|
||||
});
|
||||
};
|
||||
groupListener.onMemberListChange = (arg) => {
|
||||
// todo: 应该加一个内部自己维护的成员变动callback,用于判断成员变化通知
|
||||
// work:应该加一个内部自己维护的成员变动callback,用于判断成员变化通知
|
||||
const groupCode = arg.sceneId.split('_')[0];
|
||||
if (this.apis.GroupApi.groupMemberCache.has(groupCode)) {
|
||||
const existMembers = this.apis.GroupApi.groupMemberCache.get(groupCode)!;
|
||||
@@ -214,7 +220,7 @@ export class NapCatCore {
|
||||
if (existMember) {
|
||||
Object.assign(existMember, member);
|
||||
} else {
|
||||
existMembers!.set(uid, member);
|
||||
existMembers.set(uid, member);
|
||||
}
|
||||
//移除成员
|
||||
if (member.isDelete) {
|
||||
|
@@ -3,57 +3,57 @@ import { BuddyCategoryType, FriendRequestNotify } from '@/core/entities';
|
||||
export type OnBuddyChangeParams = BuddyCategoryType[];
|
||||
|
||||
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,
|
||||
thumbPath: 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';
|
||||
|
||||
export class NodeIKernelGroupListener {
|
||||
onGroupListInited(listEmpty: boolean): void { }
|
||||
onGroupListInited(listEmpty: boolean): any { }
|
||||
// 发现于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: {
|
||||
@@ -74,12 +74,12 @@ export class NodeIKernelGroupListener {
|
||||
hasPrev: boolean,
|
||||
hasNext: 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 {
|
||||
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
|
||||
// base64Data = base64Data.split("data:image/png;base64,")[1]
|
||||
// let buffer = Buffer.from(base64Data, 'base64')
|
||||
// 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,
|
||||
clientMsg: string,
|
||||
businessId: number,
|
||||
userTotalSpacePerDay: unknown | null,
|
||||
userUsedSpacePerDay: unknown | null
|
||||
userTotalSpacePerDay: unknown,
|
||||
userUsedSpacePerDay: unknown
|
||||
}
|
||||
|
||||
export interface GroupFileInfoUpdateParamType {
|
||||
@@ -94,108 +94,108 @@ export interface TempOnRecvParams {
|
||||
}
|
||||
|
||||
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;
|
||||
timestamp: 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
|
||||
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
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
|
||||
onSearchGroupResult(params: GroupSearchResult): void;
|
||||
onSearchGroupResult(params: GroupSearchResult): any;
|
||||
|
||||
onSearchFileKeywordsResult(params: {
|
||||
searchId: string,
|
||||
@@ -93,5 +93,5 @@ export interface NodeIKernelSearchListener {
|
||||
end: number
|
||||
}[]
|
||||
}[]
|
||||
}): void;
|
||||
}): any;
|
||||
}
|
||||
|
@@ -1,25 +1,25 @@
|
||||
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 {
|
||||
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 {
|
||||
listener(): any {
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
export class NodeIO3MiscListener {
|
||||
getOnAmgomDataPiece(...arg: unknown[]) {
|
||||
getOnAmgomDataPiece(...arg: unknown[]): any {
|
||||
|
||||
}
|
||||
}
|
@@ -16,8 +16,8 @@ export interface NativePacketExportType {
|
||||
|
||||
export class NativePacketClient extends IPacketClient {
|
||||
private readonly supportedPlatforms = ['win32.x64', 'linux.x64', 'linux.arm64', 'darwin.x64', 'darwin.arm64'];
|
||||
private MoeHooExport: { exports: NativePacketExportType } = { exports: {} };
|
||||
private sendEvent = new LRUCache<number, string>(500); // seq->trace_id
|
||||
private readonly MoeHooExport: { exports: NativePacketExportType } = { exports: {} };
|
||||
private readonly sendEvent = new LRUCache<number, string>(500); // seq->trace_id
|
||||
|
||||
constructor(context: PacketContext, logStack: 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 { PacketContext } from "@/core/packet/context/packetContext";
|
||||
import { LogStack } from "@/core/packet/context/clientContext";
|
||||
|
||||
export class wsPacketClient extends IPacketClient {
|
||||
export class WsPacketClient extends IPacketClient {
|
||||
private websocket: WebSocket | null = null;
|
||||
private reconnectAttempts: number = 0;
|
||||
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.context.logger.error(`处理消息时出错: ${err}`);
|
||||
});
|
||||
this.websocket.onerror = (error) => {
|
||||
this.websocket.onerror = (event: ErrorEvent) => {
|
||||
this.available = false;
|
||||
this.context.logger.error(`WebSocket 出错: ${error.message}`);
|
||||
this.context.logger.error(`WebSocket 出错: ${event.message}`);
|
||||
this.websocket?.close();
|
||||
reject(error);
|
||||
reject(new Error(`WebSocket 出错: ${event.message}`));
|
||||
};
|
||||
});
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@ export class PacketClientSession {
|
||||
return this.context.operation;
|
||||
}
|
||||
|
||||
// TODO: global message element adapter (?
|
||||
// work: global message element adapter (?
|
||||
get msgConverter() {
|
||||
return this.context.msgConverter;
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { PacketContext } from "@/core/packet/context/packetContext";
|
||||
import { IPacketClient } from "@/core/packet/client/baseClient";
|
||||
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 { PacketLogger } from "@/core/packet/context/loggerContext";
|
||||
|
||||
@@ -11,12 +11,12 @@ type clientPriority = {
|
||||
|
||||
const clientPriority: clientPriority = {
|
||||
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 {
|
||||
private stack: string[] = [];
|
||||
private logger: PacketLogger;
|
||||
private readonly logger: PacketLogger;
|
||||
|
||||
constructor(logger: PacketLogger) {
|
||||
this.logger = logger;
|
||||
@@ -88,7 +88,7 @@ export class PacketClientContext {
|
||||
break;
|
||||
case "frida":
|
||||
this.context.logger.info("[Core] [Packet] 使用指定的 FridaPacketClient 作为后端");
|
||||
client = new wsPacketClient(this.context, this.logStack);
|
||||
client = new WsPacketClient(this.context, this.logStack);
|
||||
break;
|
||||
case "auto":
|
||||
case undefined:
|
||||
@@ -98,9 +98,12 @@ export class PacketClientContext {
|
||||
this.context.logger.error(`未知的PacketBackend ${prefer},请检查配置文件!`);
|
||||
client = null;
|
||||
}
|
||||
if (!(client && client.check())) {
|
||||
if (!client?.check()) {
|
||||
throw new Error("[Core] [Packet] 无可用的后端,NapCat.Packet将不会加载!");
|
||||
}
|
||||
if (!client) {
|
||||
throw new Error("[Core] [Packet] 后端异常,NapCat.Packet将不会加载!");
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { LogLevel, LogWrapper } from "@/common/log";
|
||||
import { PacketContext } from "@/core/packet/context/packetContext";
|
||||
|
||||
// TODO: check bind?
|
||||
// work: check bind?
|
||||
export class PacketLogger {
|
||||
private readonly napLogger: LogWrapper;
|
||||
|
||||
|
@@ -15,7 +15,7 @@ import { NapProtoDecodeStructType, NapProtoEncodeStructType } from "@napneko/nap
|
||||
import { IndexNode, MsgInfo } from "@/core/packet/transformer/proto";
|
||||
|
||||
export class PacketOperationContext {
|
||||
private context: PacketContext;
|
||||
private readonly context: PacketContext;
|
||||
constructor(context: PacketContext) {
|
||||
this.context = context;
|
||||
}
|
||||
@@ -65,35 +65,22 @@ export class PacketOperationContext {
|
||||
}
|
||||
|
||||
async UploadResources(msg: PacketMsg[], groupUin: number = 0) {
|
||||
const reqList = [];
|
||||
for (const m of msg) {
|
||||
for (const e of m.msg) {
|
||||
const chatType = groupUin ? ChatType.KCHATTYPEGROUP : ChatType.KCHATTYPEC2C;
|
||||
const peerUid = groupUin ? String(groupUin) : this.context.napcore.basicInfo.uid;
|
||||
const reqList = msg.flatMap(m =>
|
||||
m.msg.map(e => {
|
||||
if (e instanceof PacketMsgPicElement) {
|
||||
reqList.push(this.context.highway.uploadImage({
|
||||
chatType: groupUin ? ChatType.KCHATTYPEGROUP : ChatType.KCHATTYPEC2C,
|
||||
peerUid: groupUin ? String(groupUin) : this.context.napcore.basicInfo.uid
|
||||
}, e));
|
||||
}
|
||||
if (e instanceof PacketMsgVideoElement) {
|
||||
reqList.push(this.context.highway.uploadVideo({
|
||||
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 this.context.highway.uploadImage({ chatType, peerUid }, e);
|
||||
} else if (e instanceof PacketMsgVideoElement) {
|
||||
return this.context.highway.uploadVideo({ chatType, peerUid }, e);
|
||||
} else if (e instanceof PacketMsgPttElement) {
|
||||
return this.context.highway.uploadPtt({ chatType, peerUid }, e);
|
||||
} else if (e instanceof PacketMsgFileElement) {
|
||||
return this.context.highway.uploadFile({ chatType, peerUid }, e);
|
||||
}
|
||||
return null;
|
||||
}).filter(Boolean)
|
||||
);
|
||||
const res = await Promise.allSettled(reqList);
|
||||
this.context.logger.info(`上传资源${res.length}个,失败${res.filter(r => r.status === 'rejected').length}个`);
|
||||
res.forEach((result, index) => {
|
||||
|
@@ -33,7 +33,7 @@ export interface PacketHighwaySig {
|
||||
}
|
||||
|
||||
export class PacketHighwayContext {
|
||||
private context: PacketContext;
|
||||
private readonly context: PacketContext;
|
||||
protected sig: PacketHighwaySig;
|
||||
protected logger: PacketLogger;
|
||||
protected hwClient: PacketHighwayClient;
|
||||
@@ -223,12 +223,12 @@ export class PacketHighwayContext {
|
||||
msgInfoBody: preRespData.upload.msgInfo.msgInfoBody,
|
||||
blockSize: BlockSize,
|
||||
hash: {
|
||||
fileSha1: await calculateSha1StreamBytes(video.filePath!)
|
||||
fileSha1: await calculateSha1StreamBytes(video.filePath)
|
||||
}
|
||||
});
|
||||
await this.hwClient.upload(
|
||||
1005,
|
||||
fs.createReadStream(video.filePath!, { highWaterMark: BlockSize }),
|
||||
fs.createReadStream(video.filePath, { highWaterMark: BlockSize }),
|
||||
+video.fileSize!,
|
||||
md5,
|
||||
extend
|
||||
@@ -256,7 +256,7 @@ export class PacketHighwayContext {
|
||||
});
|
||||
await this.hwClient.upload(
|
||||
1006,
|
||||
fs.createReadStream(video.thumbPath!, { highWaterMark: BlockSize }),
|
||||
fs.createReadStream(video.thumbPath, { highWaterMark: BlockSize }),
|
||||
+video.thumbSize!,
|
||||
md5,
|
||||
extend
|
||||
@@ -288,12 +288,12 @@ export class PacketHighwayContext {
|
||||
msgInfoBody: preRespData.upload.msgInfo.msgInfoBody,
|
||||
blockSize: BlockSize,
|
||||
hash: {
|
||||
fileSha1: await calculateSha1StreamBytes(video.filePath!)
|
||||
fileSha1: await calculateSha1StreamBytes(video.filePath)
|
||||
}
|
||||
});
|
||||
await this.hwClient.upload(
|
||||
1001,
|
||||
fs.createReadStream(video.filePath!, { highWaterMark: BlockSize }),
|
||||
fs.createReadStream(video.filePath, { highWaterMark: BlockSize }),
|
||||
+video.fileSize!,
|
||||
md5,
|
||||
extend
|
||||
@@ -321,7 +321,7 @@ export class PacketHighwayContext {
|
||||
});
|
||||
await this.hwClient.upload(
|
||||
1002,
|
||||
fs.createReadStream(video.thumbPath!, { highWaterMark: BlockSize }),
|
||||
fs.createReadStream(video.thumbPath, { highWaterMark: BlockSize }),
|
||||
+video.thumbSize!,
|
||||
md5,
|
||||
extend
|
||||
|
@@ -64,11 +64,11 @@ export class HighwayHttpUploader extends IHighwayUploader {
|
||||
});
|
||||
});
|
||||
req.write(frame);
|
||||
req.on('error', (error) => {
|
||||
req.on('error', (error: Error) => {
|
||||
reject(error);
|
||||
});
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
} catch (error: unknown) {
|
||||
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('.');
|
||||
};
|
||||
|
||||
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 {
|
||||
domain: {
|
||||
isEnable: true,
|
||||
ip: int32ip2str(ip.outIP!),
|
||||
ip: int32ip2str(ip.outIP ?? 0),
|
||||
},
|
||||
port: ip.outPort!
|
||||
} as NapProtoEncodeStructType<typeof proto.NTHighwayIPv4>;
|
||||
|
@@ -16,7 +16,7 @@ export class PacketMsgBuilder {
|
||||
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 msgContent = node.msg.reduceRight((acc: undefined | Uint8Array, msg: IPacketMsgElement<PacketSendMsgElement>) => {
|
||||
return acc !== undefined ? acc : msg.buildContent();
|
||||
return acc ?? msg.buildContent();
|
||||
}, undefined);
|
||||
const msgElement = node.msg.flatMap(msg => msg.buildElement() ?? []);
|
||||
if (!msgContent && !msgElement.length) {
|
||||
|
@@ -76,13 +76,13 @@ export type rawMsgWithSendMsg = {
|
||||
msg: PacketSendMsgElement[]
|
||||
}
|
||||
|
||||
// TODO: make it become adapter?
|
||||
// work:make it become adapter?
|
||||
export class PacketMsgConverter {
|
||||
private isValidElementType(type: ElementType): type is keyof ElementToPacketMsgConverters {
|
||||
return SupportedElementTypes.includes(type);
|
||||
}
|
||||
|
||||
private rawToPacketMsgConverters: ElementToPacketMsgConverters = {
|
||||
private readonly rawToPacketMsgConverters: ElementToPacketMsgConverters = {
|
||||
[ElementType.TEXT]: (element) => {
|
||||
if (element.textElement?.atType) {
|
||||
return new PacketMsgAtElement(element as SendTextElement);
|
||||
@@ -116,7 +116,7 @@ export class PacketMsgConverter {
|
||||
[ElementType.MARKDOWN]: (element) => {
|
||||
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) => {
|
||||
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";
|
||||
|
||||
// raw <-> packet
|
||||
// TODO: SendStructLongMsgElement
|
||||
// work:SendStructLongMsgElement
|
||||
export abstract class IPacketMsgElement<T extends PacketSendMsgElement> {
|
||||
protected constructor(rawElement: T) {
|
||||
}
|
||||
@@ -118,7 +118,7 @@ export class PacketMsgReplyElement extends IPacketMsgElement<SendReplyElement> {
|
||||
this.targetUin = +(element.replyElement.senderUin ?? 0);
|
||||
this.targetUid = element.replyElement.senderUidStr ?? '';
|
||||
this.time = +(element.replyElement.replyMsgTime ?? 0);
|
||||
this.elems = []; // TODO: in replyElement.sourceMsgTextElems
|
||||
this.elems = []; // work:in replyElement.sourceMsgTextElems
|
||||
}
|
||||
|
||||
get isGroupReply(): boolean {
|
||||
@@ -131,7 +131,7 @@ export class PacketMsgReplyElement extends IPacketMsgElement<SendReplyElement> {
|
||||
origSeqs: [this.isGroupReply ? this.messageClientSeq : this.messageSeq],
|
||||
senderUin: BigInt(this.targetUin),
|
||||
time: this.time,
|
||||
elems: [], // TODO: in replyElement.sourceMsgTextElems
|
||||
elems: [], // work:in replyElement.sourceMsgTextElems
|
||||
pbReserve: {
|
||||
messageId: this.messageId,
|
||||
},
|
||||
@@ -346,9 +346,9 @@ export class PacketMsgPttElement extends IPacketMsgElement<SendPttElement> {
|
||||
constructor(element: SendPttElement) {
|
||||
super(element);
|
||||
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.fileDuration = Math.round(element.pttElement.duration); // TODO: cc
|
||||
this.fileDuration = Math.round(element.pttElement.duration); // work:cc
|
||||
}
|
||||
|
||||
get valid(): boolean {
|
||||
|
@@ -25,7 +25,7 @@ class DownloadOfflineFile extends PacketTransformer<typeof proto.OidbSvcTrpcTcp0
|
||||
return OidbBase.build(0xE37, 800, body, false, false);
|
||||
}
|
||||
|
||||
// TODO: check
|
||||
// work:check
|
||||
parse(data: Buffer) {
|
||||
const oidbBody = OidbBase.parse(data).body;
|
||||
return new NapProtoMsg(proto.OidbSvcTrpcTcp0XE37Response).decode(oidbBody);
|
||||
|
@@ -16,7 +16,7 @@ class FetchSessionKey extends PacketTransformer<typeof proto.HttpConn0x6ff_501Re
|
||||
field4: 1,
|
||||
field6: 3,
|
||||
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,
|
||||
field10: 9,
|
||||
field11: 8,
|
||||
|
@@ -16,7 +16,7 @@ class UploadGroupFile extends PacketTransformer<typeof proto.OidbSvcTrpcTcp0x6D6
|
||||
appId: 4,
|
||||
busId: 102,
|
||||
entrance: 6,
|
||||
targetDirectory: '/', // TODO:
|
||||
targetDirectory: '/', // work:
|
||||
fileName: file.fileName,
|
||||
localDirectory: `/${file.fileName}`,
|
||||
fileSize: BigInt(file.fileSize),
|
||||
|
@@ -40,7 +40,7 @@ class UploadGroupImage extends PacketTransformer<typeof proto.NTV2RichMediaResp>
|
||||
fileName: img.name,
|
||||
type: {
|
||||
type: 1,
|
||||
picFormat: img.picType, //TODO: extend NapCat imgType /cc @MliKiowa
|
||||
picFormat: img.picType, //work:extend NapCat imgType /cc @MliKiowa
|
||||
videoFormat: 0,
|
||||
voiceFormat: 0,
|
||||
},
|
||||
@@ -59,7 +59,7 @@ class UploadGroupImage extends PacketTransformer<typeof proto.NTV2RichMediaResp>
|
||||
extBizInfo: {
|
||||
pic: {
|
||||
bytesPbReserveTroop: Buffer.from("0800180020004200500062009201009a0100a2010c080012001800200028003a00", 'hex'),
|
||||
textSummary: "Nya~", // TODO:
|
||||
textSummary: "Nya~", // work:
|
||||
},
|
||||
video: {
|
||||
bytesPbReserve: Buffer.alloc(0),
|
||||
|
@@ -40,7 +40,7 @@ class UploadPrivateImage extends PacketTransformer<typeof proto.NTV2RichMediaRes
|
||||
fileName: img.name,
|
||||
type: {
|
||||
type: 1,
|
||||
picFormat: img.picType, //TODO: extend NapCat imgType /cc @MliKiowa
|
||||
picFormat: img.picType, //work:extend NapCat imgType /cc @MliKiowa
|
||||
videoFormat: 0,
|
||||
voiceFormat: 0,
|
||||
},
|
||||
@@ -59,7 +59,7 @@ class UploadPrivateImage extends PacketTransformer<typeof proto.NTV2RichMediaRes
|
||||
extBizInfo: {
|
||||
pic: {
|
||||
bytesPbReserveTroop: Buffer.from("0800180020004200500062009201009a0100a2010c080012001800200028003a00", 'hex'),
|
||||
textSummary: "Nya~", // TODO:
|
||||
textSummary: "Nya~", // work:
|
||||
},
|
||||
video: {
|
||||
bytesPbReserve: Buffer.alloc(0),
|
||||
|
@@ -5,17 +5,17 @@ import * as fs from 'fs';
|
||||
import { CalculateStreamBytesTransform } from "@/core/packet/utils/crypto/sha1StreamBytesTransform";
|
||||
|
||||
function sha1Stream(readable: stream.Readable) {
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise<Buffer>((resolve, reject) => {
|
||||
readable.on('error', reject);
|
||||
readable.pipe(crypto.createHash('sha1').on('error', reject).on('data', resolve));
|
||||
}) as Promise<Buffer>;
|
||||
});
|
||||
}
|
||||
|
||||
function md5Stream(readable: stream.Readable) {
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise<Buffer>((resolve, reject) => {
|
||||
readable.on('error', reject);
|
||||
readable.pipe(crypto.createHash('md5').on('error', reject).on('data', resolve));
|
||||
}) as Promise<Buffer>;
|
||||
});
|
||||
}
|
||||
|
||||
export function calculateSha1(filePath: string): Promise<Buffer> {
|
||||
@@ -39,7 +39,7 @@ export function calculateSha1StreamBytes(filePath: string): Promise<Buffer[]> {
|
||||
calculateStreamBytes.on('end', () => {
|
||||
resolve(byteArrayList);
|
||||
});
|
||||
calculateStreamBytes.on('error', (err) => {
|
||||
calculateStreamBytes.on('error', (err: Error) => {
|
||||
reject(err);
|
||||
});
|
||||
readable.pipe(calculateStreamBytes);
|
||||
|
@@ -45,11 +45,17 @@ export class Sha1Stream {
|
||||
let e = this._state[4];
|
||||
|
||||
for (let i = 0; i < 80; i++) {
|
||||
const [f, k] = (i < 20) ? [(b & c) | ((~b) & d), 0x5A827999] :
|
||||
(i < 40) ? [b ^ c ^ d, 0x6ED9EBA1] :
|
||||
(i < 60) ? [(b & c) | (b & d) | (c & d), 0x8F1BBCDC] :
|
||||
[b ^ c ^ d, 0xCA62C1D6];
|
||||
const temp = (this.rotateLeft(a, 5) + f + k + e + w[i]) >>> 0;
|
||||
let temp;
|
||||
if (i < 20) {
|
||||
temp = ((b & c) | (~b & d)) + 0x5A827999;
|
||||
} else if (i < 40) {
|
||||
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;
|
||||
d = c;
|
||||
c = this.rotateLeft(b, 30) >>> 0;
|
||||
|
@@ -3,7 +3,7 @@ import { Sha1Stream } from "@/core/packet/utils/crypto/sha1Stream";
|
||||
|
||||
export class CalculateStreamBytesTransform extends stream.Transform {
|
||||
private readonly blockSize = 1024 * 1024;
|
||||
private sha1: Sha1Stream;
|
||||
private readonly sha1: Sha1Stream;
|
||||
private buffer: Buffer;
|
||||
private bytesRead: number;
|
||||
private readonly byteArrayList: Buffer[];
|
||||
|
@@ -9,10 +9,10 @@ import {
|
||||
type MiniAppTemplateNameList = "bili" | "weibo";
|
||||
|
||||
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;
|
||||
|
||||
private static appMap = new Map<MiniAppTemplateNameList, MiniAppInfo>();
|
||||
private static readonly appMap = new Map<MiniAppTemplateNameList, MiniAppInfo>();
|
||||
|
||||
protected constructor(template: MiniAppReqTemplateParams) {
|
||||
this.template = template;
|
||||
@@ -22,7 +22,7 @@ export abstract class MiniAppInfo {
|
||||
return this.appMap.get(name);
|
||||
}
|
||||
|
||||
static Bili = new class extends MiniAppInfo {
|
||||
static readonly Bili = new class extends MiniAppInfo {
|
||||
constructor() {
|
||||
super({
|
||||
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() {
|
||||
super({
|
||||
sdkId: MiniAppInfo.sdkId,
|
||||
|
@@ -89,7 +89,7 @@ export interface NodeIKernelGroupService {
|
||||
|
||||
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: {
|
||||
groupCode: string,
|
||||
|
@@ -29,10 +29,7 @@ import { NodeIKernelECDHService } from './services/NodeIKernelECDHService';
|
||||
import { NodeIO3MiscService } from './services/NodeIO3MiscService';
|
||||
|
||||
export interface NodeQQNTWrapperUtil {
|
||||
get(): unknown;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-new
|
||||
new(): NodeQQNTWrapperUtil;
|
||||
get(): NodeQQNTWrapperUtil;
|
||||
|
||||
getNTUserDataInfoConfig(): string;
|
||||
|
||||
|
@@ -55,11 +55,12 @@ export async function NCoreInitFramework(
|
||||
// await sleep(2500);
|
||||
// 初始化 NapCatFramework
|
||||
const loaderObject = new NapCatFramework(wrapper, session, logger, loginService, selfInfo, basicInfoWrapper, pathWrapper);
|
||||
await loaderObject.core.initCore();
|
||||
|
||||
//启动WebUi
|
||||
InitWebUi(logger, pathWrapper).then().catch(logger.logError.bind(logger));
|
||||
//初始化LLNC的Onebot实现
|
||||
new NapCatOneBot11Adapter(loaderObject.core, loaderObject.context, pathWrapper);
|
||||
await new NapCatOneBot11Adapter(loaderObject.core, loaderObject.context, pathWrapper).InitOneBot();
|
||||
}
|
||||
|
||||
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 {
|
||||
valid: false,
|
||||
message: errorMessages.join('\n') as string || '未知错误',
|
||||
message: errorMessages.join('\n') ?? '未知错误',
|
||||
};
|
||||
}
|
||||
return {
|
||||
|
@@ -6,7 +6,7 @@ export class GetFriendWithCategory extends BaseAction<void, any> {
|
||||
actionName = ActionName.GetFriendsWithCategory;
|
||||
|
||||
async _handle(payload: void) {
|
||||
return (await this.core.apis.FriendApi.getBuddyV2ExWithCate(true)).map(category => ({
|
||||
return (await this.core.apis.FriendApi.getBuddyV2ExWithCate()).map(category => ({
|
||||
...category,
|
||||
buddyList: OB11Entities.friendsV2(category.buddyList),
|
||||
}));
|
||||
|
@@ -60,7 +60,7 @@ export class GetMiniAppArk extends GetPacketStatusDepends<Payload, {
|
||||
if (payload.type) {
|
||||
reqParam = MiniAppInfoHelper.generateReq(customParams, MiniAppInfo.get(payload.type)!.template);
|
||||
} 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(
|
||||
customParams,
|
||||
{
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import BaseAction from '../BaseAction';
|
||||
import { ActionName, BaseCheckResult } from '../types';
|
||||
import { ActionName } from '../types';
|
||||
|
||||
interface Payload {
|
||||
start: number,
|
||||
@@ -13,9 +13,9 @@ export class GetProfileLike extends BaseAction<Payload, any> {
|
||||
const start = payload.start ? Number(payload.start) : 0;
|
||||
const count = payload.count ? Number(payload.count) : 10;
|
||||
const ret = await this.core.apis.UserApi.getProfileLike(this.core.selfInfo.uid, start, count);
|
||||
const listdata: any[] = ret.info.userLikeInfos[0].voteInfo.userInfos;
|
||||
for (let i = 0; i < listdata.length; i++) {
|
||||
listdata[i].uin = parseInt((await this.core.apis.UserApi.getUinByUidV2(listdata[i].uid)) || '');
|
||||
const listdata = ret.info.userLikeInfos[0].voteInfo.userInfos;
|
||||
for (const item of listdata) {
|
||||
item.uin = parseInt((await this.core.apis.UserApi.getUinByUidV2(item.uid)) || '');
|
||||
}
|
||||
return ret.info.userLikeInfos[0].voteInfo;
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@ export class OCRImage extends BaseAction<Payload, any> {
|
||||
async _handle(payload: Payload) {
|
||||
const { path, success } = (await uri2local(this.core.NapCatTempPath, payload.image));
|
||||
if (!success) {
|
||||
throw `OCR ${payload.image}失败,image字段可能格式不正确`;
|
||||
throw new Error(`OCR ${payload.image}失败,image字段可能格式不正确`);
|
||||
}
|
||||
if (path) {
|
||||
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃,需要提前判断
|
||||
@@ -29,12 +29,12 @@ export class OCRImage extends BaseAction<Payload, any> {
|
||||
fs.unlink(path, () => { });
|
||||
|
||||
if (!ret) {
|
||||
throw `OCR ${payload.file}失败`;
|
||||
throw new Error(`OCR ${payload.file}失败`);
|
||||
}
|
||||
return ret.result;
|
||||
}
|
||||
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 BaseAction from '../BaseAction';
|
||||
import { ActionName, BaseCheckResult } from '../types';
|
||||
import { ChatType, Peer } from '@/core';
|
||||
import { ActionName } from '../types';
|
||||
import { ChatType } from '@/core';
|
||||
|
||||
const SchemaData = {
|
||||
type: 'object',
|
||||
@@ -9,7 +9,7 @@ const SchemaData = {
|
||||
event_type: { type: 'number' },
|
||||
user_id: { type: ['number', 'string'] },
|
||||
},
|
||||
required: ['event_type','user_id'],
|
||||
required: ['event_type', 'user_id'],
|
||||
} as const satisfies JSONSchema;
|
||||
|
||||
type Payload = FromSchema<typeof SchemaData>;
|
||||
|
@@ -26,7 +26,7 @@ export default class SetAvatar extends BaseAction<Payload, null> {
|
||||
async _handle(payload: Payload): Promise<null> {
|
||||
const { path, success } = (await uri2local(this.core.NapCatTempPath, payload.file));
|
||||
if (!success) {
|
||||
throw `头像${payload.file}设置失败,file字段可能格式不正确`;
|
||||
throw new Error(`头像${payload.file}设置失败,file字段可能格式不正确`);
|
||||
}
|
||||
if (path) {
|
||||
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃,需要提前判断
|
||||
@@ -35,18 +35,18 @@ export default class SetAvatar extends BaseAction<Payload, null> {
|
||||
});
|
||||
|
||||
if (!ret) {
|
||||
throw `头像${payload.file}设置失败,api无返回`;
|
||||
throw new Error(`头像${payload.file}设置失败,api无返回`);
|
||||
}
|
||||
// log(`头像设置返回:${JSON.stringify(ret)}`)
|
||||
if (ret.result as number == 1004022) {
|
||||
throw `头像${payload.file}设置失败,文件可能不是图片格式`;
|
||||
throw new Error(`头像${payload.file}设置失败,文件可能不是图片格式`);
|
||||
} else if (ret.result != 0) {
|
||||
throw `头像${payload.file}设置失败,未知的错误,${ret.result}:${ret.errMsg}`;
|
||||
throw new Error(`头像${payload.file}设置失败,未知的错误,${ret.result}:${ret.errMsg}`);
|
||||
}
|
||||
} else {
|
||||
fs.unlink(path, () => { });
|
||||
|
||||
throw `头像${payload.file}设置失败,无法获取头像,文件可能不存在`;
|
||||
throw new Error(`头像${payload.file}设置失败,无法获取头像,文件可能不存在`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@@ -61,7 +61,7 @@ export class GoCQHTTPGetForwardMsgAction extends BaseAction<Payload, any> {
|
||||
}
|
||||
|
||||
const rootMsgId = MessageUnique.getShortIdByMsgId(msgId);
|
||||
const rootMsg = MessageUnique.getMsgIdAndPeerByShortId(rootMsgId || parseInt(msgId));
|
||||
const rootMsg = MessageUnique.getMsgIdAndPeerByShortId(rootMsgId ?? +msgId);
|
||||
if (!rootMsg) {
|
||||
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 MsgCount = +(payload.count ?? 20);
|
||||
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 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 startMsgId = hasMessageSeq ? (MessageUnique.getMsgIdAndPeerByShortId(+payload.message_seq!)?.MsgId ?? payload.message_seq!.toString()) : '0';
|
||||
const msgList = hasMessageSeq ?
|
||||
(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();
|
||||
//转换序号
|
||||
|
@@ -15,7 +15,7 @@ type Payload = FromSchema<typeof SchemaData>;
|
||||
export class GetGroupFileSystemInfo extends BaseAction<Payload, {
|
||||
file_count: number,
|
||||
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
|
||||
}> {
|
||||
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 msgList = hasMessageSeq ?
|
||||
(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();
|
||||
//转换序号
|
||||
|
@@ -34,15 +34,15 @@ export class SendGroupNotice extends BaseAction<Payload, null> {
|
||||
success,
|
||||
} = (await uri2local(this.core.NapCatTempPath, payload.image));
|
||||
if (!success) {
|
||||
throw `群公告${payload.image}设置失败,image字段可能格式不正确`;
|
||||
throw new Error(`群公告${payload.image}设置失败,image字段可能格式不正确`);
|
||||
}
|
||||
if (!path) {
|
||||
throw `群公告${payload.image}设置失败,获取资源失败`;
|
||||
throw new Error(`群公告${payload.image}设置失败,获取资源失败`);
|
||||
}
|
||||
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃,需要提前判断
|
||||
const ImageUploadResult = await this.core.apis.GroupApi.uploadGroupBulletinPic(payload.group_id.toString(), path);
|
||||
if (ImageUploadResult.errCode != 0) {
|
||||
throw `群公告${payload.image}设置失败,图片上传失败`;
|
||||
throw new Error(`群公告${payload.image}设置失败,图片上传失败`);
|
||||
}
|
||||
|
||||
unlink(path, () => {
|
||||
|
@@ -27,24 +27,24 @@ export default class SetGroupPortrait extends BaseAction<Payload, any> {
|
||||
async _handle(payload: Payload): Promise<any> {
|
||||
const { path, success } = (await uri2local(this.core.NapCatTempPath, payload.file));
|
||||
if (!success) {
|
||||
throw `头像${payload.file}设置失败,file字段可能格式不正确`;
|
||||
throw new Error(`头像${payload.file}设置失败,file字段可能格式不正确`);
|
||||
}
|
||||
if (path) {
|
||||
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃,需要提前判断
|
||||
const ret = await this.core.apis.GroupApi.setGroupAvatar(payload.group_id.toString(), path);
|
||||
fs.unlink(path, () => { });
|
||||
if (!ret) {
|
||||
throw `头像${payload.file}设置失败,api无返回`;
|
||||
throw new Error(`头像${payload.file}设置失败,api无返回`);
|
||||
}
|
||||
if (ret.result as number == 1004022) {
|
||||
throw `头像${payload.file}设置失败,文件可能不是图片格式或权限不足`;
|
||||
throw new Error(`头像${payload.file}设置失败,文件可能不是图片格式或权限不足`);
|
||||
} else if (ret.result != 0) {
|
||||
throw `头像${payload.file}设置失败,未知的错误,${ret.result}:${ret.errMsg}`;
|
||||
throw new Error(`头像${payload.file}设置失败,未知的错误,${ret.result}:${ret.errMsg}`);
|
||||
}
|
||||
return ret;
|
||||
} else {
|
||||
fs.unlink(path, () => {});
|
||||
throw `头像${payload.file}设置失败,无法获取头像,文件可能不存在`;
|
||||
fs.unlink(path, () => { });
|
||||
throw new Error(`头像${payload.file}设置失败,无法获取头像,文件可能不存在`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -14,7 +14,7 @@ const SchemaData = {
|
||||
|
||||
type Payload = FromSchema<typeof SchemaData>;
|
||||
|
||||
export class SetQQProfile extends BaseAction<Payload, any | null> {
|
||||
export class SetQQProfile extends BaseAction<Payload, any> {
|
||||
actionName = ActionName.SetQQProfile;
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
|
@@ -27,7 +27,7 @@ export default class GoCQHTTPUploadPrivateFile extends BaseAction<Payload, null>
|
||||
if (payload.user_id) {
|
||||
const peerUid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
||||
if (!peerUid) {
|
||||
throw `私聊${payload.user_id}不存在`;
|
||||
throw new Error( `私聊${payload.user_id}不存在`);
|
||||
}
|
||||
const isBuddy = await this.core.apis.FriendApi.isBuddy(peerUid);
|
||||
return { chatType: isBuddy ? ChatType.KCHATTYPEC2C : ChatType.KCHATTYPETEMPC2CFROMGROUP, peerUid };
|
||||
|
@@ -3,7 +3,6 @@ import { OB11Entities } from '@/onebot/entities';
|
||||
import BaseAction from '../BaseAction';
|
||||
import { ActionName } from '../types';
|
||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||
import { GroupMember } from '@/core';
|
||||
|
||||
const SchemaData = {
|
||||
type: 'object',
|
||||
@@ -44,7 +43,7 @@ class GetGroupMemberInfo extends BaseAction<Payload, OB11GroupMember> {
|
||||
} else {
|
||||
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 { ActionName } from '../types';
|
||||
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||
|
@@ -26,7 +26,7 @@ export class SendGroupAiRecord extends GetPacketStatusDepends<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 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) {
|
||||
throw new Error(errMsg);
|
||||
}
|
||||
|
@@ -28,7 +28,7 @@ class GetMsg extends BaseAction<Payload, OB11Message> {
|
||||
throw Error('参数message_id不能为空');
|
||||
}
|
||||
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) {
|
||||
throw new Error('消息不存在');
|
||||
}
|
||||
|
@@ -30,7 +30,7 @@ class MarkMsgAsRead extends BaseAction<PlayloadType, null> {
|
||||
if (payload.user_id) {
|
||||
const peerUid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
|
||||
if (!peerUid) {
|
||||
throw `私聊${payload.user_id}不存在`;
|
||||
throw new Error( `私聊${payload.user_id}不存在`);
|
||||
}
|
||||
const isBuddy = await this.core.apis.FriendApi.isBuddy(peerUid);
|
||||
return { chatType: isBuddy ? ChatType.KCHATTYPEC2C : ChatType.KCHATTYPETEMPC2CFROMGROUP, peerUid };
|
||||
|
@@ -68,7 +68,7 @@ export async function createContext(core: NapCatCore, payload: OB11PostContext,
|
||||
}
|
||||
return {
|
||||
chatType: ChatType.KCHATTYPEC2C,
|
||||
peerUid: Uid!,
|
||||
peerUid: Uid,
|
||||
guildId: '',
|
||||
};
|
||||
}
|
||||
@@ -133,7 +133,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
||||
guildId: '',
|
||||
peerUid: peer.peerUid,
|
||||
chatType: peer.chatType,
|
||||
}, (returnMsgAndResId.message)!.msgId);
|
||||
}, (returnMsgAndResId.message).msgId);
|
||||
return { message_id: msgShortId!, res_id: returnMsgAndResId.res_id };
|
||||
} else if (returnMsgAndResId.res_id && !returnMsgAndResId.message) {
|
||||
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
|
||||
.createSendElements(messages, peer);
|
||||
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?: {
|
||||
@@ -175,7 +175,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
||||
|
||||
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, {
|
||||
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用户",
|
||||
}, dp + 1);
|
||||
sendElements = uploadReturnData?.finallySendElements ? [uploadReturnData.finallySendElements] : [];
|
||||
@@ -185,7 +185,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
||||
}
|
||||
|
||||
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用户",
|
||||
groupId: msgPeer.chatType === ChatType.KCHATTYPEGROUP ? +msgPeer.peerUid : undefined,
|
||||
time: Number(node.data.time) || Date.now(),
|
||||
@@ -194,7 +194,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
||||
logger.logDebug(`handleForwardedNodesPacket[SendRaw] 开始转换 ${stringifyWithBigInt(packetMsgElements)}`);
|
||||
const transformedMsg = this.core.apis.PacketApi.pkt.msgConverter.rawMsgWithSendMsgToPacketMsg(packetMsgElements);
|
||||
logger.logDebug(`handleForwardedNodesPacket[SendRaw] 转换为 ${stringifyWithBigInt(transformedMsg)}`);
|
||||
packetMsg.push(transformedMsg!);
|
||||
packetMsg.push(transformedMsg);
|
||||
} else if (node.data.id) {
|
||||
const id = node.data.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]);
|
||||
const transformedMsg = this.core.apis.PacketApi.pkt.msgConverter.rawMsgToPacketMsg(msg, msgPeer);
|
||||
logger.logDebug(`handleForwardedNodesPacket[PureRaw] 转换为 ${stringifyWithBigInt(transformedMsg)}`);
|
||||
packetMsg.push(transformedMsg!);
|
||||
packetMsg.push(transformedMsg);
|
||||
} else {
|
||||
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>{
|
||||
if (!this.core.apis.PacketApi.available) {
|
||||
// TODO: add error stack?
|
||||
// work:add error stack?
|
||||
return {
|
||||
valid: false,
|
||||
message: "packetBackend不可用,请参照文档 https://napneko.github.io/config/advanced 和启动日志检查packetBackend状态或进行配置!" +
|
||||
|
@@ -18,13 +18,11 @@ export default class SendLike extends BaseAction<Payload, null> {
|
||||
payloadSchema = SchemaData;
|
||||
|
||||
async _handle(payload: Payload): Promise<null> {
|
||||
//logDebug('点赞参数', payload);
|
||||
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);
|
||||
//logDebug('点赞结果', result);
|
||||
if (result.result !== 0) {
|
||||
throw `点赞失败 ${result.errMsg}`;
|
||||
throw new Error(`点赞失败 ${result.errMsg}`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@@ -40,7 +40,7 @@ export class OneBotGroupApi {
|
||||
if (msg.senderUin && msg.senderUin !== '0') {
|
||||
const member = await this.core.apis.GroupApi.getGroupMember(msg.peerUid, msg.senderUin);
|
||||
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);
|
||||
member.cardName = newCardName;
|
||||
return event;
|
||||
@@ -48,7 +48,7 @@ export class OneBotGroupApi {
|
||||
}
|
||||
|
||||
for (const element of msg.elements) {
|
||||
if (element.grayTipElement && element.grayTipElement.groupElement) {
|
||||
if (element.grayTipElement?.groupElement) {
|
||||
const groupElement = element.grayTipElement.groupElement;
|
||||
if (groupElement.type == TipGroupElementType.memberIncrease) {
|
||||
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,
|
||||
name: element.fileElement.fileName,
|
||||
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(
|
||||
this.core,
|
||||
parseInt(msg.peerUid),
|
||||
parseInt((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[0].uid),
|
||||
+await this.core.apis.UserApi.getUinByUidV2(poke_uid[1].uid),
|
||||
pokedetail,
|
||||
);
|
||||
}
|
||||
@@ -165,13 +165,13 @@ export class OneBotGroupApi {
|
||||
async parseGroupBanEvent(GroupCode: string, grayTipElement: GrayTipElement) {
|
||||
const groupElement = grayTipElement?.groupElement;
|
||||
if (!groupElement?.shutUp) return undefined;
|
||||
const memberUid = groupElement.shutUp!.member.uid;
|
||||
const adminUid = groupElement.shutUp!.admin.uid;
|
||||
const memberUid = groupElement.shutUp.member.uid;
|
||||
const adminUid = groupElement.shutUp.admin.uid;
|
||||
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';
|
||||
if (memberUid) {
|
||||
memberUin = (await this.core.apis.GroupApi.getGroupMember(GroupCode, memberUid))?.uin || '';
|
||||
memberUin = (await this.core.apis.GroupApi.getGroupMember(GroupCode, memberUid))?.uin ?? '';
|
||||
} else {
|
||||
memberUin = '0'; // 0表示全员禁言
|
||||
if (duration > 0) {
|
||||
@@ -225,7 +225,7 @@ export class OneBotGroupApi {
|
||||
const memberUin = member?.uin;
|
||||
const adminMember = await this.core.apis.GroupApi.getGroupMember(GroupCode, groupElement.adminUid);
|
||||
if (memberUin) {
|
||||
const operatorUin = adminMember?.uin || memberUin;
|
||||
const operatorUin = adminMember?.uin ?? memberUin;
|
||||
return new OB11GroupIncreaseEvent(
|
||||
this.core,
|
||||
parseInt(GroupCode),
|
||||
@@ -240,7 +240,7 @@ export class OneBotGroupApi {
|
||||
async parseGroupKickEvent(GroupCode: string, grayTipElement: GrayTipElement) {
|
||||
const groupElement = grayTipElement?.groupElement;
|
||||
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) {
|
||||
return new OB11GroupDecreaseEvent(
|
||||
this.core,
|
||||
|
@@ -187,6 +187,7 @@ export class OneBotMsgApi {
|
||||
url: url,
|
||||
key: _.key,
|
||||
emoji_id: _.emojiId,
|
||||
emoji_package_id: _.emojiPackageId,
|
||||
file_unique: _.key
|
||||
},
|
||||
};
|
||||
@@ -699,16 +700,16 @@ export class OneBotMsgApi {
|
||||
//跳过空消息
|
||||
const resMsg: OB11Message = {
|
||||
self_id: parseInt(this.core.selfInfo.uin),
|
||||
user_id: parseInt(msg.senderUin!),
|
||||
user_id: parseInt(msg.senderUin),
|
||||
time: parseInt(msg.msgTime) || Date.now(),
|
||||
message_id: msg.id!,
|
||||
message_seq: msg.id!,
|
||||
real_id: msg.id!,
|
||||
message_type: msg.chatType == ChatType.KCHATTYPEGROUP ? 'group' : 'private',
|
||||
sender: {
|
||||
user_id: parseInt(msg.senderUin || '0'),
|
||||
user_id: +(msg.senderUin ?? 0),
|
||||
nickname: msg.sendNickName,
|
||||
card: msg.sendMemberName || '',
|
||||
card: msg.sendMemberName ?? '',
|
||||
},
|
||||
raw_message: '',
|
||||
font: 14,
|
||||
|
@@ -25,7 +25,7 @@ export class OB11Entities {
|
||||
user_id: parseInt(rawFriend.coreInfo.uin),
|
||||
nickname: rawFriend.coreInfo.nick,
|
||||
remark: rawFriend.coreInfo.remark ?? rawFriend.coreInfo.nick,
|
||||
sex: this.sex(rawFriend.baseInfo.sex!),
|
||||
sex: this.sex(rawFriend.baseInfo.sex),
|
||||
level: 0,
|
||||
}));
|
||||
}
|
||||
@@ -66,7 +66,7 @@ export class OB11Entities {
|
||||
sex: OB11Entities.sex(member.sex!),
|
||||
age: member.age ?? 0,
|
||||
area: '',
|
||||
level: member.memberRealLevel ?? '0',
|
||||
level: member.memberRealLevel?.toString() ?? '0',
|
||||
qq_level: member.qqLevel && calcQQLevel(member.qqLevel) || 0,
|
||||
join_time: +member.joinTime,
|
||||
last_sent_time: +member.lastSpeakTime,
|
||||
@@ -76,7 +76,7 @@ export class OB11Entities {
|
||||
is_robot: member.isRobot,
|
||||
shut_up_timestamp: member.shutUpTime,
|
||||
role: OB11Entities.groupMemberRole(member.role),
|
||||
title: member.memberSpecialTitle || '',
|
||||
title: member.memberSpecialTitle ?? '',
|
||||
|
||||
};
|
||||
}
|
||||
|
@@ -11,11 +11,11 @@ export class OB11HeartbeatEvent extends OB11BaseMetaEvent {
|
||||
status: HeartbeatStatus;
|
||||
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);
|
||||
this.interval = interval;
|
||||
this.status = {
|
||||
online: isOnline && true,
|
||||
online: isOnline,
|
||||
good: isGood,
|
||||
};
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@ export type GroupDecreaseSubType = 'leave' | 'kick' | 'kick_me';
|
||||
|
||||
export class OB11GroupDecreaseEvent extends OB11GroupNoticeEvent {
|
||||
notice_type = 'group_decrease';
|
||||
sub_type: GroupDecreaseSubType = 'leave'; // TODO: 实现其他几种子类型的识别 ("leave" | "kick" | "kick_me")
|
||||
sub_type: GroupDecreaseSubType = 'leave'; // work:实现其他几种子类型的识别 ("leave" | "kick" | "kick_me")
|
||||
operator_id: number;
|
||||
|
||||
constructor(core: NapCatCore, groupId: number, userId: number, operatorId: number, subType: GroupDecreaseSubType = 'leave') {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { OB11BaseNoticeEvent } from './OB11BaseNoticeEvent';
|
||||
import { NapCatCore } from '@/core';
|
||||
|
||||
//输入状态事件 初步完成 Mlikio wa Todo 需要做一些过滤
|
||||
//work: 输入状态事件 初步完成 Mlikiowa 需要做一些过滤
|
||||
export class OB11InputStatusEvent extends OB11BaseNoticeEvent {
|
||||
notice_type = 'notify';
|
||||
sub_type = 'input_status';
|
||||
|
@@ -25,7 +25,7 @@ export class OB11GroupPokeEvent extends OB11PokeEvent {
|
||||
raw_info: any;
|
||||
|
||||
//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);
|
||||
this.group_id = group_id;
|
||||
this.target_id = target_id;
|
||||
|
@@ -6,7 +6,6 @@ import {
|
||||
GroupNotifyMsgStatus,
|
||||
GroupNotifyMsgType,
|
||||
InstanceContext,
|
||||
MsgSourceType,
|
||||
NapCatCore,
|
||||
NodeIKernelBuddyListener,
|
||||
NodeIKernelGroupListener,
|
||||
@@ -45,8 +44,6 @@ import { OB11FriendRecallNoticeEvent } from '@/onebot/event/notice/OB11FriendRec
|
||||
import { OB11GroupRecallNoticeEvent } from '@/onebot/event/notice/OB11GroupRecallNoticeEvent';
|
||||
import { LRUCache } from '@/common/lru-cache';
|
||||
import { NodeIKernelRecentContactListener } from '@/core/listeners/NodeIKernelRecentContactListener';
|
||||
import { Native } from '@/native';
|
||||
import { decodeMessage, decodeRecallGroup } from "@/core/helper/adaptSysMessageDecoder";
|
||||
import { BotOfflineEvent } from './event/notice/BotOfflineEvent';
|
||||
|
||||
//OneBot实现类
|
||||
@@ -58,8 +55,7 @@ export class NapCatOneBot11Adapter {
|
||||
apis: StableOneBotApiWrapper;
|
||||
networkManager: OB11NetworkManager;
|
||||
actions: ActionMap;
|
||||
nativeCore: Native | undefined;
|
||||
private bootTime = Date.now() / 1000;
|
||||
private readonly bootTime = Date.now() / 1000;
|
||||
recallMsgCache = new LRUCache<string, RawMessage>(100);
|
||||
|
||||
constructor(core: NapCatCore, context: InstanceContext, pathWrapper: NapCatPathWrapper) {
|
||||
@@ -75,41 +71,8 @@ export class NapCatOneBot11Adapter {
|
||||
};
|
||||
this.actions = createActionMap(this, core);
|
||||
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() {
|
||||
const selfInfo = this.core.selfInfo;
|
||||
const ob11Config = this.configLoader.configData;
|
||||
@@ -211,8 +174,7 @@ export class NapCatOneBot11Adapter {
|
||||
} else {
|
||||
await this.networkManager.closeAdapterByPredicate(adapter => adapter instanceof OB11ActiveHttpAdapter);
|
||||
}
|
||||
} else {
|
||||
if (now.http.enablePost) {
|
||||
} else if (now.http.enablePost) {
|
||||
const { added, removed } = this.findDifference<string>(prev.http.postUrls, now.http.postUrls);
|
||||
await this.networkManager.closeAdapterByPredicate(
|
||||
adapter => adapter instanceof OB11ActiveHttpAdapter && removed.includes(adapter.url),
|
||||
@@ -223,7 +185,7 @@ export class NapCatOneBot11Adapter {
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// check difference in passive websocket (Ws)
|
||||
if (prev.ws.enable !== now.ws.enable) {
|
||||
@@ -251,8 +213,7 @@ export class NapCatOneBot11Adapter {
|
||||
adapter => adapter instanceof OB11ActiveWebSocketAdapter,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (now.reverseWs.enable) {
|
||||
} else if (now.reverseWs.enable) {
|
||||
const { added, removed } = this.findDifference<string>(prev.reverseWs.urls, now.reverseWs.urls);
|
||||
await this.networkManager.closeAdapterByPredicate(
|
||||
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[] } {
|
||||
@@ -305,10 +266,8 @@ export class NapCatOneBot11Adapter {
|
||||
},
|
||||
m.msgId,
|
||||
);
|
||||
// if (m.sourceType == MsgSourceType.K_DOWN_SOURCETYPE_AIOINNER) {
|
||||
await this.emitMsg(m)
|
||||
.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);
|
||||
await this.networkManager.emitEvent(new OB11FriendRequestEvent(
|
||||
this.core,
|
||||
parseInt(requesterUin!),
|
||||
+requesterUin,
|
||||
req.extWords,
|
||||
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) {
|
||||
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 subType: GroupDecreaseSubType = 'leave';
|
||||
if (notify.user2.uid) {
|
||||
@@ -458,7 +417,7 @@ export class NapCatOneBot11Adapter {
|
||||
].includes(notify.type) && notify.status == GroupNotifyMsgStatus.KUNHANDLE) {
|
||||
this.context.logger.logDebug('有加群请求');
|
||||
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))) {
|
||||
requestUin = (await this.core.apis.UserApi.getUserDetailInfo(notify.user1.uid)).uin;
|
||||
}
|
||||
@@ -540,10 +499,9 @@ export class NapCatOneBot11Adapter {
|
||||
this.context.logger.logDebug('转化为 OB11Message', ob11Msg);
|
||||
if (debug) {
|
||||
ob11Msg.raw = message;
|
||||
} else {
|
||||
if (ob11Msg.message.length === 0) {
|
||||
} else if (ob11Msg.message.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
const isSelfMsg = ob11Msg.user_id.toString() == this.core.selfInfo.uin;
|
||||
if (isSelfMsg && !reportSelfMessage) {
|
||||
@@ -603,7 +561,7 @@ export class NapCatOneBot11Adapter {
|
||||
for (const message of msgList) {
|
||||
// log("message update", message.sendStatus, message.msgId, message.msgSeq)
|
||||
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);
|
||||
// 撤回消息上报
|
||||
let oriMessageId = MessageUnique.getShortIdByMsgId(message.msgId);
|
||||
@@ -613,7 +571,7 @@ export class NapCatOneBot11Adapter {
|
||||
if (message.chatType == ChatType.KCHATTYPEC2C) {
|
||||
const friendRecallEvent = new OB11FriendRecallNoticeEvent(
|
||||
this.core,
|
||||
parseInt(message!.senderUin),
|
||||
+message.senderUin,
|
||||
oriMessageId,
|
||||
);
|
||||
this.networkManager.emitEvent(friendRecallEvent)
|
||||
@@ -624,13 +582,13 @@ export class NapCatOneBot11Adapter {
|
||||
const operatorUid = element.grayTipElement?.revokeElement.operatorUid;
|
||||
if (!operatorUid) return;
|
||||
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(
|
||||
this.core,
|
||||
parseInt(message.peerUin),
|
||||
parseInt(message.senderUin),
|
||||
parseInt(operatorId),
|
||||
+message.peerUin,
|
||||
+message.senderUin,
|
||||
+operatorId,
|
||||
oriMessageId
|
||||
);
|
||||
this.networkManager.emitEvent(groupRecallEvent)
|
||||
|
@@ -18,7 +18,7 @@ export class OB11ActiveWebSocketAdapter implements IOB11NetworkAdapter {
|
||||
public url: string,
|
||||
public reconnectIntervalInMillis: number,
|
||||
public heartbeatIntervalInMillis: number,
|
||||
private token: string,
|
||||
private readonly token: string,
|
||||
public core: NapCatCore,
|
||||
public actions: ActionMap,
|
||||
) {
|
||||
@@ -37,7 +37,7 @@ export class OB11ActiveWebSocketAdapter implements IOB11NetworkAdapter {
|
||||
}
|
||||
this.heartbeatRef = setInterval(() => {
|
||||
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);
|
||||
await this.tryConnect();
|
||||
@@ -148,7 +148,6 @@ export class OB11ActiveWebSocketAdapter implements IOB11NetworkAdapter {
|
||||
return;
|
||||
}
|
||||
const retdata = await action.websocketHandle(receiveData.params, echo ?? '');
|
||||
const packet = Object.assign({}, retdata);
|
||||
this.checkStateAndReply<any>(packet);
|
||||
this.checkStateAndReply<any>({ ...retdata });
|
||||
}
|
||||
}
|
||||
|
@@ -145,7 +145,7 @@ export class OB11PassiveWebSocketAdapter implements IOB11NetworkAdapter {
|
||||
this.wsClientsMutex.runExclusive(async () => {
|
||||
this.wsClientWithEvent.forEach((wsClient) => {
|
||||
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;
|
||||
}
|
||||
const retdata = await action.websocketHandle(receiveData.params, echo ?? '');
|
||||
const packet = Object.assign({}, retdata);
|
||||
this.checkStateAndReply<any>(packet, wsClient);
|
||||
this.checkStateAndReply<any>({ ...retdata }, wsClient);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -34,33 +34,16 @@ program.option('-q, --qq [number]', 'QQ号').parse(process.argv);
|
||||
const cmdOptions = program.opts();
|
||||
|
||||
// NapCat Shell App ES 入口文件
|
||||
export async function NCoreInitShell() {
|
||||
console.log('NapCat Shell App Loading...');
|
||||
async function handleUncaughtExceptions(logger: LogWrapper) {
|
||||
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) => {
|
||||
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();
|
||||
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] = (() => {
|
||||
function getDataPaths(wrapper: WrapperNodeApi): [string, string] {
|
||||
if (os.platform() === 'darwin') {
|
||||
const userPath = os.homedir();
|
||||
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');
|
||||
return [dataPath, dataPathGlobal];
|
||||
})();
|
||||
}
|
||||
|
||||
function getPlatformType(): PlatformType {
|
||||
const platformMapping: Partial<Record<NodeJS.Platform, PlatformType>> = {
|
||||
win32: PlatformType.KWINDOWS,
|
||||
darwin: PlatformType.KMAC,
|
||||
linux: PlatformType.KLINUX,
|
||||
};
|
||||
const systemPlatform = platformMapping[os.platform()] ?? PlatformType.KWINDOWS;
|
||||
if (!basicInfoWrapper.QQVersionAppid || !basicInfoWrapper.QQVersionQua) throw new Error('QQVersionAppid or QQVersionQua is not defined');
|
||||
// from initConfig
|
||||
return platformMapping[os.platform()] ?? PlatformType.KWINDOWS;
|
||||
}
|
||||
|
||||
async function initializeEngine(
|
||||
engine: any,
|
||||
basicInfoWrapper: QQBasicInfoWrapper,
|
||||
dataPathGlobal: string,
|
||||
systemPlatform: PlatformType,
|
||||
systemVersion: string
|
||||
) {
|
||||
engine.initWithDeskTopConfig(
|
||||
{
|
||||
base_path_prefix: '',
|
||||
@@ -98,33 +90,38 @@ export async function NCoreInitShell() {
|
||||
},
|
||||
new NodeIGlobalAdapter(),
|
||||
);
|
||||
}
|
||||
|
||||
async function initializeLoginService(
|
||||
loginService: NodeIKernelLoginService,
|
||||
basicInfoWrapper: QQBasicInfoWrapper,
|
||||
dataPathGlobal: string,
|
||||
systemVersion: string,
|
||||
hostname: string
|
||||
) {
|
||||
loginService.initConfig({
|
||||
machineId: '',
|
||||
appid: basicInfoWrapper.QQVersionAppid,
|
||||
appid: basicInfoWrapper.QQVersionAppid ?? '',
|
||||
platVer: systemVersion,
|
||||
commonPath: dataPathGlobal,
|
||||
clientVer: basicInfoWrapper.getFullQQVesion(),
|
||||
hostName: hostname,
|
||||
});
|
||||
}
|
||||
|
||||
let quickLoginUin = cmdOptions.qq; // undefined | 'true' | string
|
||||
const historyLoginList = (await loginService.getLoginList()).LocalLoginInfoList;
|
||||
if (quickLoginUin == 'true') {
|
||||
if (historyLoginList.length > 0) {
|
||||
quickLoginUin = historyLoginList[0].uin;
|
||||
logger.log(`-q 指令指定使用最近的 QQ ${quickLoginUin} 进行快速登录`);
|
||||
} else {
|
||||
quickLoginUin = '';
|
||||
}
|
||||
}
|
||||
const dataTimestape = new Date().getTime().toString();
|
||||
o3Service.reportAmgomWeather('login', 'a1', [dataTimestape, '0', '0']);
|
||||
const selfInfo = await new Promise<SelfInfo>((resolve) => {
|
||||
async function handleLogin(
|
||||
loginService: NodeIKernelLoginService,
|
||||
logger: LogWrapper,
|
||||
pathWrapper: NapCatPathWrapper,
|
||||
quickLoginUin: string | undefined,
|
||||
historyLoginList: any[]
|
||||
): Promise<SelfInfo> {
|
||||
return new Promise<SelfInfo>((resolve) => {
|
||||
const loginListener = new NodeIKernelLoginListener();
|
||||
let isLogined = false;
|
||||
// from constructor
|
||||
|
||||
loginListener.onUserLoggedIn = (userid: string) => {
|
||||
logger.logError.bind(logger)(`当前账号(${userid})已登录,无法重复登录`);
|
||||
logger.logError(`当前账号(${userid})已登录,无法重复登录`);
|
||||
};
|
||||
|
||||
loginListener.onQRCodeLoginSucceed = async (loginResult) => {
|
||||
@@ -132,13 +129,12 @@ export async function NCoreInitShell() {
|
||||
resolve({
|
||||
uid: loginResult.uid,
|
||||
uin: loginResult.uin,
|
||||
nick: '', // 获取不到
|
||||
nick: '',
|
||||
online: true,
|
||||
});
|
||||
};
|
||||
|
||||
loginListener.onQRCodeGetPicture = ({ pngBase64QrcodeData, qrcodeUrl }) => {
|
||||
//设置WebuiQrcode
|
||||
WebUiDataRuntime.setQQLoginQrcodeURL(qrcodeUrl);
|
||||
|
||||
const realBase64 = pngBase64QrcodeData.replace(/^data:image\/\w+;base64,/, '');
|
||||
@@ -157,50 +153,46 @@ export async function NCoreInitShell() {
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
loginListener.onQRCodeSessionFailed = (errType: number, errCode: number, errMsg: string) => {
|
||||
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) {
|
||||
// 二维码过期刷新
|
||||
}
|
||||
loginService.getQRCodePicture();
|
||||
}
|
||||
};
|
||||
|
||||
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));
|
||||
const isConnect = loginService.connect();
|
||||
if (!isConnect) {
|
||||
logger.logError.bind(logger)('核心登录服务连接失败!');
|
||||
logger.logError('核心登录服务连接失败!');
|
||||
return;
|
||||
}
|
||||
|
||||
logger.log('核心登录服务连接成功!');
|
||||
// 实现WebUi快速登录
|
||||
|
||||
loginService.getLoginList().then((res) => {
|
||||
// 遍历 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()));
|
||||
});
|
||||
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) => {
|
||||
return await new Promise((resolve) => {
|
||||
if (uin) {
|
||||
logger.log.bind(logger)('正在快速登录 ', uin);
|
||||
logger.log('正在快速登录 ', uin);
|
||||
loginService.quickLoginWithUin(uin).then(res => {
|
||||
if (res.loginErrorInfo.errMsg) {
|
||||
resolve({ result: false, message: res.loginErrorInfo.errMsg });
|
||||
}
|
||||
resolve({ result: true, message: '' });
|
||||
}).catch((e) => {
|
||||
logger.logError.bind(logger)(e);
|
||||
logger.logError(e);
|
||||
resolve({ result: false, message: '快速登录发生错误' });
|
||||
});
|
||||
} else {
|
||||
@@ -216,14 +208,14 @@ export async function NCoreInitShell() {
|
||||
loginService.quickLoginWithUin(quickLoginUin)
|
||||
.then(result => {
|
||||
if (result.loginErrorInfo.errMsg) {
|
||||
logger.logError.bind(logger)('快速登录错误:', result.loginErrorInfo.errMsg);
|
||||
logger.logError('快速登录错误:', result.loginErrorInfo.errMsg);
|
||||
if (!isLogined) loginService.getQRCodePicture();
|
||||
}
|
||||
})
|
||||
.catch();
|
||||
}, 1000);
|
||||
} else {
|
||||
logger.logError.bind(logger)('快速登录失败,未找到该 QQ 历史登录记录,将使用二维码登录方式');
|
||||
logger.logError('快速登录失败,未找到该 QQ 历史登录记录,将使用二维码登录方式');
|
||||
if (!isLogined) loginService.getQRCodePicture();
|
||||
}
|
||||
} else {
|
||||
@@ -237,37 +229,20 @@ export async function NCoreInitShell() {
|
||||
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();
|
||||
guid = guid.slice(0, 8) + '-' + guid.slice(8, 12) + '-' + guid.slice(12, 16) + '-' + guid.slice(16, 20) + '-' + guid.slice(20);
|
||||
//console.log('guid:', guid);
|
||||
//NodeIO3MiscService/reportAmgomWeather login a6 [ '1726748166943', '184', '329' ]
|
||||
o3Service.reportAmgomWeather('login', 'a6', [dataTimestape, '184', '329']);
|
||||
// if(session.getUnitedConfigService()){
|
||||
// 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,
|
||||
);
|
||||
async function initializeSession(
|
||||
session: NodeIQQNTWrapperSession,
|
||||
sessionConfig: any,
|
||||
logger: LogWrapper
|
||||
) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const sessionListener = new NodeIKernelSessionListener();
|
||||
sessionListener.onSessionInitComplete = (r: unknown) => {
|
||||
if (r === 0) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(r);
|
||||
reject(new Error('登录异常' + r?.toString()));
|
||||
}
|
||||
};
|
||||
session.init(
|
||||
@@ -278,21 +253,74 @@ export async function NCoreInitShell() {
|
||||
);
|
||||
try {
|
||||
session.startNT(0);
|
||||
} catch (_) { /* Empty */
|
||||
} catch (_) {
|
||||
try {
|
||||
session.startNT();
|
||||
} catch (e) {
|
||||
reject('init failed ' + e);
|
||||
} catch (e: unknown) {
|
||||
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');
|
||||
fs.mkdirSync(dataPath, { recursive: true });
|
||||
logger.logDebug('本账号数据/缓存目录:', accountDataPath);
|
||||
|
||||
new NapCatShell(
|
||||
await new NapCatShell(
|
||||
wrapper,
|
||||
session,
|
||||
logger,
|
||||
@@ -300,9 +328,10 @@ export async function NCoreInitShell() {
|
||||
selfInfo,
|
||||
basicInfoWrapper,
|
||||
pathWrapper,
|
||||
);
|
||||
).InitNapCat();
|
||||
}
|
||||
|
||||
|
||||
export class NapCatShell {
|
||||
readonly core: NapCatCore;
|
||||
readonly context: InstanceContext;
|
||||
@@ -327,8 +356,13 @@ export class NapCatShell {
|
||||
};
|
||||
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