Compare commits

...

125 Commits

Author SHA1 Message Date
手瓜一十雪
44f51a93c8 release: 2.2.13 2024-08-26 17:46:17 +08:00
手瓜一十雪
66c8537b41 feat: support->27391 2024-08-26 17:44:04 +08:00
手瓜一十雪
86ae6dd332 fix: music sign 2024-08-26 17:23:39 +08:00
Seijo Cecilia
69380c9c73 Merge remote-tracking branch 'origin/main' 2024-08-26 16:27:43 +08:00
Seijo Cecilia
3d3759137c fix: remove redundant uid in GetStrangerInfo 2024-08-26 16:27:29 +08:00
手瓜一十雪
9b9b8f6f6f fix: type 2024-08-26 16:26:10 +08:00
手瓜一十雪
8ff87a8245 feat: getGroupExtFE0Info 2024-08-26 16:12:29 +08:00
Seijo Cecilia
d1896da171 update: promise executor functions should not be async 2024-08-26 15:40:27 +08:00
Seijo Cecilia
0bc4f6fd96 refactor: enhanced type definition for other methods 2024-08-26 15:37:17 +08:00
Seijo Cecilia
b16a429686 chore: reformat code style 2024-08-26 14:58:04 +08:00
Seijo Cecilia
fa1d266696 Merge remote-tracking branch 'origin/main' 2024-08-26 14:36:41 +08:00
Seijo Cecilia
d5dd2e9551 update: optimize entity factory (formerly converter.ts) 2024-08-26 14:36:10 +08:00
手瓜一十雪
be57c312c4 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-08-26 14:30:29 +08:00
手瓜一十雪
f180687ba3 refactor: action param handle 2024-08-26 14:30:11 +08:00
Seijo Cecilia
3f3d9cc6f1 refactor: move calls & clean code 2024-08-26 14:22:08 +08:00
Seijo Cecilia
4f98c0d045 refactor: make quick action apis instance methods 2024-08-26 14:14:49 +08:00
Seijo Cecilia
c254441d40 Merge remote-tracking branch 'origin/main' 2024-08-26 14:01:21 +08:00
手瓜一十雪
17cbe74fa3 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-08-26 14:01:06 +08:00
Seijo Cecilia
7aa0bd9b79 refactor: move all callNormalEvent calls to V2 substitutes 2024-08-26 14:00:48 +08:00
手瓜一十雪
2553cf6b72 style: lint 2024-08-26 13:58:28 +08:00
linyuchen
fe9050aeda Update README.md 2024-08-26 13:52:00 +08:00
Wesley F. Young
7092894d22 refactor: normalize file names in common/utils 2024-08-26 12:48:45 +08:00
Wesley F. Young
af6ac26664 chore: lint & style 2024-08-26 12:44:44 +08:00
Wesley F. Young
a22ef67486 fix: type definition for json data 2024-08-26 12:39:32 +08:00
Wesley F. Young
7bb57cd78a fix: use allSettled instead of all when parsing raw message 2024-08-26 12:38:39 +08:00
Wesley F. Young
89b69bbdf8 Merge remote-tracking branch 'origin/main' 2024-08-26 12:02:47 +08:00
Wesley F. Young
e21c779d06 refactor: enhanced type definition for callNormalEvent
类型体操,伟大,无需多言!
2024-08-26 12:02:41 +08:00
手瓜一十雪
dfa3553b71 chore: 谁打的不规范日志 2024-08-26 11:35:18 +08:00
手瓜一十雪
19097388d0 chore: onRecvSysMsg 2024-08-26 11:33:17 +08:00
Wesley F. Young
a71eddbed2 fix: reference error 2024-08-26 11:25:37 +08:00
手瓜一十雪
65bbed0c26 Merge pull request #304 from intling-luo/main
修改群公告的参数名 feed_id 为 notice_id
2024-08-26 11:11:32 +08:00
ling
871cc61dfc 修改群公告的参数名 feed_id 为 notice_id 2024-08-26 10:37:11 +08:00
Wesley F. Young
bc62feb71b refactor: normalize naming 2024-08-26 10:04:31 +08:00
Wesley F. Young
0bba329999 refactor: make sendMsg(WithOb11UniqueId) an instance method 2024-08-26 09:34:51 +08:00
Wesley F. Young
b1a1fdbeee refactor: rename all coreContext -> core 2024-08-26 09:19:50 +08:00
Wesley F. Young
542c5beb1b chore: suppress type check 2024-08-26 09:09:33 +08:00
手瓜一十雪
7b87b0919b release: 2.2.12 2024-08-26 02:57:08 +08:00
手瓜一十雪
9c34f558d3 release: 2.2.11 2024-08-26 02:16:24 +08:00
手瓜一十雪
3e2da3b490 release: v2.2.10 2024-08-26 01:58:41 +08:00
手瓜一十雪
fb4a4f50be release: v2.2.9 2024-08-26 01:52:09 +08:00
手瓜一十雪
6596e9cab6 style: 27333 类型跟进 2024-08-26 01:24:22 +08:00
手瓜一十雪
f1b137f2e1 style: 移除老旧代码 2024-08-26 01:07:01 +08:00
手瓜一十雪
535720d0fe style: lint 2024-08-26 01:00:07 +08:00
手瓜一十雪
f063cf4a16 style: 移除无用代码 2024-08-26 00:50:17 +08:00
手瓜一十雪
90bbdbf2fe style: fix 2024-08-26 00:46:58 +08:00
手瓜一十雪
5f1d8fb99d style: RegExec match->exec 2024-08-26 00:45:12 +08:00
手瓜一十雪
5486ffcdcc chore: 移除无用代码 2024-08-26 00:38:19 +08:00
手瓜一十雪
adfd123970 style: lint 2024-08-26 00:29:52 +08:00
手瓜一十雪
f1a364bfa2 style: lint 2024-08-26 00:21:49 +08:00
手瓜一十雪
9da714bf15 style: fix 2024-08-26 00:17:42 +08:00
手瓜一十雪
fc73295520 build: 2.2.9 2024-08-26 00:09:07 +08:00
手瓜一十雪
ab955e41fb style: 代码质量提高 2024-08-26 00:05:33 +08:00
手瓜一十雪
c64367335c Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-08-26 00:01:47 +08:00
手瓜一十雪
edc787eb3e style: lint 2024-08-26 00:01:44 +08:00
手瓜一十雪
f2c69fc68b style: remove 2024-08-25 23:59:34 +08:00
手瓜一十雪
d947fe743b Merge pull request #303 from NapNeko/dev/RefactoredMsgParsers
style: Error Object
2024-08-25 23:57:58 +08:00
手瓜一十雪
5b37ae9026 fix 2024-08-25 23:57:16 +08:00
手瓜一十雪
ec9e042b29 Merge pull request #301 from NapNeko/dev/RefactoredMsgParsers
refactor: make static functions dynamic
2024-08-25 23:50:44 +08:00
手瓜一十雪
337ac0eab9 fix: 过滤无效null类型 2024-08-25 23:50:34 +08:00
手瓜一十雪
f6a1b784c4 fix: type 2024-08-25 23:42:48 +08:00
手瓜一十雪
332fcecb78 Merge branch 'main' into dev/RefactoredMsgParsers 2024-08-25 23:16:49 +08:00
手瓜一十雪
18590be1e7 fix: 修正正确类型 2024-08-25 23:04:34 +08:00
手瓜一十雪
b76edcaf1d chore: merge main 2024-08-25 22:43:29 +08:00
手瓜一十雪
6024cabb69 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-08-25 22:36:53 +08:00
手瓜一十雪
08446e648e release: 2.2.8 2024-08-25 22:36:42 +08:00
Alen
14af7a3572 Merge pull request #302 from cnxysoft/upmain
fix: 多个问题
2024-08-25 22:23:58 +08:00
Alen
cdc4275f81 fix: 多个问题
修复group_increase事件上报
修复启动时加载群员信息失败
修复文件发送失败
2024-08-25 22:23:06 +08:00
手瓜一十雪
a9ade98315 style: remove unless 2024-08-25 22:12:38 +08:00
手瓜一十雪
f3ae6fa70f style: fix 2024-08-25 22:09:30 +08:00
手瓜一十雪
96457bbec3 Merge branch 'main' into dev/RefactoredMsgParsers 2024-08-25 22:00:20 +08:00
手瓜一十雪
8f465e376e style: type 2024-08-25 21:59:07 +08:00
手瓜一十雪
adc366a959 style: 清理不规范代码 2024-08-25 21:54:20 +08:00
手瓜一十雪
a20a6bc8bb Merge branch 'main' into dev/RefactoredMsgParsers 2024-08-25 21:49:28 +08:00
手瓜一十雪
b176fa66d4 style: 样式处理 2024-08-25 21:47:55 +08:00
手瓜一十雪
f81b1926fb Merge branch 'main' into dev/RefactoredMsgParsers 2024-08-25 21:37:56 +08:00
手瓜一十雪
7b7609a068 style: 标准化样式 2024-08-25 21:37:36 +08:00
Seijo Cecilia
670d4108e6 fix: typo 2024-08-25 20:46:20 +08:00
Seijo Cecilia
a5c7b88a40 fix: createSendElements reference 2024-08-25 20:46:03 +08:00
Seijo Cecilia
e52b2e6d69 fix: createSendElements reference 2024-08-25 20:00:14 +08:00
Seijo Cecilia
e4066fb8df refactor: completely remove genMessage.ts 2024-08-25 19:53:20 +08:00
Seijo Cecilia
f7a0fb22b4 refactor: make SendMsg a single file again 2024-08-25 19:45:14 +08:00
Seijo Cecilia
cad2ae723c refactor: normalize method name 2024-08-25 19:43:41 +08:00
Seijo Cecilia
889a8c6093 fix: sync fixes in handling forwarded nodes 2024-08-25 19:43:01 +08:00
Seijo Cecilia
573418914f Merge branch 'main' into dev/RefactoredMsgParsers 2024-08-25 19:40:40 +08:00
Seijo Cecilia
d7fb6f9c05 refactor: ob11 to raw message constructors 2024-08-25 19:38:35 +08:00
手瓜一十雪
136e27d655 fix: 消息组合 2024-08-25 19:38:19 +08:00
Seijo Cecilia
d5ff2d7099 fix: from || to ?? 2024-08-25 18:20:58 +08:00
Seijo Cecilia
2a7f8d0c99 refactor: raw message parsers 2024-08-25 17:54:50 +08:00
手瓜一十雪
e3ca5df713 Delete .github/workflows/codacy.yml 2024-08-25 12:52:31 +08:00
手瓜一十雪
bda32f3e8f chore:update 2024-08-25 12:08:36 +08:00
手瓜一十雪
a7c6e45a92 chore: codacy 2024-08-25 12:02:03 +08:00
手瓜一十雪
7c20ca9b64 style:lint 2024-08-25 11:45:50 +08:00
手瓜一十雪
a201461eff chore: lint 2024-08-25 11:18:11 +08:00
Seijo Cecilia
e5d9df37c5 Merge remote-tracking branch 'origin/main' 2024-08-25 10:14:42 +08:00
Seijo Cecilia
106fbaf086 refactor: make parseMessage an instance method 2024-08-25 10:14:11 +08:00
Alen
a0024c98d5 release: 2.2.7 2024-08-25 09:59:07 +08:00
Alen
684a702638 Merge pull request #300 from cnxysoft/upmain
fix: 多处修复
2024-08-25 09:47:07 +08:00
Alen
aec4a009d1 fix: 撤回重复上报 2024-08-25 09:44:40 +08:00
Alen
822af575c9 fix: 群相关
group_admin事件上报
群成员信息/群列表缓存
ProfileService新增事件
2024-08-25 02:08:14 +08:00
Alen
485efa7d44 Merge branch 'main' into upmain 2024-08-25 01:25:12 +08:00
手瓜一十雪
3d09d45423 build: 2.2.7
DelGroupNotice
2024-08-24 23:50:05 +08:00
手瓜一十雪
4c69c6d9fd fix: v2.2.6 2024-08-24 23:24:24 +08:00
手瓜一十雪
920a41acef build: 2.2.6-test 2024-08-24 23:22:32 +08:00
Alen
0cf13a284c Merge branch 'main' into upmain 2024-08-24 22:26:56 +08:00
手瓜一十雪
a89cdef436 chore: kickMemberV2Inner 2024-08-24 22:23:44 +08:00
手瓜一十雪
881d88f4ad feat: quitGroupV2 2024-08-24 22:12:14 +08:00
Alen
a72c96f56d Merge branch 'main' into upmain 2024-08-24 21:54:43 +08:00
手瓜一十雪
bc8235b209 fix: 移除无用代码 2024-08-24 21:54:11 +08:00
手瓜一十雪
0087495749 fix: 类型推断 2024-08-24 21:50:29 +08:00
手瓜一十雪
9560afd4a7 fix: 一处错误推断 2024-08-24 21:47:39 +08:00
手瓜一十雪
56ec8559a0 fix: type 2024-08-24 21:42:49 +08:00
手瓜一十雪
99ca79ac7d chore: 去掉无用注释 2024-08-24 12:07:40 +08:00
手瓜一十雪
24564f4c74 release: 2.2.5 2024-08-24 12:05:07 +08:00
手瓜一十雪
212c802a1e fix: BuddyReq 2024-08-24 11:52:50 +08:00
手瓜一十雪
984b5d6c40 fix: 好友申请重复推送 2024-08-24 11:26:05 +08:00
手瓜一十雪
0e3a4191a9 Merge pull request #298 from shengwang52005/readme
docs: 增强胡言乱语水平
2024-08-24 01:03:21 +08:00
Miaowing
570a34bca5 docs: 增强胡言乱语水平
增强胡言乱语水平
2024-08-24 00:16:16 +08:00
手瓜一十雪
c9a0c29286 build: 2.2.0 2024-08-23 20:46:45 +08:00
手瓜一十雪
b5f804ec22 build: CQ码回滚 提高兼容 2024-08-23 20:46:23 +08:00
手瓜一十雪
dadbb83271 docs: 提高胡言乱语水平 2024-08-23 12:54:04 +08:00
手瓜一十雪
dcf0a06217 chore: 扩大范围 2024-08-23 11:20:29 +08:00
手瓜一十雪
3b5e6553cd chore 2024-08-23 11:04:47 +08:00
手瓜一十雪
509390af20 release: 2.2.2 2024-08-23 11:01:24 +08:00
手瓜一十雪
9ad511a9c0 release: 2.2.1 2024-08-23 10:57:13 +08:00
手瓜一十雪
89c102513d release: 2.2.0 2024-08-23 10:55:19 +08:00
162 changed files with 2987 additions and 3565 deletions

View File

@@ -3,36 +3,35 @@
</div> </div>
--- ---
## To Be Continued ## 欢迎回来
当前版本 (v2.1.x) 请使用内核构建版本(版本号最后的五位数)为 27187 以上的 PC NTQQ 运行 NapCatQQ (aka 猫猫框架) 是现代化的基于 NTQQ 的 Bot 协议端实现
## 项目介绍 ## 猫猫技能
NapCatQQ 是现代化的基于 NTQQ 的 Bot 协议端实现。
## 项目优势
- [x] **多种启动方式**支持以无头、LiteLoader 插件、仅 QQ GUI 三种方式启动 - [x] **多种启动方式**支持以无头、LiteLoader 插件、仅 QQ GUI 三种方式启动
- [x] **低占用**:无头模式占用资源极低,适合在服务器上运行 - [x] **低占用**:无头模式占用资源极低,适合在服务器上运行
- [x] **超多接口**在实现大部分Onebot接口上扩展了一套私有API - [x] **超多接口**在实现大部分Onebot接口上扩展了一套私有API
- [x] **WebUI**:自带 WebUI 支持,远程管理更加便捷 - [x] **WebUI**:自带 WebUI 支持,远程管理更加便捷
## 如何使用 ## 使用猫猫
可前往 [Release](https://github.com/NapNeko/NapCatQQ/releases/) 页面下载最新版本 可前往 [Release](https://github.com/NapNeko/NapCatQQ/releases/) 页面下载最新版本
**首次使用**请务必前往[官方文档](https://napneko.github.io/)查看使用教程。 **首次使用**请务必前往[官方文档](https://napneko.github.io/)查看使用教程。
## 相关链接 ## 回家旅途
[QQ Group](https://qm.qq.com/q/VfjAq5HIMS) [QQ Group](https://qm.qq.com/q/VfjAq5HIMS)
[Telegram Link](https://t.me/+nLZEnpne-pQ1OWFl) [Telegram Link](https://t.me/+nLZEnpne-pQ1OWFl)
## 鸣谢名单 ## 猫猫朋友
感谢 [LLOneBot](https://github.com/LLOneBot/LLOneBot) 提供初始版本基础 感谢 [LLOneBot](https://github.com/LLOneBot/LLOneBot) 提供初始版本基础
感谢 [Lagrange](https://github.com/LagrangeDev/Lagrange.Core) 对本项目的大力支持 感谢 [Lagrange](https://github.com/LagrangeDev/Lagrange.Core) 对本项目的大力支持
--- ---
## 使用许可 ## 约法三章
> [!CAUTION]\
> **请不要在 QQ 官方群聊和任何影响力较大的简中互联网平台(包括但不限于: 哔哩哔哩,微博,知乎,抖音等)发布和讨论*任何*与本项目存在相关性的信息**
任何使用本仓库代码的地方,都应当严格遵守[本仓库开源许可](./LICENSE)。**此外,禁止任何项目未经授权二次分发或基于 NapCat 代码开发。** 任何使用本仓库代码的地方,都应当严格遵守[本仓库开源许可](./LICENSE)。**此外,禁止任何项目未经授权二次分发或基于 NapCat 代码开发。**

View File

@@ -4,7 +4,7 @@
"name": "NapCatQQ", "name": "NapCatQQ",
"slug": "NapCat.Framework", "slug": "NapCat.Framework",
"description": "高性能的 OneBot 11 协议实现", "description": "高性能的 OneBot 11 协议实现",
"version": "2.2.4", "version": "2.2.13",
"icon": "./logo.png", "icon": "./logo.png",
"authors": [ "authors": [
{ {

View File

@@ -2,7 +2,7 @@
"name": "napcat", "name": "napcat",
"private": true, "private": true,
"type": "module", "type": "module",
"version": "2.2.4", "version": "2.2.13",
"scripts": { "scripts": {
"build:framework": "vite build --mode framework", "build:framework": "vite build --mode framework",
"build:shell": "vite build --mode shell", "build:shell": "vite build --mode shell",

View File

@@ -1,7 +1,8 @@
import { NodeIQQNTWrapperSession } from '@/core/wrapper/wrapper'; import { NodeIQQNTWrapperSession } from '@/core/wrapper/wrapper';
import { randomUUID } from 'crypto'; import { randomUUID } from 'crypto';
import { ListenerNamingMapping, ServiceNamingMapping } from '@/core';
interface Internal_MapKey { interface InternalMapKey {
timeout: number; timeout: number;
createtime: number; createtime: number;
func: (...arg: any[]) => any; func: (...arg: any[]) => any;
@@ -10,34 +11,27 @@ interface Internal_MapKey {
export type ListenerClassBase = Record<string, string>; export type ListenerClassBase = Record<string, string>;
export interface ListenerIBase {
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(listener: any): ListenerClassBase;
}
export class LegacyNTEventWrapper { export class LegacyNTEventWrapper {
private WrapperSession: NodeIQQNTWrapperSession | undefined; //WrapperSession private WrapperSession: NodeIQQNTWrapperSession | undefined; //WrapperSession
private listenerManager: Map<string, ListenerClassBase> = new Map<string, ListenerClassBase>(); //ListenerName-Unique -> Listener实例 private listenerManager: Map<string, ListenerClassBase> = new Map<string, ListenerClassBase>(); //ListenerName-Unique -> Listener实例
private EventTask = new Map<string, Map<string, Map<string, Internal_MapKey>>>(); //tasks ListenerMainName -> ListenerSubName-> uuid -> {timeout,createtime,func} private EventTask = new Map<string, Map<string, Map<string, InternalMapKey>>>(); //tasks ListenerMainName -> ListenerSubName-> uuid -> {timeout,createtime,func}
constructor( constructor(
wrapperSession: NodeIQQNTWrapperSession wrapperSession: NodeIQQNTWrapperSession,
) { ) {
this.WrapperSession = wrapperSession; this.WrapperSession = wrapperSession;
} }
createProxyDispatch(ListenerMainName: string) { createProxyDispatch(ListenerMainName: string) {
// eslint-disable-next-line @typescript-eslint/no-this-alias const dispatcherListenerFunc = this.dispatcherListener.bind(this);
const current = this;
return new Proxy( return new Proxy(
{}, {},
{ {
get(target: any, prop: any, receiver: any) { get(target: any, prop: any, receiver: any) {
// console.log('get', prop, typeof target[prop]);
if (typeof target[prop] === 'undefined') { if (typeof target[prop] === 'undefined') {
// 如果方法不存在返回一个函数这个函数调用existentMethod // 如果方法不存在返回一个函数这个函数调用existentMethod
return (...args: any[]) => { return (...args: any[]) => {
current.dispatcherListener.apply(current, [ListenerMainName, prop, ...args]).then(); dispatcherListenerFunc(ListenerMainName, prop, ...args).then();
}; };
} }
// 如果方法存在,正常返回 // 如果方法存在,正常返回
@@ -47,7 +41,13 @@ export class LegacyNTEventWrapper {
); );
} }
createEventFunction<T extends (...args: any) => any>(eventName: string): T | undefined { createEventFunction<
Service extends keyof ServiceNamingMapping,
ServiceMethod extends Exclude<keyof ServiceNamingMapping[Service], symbol>,
// eslint-disable-next-line
// @ts-ignore
T extends (...args: any) => any = ServiceNamingMapping[Service][ServiceMethod],
>(eventName: `${Service}/${ServiceMethod}`): T | undefined {
const eventNameArr = eventName.split('/'); const eventNameArr = eventName.split('/');
type eventType = { type eventType = {
[key: string]: () => { [key: string]: (...params: Parameters<T>) => Promise<ReturnType<T>> }; [key: string]: () => { [key: string]: (...params: Parameters<T>) => Promise<ReturnType<T>> };
@@ -55,8 +55,6 @@ export class LegacyNTEventWrapper {
if (eventNameArr.length > 1) { if (eventNameArr.length > 1) {
const serviceName = 'get' + eventNameArr[0].replace('NodeIKernel', ''); const serviceName = 'get' + eventNameArr[0].replace('NodeIKernel', '');
const eventName = eventNameArr[1]; const eventName = eventNameArr[1];
//getNodeIKernelGroupListener,GroupService
//console.log('2', eventName);
const services = (this.WrapperSession as unknown as eventType)[serviceName](); const services = (this.WrapperSession as unknown as eventType)[serviceName]();
let event = services[eventName]; let event = services[eventName];
//重新绑定this //重新绑定this
@@ -72,10 +70,11 @@ export class LegacyNTEventWrapper {
const existListener = this.listenerManager.get(listenerMainName + uniqueCode); const existListener = this.listenerManager.get(listenerMainName + uniqueCode);
if (!existListener) { if (!existListener) {
const Listener = this.createProxyDispatch(listenerMainName); const Listener = this.createProxyDispatch(listenerMainName);
const ServiceSubName = listenerMainName.match(/^NodeIKernel(.*?)Listener$/)![1]; const ServiceSubName = /^NodeIKernel(.*?)Listener$/.exec(listenerMainName)![1];
const Service = 'NodeIKernel' + ServiceSubName + 'Service/addKernel' + ServiceSubName + 'Listener'; const Service = `NodeIKernel${ServiceSubName}Service/addKernel${ServiceSubName}Listener`;
const addfunc = this.createEventFunction<(listener: T) => number>(Service); // eslint-disable-next-line
addfunc!(Listener as T); // @ts-ignore
this.createEventFunction(Service)(Listener as T);
this.listenerManager.set(listenerMainName + uniqueCode, Listener); this.listenerManager.set(listenerMainName + uniqueCode, Listener);
return Listener as T; return Listener as T;
} }
@@ -84,62 +83,62 @@ export class LegacyNTEventWrapper {
//统一回调清理事件 //统一回调清理事件
async dispatcherListener(ListenerMainName: string, ListenerSubName: string, ...args: any[]) { async dispatcherListener(ListenerMainName: string, ListenerSubName: string, ...args: any[]) {
//console.log("[EventDispatcher]",ListenerMainName, ListenerSubName, ...args);
this.EventTask.get(ListenerMainName) this.EventTask.get(ListenerMainName)
?.get(ListenerSubName) ?.get(ListenerSubName)
?.forEach((task, uuid) => { ?.forEach((task, uuid) => {
//console.log(task.func, uuid, task.createtime, task.timeout);
if (task.createtime + task.timeout < Date.now()) { if (task.createtime + task.timeout < Date.now()) {
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.delete(uuid); this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.delete(uuid);
return; return;
} }
if (task.checker && task.checker(...args)) { if (task?.checker?.(...args)) {
task.func(...args); task.func(...args);
} }
}); });
} }
async callNoListenerEvent<EventType extends (...args: any[]) => Promise<any> | any>( async callNoListenerEvent<
EventName = '', Service extends keyof ServiceNamingMapping,
timeout: number = 3000, ServiceMethod extends Exclude<keyof ServiceNamingMapping[Service], symbol>,
// eslint-disable-next-line
// @ts-ignore
EventType extends (...args: any) => any = ServiceNamingMapping[Service][ServiceMethod],
>(
serviceAndMethod: `${Service}/${ServiceMethod}`,
...args: Parameters<EventType> ...args: Parameters<EventType>
) { ): Promise<Awaited<ReturnType<EventType>>> {
return new Promise<Awaited<ReturnType<EventType>>>(async (resolve, reject) => { return (this.createEventFunction(serviceAndMethod))!(...args);
const EventFunc = this.createEventFunction<EventType>(EventName);
let complete = false;
setTimeout(() => {
if (!complete) {
reject(new Error('NTEvent EventName:' + EventName + ' timeout'));
}
}, timeout);
const retData = await EventFunc!(...args);
complete = true;
resolve(retData);
});
} }
async RegisterListen<ListenerType extends (...args: any[]) => void>( async registerListen<
ListenerName = '', Listener extends keyof ListenerNamingMapping,
ListenerMethod extends Exclude<keyof ListenerNamingMapping[Listener], symbol>,
// eslint-disable-next-line
// @ts-ignore
ListenerType extends (...args: any) => any = ListenerNamingMapping[Listener][ListenerMethod],
>(
listenerAndMethod: `${Listener}/${ListenerMethod}`,
waitTimes = 1, waitTimes = 1,
timeout = 5000, timeout = 5000,
checker: (...args: Parameters<ListenerType>) => boolean, checker: (...args: Parameters<ListenerType>) => boolean,
) { ) {
return new Promise<Parameters<ListenerType>>((resolve, reject) => { return new Promise<Parameters<ListenerType>>((resolve, reject) => {
const ListenerNameList = ListenerName.split('/'); const ListenerNameList = listenerAndMethod.split('/');
const ListenerMainName = ListenerNameList[0]; const ListenerMainName = ListenerNameList[0];
const ListenerSubName = ListenerNameList[1]; const ListenerSubName = ListenerNameList[1];
const id = randomUUID(); const id = randomUUID();
let complete = 0; let complete = 0;
let retData: Parameters<ListenerType> | undefined = undefined; let retData: Parameters<ListenerType> | undefined = undefined;
const databack = () => {
function sendDataCallback() {
if (complete == 0) { if (complete == 0) {
reject(new Error(' ListenerName:' + ListenerName + ' timeout')); reject(new Error(' ListenerName:' + listenerAndMethod + ' timeout'));
} else { } else {
resolve(retData!); resolve(retData!);
} }
}; }
const timeoutRef = setTimeout(databack, timeout);
const eventCallbak = { const timeoutRef = setTimeout(sendDataCallback, timeout);
const eventCallback = {
timeout: timeout, timeout: timeout,
createtime: Date.now(), createtime: Date.now(),
checker: checker, checker: checker,
@@ -148,7 +147,7 @@ export class LegacyNTEventWrapper {
retData = args; retData = args;
if (complete >= waitTimes) { if (complete >= waitTimes) {
clearTimeout(timeoutRef); clearTimeout(timeoutRef);
databack(); sendDataCallback();
} }
}, },
}; };
@@ -158,17 +157,118 @@ export class LegacyNTEventWrapper {
if (!this.EventTask.get(ListenerMainName)?.get(ListenerSubName)) { if (!this.EventTask.get(ListenerMainName)?.get(ListenerSubName)) {
this.EventTask.get(ListenerMainName)?.set(ListenerSubName, new Map()); this.EventTask.get(ListenerMainName)?.set(ListenerSubName, new Map());
} }
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallbak); this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallback);
this.createListenerFunction(ListenerMainName); this.createListenerFunction(ListenerMainName);
}); });
} }
async CallNormalEvent< async callNormalEventV2<
EventType extends (...args: any[]) => Promise<any>, Service extends keyof ServiceNamingMapping,
ListenerType extends (...args: any[]) => void ServiceMethod extends Exclude<keyof ServiceNamingMapping[Service], symbol>,
Listener extends keyof ListenerNamingMapping,
ListenerMethod extends Exclude<keyof ListenerNamingMapping[Listener], symbol>,
// eslint-disable-next-line
// @ts-ignore
EventType extends (...args: any) => any = ServiceNamingMapping[Service][ServiceMethod],
// eslint-disable-next-line
// @ts-ignore
ListenerType extends (...args: any) => any = ListenerNamingMapping[Listener][ListenerMethod]
>( >(
EventName = '', serviceAndMethod: `${Service}/${ServiceMethod}`,
ListenerName = '', listenerAndMethod: `${Listener}/${ListenerMethod}`,
args: Parameters<EventType>,
checkerEvent: (ret: Awaited<ReturnType<EventType>>) => boolean = () => true,
checkerListener: (...args: Parameters<ListenerType>) => boolean = () => true,
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() {
if (complete == 0) {
reject(
new Error(
'Timeout: NTEvent serviceAndMethod:' +
serviceAndMethod +
' ListenerName:' +
listenerAndMethod +
' EventRet:\n' +
JSON.stringify(retEvent, null, 4) +
'\n',
),
);
} else {
resolve([retEvent as Awaited<ReturnType<EventType>>, ...retData!]);
}
}
const ListenerNameList = listenerAndMethod.split('/');
const ListenerMainName = ListenerNameList[0];
const ListenerSubName = ListenerNameList[1];
const timeoutRef = setTimeout(sendDataCallback, timeout);
const eventCallback = {
timeout: timeout,
createtime: Date.now(),
checker: checkerListener,
func: (...args: any[]) => {
complete++;
retData = args as Parameters<ListenerType>;
if (complete >= callbackTimesToWait) {
clearTimeout(timeoutRef);
sendDataCallback();
}
},
};
if (!this.EventTask.get(ListenerMainName)) {
this.EventTask.set(ListenerMainName, new Map());
}
if (!this.EventTask.get(ListenerMainName)?.get(ListenerSubName)) {
this.EventTask.get(ListenerMainName)?.set(ListenerSubName, new Map());
}
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallback);
this.createListenerFunction(ListenerMainName);
const eventFunction = this.createEventFunction(serviceAndMethod);
retEvent = await eventFunction!(...(args));
if (!checkerEvent(retEvent)) {
clearTimeout(timeoutRef);
reject(
new Error(
'EventChecker Failed: NTEvent serviceAndMethod:' +
serviceAndMethod +
' ListenerName:' +
listenerAndMethod +
' EventRet:\n' +
JSON.stringify(retEvent, null, 4) +
'\n',
),
);
}
},
);
}
/*
async callNormalEvent<
Service extends keyof ServiceNamingMapping,
ServiceMethod extends Exclude<keyof ServiceNamingMapping[Service], symbol>,
Listener extends keyof ListenerNamingMapping,
ListenerMethod extends Exclude<keyof ListenerNamingMapping[Listener], symbol>,
// eslint-disable-next-line
// @ts-ignore
EventType extends (...args: any) => any = ServiceNamingMapping[Service][ServiceMethod],
// eslint-disable-next-line
// @ts-ignore
ListenerType extends (...args: any) => any = ListenerNamingMapping[Listener][ListenerMethod]
>(
serviceAndMethod: `${Service}/${ServiceMethod}`,
listenerAndMethod: `${Listener}/${ListenerMethod}`,
waitTimes = 1, waitTimes = 1,
timeout: number = 3000, timeout: number = 3000,
checker: (...args: Parameters<ListenerType>) => boolean, checker: (...args: Parameters<ListenerType>) => boolean,
@@ -185,9 +285,9 @@ export class LegacyNTEventWrapper {
reject( reject(
new Error( new Error(
'Timeout: NTEvent EventName:' + 'Timeout: NTEvent EventName:' +
EventName + serviceAndMethod +
' ListenerName:' + ' ListenerName:' +
ListenerName + listenerAndMethod +
' EventRet:\n' + ' EventRet:\n' +
JSON.stringify(retEvent, null, 4) + JSON.stringify(retEvent, null, 4) +
'\n', '\n',
@@ -198,7 +298,7 @@ export class LegacyNTEventWrapper {
} }
}; };
const ListenerNameList = ListenerName.split('/'); const ListenerNameList = listenerAndMethod.split('/');
const ListenerMainName = ListenerNameList[0]; const ListenerMainName = ListenerNameList[0];
const ListenerSubName = ListenerNameList[1]; const ListenerSubName = ListenerNameList[1];
@@ -226,34 +326,10 @@ export class LegacyNTEventWrapper {
} }
this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallbak); this.EventTask.get(ListenerMainName)?.get(ListenerSubName)?.set(id, eventCallbak);
this.createListenerFunction(ListenerMainName); this.createListenerFunction(ListenerMainName);
const EventFunc = this.createEventFunction<EventType>(EventName); const EventFunc = this.createEventFunction<EventType>(serviceAndMethod);
retEvent = await EventFunc!(...(args as any[])); retEvent = await EventFunc!(...(args as any[]));
}, },
); );
} }
*/
} }
// 示例代码 快速创建事件
// let NTEvent = new NTEventWrapper();
// let TestEvent = NTEvent.CreatEventFunction<(force: boolean) => Promise<Number>>('NodeIKernelProfileLikeService/GetTest');
// if (TestEvent) {
// TestEvent(true);
// }
// 示例代码 快速创建监听Listener类
// let NTEvent = new NTEventWrapper();
// NTEvent.CreatListenerFunction<NodeIKernelMsgListener>('NodeIKernelMsgListener', 'core')
// 调用接口
//let NTEvent = new NTEventWrapper();
//let ret = await NTEvent.CallNormalEvent<(force: boolean) => Promise<Number>, (data1: string, data2: number) => void>('NodeIKernelProfileLikeService/GetTest', 'NodeIKernelMsgListener/onAddSendMsg', 1, 3000, true);
// 注册监听 解除监听
// NTEventDispatch.RigisterListener('NodeIKernelMsgListener/onAddSendMsg','core',cb);
// NTEventDispatch.UnRigisterListener('NodeIKernelMsgListener/onAddSendMsg','core');
// let GetTest = NTEventDispatch.CreatEvent('NodeIKernelProfileLikeService/GetTest','NodeIKernelMsgListener/onAddSendMsg',Mode);
// GetTest('test');
// always模式
// NTEventDispatch.CreatEvent('NodeIKernelProfileLikeService/GetTest','NodeIKernelMsgListener/onAddSendMsg',Mode,(...args:any[])=>{ console.log(args) });

View File

@@ -6,6 +6,8 @@ export type ListenerClassBase = Record<string, string>;
export interface ListenerIBase { export interface ListenerIBase {
// eslint-disable-next-line @typescript-eslint/no-misused-new // eslint-disable-next-line @typescript-eslint/no-misused-new
new(listener: any): ListenerClassBase; new(listener: any): ListenerClassBase;
[key: string]: any;
} }
export class NTEventChannel extends EventEmitter { export class NTEventChannel extends EventEmitter {
@@ -26,12 +28,11 @@ export class NTEventChannel extends EventEmitter {
} }
createProxyDispatch(ListenerMainName: string) { createProxyDispatch(ListenerMainName: string) {
// eslint-disable-next-line @typescript-eslint/no-this-alias const dispatcherListener = this.dispatcherListener.bind(this);
const current = this;
return new Proxy({}, { return new Proxy({}, {
get(_target: any, prop: any, _receiver: any) { get(_target: any, prop: any, _receiver: any) {
return (...args: any[]) => { return (...args: any[]) => {
current.dispatcherListener.apply(current, [ListenerMainName + '/' + prop, ...args]); dispatcherListener(ListenerMainName + '/' + prop, ...args);
}; };
}, },
}); });
@@ -47,7 +48,7 @@ export class NTEventChannel extends EventEmitter {
Listener = new ListenerType(this.createProxyDispatch(listenerMainName)); Listener = new ListenerType(this.createProxyDispatch(listenerMainName));
if (!Listener) throw new Error('Init Listener failed'); if (!Listener) throw new Error('Init Listener failed');
//实例化NTQQ Listener外包装 //实例化NTQQ Listener外包装
const ServiceSubName = listenerMainName.match(/^NodeIKernel(.*?)Listener$/)![1]; const ServiceSubName = /^NodeIKernel(.*?)Listener$/.exec(listenerMainName)![1];
const Service = 'NodeIKernel' + ServiceSubName + 'Service/addKernel' + ServiceSubName + 'Listener'; const Service = 'NodeIKernel' + ServiceSubName + 'Service/addKernel' + ServiceSubName + 'Listener';
const addfunc = this.createEventFunction<(listener: T) => number>(Service); const addfunc = this.createEventFunction<(listener: T) => number>(Service);
//添加Listener到NTQQ //添加Listener到NTQQ
@@ -122,17 +123,9 @@ export class NTEventChannel extends EventEmitter {
async callEvent<EventType extends (...args: any[]) => Promise<any> | any>( async callEvent<EventType extends (...args: any[]) => Promise<any> | any>(
EventName = '', timeout: number = 3000, ...args: Parameters<EventType>) { EventName = '', timeout: number = 3000, ...args: Parameters<EventType>) {
return new Promise<Awaited<ReturnType<EventType>>>(async (resolve, reject) => { return new Promise<Awaited<ReturnType<EventType>>>((resolve) => {
const EventFunc = this.createEventFunction<EventType>(EventName); const EventFunc = this.createEventFunction<EventType>(EventName);
let complete = false; EventFunc!(...args).then((retData: Awaited<ReturnType<EventType>> | PromiseLike<Awaited<ReturnType<EventType>>>) => resolve(retData));
const Timeouter = setTimeout(() => {
if (!complete) {
reject(new Error('NTEvent EventName:' + EventName + ' timeout'));
}
}, timeout);
const retData = await EventFunc!(...args);
complete = true;
resolve(retData);
}); });
} }
} }

View File

@@ -2,7 +2,7 @@ import path, { dirname } from 'path';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
import fs from 'fs'; import fs from 'fs';
export const napcat_version = '2.2.4'; export const napcat_version = '2.2.13';
export class NapCatPathWrapper { export class NapCatPathWrapper {
binaryPath: string; binaryPath: string;

View File

@@ -4,13 +4,13 @@ import type { NapCatCore } from '@/core';
export abstract class ConfigBase<T> { export abstract class ConfigBase<T> {
name: string; name: string;
coreContext: NapCatCore; core: NapCatCore;
configPath: string; configPath: string;
configData: T = {} as T; configData: T = {} as T;
protected constructor(name: string, coreContext: NapCatCore, configPath: string) { protected constructor(name: string, core: NapCatCore, configPath: string) {
this.name = name; this.name = name;
this.coreContext = coreContext; this.core = core;
this.configPath = configPath; this.configPath = configPath;
fs.mkdirSync(this.configPath, { recursive: true }); fs.mkdirSync(this.configPath, { recursive: true });
this.read(); this.read();
@@ -28,8 +28,8 @@ export abstract class ConfigBase<T> {
} }
read(): T { read(): T {
const logger = this.coreContext.context.logger; const logger = this.core.context.logger;
const configPath = this.getConfigPath(this.coreContext.selfInfo.uin); const configPath = this.getConfigPath(this.core.selfInfo.uin);
if (!fs.existsSync(configPath)) { if (!fs.existsSync(configPath)) {
try { try {
fs.writeFileSync(configPath, fs.readFileSync(this.getConfigPath(undefined), 'utf-8')); fs.writeFileSync(configPath, fs.readFileSync(this.getConfigPath(undefined), 'utf-8'));
@@ -53,9 +53,9 @@ export abstract class ConfigBase<T> {
} }
save(newConfigData: T = this.configData as T) { save(newConfigData: T = this.configData) {
const logger = this.coreContext.context.logger; const logger = this.core.context.logger;
const selfInfo = this.coreContext.selfInfo; const selfInfo = this.core.selfInfo;
this.configData = newConfigData; this.configData = newConfigData;
const configPath = this.getConfigPath(selfInfo.uin); const configPath = this.getConfigPath(selfInfo.uin);
try { try {

View File

@@ -4,6 +4,7 @@ import crypto, { randomUUID } from 'crypto';
import util from 'util'; import util from 'util';
import path from 'node:path'; import path from 'node:path';
import * as fileType from 'file-type'; import * as fileType from 'file-type';
import { solveProblem } from './helper';
export function isGIF(path: string) { export function isGIF(path: string) {
const buffer = Buffer.alloc(4); const buffer = Buffer.alloc(4);
@@ -12,6 +13,7 @@ export function isGIF(path: string) {
fs.closeSync(fd); fs.closeSync(fd);
return buffer.toString() === 'GIF8'; return buffer.toString() === 'GIF8';
} }
// 定义一个异步函数来检查文件是否存在 // 定义一个异步函数来检查文件是否存在
export function checkFileReceived(path: string, timeout: number = 3000): Promise<void> { export function checkFileReceived(path: string, timeout: number = 3000): Promise<void> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@@ -122,15 +124,14 @@ export interface HttpDownloadOptions {
} }
export async function httpDownload(options: string | HttpDownloadOptions): Promise<Buffer> { export async function httpDownload(options: string | HttpDownloadOptions): Promise<Buffer> {
const chunks: Buffer[] = []; // const chunks: Buffer[] = [];
let url: string; let url: string;
let headers: Record<string, string> = { let headers: Record<string, string> = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36',
}; };
if (typeof options === 'string') { if (typeof options === 'string') {
url = options; url = options;
const host = new URL(url).hostname; headers['Host'] = new URL(url).hostname;
headers['Host'] = host;
} else { } else {
url = options.url; url = options.url;
if (options.headers) { if (options.headers) {
@@ -185,25 +186,28 @@ export enum FileUriType {
} }
export async function checkUriType(Uri: string) { export async function checkUriType(Uri: string) {
//先判断是否是本地文件
try { const LocalFileRet = await solveProblem((uri: string) => {
if (fs.existsSync(Uri)) return { Uri: Uri, Type: FileUriType.Local }; if (fs.existsSync(uri)) {
} catch (error) { return { Uri: uri, Type: FileUriType.Local };
} }
try { return undefined;
}, Uri);
if (LocalFileRet) return LocalFileRet;
const OtherFileRet = await solveProblem((uri: string) => {
//再判断是否是Http //再判断是否是Http
if (Uri.startsWith('http://') || Uri.startsWith('https://')) { if (uri.startsWith('http://') || uri.startsWith('https://')) {
return { Uri: Uri, Type: FileUriType.Remote }; return { Uri: uri, Type: FileUriType.Remote };
} }
//再判断是否是Base64 //再判断是否是Base64
if (Uri.startsWith('base64://')) { if (uri.startsWith('base64://')) {
return { Uri: Uri, Type: FileUriType.Base64 }; return { Uri: uri, Type: FileUriType.Base64 };
} }
if (Uri.startsWith('file://')) { if (uri.startsWith('file://')) {
let pathname: string;
let filePath: string; let filePath: string;
// await fs.copyFile(url.pathname, filePath); // await fs.copyFile(url.pathname, filePath);
pathname = decodeURIComponent(new URL(Uri).pathname); const pathname = decodeURIComponent(new URL(uri).pathname);
if (process.platform === 'win32') { if (process.platform === 'win32') {
filePath = pathname.slice(1); filePath = pathname.slice(1);
} else { } else {
@@ -211,8 +215,9 @@ export async function checkUriType(Uri: string) {
} }
return { Uri: filePath, Type: FileUriType.Local }; return { Uri: filePath, Type: FileUriType.Local };
} }
} catch (error) { }, Uri);
} if (OtherFileRet) return OtherFileRet;
return { Uri: Uri, Type: FileUriType.Unknown }; return { Uri: Uri, Type: FileUriType.Unknown };
} }
@@ -232,7 +237,7 @@ export async function uri2local(dir: string, uri: string, filename: string | und
//接下来都要有文件名 //接下来都要有文件名
if (!filename) filename = randomUUID(); if (!filename) filename = randomUUID();
//解析Http和Https协议 //解析Http和Https协议
if (UriType == FileUriType.Remote) { if (UriType == FileUriType.Remote) {
const pathInfo = path.parse(decodeURIComponent(new URL(HandledUri).pathname)); const pathInfo = path.parse(decodeURIComponent(new URL(HandledUri).pathname));
if (pathInfo.name) { if (pathInfo.name) {
@@ -264,4 +269,4 @@ export async function uri2local(dir: string, uri: string, filename: string | und
return { success: true, errMsg: '', fileName: filename, ext: fileExt, path: filePath, isLocal: true }; return { success: true, errMsg: '', fileName: filename, ext: fileExt, path: filePath, isLocal: true };
} }
return { success: false, errMsg: '未知文件类型', fileName: '', ext: '', path: '', isLocal: false }; return { success: false, errMsg: '未知文件类型', fileName: '', ext: '', path: '', isLocal: false };
} }

View File

@@ -3,8 +3,28 @@ import fs from 'fs';
import os from 'node:os'; import os from 'node:os';
import { QQLevel } from '@/core'; import { QQLevel } from '@/core';
//下面这个类是用于将uid+msgid合并的类 export async function solveProblem<T extends (...arg: any[]) => any>(func: T, ...args: Parameters<T>): Promise<ReturnType<T> | undefined> {
return new Promise<ReturnType<T> | undefined>((resolve) => {
try {
const result = func(...args);
resolve(result);
} catch (e) {
resolve(undefined);
}
});
}
export async function solveAsyncProblem<T extends (...args: any[]) => Promise<any>>(func: T, ...args: Parameters<T>): Promise<Awaited<ReturnType<T>> | undefined> {
return new Promise<Awaited<ReturnType<T>> | undefined>((resolve) => {
func(...args).then((result) => {
resolve(result);
}).catch(() => {
resolve(undefined);
});
});
}
//下面这个类是用于将uid+msgid合并的类
export class UUIDConverter { export class UUIDConverter {
static encode(highStr: string, lowStr: string): string { static encode(highStr: string, lowStr: string): string {
const high = BigInt(highStr); const high = BigInt(highStr);
@@ -12,11 +32,10 @@ export class UUIDConverter {
const highHex = high.toString(16).padStart(16, '0'); const highHex = high.toString(16).padStart(16, '0');
const lowHex = low.toString(16).padStart(16, '0'); const lowHex = low.toString(16).padStart(16, '0');
const combinedHex = highHex + lowHex; const combinedHex = highHex + lowHex;
const uuid = `${combinedHex.substring(0, 8)}-${combinedHex.substring(8, 12)}-${combinedHex.substring( return `${combinedHex.substring(0, 8)}-${combinedHex.substring(8, 12)}-${combinedHex.substring(
12, 12,
16, 16,
)}-${combinedHex.substring(16, 20)}-${combinedHex.substring(20)}`; )}-${combinedHex.substring(16, 20)}-${combinedHex.substring(20)}`;
return uuid;
} }
static decode(uuid: string): { high: string; low: string } { static decode(uuid: string): { high: string; low: string } {
@@ -103,11 +122,11 @@ export function getDefaultQQVersionConfigInfo(): QQVersionConfigType {
}; };
} }
return { return {
baseVersion: '9.9.15-27254', baseVersion: '9.9.15-27391',
curVersion: '9.9.15-27254', curVersion: '9.9.15-27391',
prevVersion: '', prevVersion: '',
onErrorVersions: [], onErrorVersions: [],
buildId: '27254', buildId: '27391',
}; };
} }

View File

@@ -177,12 +177,12 @@ export function rawMessageToText(msg: RawMessage, recursiveLevel = 0): string {
if (element.replyElement) { if (element.replyElement) {
const recordMsgOrNull = msg.records.find( const recordMsgOrNull = msg.records.find(
record => element.replyElement!.sourceMsgIdInRecords === record.msgId record => element.replyElement!.sourceMsgIdInRecords === record.msgId,
); );
return `[回复消息 ${ return `[回复消息 ${
recordMsgOrNull && recordMsgOrNull &&
recordMsgOrNull.peerUin != '284840486' // 非转发消息; 否则定位不到 recordMsgOrNull.peerUin != '284840486' // 非转发消息; 否则定位不到
? ?
rawMessageToText(recordMsgOrNull, recursiveLevel + 1) : rawMessageToText(recordMsgOrNull, recursiveLevel + 1) :
`未找到消息记录 (MsgId = ${element.replyElement.sourceMsgIdInRecords})` `未找到消息记录 (MsgId = ${element.replyElement.sourceMsgIdInRecords})`
}]`; }]`;

View File

@@ -15,23 +15,13 @@ export class LimitedHashTable<K, V> {
} }
set(key: K, value: V): void { set(key: K, value: V): void {
// const isExist = this.keyToValue.get(key);
// if (isExist && isExist === value) {
// return;
// }
this.keyToValue.set(key, value); this.keyToValue.set(key, value);
this.valueToKey.set(value, key); this.valueToKey.set(value, key);
while (this.keyToValue.size !== this.valueToKey.size) { while (this.keyToValue.size !== this.valueToKey.size) {
//console.log('keyToValue.size !== valueToKey.size Error Atom');
this.keyToValue.clear(); this.keyToValue.clear();
this.valueToKey.clear(); this.valueToKey.clear();
} }
// console.log('---------------');
// console.log(this.keyToValue);
// console.log(this.valueToKey);
// console.log('---------------');
while (this.keyToValue.size > this.maxSize || this.valueToKey.size > this.maxSize) { while (this.keyToValue.size > this.maxSize || this.valueToKey.size > this.maxSize) {
//console.log(this.keyToValue.size > this.maxSize, this.valueToKey.size > this.maxSize);
const oldestKey = this.keyToValue.keys().next().value; const oldestKey = this.keyToValue.keys().next().value;
this.valueToKey.delete(this.keyToValue.get(oldestKey)!); this.valueToKey.delete(this.keyToValue.get(oldestKey)!);
this.keyToValue.delete(oldestKey); this.keyToValue.delete(oldestKey);
@@ -101,17 +91,13 @@ class MessageUniqueWrapper {
return ret.map((t) => t?.MsgId).filter((t) => t !== undefined); return ret.map((t) => t?.MsgId).filter((t) => t !== undefined);
} }
createMsg(peer: Peer, msgId: string): number | undefined { createMsg(peer: Peer, msgId: string) {
const key = `${msgId}|${peer.chatType}|${peer.peerUid}`; const key = `${msgId}|${peer.chatType}|${peer.peerUid}`;
const hash = crypto.createHash('md5').update(key).digest(); const hash = crypto.createHash('md5').update(key).digest();
//设置第一个bit为0 保证shortId为正数 //设置第一个bit为0 保证shortId为正数
hash[0] &= 0x7f; hash[0] &= 0x7f;
const shortId = hash.readInt32BE(0); const shortId = hash.readInt32BE(0);
//减少性能损耗 //减少性能损耗
// const isExist = this.msgIdMap.getKey(shortId);
// if (isExist && isExist === msgId) {
// return shortId;
// }
this.msgIdMap.set(msgId, shortId); this.msgIdMap.set(msgId, shortId);
this.msgDataMap.set(key, shortId); this.msgDataMap.set(key, shortId);
return shortId; return shortId;

View File

@@ -3,7 +3,6 @@ import { LogWrapper } from './log';
export function proxyHandlerOf(logger: LogWrapper) { export function proxyHandlerOf(logger: LogWrapper) {
return { return {
get(target: any, prop: any, receiver: any) { get(target: any, prop: any, receiver: any) {
// console.log('get', prop, typeof target[prop]);
if (typeof target[prop] === 'undefined') { if (typeof target[prop] === 'undefined') {
// 如果方法不存在返回一个函数这个函数调用existentMethod // 如果方法不存在返回一个函数这个函数调用existentMethod
return (..._args: unknown[]) => { return (..._args: unknown[]) => {

View File

@@ -46,7 +46,7 @@ export class QQBasicInfoWrapper {
} }
requireMinNTQQBuild(buildStr: string) { requireMinNTQQBuild(buildStr: string) {
const currentBuild = parseInt(this.getQQBuildStr() || '0'); const currentBuild = +(this.getQQBuildStr() ?? '0');
if (currentBuild == 0) throw new Error('QQBuildStr获取失败'); if (currentBuild == 0) throw new Error('QQBuildStr获取失败');
return currentBuild >= parseInt(buildStr); return currentBuild >= parseInt(buildStr);
} }
@@ -77,5 +77,3 @@ export class QQBasicInfoWrapper {
return { appid: systemPlatform === 'linux' ? '537240795' : '537240709', qua: this.getQUAInternal() }; return { appid: systemPlatform === 'linux' ? '537240795' : '537240709', qua: this.getQUAInternal() };
} }
} }
export let QQBasicInfo: QQBasicInfoWrapper | undefined;

View File

@@ -30,7 +30,7 @@ export async function getMachineId(): Promise<string> {
if (!machineId) { if (!machineId) {
machineId = (async () => { machineId = (async () => {
const id = await getMacMachineId(); const id = await getMacMachineId();
return id || randomUUID(); // fallback, generate a UUID return id ?? randomUUID(); // fallback, generate a UUID
})(); })();
} }

File diff suppressed because one or more lines are too long

View File

@@ -1,17 +1,4 @@
interface IDependsAdapter { export class NodeIDependsAdapter {
onMSFStatusChange(arg1: number, arg2: number): void;
onMSFSsoError(args: unknown): void;
getGroupCode(args: unknown): void;
}
export interface NodeIDependsAdapter extends IDependsAdapter {
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(adapter: IDependsAdapter): NodeIDependsAdapter;
}
export class DependsAdapter implements IDependsAdapter {
onMSFStatusChange(arg1: number, arg2: number) { onMSFStatusChange(arg1: number, arg2: number) {
// console.log(arg1, arg2); // console.log(arg1, arg2);
// if (arg1 == 2 && arg2 == 2) { // if (arg1 == 2 && arg2 == 2) {

View File

@@ -1,17 +1,4 @@
interface IDispatcherAdapter { export class NodeIDispatcherAdapter {
dispatchRequest(arg: unknown): void;
dispatchCall(arg: unknown): void;
dispatchCallWithJson(arg: unknown): void;
}
export interface NodeIDispatcherAdapter extends IDispatcherAdapter {
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(adapter: IDispatcherAdapter): NodeIDispatcherAdapter;
}
export class DispatcherAdapter implements IDispatcherAdapter {
dispatchRequest(arg: unknown) { dispatchRequest(arg: unknown) {
} }

View File

@@ -1,27 +1,4 @@
interface IGlobalAdapter { export class NodeIGlobalAdapter {
onLog(...args: unknown[]): void;
onGetSrvCalTime(...args: unknown[]): void;
onShowErrUITips(...args: unknown[]): void;
fixPicImgType(...args: unknown[]): void;
getAppSetting(...args: unknown[]): void;
onInstallFinished(...args: unknown[]): void;
onUpdateGeneralFlag(...args: unknown[]): void;
onGetOfflineMsg(...args: unknown[]): void;
}
export interface NodeIGlobalAdapter extends IGlobalAdapter {
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(adapter: IGlobalAdapter): NodeIGlobalAdapter;
}
export class GlobalAdapter implements IGlobalAdapter {
onLog(...args: unknown[]) { onLog(...args: unknown[]) {
} }

View File

@@ -8,17 +8,27 @@ import {
IMAGE_HTTP_HOST_NT, IMAGE_HTTP_HOST_NT,
Peer, Peer,
PicElement, PicElement,
PicType,
SendFileElement,
SendPicElement,
SendPttElement,
SendVideoElement,
} from '@/core/entities'; } from '@/core/entities';
import path from 'path'; import path from 'path';
import fs from 'fs'; import fs from 'fs';
import fsPromises from 'fs/promises'; import fsPromises from 'fs/promises';
import { InstanceContext, NapCatCore, OnRichMediaDownloadCompleteParams } from '@/core'; import { InstanceContext, NapCatCore } from '@/core';
import * as fileType from 'file-type'; import * as fileType from 'file-type';
import imageSize from 'image-size'; import imageSize from 'image-size';
import { ISizeCalculationResult } from 'image-size/dist/types/interface'; import { ISizeCalculationResult } from 'image-size/dist/types/interface';
import { NodeIKernelSearchService } from '../services/NodeIKernelSearchService'; import { NodeIKernelSearchService } from '../services/NodeIKernelSearchService';
import { RkeyManager } from '../helper/rkey'; import { RkeyManager } from '../helper/rkey';
import { calculateFileMD5 } from '@/common/utils/file'; import { calculateFileMD5, isGIF } from '@/common/utils/file';
import pathLib from 'node:path';
import { defaultVideoThumbB64, getVideoInfo } from '@/common/utils/video';
import ffmpeg from 'fluent-ffmpeg';
import fsnormal from 'node:fs';
import { encodeSilk } from '@/common/utils/audio';
export class NTQQFileApi { export class NTQQFileApi {
@@ -84,6 +94,212 @@ export class NTQQFileApi {
}; };
} }
async createValidSendFileElement(
filePath: string,
fileName: string = '',
folderId: string = '',
): Promise<SendFileElement> {
const {
fileName: _fileName,
path,
fileSize,
} = await this.core.apis.FileApi.uploadFile(filePath, ElementType.FILE);
if (fileSize === 0) {
throw new Error('文件异常大小为0');
}
return {
elementType: ElementType.FILE,
elementId: '',
fileElement: {
fileName: fileName || _fileName,
folderId: folderId,
filePath: path,
fileSize: (fileSize).toString(),
},
};
}
async createValidSendPicElement(
picPath: string,
summary: string = '',
subType: 0 | 1 = 0,
): Promise<SendPicElement> {
const {
md5,
fileName,
path,
fileSize,
} = await this.core.apis.FileApi.uploadFile(picPath, ElementType.PIC, subType);
if (fileSize === 0) {
throw new Error('文件异常大小为0');
}
const imageSize = await this.core.apis.FileApi.getImageSize(picPath);
const picElement: any = {
md5HexStr: md5,
fileSize: fileSize.toString(),
picWidth: imageSize?.width,
picHeight: imageSize?.height,
fileName: fileName,
sourcePath: path,
original: true,
picType: isGIF(picPath) ? PicType.gif : PicType.jpg,
picSubType: subType,
fileUuid: '',
fileSubId: '',
thumbFileSize: 0,
summary,
};
return {
elementType: ElementType.PIC,
elementId: '',
picElement,
};
}
async createValidSendVideoElement(
filePath: string,
fileName: string = '',
diyThumbPath: string = '',
): Promise<SendVideoElement> {
const logger = this.core.context.logger;
const {
fileName: _fileName,
path,
fileSize,
md5,
} = await this.core.apis.FileApi.uploadFile(filePath, ElementType.VIDEO);
if (fileSize === 0) {
throw new Error('文件异常大小为0');
}
let thumb = path.replace(`${pathLib.sep}Ori${pathLib.sep}`, `${pathLib.sep}Thumb${pathLib.sep}`);
thumb = pathLib.dirname(thumb);
let videoInfo = {
width: 1920, height: 1080,
time: 15,
format: 'mp4',
size: fileSize,
filePath,
};
try {
videoInfo = await getVideoInfo(path, logger);
} catch (e) {
logger.logError('获取视频信息失败', e);
}
const createThumb = new Promise<string | undefined>((resolve, reject) => {
const thumbFileName = `${md5}_0.png`;
const thumbPath = pathLib.join(thumb, thumbFileName);
ffmpeg(filePath)
.on('error', (err) => {
logger.logDebug('获取视频封面失败,使用默认封面', err);
if (diyThumbPath) {
fsPromises.copyFile(diyThumbPath, thumbPath).then(() => {
resolve(thumbPath);
}).catch(reject);
} else {
fsnormal.writeFileSync(thumbPath, Buffer.from(defaultVideoThumbB64, 'base64'));
resolve(thumbPath);
}
})
.screenshots({
timestamps: [0],
filename: thumbFileName,
folder: thumb,
size: videoInfo.width + 'x' + videoInfo.height,
}).on('end', () => {
resolve(thumbPath);
});
});
const thumbPath = new Map();
const _thumbPath = await createThumb;
const thumbSize = _thumbPath ? (await fsPromises.stat(_thumbPath)).size : 0;
// log("生成缩略图", _thumbPath)
thumbPath.set(0, _thumbPath);
const thumbMd5 = _thumbPath ? await calculateFileMD5(_thumbPath) : '';
// "fileElement": {
// "fileMd5": "",
// "fileName": "1.mp4",
// "filePath": "C:\\Users\\nanae\\OneDrive\\Desktop\\1.mp4",
// "fileSize": "1847007",
// "picHeight": 1280,
// "picWidth": 720,
// "picThumbPath": {},
// "file10MMd5": "",
// "fileSha": "",
// "fileSha3": "",
// "fileUuid": "",
// "fileSubId": "",
// "thumbFileSize": 750
// }
return {
elementType: ElementType.VIDEO,
elementId: '',
videoElement: {
fileName: fileName || _fileName,
filePath: path,
videoMd5: md5,
thumbMd5,
fileTime: videoInfo.time,
thumbPath: thumbPath,
thumbSize,
thumbWidth: videoInfo.width,
thumbHeight: videoInfo.height,
fileSize: '' + fileSize,
// fileFormat: videotype
// fileUuid: "",
// transferStatus: 0,
// progress: 0,
// invalidState: 0,
// fileSubId: "",
// fileBizId: null,
// originVideoMd5: "",
// fileFormat: 2,
// import_rich_media_context: null,
// sourceVideoCodecFormat: 2
},
};
}
async createValidSendPttElement(pttPath: string): Promise<SendPttElement> {
const {
converted,
path: silkPath,
duration,
} = await encodeSilk(pttPath, this.core.NapCatTempPath, this.core.context.logger);
// 生成语音 Path: silkPath Time: duration
if (!silkPath) {
throw new Error('语音转换失败, 请检查语音文件是否正常');
}
const { md5, fileName, path, fileSize } = await this.core.apis.FileApi.uploadFile(silkPath, ElementType.PTT);
if (fileSize === 0) {
throw new Error('文件异常大小为0');
}
if (converted) {
fsPromises.unlink(silkPath);
}
return {
elementType: ElementType.PTT,
elementId: '',
pttElement: {
fileName: fileName,
filePath: path,
md5HexStr: md5,
fileSize: fileSize,
// duration: Math.max(1, Math.round(fileSize / 1024 / 3)), // 一秒钟大概是3kb大小, 小于1秒的按1秒算
duration: duration ?? 1,
formatType: 1,
voiceType: 1,
voiceChangeType: 0,
canConvert2Text: true,
waveAmplitudes: [
0, 18, 9, 23, 16, 17, 16, 15, 44, 17, 24, 20, 14, 15, 17,
],
fileSubId: '',
playState: 1,
autoConvertText: 0,
},
};
}
async downloadMediaByUuid() { async downloadMediaByUuid() {
//napCatCore.session.getRichMediaService().downloadFileForFileUuid(); //napCatCore.session.getRichMediaService().downloadFileForFileUuid();
} }
@@ -102,66 +318,45 @@ export class NTQQFileApi {
return sourcePath; return sourcePath;
} }
} }
const data = await this.core.eventWrapper.CallNormalEvent< const [, fileTransNotifyInfo] = await this.core.eventWrapper.callNormalEventV2(
( 'NodeIKernelMsgService/downloadRichMedia',
params: { 'NodeIKernelMsgListener/onRichMediaDownloadComplete',
fileModelId: string, [{
downloadSourceType: number, fileModelId: '0',
triggerType: number, downloadSourceType: 0,
msgId: string, triggerType: 1,
chatType: ChatType, msgId: msgId,
peerUid: string, chatType: chatType,
elementId: string, peerUid: peerUid,
thumbSize: number, elementId: elementId,
downloadType: number, thumbSize: 0,
filePath: string downloadType: 1,
}) => Promise<unknown>, filePath: thumbPath,
(fileTransNotifyInfo: OnRichMediaDownloadCompleteParams) => void }],
>( () => true,
'NodeIKernelMsgService/downloadRichMedia', (arg) => arg.msgId === msgId,
'NodeIKernelMsgListener/onRichMediaDownloadComplete', 1,
1, timeout,
timeout, );
(arg: OnRichMediaDownloadCompleteParams) => {
if (arg.msgId === msgId) {
return true;
}
return false;
},
{
fileModelId: '0',
downloadSourceType: 0,
triggerType: 1,
msgId: msgId,
chatType: chatType,
peerUid: peerUid,
elementId: elementId,
thumbSize: 0,
downloadType: 1,
filePath: thumbPath,
},
);
const msg = await this.core.apis.MsgApi.getMsgsByMsgId({ const msg = await this.core.apis.MsgApi.getMsgsByMsgId({
guildId: '', guildId: '',
chatType: chatType, chatType: chatType,
peerUid: peerUid, peerUid: peerUid,
}, [msgId]); }, [msgId]);
if (msg.msgList.length === 0) { if (msg.msgList.length === 0) {
return data[1].filePath; return fileTransNotifyInfo.filePath;
} }
//获取原始消息 //获取原始消息
const FileElements = msg?.msgList[0]?.elements?.find(e => e.elementId === elementId); const FileElements = msg?.msgList[0]?.elements?.find(e => e.elementId === elementId);
if (!FileElements) { if (!FileElements) {
//失败则就乱来 Todo //失败则就乱来 Todo
return data[1].filePath; return fileTransNotifyInfo.filePath;
} }
//从原始消息获取文件路径 //从原始消息获取文件路径
const filePath = return FileElements?.fileElement?.filePath ??
FileElements?.fileElement?.filePath || FileElements?.pttElement?.filePath ??
FileElements?.pttElement?.filePath || FileElements?.videoElement?.filePath ??
FileElements?.videoElement?.filePath ||
FileElements?.picElement?.sourcePath; FileElements?.picElement?.sourcePath;
return filePath;
} }
async getImageSize(filePath: string): Promise<ISizeCalculationResult | undefined> { async getImageSize(filePath: string): Promise<ISizeCalculationResult | undefined> {
@@ -236,56 +431,14 @@ export class NTQQFileApi {
} }
async searchfile(keys: string[]) { async searchfile(keys: string[]) {
type EventType = NodeIKernelSearchService['searchFileWithKeywords']; const Event = this.core.eventWrapper.createEventFunction('NodeIKernelSearchService/searchFileWithKeywords');
const id = await Event!(keys, 12);
interface OnListener { const Listener = this.core.eventWrapper.registerListen(
searchId: string,
hasMore: boolean,
resultItems: {
chatType: ChatType,
buddyChatInfo: any[],
discussChatInfo: any[],
groupChatInfo:
{
groupCode: string,
isConf: boolean,
hasModifyConfGroupFace: boolean,
hasModifyConfGroupName: boolean,
groupName: string,
remark: string
}[],
dataLineChatInfo: any[],
tmpChatInfo: any[],
msgId: string,
msgSeq: string,
msgTime: string,
senderUid: string,
senderNick: string,
senderRemark: string,
senderCard: string,
elemId: string,
elemType: number,
fileSize: string,
filePath: string,
fileName: string,
hits:
{
start: number,
end: number
}[]
}[]
}
const Event = this.core.eventWrapper.createEventFunction<EventType>('NodeIKernelSearchService/searchFileWithKeywords');
let id = '';
const Listener = this.core.eventWrapper.RegisterListen<(params: OnListener) => void>
(
'NodeIKernelSearchListener/onSearchFileKeywordsResult', 'NodeIKernelSearchListener/onSearchFileKeywordsResult',
1, 1,
20000, 20000,
(params) => id !== '' && params.searchId == id, (params) => id !== '' && params.searchId == id,
); );
id = await Event!(keys, 12);
const [ret] = (await Listener); const [ret] = (await Listener);
return ret; return ret;
} }
@@ -297,7 +450,7 @@ export class NTQQFileApi {
const url: string = element.originImageUrl!; // 没有域名 const url: string = element.originImageUrl!; // 没有域名
const md5HexStr = element.md5HexStr; const md5HexStr = element.md5HexStr;
const fileMd5 = element.md5HexStr; const fileMd5 = element.md5HexStr;
const fileUuid = element.fileUuid; // const fileUuid = element.fileUuid;
if (url) { if (url) {
const UrlParse = new URL(IMAGE_HTTP_HOST + url);//临时解析拼接 const UrlParse = new URL(IMAGE_HTTP_HOST + url);//临时解析拼接
@@ -317,7 +470,7 @@ export class NTQQFileApi {
} }
} else if (fileMd5 || md5HexStr) { } else if (fileMd5 || md5HexStr) {
// 没有url需要自己拼接 // 没有url需要自己拼接
return `${IMAGE_HTTP_HOST}/gchatpic_new/0/0-0-${(fileMd5 || md5HexStr)!.toUpperCase()}/0`; return `${IMAGE_HTTP_HOST}/gchatpic_new/0/0-0-${(fileMd5 ?? md5HexStr)!.toUpperCase()}/0`;
} }
this.context.logger.logDebug('图片url获取失败', element); this.context.logger.logDebug('图片url获取失败', element);
return ''; return '';
@@ -369,9 +522,9 @@ export class NTQQFileCacheApi {
} }
getFileCacheInfo(fileType: CacheFileType, pageSize: number = 1000, lastRecord?: CacheFileListItem) { getFileCacheInfo(fileType: CacheFileType, pageSize: number = 1000, lastRecord?: CacheFileListItem) {
const _lastRecord = lastRecord ? lastRecord : { fileType: fileType }; // const _lastRecord = lastRecord ? lastRecord : { fileType: fileType };
//需要五个参数 // 需要五个参数
//return napCatCore.session.getStorageCleanService().getFileCacheInfo(); // return napCatCore.session.getStorageCleanService().getFileCacheInfo();
} }
async clearChatCache(chats: ChatCacheListItemBasic[] = [], fileKeys: string[] = []) { async clearChatCache(chats: ChatCacheListItemBasic[] = [], fileKeys: string[] = []) {

View File

@@ -1,11 +1,12 @@
import { Friend, FriendV2, User } from '@/core/entities'; import { FriendV2 } from '@/core/entities';
import { BuddyListReqType, InstanceContext, NapCatCore, NodeIKernelProfileService, OnBuddyChangeParams } from '@/core'; import { BuddyListReqType, InstanceContext, NapCatCore, NodeIKernelProfileService } from '@/core';
import { LimitedHashTable } from '@/common/utils/MessageUnique'; import { LimitedHashTable } from '@/common/utils/message-unique';
export class NTQQFriendApi { export class NTQQFriendApi {
context: InstanceContext; context: InstanceContext;
core: NapCatCore; core: NapCatCore;
//friends: Map<string, Friend> = new Map<string, FriendV2>();
// friends: Map<string, Friend> = new Map<string, FriendV2>();
constructor(context: InstanceContext, core: NapCatCore) { constructor(context: InstanceContext, core: NapCatCore) {
this.context = context; this.context = context;
@@ -20,8 +21,8 @@ export class NTQQFriendApi {
const buddyService = this.context.session.getBuddyService(); const buddyService = this.context.session.getBuddyService();
const buddyListV2 = refresh ? await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL) : await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL); const buddyListV2 = refresh ? await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL) : await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL);
uids.push(...buddyListV2.data.flatMap(item => item.buddyUids)); uids.push(...buddyListV2.data.flatMap(item => item.buddyUids));
const data = await this.core.eventWrapper.callNoListenerEvent<NodeIKernelProfileService['getCoreAndBaseInfo']>( const data = await this.core.eventWrapper.callNoListenerEvent(
'NodeIKernelProfileService/getCoreAndBaseInfo', 5000, 'nodeStore', uids, 'NodeIKernelProfileService/getCoreAndBaseInfo', 'nodeStore', uids,
); );
return Array.from(data.values()); return Array.from(data.values());
} }
@@ -32,10 +33,10 @@ export class NTQQFriendApi {
const buddyService = this.context.session.getBuddyService(); const buddyService = this.context.session.getBuddyService();
const buddyListV2 = refresh ? await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL) : await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL); const buddyListV2 = refresh ? await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL) : await buddyService.getBuddyListV2('0', BuddyListReqType.KNOMAL);
uids.push(...buddyListV2.data.flatMap(item => item.buddyUids)); uids.push(...buddyListV2.data.flatMap(item => item.buddyUids));
const data = await this.core.eventWrapper.callNoListenerEvent<NodeIKernelProfileService['getCoreAndBaseInfo']>( const data = await this.core.eventWrapper.callNoListenerEvent(
'NodeIKernelProfileService/getCoreAndBaseInfo', 5000, 'nodeStore', uids, 'NodeIKernelProfileService/getCoreAndBaseInfo', 'nodeStore', uids,
); );
data.forEach((value, key) => { data.forEach((value) => {
retMap.set(value.uin!, value.uid!); retMap.set(value.uin!, value.uid!);
}); });
//console.log('getBuddyIdMap', retMap.getValue); //console.log('getBuddyIdMap', retMap.getValue);
@@ -54,8 +55,8 @@ export class NTQQFriendApi {
}); });
return item.buddyUids; return item.buddyUids;
})); }));
const data = await this.core.eventWrapper.callNoListenerEvent<NodeIKernelProfileService['getCoreAndBaseInfo']>( const data = await this.core.eventWrapper.callNoListenerEvent(
'NodeIKernelProfileService/getCoreAndBaseInfo', 5000, 'nodeStore', uids, 'NodeIKernelProfileService/getCoreAndBaseInfo', 'nodeStore', uids,
); );
return buddyListV2.map(category => ({ return buddyListV2.map(category => ({
categoryId: category.categoryId, categoryId: category.categoryId,
@@ -71,28 +72,17 @@ export class NTQQFriendApi {
return this.context.session.getBuddyService().isBuddy(uid); return this.context.session.getBuddyService().isBuddy(uid);
} }
/** async clearBuddyReqUnreadCnt() {
* @deprecated return this.context.session.getBuddyService().clearBuddyReqUnreadCnt();
* @param forced }
* @returns
*/ async getBuddyReq() {
async getFriends(forced = false): Promise<User[]> { const [, ret] = await this.core.eventWrapper.callNormalEventV2(
const [_retData, _BuddyArg] = await this.core.eventWrapper.CallNormalEvent<(force: boolean) => Promise<any>, (arg: OnBuddyChangeParams) => void> 'NodeIKernelBuddyService/getBuddyReq',
( 'NodeIKernelBuddyListener/onBuddyReqChange',
'NodeIKernelBuddyService/getBuddyList', [],
'NodeIKernelBuddyListener/onBuddyListChange', );
1, return ret;
5000,
() => true,
forced,
);
const friends: User[] = [];
for (const categoryItem of _BuddyArg) {
for (const friend of categoryItem.buddyList) {
friends.push(friend);
}
}
return friends;
} }
async handleFriendRequest(flag: string, accept: boolean) { async handleFriendRequest(flag: string, accept: boolean) {

View File

@@ -4,15 +4,14 @@ import {
Group, Group,
GroupMember, GroupMember,
GroupMemberRole, GroupMemberRole,
GroupNotify,
GroupRequestOperateTypes, GroupRequestOperateTypes,
InstanceContext, InstanceContext,
KickMemberV2Req,
MemberExtSourceType, MemberExtSourceType,
NapCatCore, NapCatCore,
NodeIKernelGroupListener,
NodeIKernelGroupService, NodeIKernelGroupService,
} from '@/core'; } from '@/core';
import { isNumeric, runAllWithTimeout } from '@/common/utils/helper'; import { isNumeric, runAllWithTimeout, sleep } from '@/common/utils/helper';
export class NTQQGroupApi { export class NTQQGroupApi {
context: InstanceContext; context: InstanceContext;
@@ -20,11 +19,15 @@ export class NTQQGroupApi {
groupCache: Map<string, Group> = new Map<string, Group>(); groupCache: Map<string, Group> = new Map<string, Group>();
groupMemberCache: Map<string, Map<string, GroupMember>> = new Map<string, Map<string, GroupMember>>(); groupMemberCache: Map<string, Map<string, GroupMember>> = new Map<string, Map<string, GroupMember>>();
groups: Group[] = []; groups: Group[] = [];
constructor(context: InstanceContext, core: NapCatCore) { constructor(context: InstanceContext, core: NapCatCore) {
this.context = context; this.context = context;
this.core = core; this.core = core;
this.initCache().then().catch(context.logger.logError); sleep(1000).then(() => {
this.initCache().then().catch(context.logger.logError);
});
} }
async initCache() { async initCache() {
this.groups = await this.getGroups(); this.groups = await this.getGroups();
for (const group of this.groups) { for (const group of this.groups) {
@@ -34,24 +37,60 @@ export class NTQQGroupApi {
} }
this.context.logger.logDebug(`加载${this.groups.length}个群组缓存完成`); this.context.logger.logDebug(`加载${this.groups.length}个群组缓存完成`);
} }
async setGroupAvatar(gc: string, filePath: string) { async setGroupAvatar(gc: string, filePath: string) {
return this.context.session.getGroupService().setHeader(gc, filePath); return this.context.session.getGroupService().setHeader(gc, filePath);
} }
async getGroups(forced = false) { async getGroups(forced = false) {
type ListenerType = NodeIKernelGroupListener['onGroupListUpdate']; const [, , groupList] = await this.core.eventWrapper.callNormalEventV2(
const [_retData, _updateType, groupList] = await this.core.eventWrapper.CallNormalEvent<(force: boolean) => Promise<any>, ListenerType>
(
'NodeIKernelGroupService/getGroupList', 'NodeIKernelGroupService/getGroupList',
'NodeIKernelGroupListener/onGroupListUpdate', 'NodeIKernelGroupListener/onGroupListUpdate',
1, [forced],
5000, );
() => true,
forced,
);
return groupList; return groupList;
} }
async getGroupExtFE0Info(GroupCode: string[], forced = true) {
return this.context.session.getGroupService().getGroupExt0xEF0Info(
GroupCode,
[],
{
bindGuildId: 1,
blacklistExpireTime: 1,
companyId: 1,
essentialMsgPrivilege: 1,
essentialMsgSwitch: 1,
fullGroupExpansionSeq: 1,
fullGroupExpansionSwitch: 1,
gangUpId: 1,
groupAioBindGuildId: 1,
groupBindGuildIds: 1,
groupBindGuildSwitch: 1,
groupExcludeGuildIds: 1,
groupExtFlameData: 1,
groupFlagPro1: 1,
groupInfoExtSeq: 1,
groupOwnerId: 1,
groupSquareSwitch: 1,
hasGroupCustomPortrait: 1,
inviteRobotMemberExamine: 1,
inviteRobotMemberSwitch: 1,
inviteRobotSwitch: 1,
isLimitGroupRtc: 1,
lightCharNum: 1,
luckyWord: 1,
luckyWordId: 1,
msgEventSeq: 1,
qqMusicMedalSwitch: 1,
reserve: 1,
showPlayTogetherSwitch: 1,
starId: 1,
todoSeq: 1,
viewedMsgDisappearTime: 1
},
forced
);
}
async getGroup(groupCode: string, forced = false) { async getGroup(groupCode: string, forced = false) {
let group = this.groupCache.get(groupCode.toString()); let group = this.groupCache.get(groupCode.toString());
if (!group) { if (!group) {
@@ -139,8 +178,7 @@ export class NTQQGroupApi {
members = await this.getGroupMembers(groupCodeStr); members = await this.getGroupMembers(groupCodeStr);
// 更新群成员列表 // 更新群成员列表
this.groupMemberCache.set(groupCodeStr, members); this.groupMemberCache.set(groupCodeStr, members);
} } catch (e) {
catch (e) {
return null; return null;
} }
} }
@@ -220,6 +258,24 @@ export class NTQQGroupApi {
return this.context.session.getGroupService().addGroupEssence(param); return this.context.session.getGroupService().addGroupEssence(param);
} }
async kickMemberV2Inner(param: KickMemberV2Req) {
return this.context.session.getGroupService().kickMemberV2(param);
}
async deleteGroupBulletin(GroupCode: string, noticeId: string) {
const _Pskey = (await this.core.apis.UserApi.getPSkey(['qun.qq.com'])).domainPskeyMap.get('qun.qq.com')!;
return this.context.session.getGroupService().deleteGroupBulletin(GroupCode, _Pskey, noticeId);
}
async quitGroupV2(GroupCode: string, needDeleteLocalMsg: boolean) {
const param = {
groupCode: GroupCode,
needDeleteLocalMsg: needDeleteLocalMsg,
};
//应该是直接返回不需要Listener的 未经测试 需测试再发布
return this.context.session.getGroupService().quitGroupV2(param);
}
async removeGroupEssence(GroupCode: string, msgId: string) { async removeGroupEssence(GroupCode: string, msgId: string) {
// 代码没测过 // 代码没测过
// 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom // 需要 ob11msgid->msgId + (peer) -> msgSeq + msgRandom
@@ -238,36 +294,30 @@ export class NTQQGroupApi {
} }
async getSingleScreenNotifies(num: number) { async getSingleScreenNotifies(num: number) {
const [_retData, _doubt, _seq, notifies] = await this.core.eventWrapper.CallNormalEvent<(arg1: boolean, arg2: string, arg3: number) => Promise<any>, (doubt: boolean, seq: string, notifies: GroupNotify[]) => void> const [, , , notifies] = await this.core.eventWrapper.callNormalEventV2(
(
'NodeIKernelGroupService/getSingleScreenNotifies', 'NodeIKernelGroupService/getSingleScreenNotifies',
'NodeIKernelGroupListener/onGroupSingleScreenNotifies', 'NodeIKernelGroupListener/onGroupSingleScreenNotifies',
1, [
5000, false,
() => true, '',
false, num,
'', ],
num, );
);
return notifies; return notifies;
} }
async getGroupMemberV2(GroupCode: string, uid: string, forced = false) { async getGroupMemberV2(GroupCode: string, uid: string, forced = false) {
//type ListenerType = NodeIKernelGroupListener['onMemberInfoChange'];
type EventType = NodeIKernelGroupService['getMemberInfo']; type EventType = NodeIKernelGroupService['getMemberInfo'];
// NTEventDispatch.CreatListenerFunction('NodeIKernelGroupListener/onGroupMemberInfoUpdate', const Listener = this.core.eventWrapper.registerListen(
//return napCatCore.session.getGroupService().getMemberInfo(GroupCode, [uid], forced);
const Listener = this.core.eventWrapper.RegisterListen<(params: any) => void>
(
'NodeIKernelGroupListener/onMemberInfoChange', 'NodeIKernelGroupListener/onMemberInfoChange',
1, 1,
forced ? 5000 : 250, forced ? 5000 : 250,
(params) => { (params) => params === GroupCode,
return params === GroupCode; );
}, const retData = await (
); this.core.eventWrapper
const EventFunc = this.core.eventWrapper.createEventFunction<EventType>('NodeIKernelGroupService/getMemberInfo'); .createEventFunction('NodeIKernelGroupService/getMemberInfo')
const retData = await EventFunc!(GroupCode, [uid], forced); )!(GroupCode, [uid], forced);
if (retData.result !== 0) { if (retData.result !== 0) {
throw new Error(`${retData.errMsg}`); throw new Error(`${retData.errMsg}`);
} }
@@ -278,20 +328,6 @@ export class NTQQGroupApi {
member = members.get(uid); member = members.get(uid);
} }
return member; return member;
// 原本的方法: (no_cache 下效率很高, cache 下效率一致)
// const [, , , _members] = await this.core.eventWrapper.CallNormalEvent<EventType, ListenerType>
// (
// 'NodeIKernelGroupService/getMemberInfo',
// 'NodeIKernelGroupListener/onMemberInfoChange',
// 1,
// 5000,
// (groupCode: string, changeType: number, members: Map<string, GroupMember>) => {
// return groupCode == GroupCode && members.has(uid);
// },
// GroupCode, [uid], forced,
// );
// return _members.get(uid);
} }
async getGroupMembers(groupQQ: string, num = 3000): Promise<Map<string, GroupMember>> { async getGroupMembers(groupQQ: string, num = 3000): Promise<Map<string, GroupMember>> {
@@ -299,10 +335,10 @@ export class NTQQGroupApi {
const sceneId = groupService.createMemberListScene(groupQQ, 'groupMemberList_MainWindow'); const sceneId = groupService.createMemberListScene(groupQQ, 'groupMemberList_MainWindow');
const result = await groupService.getNextMemberList(sceneId!, undefined, num); const result = await groupService.getNextMemberList(sceneId!, undefined, num);
if (result.errCode !== 0) { if (result.errCode !== 0) {
throw ('获取群成员列表出错,' + result.errMsg); throw new Error('获取群成员列表出错,' + result.errMsg);
} }
//logDebug(`获取群(${groupQQ})成员列表结果:`, `finish: ${result.result.finish}`); //, Array.from(result.result.infos.values())); this.context.logger.logDebug(`获取群(${groupQQ})成员列表结果:`, `members: ${result.result.infos.size}`); //, Array.from(result.result.infos.values()));
return result.result.infos; return result.result.infos;
/* /*
console.log(sceneId); console.log(sceneId);
@@ -327,13 +363,10 @@ export class NTQQGroupApi {
} }
async getArkJsonGroupShare(GroupCode: string) { async getArkJsonGroupShare(GroupCode: string) {
const ret = await this.core.eventWrapper.callNoListenerEvent<(GroupId: string) => Promise<GeneralCallResult & { const ret = await this.core.eventWrapper.callNoListenerEvent(
arkJson: string
}>>(
'NodeIKernelGroupService/getGroupRecommendContactArkJson', 'NodeIKernelGroupService/getGroupRecommendContactArkJson',
5000,
GroupCode, GroupCode,
); ) as GeneralCallResult & { arkJson: string };
return ret.arkJson; return ret.arkJson;
} }
@@ -357,7 +390,7 @@ export class NTQQGroupApi {
'seq': seq, // 通知序列号 'seq': seq, // 通知序列号
'type': type, 'type': type,
'groupCode': groupCode, 'groupCode': groupCode,
'postscript': reason || ' ', // 仅传空值可能导致处理失败,故默认给个空格 'postscript': reason ?? ' ', // 仅传空值可能导致处理失败,故默认给个空格
}, },
}); });
} }

View File

@@ -1,6 +1,5 @@
import { ChatType, GetFileListParam, Peer, RawMessage, SendMessageElement, SendStatusType } from '@/core/entities'; import { ChatType, GetFileListParam, Peer, RawMessage, SendMessageElement, SendStatusType } from '@/core/entities';
import { InstanceContext, NapCatCore } from '@/core'; import { InstanceContext, NapCatCore } from '@/core';
import { onGroupFileInfoUpdateParamType } from '@/core/listeners';
import { GeneralCallResult } from '@/core/services/common'; import { GeneralCallResult } from '@/core/services/common';
export class NTQQMsgApi { export class NTQQMsgApi {
@@ -19,10 +18,11 @@ export class NTQQMsgApi {
async sendShowInputStatusReq(peer: Peer, eventType: number) { async sendShowInputStatusReq(peer: Peer, eventType: number) {
return this.context.session.getMsgService().sendShowInputStatusReq(peer.chatType, eventType, peer.peerUid); return this.context.session.getMsgService().sendShowInputStatusReq(peer.chatType, eventType, peer.peerUid);
} }
async getMsgEmojiLikesList(peer: Peer, msgSeq: string, emojiId: string, emojiType: string, count: number = 20) { async getMsgEmojiLikesList(peer: Peer, msgSeq: string, emojiId: string, emojiType: string, count: number = 20) {
//console.log(peer, msgSeq, emojiId, emojiType, count); //console.log(peer, msgSeq, emojiId, emojiType, count);
//注意此处emojiType 可选值一般为1-2 2好像是unicode表情dec值 大部分情况 Taged M likiowa //注意此处emojiType 可选值一般为1-2 2好像是unicode表情dec值 大部分情况 Taged M likiowa
return this.context.session.getMsgService().getMsgEmojiLikesList(peer, msgSeq, emojiId, emojiType, '', false, 20); return this.context.session.getMsgService().getMsgEmojiLikesList(peer, msgSeq, emojiId, emojiType, '', false, count);
} }
// napCatCore: NapCatCore | null = null; // napCatCore: NapCatCore | null = null;
@@ -40,6 +40,7 @@ export class NTQQMsgApi {
emojiId = emojiId.toString(); emojiId = emojiId.toString();
return this.context.session.getMsgService().setMsgEmojiLikes(peer, msgSeq, emojiId, emojiId.length > 3 ? '2' : '1', set); return this.context.session.getMsgService().setMsgEmojiLikes(peer, msgSeq, emojiId, emojiId.length > 3 ? '2' : '1', set);
} }
async getMultiMsg(peer: Peer, rootMsgId: string, parentMsgId: string): Promise<GeneralCallResult & { async getMultiMsg(peer: Peer, rootMsgId: string, parentMsgId: string): Promise<GeneralCallResult & {
msgList: RawMessage[] msgList: RawMessage[]
} | undefined> { } | undefined> {
@@ -51,7 +52,7 @@ export class NTQQMsgApi {
} }
async getLastestMsgByUids(peer: Peer, count: number = 20, isReverseOrder: boolean = false) { async getLastestMsgByUids(peer: Peer, count: number = 20, isReverseOrder: boolean = false) {
const ret = await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', '0', { return await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', '0', {
chatInfo: peer, chatInfo: peer,
filterMsgType: [], filterMsgType: [],
filterSendersUid: [], filterSendersUid: [],
@@ -61,7 +62,6 @@ export class NTQQMsgApi {
isIncludeCurrent: true, isIncludeCurrent: true,
pageLimit: count, pageLimit: count,
}); });
return ret;
} }
async getMsgsByMsgId(peer: Peer | undefined, msgIds: string[] | undefined) { async getMsgsByMsgId(peer: Peer | undefined, msgIds: string[] | undefined) {
@@ -80,7 +80,7 @@ export class NTQQMsgApi {
} }
async queryMsgsWithFilterExWithSeq(peer: Peer, msgSeq: string) { async queryMsgsWithFilterExWithSeq(peer: Peer, msgSeq: string) {
const ret = await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', msgSeq, { return await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', msgSeq, {
chatInfo: peer,//此处为Peer 为关键查询参数 没有啥也没有 by mlik iowa chatInfo: peer,//此处为Peer 为关键查询参数 没有啥也没有 by mlik iowa
filterMsgType: [], filterMsgType: [],
filterSendersUid: [], filterSendersUid: [],
@@ -90,17 +90,17 @@ export class NTQQMsgApi {
isIncludeCurrent: true, isIncludeCurrent: true,
pageLimit: 1, pageLimit: 1,
}); });
return ret;
} }
async getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, z: boolean) { async getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, z: boolean) {
return await this.context.session.getMsgService().getMsgsBySeqAndCount(peer, seq, count, desc, z); return await this.context.session.getMsgService().getMsgsBySeqAndCount(peer, seq, count, desc, z);
} }
async getMsgExBySeq(peer: Peer, msgSeq: string) { async getMsgExBySeq(peer: Peer, msgSeq: string) {
const DateNow = Math.floor(Date.now() / 1000); const DateNow = Math.floor(Date.now() / 1000);
const filterMsgFromTime = (DateNow - 300).toString(); const filterMsgFromTime = (DateNow - 300).toString();
const filterMsgToTime = DateNow.toString(); const filterMsgToTime = DateNow.toString();
const ret = await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', msgSeq, { return await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', msgSeq, {
chatInfo: peer,//此处为Peer 为关键查询参数 没有啥也没有 by mlik iowa chatInfo: peer,//此处为Peer 为关键查询参数 没有啥也没有 by mlik iowa
filterMsgType: [], filterMsgType: [],
filterSendersUid: [], filterSendersUid: [],
@@ -110,29 +110,29 @@ export class NTQQMsgApi {
isIncludeCurrent: true, isIncludeCurrent: true,
pageLimit: 100, pageLimit: 100,
}); });
return ret;
} }
async setMsgRead(peer: Peer) { async setMsgRead(peer: Peer) {
return this.context.session.getMsgService().setMsgRead(peer); return this.context.session.getMsgService().setMsgRead(peer);
} }
async getGroupFileList(GroupCode: string, params: GetFileListParam) { async getGroupFileList(GroupCode: string, params: GetFileListParam) {
const data = await this.core.eventWrapper.CallNormalEvent< const [, groupFileListResult] = await this.core.eventWrapper.callNormalEventV2(
(GroupCode: string, params: GetFileListParam) => Promise<unknown>, 'NodeIKernelRichMediaService/getGroupFileList',
(groupFileListResult: onGroupFileInfoUpdateParamType) => void 'NodeIKernelMsgListener/onGroupFileInfoUpdate',
>( [
'NodeIKernelRichMediaService/getGroupFileList',
'NodeIKernelMsgListener/onGroupFileInfoUpdate',
1,
5000,
(groupFileListResult: onGroupFileInfoUpdateParamType) => {
//Developer Mlikiowa Todo: 此处有问题 无法判断是否成功
return true;
},
GroupCode, GroupCode,
params, params,
); ],
return data[1].item; () => true,
( /* groupFileListResult: GroupFileInfoUpdateParamType */) => {
//Developer Mlikiowa Todo: 此处有问题 无法判断是否成功
return true;
},
1,
5000,
);
return groupFileListResult.item;
} }
async getMsgHistory(peer: Peer, msgId: string, count: number, isReverseOrder: boolean = false) { async getMsgHistory(peer: Peer, msgId: string, count: number, isReverseOrder: boolean = false) {
@@ -146,29 +146,32 @@ export class NTQQMsgApi {
peerUid: peer.peerUid, peerUid: peer.peerUid,
}, msgIds); }, msgIds);
} }
async PrepareTempChat(toUserUid: string, GroupCode: string, nickname: string) { async PrepareTempChat(toUserUid: string, GroupCode: string, nickname: string) {
//By Jadx/Ida Mlikiowa //By Jadx/Ida Mlikiowa
const TempGameSession = { const TempGameSession = {
nickname: "", nickname: '',
gameAppId: "", gameAppId: '',
selfTinyId: "", selfTinyId: '',
peerRoleId: "", peerRoleId: '',
peerOpenId: "", peerOpenId: '',
}; };
return this.context.session.getMsgService().prepareTempChat({ return this.context.session.getMsgService().prepareTempChat({
chatType: ChatType.KCHATTYPETEMPC2CFROMGROUP, chatType: ChatType.KCHATTYPETEMPC2CFROMGROUP,
peerUid: toUserUid, peerUid: toUserUid,
peerNickname: nickname, peerNickname: nickname,
fromGroupCode: GroupCode, fromGroupCode: GroupCode,
sig: "", sig: '',
selfPhone: "", selfPhone: '',
selfUid: this.core.selfInfo.uid, selfUid: this.core.selfInfo.uid,
gameSession: TempGameSession gameSession: TempGameSession,
}); });
} }
async getTempChatInfo(chatType: ChatType, peerUid: string) { async getTempChatInfo(chatType: ChatType, peerUid: string) {
return this.context.session.getMsgService().getTempChatInfo(chatType, peerUid); return this.context.session.getMsgService().getTempChatInfo(chatType, peerUid);
} }
async sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) { async sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
//唉? !我有个想法 //唉? !我有个想法
if (peer.chatType === ChatType.KCHATTYPETEMPC2CFROMGROUP && peer.guildId && peer.guildId !== '') { if (peer.chatType === ChatType.KCHATTYPETEMPC2CFROMGROUP && peer.guildId && peer.guildId !== '') {
@@ -179,33 +182,32 @@ export class NTQQMsgApi {
} }
const msgId = await this.generateMsgUniqueId(peer.chatType, await this.getServerTime()); const msgId = await this.generateMsgUniqueId(peer.chatType, await this.getServerTime());
peer.guildId = msgId; peer.guildId = msgId;
const data = await this.core.eventWrapper.CallNormalEvent< const [, msgList] = await this.core.eventWrapper.callNormalEventV2(
(msgId: string, peer: Peer, msgElements: SendMessageElement[], map: Map<any, any>) => Promise<unknown>, 'NodeIKernelMsgService/sendMsg',
(msgList: RawMessage[]) => void 'NodeIKernelMsgListener/onMsgInfoListUpdate',
>( [
'NodeIKernelMsgService/sendMsg',
'NodeIKernelMsgListener/onMsgInfoListUpdate',
1,
timeout,
(msgRecords: RawMessage[]) => {
for (const msgRecord of msgRecords) {
if (msgRecord.guildId === msgId && msgRecord.sendStatus === SendStatusType.KSEND_STATUS_SUCCESS) {
return true;
}
}
return false;
},
'0', '0',
peer, peer,
msgElements, msgElements,
new Map(), new Map(),
); ],
const retMsg = data[1].find(msgRecord => { () => true,
msgRecords => {
for (const msgRecord of msgRecords) {
if (msgRecord.guildId === msgId && msgRecord.sendStatus === SendStatusType.KSEND_STATUS_SUCCESS) {
return true;
}
}
return false;
},
1,
timeout,
);
return msgList.find(msgRecord => {
if (msgRecord.guildId === msgId) { if (msgRecord.guildId === msgId) {
return true; return true;
} }
}); });
return retMsg;
} }
async generateMsgUniqueId(chatType: number, time: string) { async generateMsgUniqueId(chatType: number, time: string) {
@@ -224,34 +226,32 @@ export class NTQQMsgApi {
const msgInfos = msgIds.map(id => { const msgInfos = msgIds.map(id => {
return { msgId: id, senderShowName: this.core.selfInfo.nick }; return { msgId: id, senderShowName: this.core.selfInfo.nick };
}); });
const data = await this.core.eventWrapper.CallNormalEvent< const [, msgList] = await this.core.eventWrapper.callNormalEventV2(
(msgInfo: typeof msgInfos, srcPeer: Peer, destPeer: Peer, comment: Array<any>, attr: Map<any, any>) => Promise<unknown>, 'NodeIKernelMsgService/multiForwardMsgWithComment',
(msgList: RawMessage[]) => void 'NodeIKernelMsgListener/onMsgInfoListUpdate',
>( [
'NodeIKernelMsgService/multiForwardMsgWithComment',
'NodeIKernelMsgListener/onMsgInfoListUpdate',
1,
5000,
(msgRecords: RawMessage[]) => {
for (const msgRecord of msgRecords) {
if (msgRecord.peerUid == destPeer.peerUid && msgRecord.senderUid == this.core.selfInfo.uid) {
return true;
}
}
return false;
},
msgInfos, msgInfos,
srcPeer, srcPeer,
destPeer, destPeer,
[], [],
new Map(), new Map(),
); ],
for (const msg of data[1]) { () => true,
(msgRecords) => {
for (const msgRecord of msgRecords) {
if (msgRecord.peerUid == destPeer.peerUid && msgRecord.senderUid == this.core.selfInfo.uid) {
return true;
}
}
return false;
},
);
for (const msg of msgList) {
const arkElement = msg.elements.find(ele => ele.arkElement); const arkElement = msg.elements.find(ele => ele.arkElement);
if (!arkElement) { if (!arkElement) {
continue; continue;
} }
const forwardData: any = JSON.parse(arkElement.arkElement?.bytesData || ""); const forwardData: any = JSON.parse(arkElement.arkElement?.bytesData ?? '');
if (forwardData.app != 'com.tencent.multimsg') { if (forwardData.app != 'com.tencent.multimsg') {
continue; continue;
} }

View File

@@ -2,77 +2,6 @@ import { RequestUtil } from '@/common/utils/request';
import { MiniAppLuaJsonType } from '@/core'; import { MiniAppLuaJsonType } from '@/core';
import { InstanceContext, NapCatCore } from '..'; import { InstanceContext, NapCatCore } from '..';
// let t = await napCatCore.session.getGroupService().shareDigest({
// appId: "100497308",
// appType: 1,
// msgStyle: 0,
// recvUin: "726067488",
// sendType: 1,
// clientInfo: {
// platform: 1
// },
// richMsg: {
// usingArk: true,
// title: "Bot测试title",
// summary: "Bot测试summary",
// url: "https://www.bilibili.com",
// pictureUrl: "https://y.qq.com/music/photo_new/T002R300x300M0000035DC6W4ZpSqf_1.jpg?max_age=2592000",
// brief: "Bot测试brief",
// }
// });
// {
// errCode: 0,
// errMsg: '',
// rsp: {
// sendType: 1,
// recvUin: '726067488',
// recvOpenId: '',
// errCode: 901501,
// errMsg: 'imagent service_error:150_OIDB_NO_PRIV',
// extInfo: {
// wording: '消息下发失败(错误码901501)',
// jumpResult: 0,
// jumpUrl: '',
// level: 0,
// subLevel: 0,
// developMsg: 'imagent error'
// }
// }
// }
// export class MusicSign {
// private readonly url: string;
// constructor(url: string) {
// this.url = url;
// }
// sign(postData: CustomMusicSignPostData | IdMusicSignPostData): Promise<any> {
// return new Promise((resolve, reject) => {
// fetch(this.url, {
// method: 'POST', // 指定请求方法为 POST
// headers: {
// 'Content-Type': 'application/json' // 设置请求头,指明发送的数据类型为 JSON
// },
// body: JSON.stringify(postData) // 将 JavaScript 对象转换为 JSON 字符串作为请求体
// })
// .then(response => {
// if (!response.ok) {
// reject(response.statusText); // 请求失败,返回错误信息
// }
// return response.json(); // 解析 JSON 格式的响应体
// })
// .then(data => {
// logDebug('音乐消息生成成功', data);
// resolve(data);
// })
// .catch(error => {
// reject(error);
// });
// });
// }
// }
export class NTQQMusicSignApi { export class NTQQMusicSignApi {
context: InstanceContext; context: InstanceContext;
core: NapCatCore; core: NapCatCore;

View File

@@ -28,19 +28,12 @@ export class NTQQSystemApi {
//1-2-162b9b42-65b9-4405-a8ed-2e256ec8aa50 //1-2-162b9b42-65b9-4405-a8ed-2e256ec8aa50
async getArkJsonCollection(cid: string) { async getArkJsonCollection(cid: string) {
const ret = await this.core.eventWrapper.callNoListenerEvent<(cid: string) => Promise<GeneralCallResult & { return await this.core.eventWrapper.callNoListenerEvent('NodeIKernelCollectionService/collectionArkShare', '1717662698058');
arkJson: string
}>>(
'NodeIKernelCollectionService/collectionArkShare',
5000,
'1717662698058',
);
return ret;
} }
async BootMiniApp(appfile: string, params: string) { async BootMiniApp(appfile: string, params: string) {
await this.context.session.getNodeMiscService().setMiniAppVersion('2.16.4'); await this.context.session.getNodeMiscService().setMiniAppVersion('2.16.4');
const c = await this.context.session.getNodeMiscService().getMiniAppPath(); // const c = await this.context.session.getNodeMiscService().getMiniAppPath();
return this.context.session.getNodeMiscService().startNewMiniApp(appfile, params); return this.context.session.getNodeMiscService().startNewMiniApp(appfile, params);
} }

View File

@@ -1,8 +1,8 @@
import type { ModifyProfileParams, User, UserDetailInfoByUin, UserDetailInfoByUinV2 } from '@/core/entities'; import type { ModifyProfileParams, User, UserDetailInfoByUinV2 } from '@/core/entities';
import { NodeIKernelProfileListener } from '@/core/listeners';
import { RequestUtil } from '@/common/utils/request'; import { RequestUtil } from '@/common/utils/request';
import { NodeIKernelProfileService, ProfileBizType, UserDetailSource } from '@/core/services'; import { ProfileBizType, UserDetailSource } from '@/core/services';
import { InstanceContext, NapCatCore } from '..'; import { InstanceContext, NapCatCore } from '..';
import { solveAsyncProblem } from '@/common/utils/helper';
export class NTQQUserApi { export class NTQQUserApi {
context: InstanceContext; context: InstanceContext;
@@ -64,17 +64,18 @@ export class NTQQUserApi {
} }
async fetchUserDetailInfos(uids: string[]) { async fetchUserDetailInfos(uids: string[]) {
//26702 以上使用新接口 .Dev Mlikiowa // TODO: 26702 以上使用新接口 .Dev MliKiowa
type EventService = NodeIKernelProfileService['fetchUserDetailInfo'];
type EventListener = NodeIKernelProfileListener['onUserDetailInfoChanged'];
const retData: User[] = []; const retData: User[] = [];
const [_retData, _retListener] = await this.core.eventWrapper.CallNormalEvent< const [_retData, _retListener] = await this.core.eventWrapper.callNormalEventV2(
EventService, EventListener
>(
'NodeIKernelProfileService/fetchUserDetailInfo', 'NodeIKernelProfileService/fetchUserDetailInfo',
'NodeIKernelProfileListener/onUserDetailInfoChanged', 'NodeIKernelProfileListener/onUserDetailInfoChanged',
uids.length, [
5000, 'BuddyProfileStore',
uids,
UserDetailSource.KSERVER,
[ProfileBizType.KALL],
],
() => true,
(profile) => { (profile) => {
if (uids.includes(profile.uid)) { if (uids.includes(profile.uid)) {
const RetUser: User = { const RetUser: User = {
@@ -91,28 +92,24 @@ export class NTQQUserApi {
} }
return false; return false;
}, },
'BuddyProfileStore', uids.length,
uids,
UserDetailSource.KSERVER,
[ProfileBizType.KALL],
); );
return retData; return retData;
} }
async fetchUserDetailInfo(uid: string, mode: UserDetailSource = UserDetailSource.KDB) { async fetchUserDetailInfo(uid: string, mode: UserDetailSource = UserDetailSource.KDB) {
type EventService = NodeIKernelProfileService['fetchUserDetailInfo']; const [_retData, profile] = await this.core.eventWrapper.callNormalEventV2(
type EventListener = NodeIKernelProfileListener['onUserDetailInfoChanged'];
const [_retData, profile] = await this.core.eventWrapper.CallNormalEvent<EventService, EventListener>(
'NodeIKernelProfileService/fetchUserDetailInfo', 'NodeIKernelProfileService/fetchUserDetailInfo',
'NodeIKernelProfileListener/onUserDetailInfoChanged', 'NodeIKernelProfileListener/onUserDetailInfoChanged',
1, [
5000, 'BuddyProfileStore',
[uid],
mode,
[ProfileBizType.KALL],
],
() => true,
(profile) => profile.uid === uid, (profile) => profile.uid === uid,
'BuddyProfileStore',
[uid],
mode,
[ProfileBizType.KALL],
); );
const RetUser: User = { const RetUser: User = {
...profile.simpleInfo.coreInfo, ...profile.simpleInfo.coreInfo,
@@ -128,12 +125,9 @@ export class NTQQUserApi {
} }
async getUserDetailInfo(uid: string): Promise<User> { async getUserDetailInfo(uid: string): Promise<User> {
try { const retUser = await solveAsyncProblem(async (uid) => this.fetchUserDetailInfo(uid, UserDetailSource.KDB), uid);
const retUser = await this.fetchUserDetailInfo(uid, UserDetailSource.KDB); if (retUser && retUser.uin !== '0') {
if (retUser.uin !== '0') { return retUser;
return retUser;
}
} catch (e) {
} }
this.context.logger.logDebug('[NapCat] [Mark] getUserDetailInfo Mode1 Failed.'); this.context.logger.logDebug('[NapCat] [Mark] getUserDetailInfo Mode1 Failed.');
return this.fetchUserDetailInfo(uid, UserDetailSource.KSERVER); return this.fetchUserDetailInfo(uid, UserDetailSource.KSERVER);
@@ -148,8 +142,7 @@ export class NTQQUserApi {
const ClientKeyData = await this.forceFetchClientKey(); const ClientKeyData = await this.forceFetchClientKey();
const requestUrl = 'https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=' + this.core.selfInfo.uin + const requestUrl = 'https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=' + this.core.selfInfo.uin +
'&clientkey=' + ClientKeyData.clientKey + '&u1=https%3A%2F%2F' + domain + '%2F' + this.core.selfInfo.uin + '%2Finfocenter&keyindex=19%27'; '&clientkey=' + ClientKeyData.clientKey + '&u1=https%3A%2F%2F' + domain + '%2F' + this.core.selfInfo.uin + '%2Finfocenter&keyindex=19%27';
const cookies: { [key: string]: string; } = await RequestUtil.HttpsGetCookies(requestUrl); return await RequestUtil.HttpsGetCookies(requestUrl);
return cookies;
} }
async getPSkey(domainList: string[]) { async getPSkey(domainList: string[]) {
@@ -172,8 +165,7 @@ export class NTQQUserApi {
async getQzoneCookies() { async getQzoneCookies() {
const ClientKeyData = await this.forceFetchClientKey(); const ClientKeyData = await this.forceFetchClientKey();
const requestUrl = 'https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=' + this.core.selfInfo.uin + '&clientkey=' + ClientKeyData.clientKey + '&u1=https%3A%2F%2Fuser.qzone.qq.com%2F' + this.core.selfInfo.uin + '%2Finfocenter&keyindex=19%27'; const requestUrl = 'https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=' + this.core.selfInfo.uin + '&clientkey=' + ClientKeyData.clientKey + '&u1=https%3A%2F%2Fuser.qzone.qq.com%2F' + this.core.selfInfo.uin + '%2Finfocenter&keyindex=19%27';
const cookies: { [key: string]: string; } = await RequestUtil.HttpsGetCookies(requestUrl); return await RequestUtil.HttpsGetCookies(requestUrl);
return cookies;
} }
//需要异常处理 //需要异常处理
@@ -184,7 +176,7 @@ export class NTQQUserApi {
throw new Error('getClientKey Error'); throw new Error('getClientKey Error');
} }
const clientKey = ClientKeyData.clientKey; const clientKey = ClientKeyData.clientKey;
const keyIndex = ClientKeyData.keyIndex; // const keyIndex = ClientKeyData.keyIndex;
const requestUrl = 'https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=' + this.core.selfInfo.uin + '&clientkey=' + clientKey + '&u1=https%3A%2F%2Fh5.qzone.qq.com%2Fqqnt%2Fqzoneinpcqq%2Ffriend%3Frefresh%3D0%26clientuin%3D0%26darkMode%3D0&keyindex=19%27'; const requestUrl = 'https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=' + this.core.selfInfo.uin + '&clientkey=' + clientKey + '&u1=https%3A%2F%2Fh5.qzone.qq.com%2Fqqnt%2Fqzoneinpcqq%2Ffriend%3Frefresh%3D0%26clientuin%3D0%26darkMode%3D0&keyindex=19%27';
const cookies: { [key: string]: string; } = await RequestUtil.HttpsGetCookies(requestUrl); const cookies: { [key: string]: string; } = await RequestUtil.HttpsGetCookies(requestUrl);
const skey = cookies['skey']; const skey = cookies['skey'];
@@ -239,8 +231,7 @@ export class NTQQUserApi {
} }
async getUserDetailInfoByUinV2(Uin: string) { async getUserDetailInfoByUinV2(Uin: string) {
return await this.core.eventWrapper.callNoListenerEvent<(Uin: string) => Promise<UserDetailInfoByUinV2>> return await this.core.eventWrapper.callNoListenerEvent('NodeIKernelProfileService/getUserDetailInfoByUin', Uin);
('NodeIKernelProfileService/getUserDetailInfoByUin', 5000, Uin);
} }
async forceFetchClientKey() { async forceFetchClientKey() {

View File

@@ -20,14 +20,13 @@ export class NTQQWebApi {
async shareDigest(groupCode: string, msgSeq: string, msgRandom: string, targetGroupCode: string) { async shareDigest(groupCode: string, msgSeq: string, msgRandom: string, targetGroupCode: string) {
const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com'); const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com');
const url = `https://qun.qq.com/cgi-bin/group_digest/share_digest?${ const url = `https://qun.qq.com/cgi-bin/group_digest/share_digest?${new URLSearchParams({
new URLSearchParams({ bkn: this.getBknFromCookie(cookieObject),
bkn: this.getBknFromCookie(cookieObject), group_code: groupCode,
group_code: groupCode, msg_seq: msgSeq,
msg_seq: msgSeq, msg_random: msgRandom,
msg_random: msgRandom, target_group_code: targetGroupCode,
target_group_code: targetGroupCode, }).toString()
}).toString()
}`; }`;
try { try {
return RequestUtil.HttpGetText(url, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) }); return RequestUtil.HttpGetText(url, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) });
@@ -38,13 +37,12 @@ export class NTQQWebApi {
async getGroupEssenceMsg(GroupCode: string, page_start: string) { async getGroupEssenceMsg(GroupCode: string, page_start: string) {
const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com'); const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com');
const url = `https://qun.qq.com/cgi-bin/group_digest/digest_list?${ const url = `https://qun.qq.com/cgi-bin/group_digest/digest_list?${new URLSearchParams({
new URLSearchParams({ bkn: this.getBknFromCookie(cookieObject),
bkn: this.getBknFromCookie(cookieObject), group_code: GroupCode,
group_code: GroupCode, page_start,
page_start, page_limit: '20',
page_limit: '20', }).toString()
}).toString()
}`; }`;
let ret; let ret;
try { try {
@@ -65,14 +63,13 @@ export class NTQQWebApi {
const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com'); const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com');
const retList: Promise<WebApiGroupMemberRet>[] = []; const retList: Promise<WebApiGroupMemberRet>[] = [];
const fastRet = await RequestUtil.HttpGetJson<WebApiGroupMemberRet> const fastRet = await RequestUtil.HttpGetJson<WebApiGroupMemberRet>
(`https://qun.qq.com/cgi-bin/qun_mgr/search_group_members?${ (`https://qun.qq.com/cgi-bin/qun_mgr/search_group_members?${new URLSearchParams({
new URLSearchParams({ st: '0',
st: '0', end: '40',
end: '40', sort: '1',
sort: '1', gc: GroupCode,
gc: GroupCode, bkn: this.getBknFromCookie(cookieObject),
bkn: this.getBknFromCookie(cookieObject), }).toString()
}).toString()
}`, 'POST', '', { 'Cookie': this.cookieToString(cookieObject) }); }`, 'POST', '', { 'Cookie': this.cookieToString(cookieObject) });
if (!fastRet?.count || fastRet?.errcode !== 0 || !fastRet?.mems) { if (!fastRet?.count || fastRet?.errcode !== 0 || !fastRet?.mems) {
return []; return [];
@@ -86,14 +83,13 @@ export class NTQQWebApi {
//遍历批量请求 //遍历批量请求
for (let i = 2; i <= PageNum; i++) { for (let i = 2; i <= PageNum; i++) {
const ret = RequestUtil.HttpGetJson<WebApiGroupMemberRet> const ret = RequestUtil.HttpGetJson<WebApiGroupMemberRet>
(`https://qun.qq.com/cgi-bin/qun_mgr/search_group_members?${ (`https://qun.qq.com/cgi-bin/qun_mgr/search_group_members?${new URLSearchParams({
new URLSearchParams({ st: ((i - 1) * 40).toString(),
st: ((i - 1) * 40).toString(), end: (i * 40).toString(),
end: (i * 40).toString(), sort: '1',
sort: '1', gc: GroupCode,
gc: GroupCode, bkn: this.getBknFromCookie(cookieObject),
bkn: this.getBknFromCookie(cookieObject), }).toString()
}).toString()
}`, 'POST', '', { 'Cookie': this.cookieToString(cookieObject) }); }`, 'POST', '', { 'Cookie': this.cookieToString(cookieObject) });
retList.push(ret); retList.push(ret);
} }
@@ -127,15 +123,14 @@ export class NTQQWebApi {
let ret: any = undefined; let ret: any = undefined;
try { try {
ret = await RequestUtil.HttpGetJson<any> ret = await RequestUtil.HttpGetJson<any>
(`https://web.qun.qq.com/cgi-bin/announce/add_qun_notice${ (`https://web.qun.qq.com/cgi-bin/announce/add_qun_notice${new URLSearchParams({
new URLSearchParams({ bkn: this.getBknFromCookie(cookieObject),
bkn: this.getBknFromCookie(cookieObject), qid: GroupCode,
qid: GroupCode, text: Content,
text: Content, pinned: '0',
pinned: '0', type: '1',
type: '1', settings: '{"is_show_edit_card":1,"tip_window_type":1,"confirm_required":1}',
settings: '{"is_show_edit_card":1,"tip_window_type":1,"confirm_required":1}', }).toString()
}).toString()
}`, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) }); }`, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) });
return ret; return ret;
} catch (e) { } catch (e) {
@@ -147,15 +142,10 @@ export class NTQQWebApi {
const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com'); const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com');
let ret: WebApiGroupNoticeRet | undefined = undefined; let ret: WebApiGroupNoticeRet | undefined = undefined;
try { try {
ret = await RequestUtil.HttpGetJson<WebApiGroupNoticeRet>(`https://web.qun.qq.com/cgi-bin/announce/get_t_list?${ const url = 'https://web.qun.qq.com/cgi-bin/announce/get_t_list?bkn=' +
new URLSearchParams({ this.getBknFromCookie(cookieObject) + '&qid=' + GroupCode + '&ft=23&ni=1&n=1&i=1&log_read=1&platform=1&s=-1&n=20';
bkn: this.getBknFromCookie(cookieObject),
qid: GroupCode, ret = await RequestUtil.HttpGetJson<WebApiGroupNoticeRet>(url, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) });
type: '1',
start: '0',
num: '1',
}).toString()
}`, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) });
if (ret?.ec !== 0) { if (ret?.ec !== 0) {
return undefined; return undefined;
} }
@@ -168,16 +158,15 @@ export class NTQQWebApi {
async getGroupHonorInfo(groupCode: string, getType: WebHonorType) { async getGroupHonorInfo(groupCode: string, getType: WebHonorType) {
const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com'); const cookieObject = await this.core.apis.UserApi.getCookies('qun.qq.com');
const getDataInternal = async (Internal_groupCode: string, Internal_type: number) => { const getDataInternal = async (Internal_groupCode: string, Internal_type: number) => {
const url = `https://qun.qq.com/interactive/honorlist?${ const url = `https://qun.qq.com/interactive/honorlist?${new URLSearchParams({
new URLSearchParams({ gc: Internal_groupCode,
gc: Internal_groupCode, type: Internal_type.toString(),
type: Internal_type.toString(), }).toString()
}).toString()
}`; }`;
let resJson; let resJson;
try { try {
const res = await RequestUtil.HttpGetText(url, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) }); const res = await RequestUtil.HttpGetText(url, 'GET', '', { 'Cookie': this.cookieToString(cookieObject) });
const match = res.match(/window\.__INITIAL_STATE__=(.*?);/); const match = /window\.__INITIAL_STATE__=(.*?);/.exec(res);
if (match) { if (match) {
resJson = JSON.parse(match[1].trim()); resJson = JSON.parse(match[1].trim());
} }

View File

@@ -1,10 +1,10 @@
import { NodeQQNTWrapperUtil, NTApiContext, WrapperNodeApi } from '@/core/wrapper'; import { NodeQQNTWrapperUtil, StableNTApiWrapper, WrapperNodeApi } from '@/core/wrapper';
import path from 'node:path'; import path from 'node:path';
import fs from 'node:fs'; import fs from 'node:fs';
import { InstanceContext } from './wrapper'; import { InstanceContext } from './wrapper';
import { proxiedListenerOf } from '@/common/utils/proxy-handler'; import { proxiedListenerOf } from '@/common/utils/proxy-handler';
import { GroupListener, MsgListener, ProfileListener } from './listeners'; import { NodeIKernelGroupListener, NodeIKernelMsgListener, NodeIKernelProfileListener } from './listeners';
import { GroupMember, SelfInfo } from './entities'; import { DataSource, GroupMember, SelfInfo } from './entities';
import { LegacyNTEventWrapper } from '@/common/framework/event-legacy'; import { LegacyNTEventWrapper } from '@/common/framework/event-legacy';
import { NTQQFileApi, NTQQFriendApi, NTQQGroupApi, NTQQMsgApi, NTQQSystemApi, NTQQUserApi, NTQQWebApi } from './apis'; import { NTQQFileApi, NTQQFriendApi, NTQQGroupApi, NTQQMsgApi, NTQQSystemApi, NTQQUserApi, NTQQWebApi } from './apis';
import os from 'node:os'; import os from 'node:os';
@@ -30,7 +30,7 @@ export function loadQQWrapper(QQVersion: string): WrapperNodeApi {
export class NapCatCore { export class NapCatCore {
readonly context: InstanceContext; readonly context: InstanceContext;
readonly apis: NTApiContext; readonly apis: StableNTApiWrapper;
readonly eventWrapper: LegacyNTEventWrapper; readonly eventWrapper: LegacyNTEventWrapper;
// readonly eventChannel: NTEventChannel; // readonly eventChannel: NTEventChannel;
NapCatDataPath: string; NapCatDataPath: string;
@@ -89,7 +89,7 @@ export class NapCatCore {
// Renamed from 'InitDataListener' // Renamed from 'InitDataListener'
async initNapCatCoreListeners() { async initNapCatCoreListeners() {
const msgListener = new MsgListener(); const msgListener = new NodeIKernelMsgListener();
msgListener.onRecvMsg = (msgs) => { msgListener.onRecvMsg = (msgs) => {
msgs.forEach(msg => this.context.logger.logMessage(msg, this.selfInfo)); msgs.forEach(msg => this.context.logger.logMessage(msg, this.selfInfo));
}; };
@@ -98,10 +98,10 @@ export class NapCatCore {
}; };
//await sleep(2500); //await sleep(2500);
this.context.session.getMsgService().addKernelMsgListener( this.context.session.getMsgService().addKernelMsgListener(
proxiedListenerOf(msgListener, this.context.logger) as any proxiedListenerOf(msgListener, this.context.logger) as any,
); );
const profileListener = new ProfileListener(); const profileListener = new NodeIKernelProfileListener();
profileListener.onProfileDetailInfoChanged = (profile) => { profileListener.onProfileDetailInfoChanged = (profile) => {
if (profile.uid === this.selfInfo.uid) { if (profile.uid === this.selfInfo.uid) {
Object.assign(this.selfInfo, profile); Object.assign(this.selfInfo, profile);
@@ -117,7 +117,7 @@ export class NapCatCore {
); );
// 群相关 // 群相关
const groupListener = new GroupListener(); const groupListener = new NodeIKernelGroupListener();
groupListener.onGroupListUpdate = (updateType, groupList) => { groupListener.onGroupListUpdate = (updateType, groupList) => {
// console.log("onGroupListUpdate", updateType, groupList) // console.log("onGroupListUpdate", updateType, groupList)
groupList.map(g => { groupList.map(g => {
@@ -125,8 +125,7 @@ export class NapCatCore {
//群成员数量变化 应该刷新缓存 //群成员数量变化 应该刷新缓存
if (existGroup && g.memberCount === existGroup.memberCount) { if (existGroup && g.memberCount === existGroup.memberCount) {
Object.assign(existGroup, g); Object.assign(existGroup, g);
} } else {
else {
this.apis.GroupApi.groupCache.set(g.groupCode, g); this.apis.GroupApi.groupCache.set(g.groupCode, g);
// 获取群成员 // 获取群成员
} }
@@ -149,8 +148,7 @@ export class NapCatCore {
const existMember = existMembers.get(uid); const existMember = existMembers.get(uid);
if (existMember) { if (existMember) {
Object.assign(existMember, member); Object.assign(existMember, member);
} } else {
else {
existMembers!.set(uid, member); existMembers!.set(uid, member);
} }
//移除成员 //移除成员
@@ -158,15 +156,14 @@ export class NapCatCore {
existMembers.delete(uid); existMembers.delete(uid);
} }
}); });
} } else {
else {
this.apis.GroupApi.groupMemberCache.set(groupCode, arg.infos); this.apis.GroupApi.groupMemberCache.set(groupCode, arg.infos);
} }
// console.log('onMemberListChange', groupCode, arg); // console.log('onMemberListChange', groupCode, arg);
}; };
groupListener.onMemberInfoChange = (groupCode, changeType, members) => { groupListener.onMemberInfoChange = (groupCode, dataSource, members) => {
//console.log('onMemberInfoChange', groupCode, changeType, members); //console.log('onMemberInfoChange', groupCode, changeType, members);
if (changeType === 0 && members.get(this.selfInfo.uid)?.isDelete) { if (dataSource === DataSource.LOCAL && members.get(this.selfInfo.uid)?.isDelete) {
// 自身退群或者被踢退群 5s用于Api操作 之后不再出现 // 自身退群或者被踢退群 5s用于Api操作 之后不再出现
setTimeout(() => { setTimeout(() => {
this.apis.GroupApi.groupCache.delete(groupCode); this.apis.GroupApi.groupCache.delete(groupCode);
@@ -182,8 +179,7 @@ export class NapCatCore {
member.isChangeRole = this.checkAdminEvent(groupCode, member, existMember); member.isChangeRole = this.checkAdminEvent(groupCode, member, existMember);
// 更新成员信息 // 更新成员信息
Object.assign(existMember, member); Object.assign(existMember, member);
} } else {
else {
existMembers.set(uid, member); existMembers.set(uid, member);
} }
//移除成员 //移除成员
@@ -191,18 +187,18 @@ export class NapCatCore {
existMembers.delete(uid); existMembers.delete(uid);
} }
}); });
} } else {
else {
this.apis.GroupApi.groupMemberCache.set(groupCode, members); this.apis.GroupApi.groupMemberCache.set(groupCode, members);
} }
}; };
this.context.session.getGroupService().addKernelGroupListener( this.context.session.getGroupService().addKernelGroupListener(
proxiedListenerOf(profileListener, this.context.logger) as any proxiedListenerOf(groupListener, this.context.logger) as any,
); );
} }
checkAdminEvent(groupCode: string, memberNew: GroupMember, memberOld: GroupMember | undefined): boolean { checkAdminEvent(groupCode: string, memberNew: GroupMember, memberOld: GroupMember | undefined): boolean {
if (memberNew.role !== memberOld?.role) { if (memberNew.role !== memberOld?.role) {
this.context.logger.log(`${groupCode} ${memberNew.nick} 角色变更为 ${memberNew.role === 3 ? '管理员' : '群员'}`); this.context.logger.logDebug(`${groupCode} ${memberNew.nick} 角色变更为 ${memberNew.role === 3 ? '管理员' : '群员'}`);
return true; return true;
} }
return false; return false;

View File

@@ -1,4 +1,68 @@
import { QQLevel, Sex, User } from './user'; import { QQLevel, Sex } from './user';
export interface KickMemberInfo {
optFlag: number,
optOperate: number,
optMemberUid: string,
optBytesMsg: string,
}
//getGroupDetailInfo GroupCode,GroupInfoSource
export enum GroupInfoSource {
KUNSPECIFIED,
KBIGDATACARD,
KDATACARD,
KNOTICE,
KAIO,
KRECENTCONTACT,
KMOREPANEL
}
export interface GroupExt0xEF0InfoFilter {
bindGuildId: number;
blacklistExpireTime: number;
companyId: number;
essentialMsgPrivilege: number;
essentialMsgSwitch: number;
fullGroupExpansionSeq: number;
fullGroupExpansionSwitch: number;
gangUpId: number;
groupAioBindGuildId: number;
groupBindGuildIds: number;
groupBindGuildSwitch: number;
groupExcludeGuildIds: number;
groupExtFlameData: number;
groupFlagPro1: number;
groupInfoExtSeq: number;
groupOwnerId: number;
groupSquareSwitch: number;
hasGroupCustomPortrait: number;
inviteRobotMemberExamine: number;
inviteRobotMemberSwitch: number;
inviteRobotSwitch: number;
isLimitGroupRtc: number;
lightCharNum: number;
luckyWord: number;
luckyWordId: number;
msgEventSeq: number;
qqMusicMedalSwitch: number;
reserve: number;
showPlayTogetherSwitch: number;
starId: number;
todoSeq: number;
viewedMsgDisappearTime: number;
}
export interface KickMemberV2Req {
groupCode: string,
kickFlag: number,
kickList: Array<KickMemberInfo>,
kickListUids: Array<string>,
kickMsg: string
}
export enum DataSource {
LOCAL,
REMOTE
}
export enum GroupListUpdateType { export enum GroupListUpdateType {
REFRESHALL, REFRESHALL,
@@ -6,13 +70,15 @@ export enum GroupListUpdateType {
MODIFIED, MODIFIED,
REMOVE REMOVE
} }
export interface GroupMemberCache { export interface GroupMemberCache {
group: { group: {
data: GroupMember[]; data: GroupMember[];
isExpired: boolean; isExpired: boolean;
} };
isExpired: boolean; isExpired: boolean;
} }
export interface Group { export interface Group {
groupCode: string, groupCode: string,
createTime?: string,//高版本才有 createTime?: string,//高版本才有

View File

@@ -1,4 +1,4 @@
import { GroupMemberRole } from './group'; import { GroupMemberRole } from '@/core';
export interface Peer { export interface Peer {
chatType: ChatType; chatType: ChatType;
@@ -145,6 +145,7 @@ export interface TaskTopMsgElement {
iconUrl: string; iconUrl: string;
topMsgType: number; topMsgType: number;
} }
export enum NTMsgType { export enum NTMsgType {
KMSGTYPEARKSTRUCT = 11, KMSGTYPEARKSTRUCT = 11,
KMSGTYPEFACEBUBBLE = 24, KMSGTYPEFACEBUBBLE = 24,
@@ -168,6 +169,7 @@ export enum NTMsgType {
KMSGTYPEVIDEO = 7, KMSGTYPEVIDEO = 7,
KMSGTYPEWALLET = 10 KMSGTYPEWALLET = 10
} }
export interface SendTaskTopMsgElement { export interface SendTaskTopMsgElement {
elementType: ElementType.TASKTOPMSG; elementType: ElementType.TASKTOPMSG;
elementId: string; elementId: string;
@@ -355,6 +357,7 @@ export enum NTMsgAtType {
ATTYPESUMMONROLE = 256, ATTYPESUMMONROLE = 256,
ATTYPEUNKNOWN = 0 ATTYPEUNKNOWN = 0
} }
export interface SendPicElement { export interface SendPicElement {
elementType: ElementType.PIC; elementType: ElementType.PIC;
elementId: string; elementId: string;
@@ -411,7 +414,7 @@ export interface ShareLocationElement {
ext: string; ext: string;
} }
export interface sendShareLocationElement { export interface SendShareLocationElement {
elementType: ElementType.SHARELOCATION; elementType: ElementType.SHARELOCATION;
elementId: string; elementId: string;
shareLocationElement?: ShareLocationElement; shareLocationElement?: ShareLocationElement;
@@ -461,7 +464,7 @@ export interface SendMarkdownElement {
export type SendMessageElement = SendTextElement | SendPttElement | export type SendMessageElement = SendTextElement | SendPttElement |
SendPicElement | SendReplyElement | SendFaceElement | SendMarketFaceElement | SendFileElement | SendPicElement | SendReplyElement | SendFaceElement | SendMarketFaceElement | SendFileElement |
SendVideoElement | SendArkElement | SendMarkdownElement | sendShareLocationElement; SendVideoElement | SendArkElement | SendMarkdownElement | SendShareLocationElement;
export interface TextElement { export interface TextElement {
content: string; content: string;
@@ -511,6 +514,7 @@ export enum AtType {
atAll = 1, atAll = 1,
atUser = 2 atUser = 2
} }
// 来自Android分析 // 来自Android分析
export enum ChatType { export enum ChatType {
KCHATTYPEADELIE = 42, KCHATTYPEADELIE = 42,
@@ -626,6 +630,7 @@ export enum NTGrayTipElementSubTypeV2 {
GRAYTIP_ELEMENT_SUBTYPE_WALLET = 16, GRAYTIP_ELEMENT_SUBTYPE_WALLET = 16,
GRAYTIP_ELEMENT_SUBTYPE_XMLMSG = 12, GRAYTIP_ELEMENT_SUBTYPE_XMLMSG = 12,
} }
export interface GrayTipElement { export interface GrayTipElement {
subElementType: NTGrayTipElementSubTypeV2; subElementType: NTGrayTipElementSubTypeV2;
revokeElement: { revokeElement: {
@@ -848,47 +853,14 @@ export interface MultiForwardMsgElement {
resId: string; resId: string;
fileName: string; fileName: string;
} }
export enum NTSubMsgType {
KMSGSUBTYPEARKGROUPANNOUNCE = 3,
KMSGSUBTYPEARKGROUPANNOUNCECONFIRMREQUIRED = 4,
KMSGSUBTYPEARKGROUPGIFTATME = 5,
KMSGSUBTYPEARKGROUPTASKATALL = 6,
KMSGSUBTYPEARKMULTIMSG = 7,
KMSGSUBTYPEARKNORMAL = 0,
KMSGSUBTYPEARKTENCENTDOCFROMMINIAPP = 1,
KMSGSUBTYPEARKTENCENTDOCFROMPLUSPANEL = 2,
KMSGSUBTYPEEMOTICON = 15,
KMSGSUBTYPEFILEAPP = 11,
KMSGSUBTYPEFILEAUDIO = 3,
KMSGSUBTYPEFILEDOC = 4,
KMSGSUBTYPEFILEEXCEL = 6,
KMSGSUBTYPEFILEFOLDER = 13,
KMSGSUBTYPEFILEHTML = 10,
KMSGSUBTYPEFILEIPA = 14,
KMSGSUBTYPEFILENORMAL = 0,
KMSGSUBTYPEFILEPDF = 7,
KMSGSUBTYPEFILEPIC = 1,
KMSGSUBTYPEFILEPPT = 5,
KMSGSUBTYPEFILEPSD = 12,
KMSGSUBTYPEFILETXT = 8,
KMSGSUBTYPEFILEVIDEO = 2,
KMSGSUBTYPEFILEZIP = 9,
KMSGSUBTYPELINK = 5,
KMSGSUBTYPEMARKETFACE = 1,
KMSGSUBTYPEMIXEMOTICON = 7,
KMSGSUBTYPEMIXFACE = 3,
KMSGSUBTYPEMIXMARKETFACE = 2,
KMSGSUBTYPEMIXPIC = 1,
KMSGSUBTYPEMIXREPLY = 4,
KMSGSUBTYPEMIXTEXT = 0,
KMSGSUBTYPETENCENTDOC = 6
}
export enum SendStatusType { export enum SendStatusType {
KSEND_STATUS_FAILED = 0, KSEND_STATUS_FAILED = 0,
KSEND_STATUS_SENDING = 1, KSEND_STATUS_SENDING = 1,
KSEND_STATUS_SUCCESS = 2, KSEND_STATUS_SUCCESS = 2,
KSEND_STATUS_SUCCESS_NOSEQ = 3 KSEND_STATUS_SUCCESS_NOSEQ = 3
} }
export interface RawMessage { export interface RawMessage {
parentMsgPeer: Peer; parentMsgPeer: Peer;
@@ -914,7 +886,7 @@ export interface RawMessage {
msgType: NTMsgType; msgType: NTMsgType;
subMsgType: NTSubMsgType; subMsgType: number;
senderUid: string; senderUid: string;
@@ -958,4 +930,4 @@ export interface RawMessage {
records: RawMessage[]; records: RawMessage[];
elements: MessageElement[]; elements: MessageElement[];
} }

View File

@@ -1,12 +1,20 @@
export enum GroupNotifyTypes { export enum GroupNotifyMsgType {
INVITE_ME = 1, UN_SPECIFIED,
INVITED_JOIN = 4, // 有人接受了邀请入群 INVITED_BY_MEMBER,
JOIN_REQUEST = 7, REFUSE_INVITED,
ADMIN_SET = 8, REFUSED_BY_ADMINI_STRATOR,
KICK_MEMBER = 9, AGREED_TOJOIN_DIRECT,// 有人接受了邀请入群
MEMBER_EXIT = 11, // 主动退出 INVITED_NEED_ADMINI_STRATOR_PASS,
ADMIN_UNSET = 12, AGREED_TO_JOIN_BY_ADMINI_STRATOR,
ADMIN_UNSET_OTHER = 13, // 其他人取消管理员 REQUEST_JOIN_NEED_ADMINI_STRATOR_PASS,
SET_ADMIN,
KICK_MEMBER_NOTIFY_ADMIN,
KICK_MEMBER_NOTIFY_KICKED,
MEMBER_LEAVE_NOTIFY_ADMIN,// 主动退出
CANCEL_ADMIN_NOTIFY_CANCELED,
CANCEL_ADMIN_NOTIFY_ADMIN,// 其他人取消管理员
TRANSFER_GROUP_NOTIFY_OLDOWNER,
TRANSFER_GROUP_NOTIFY_ADMIN
} }
export interface GroupNotifies { export interface GroupNotifies {
@@ -15,26 +23,40 @@ export interface GroupNotifies {
notifies: GroupNotify[]; notifies: GroupNotify[];
} }
export enum GroupNotifyStatus { export enum GroupNotifyMsgStatus {
IGNORE = 0, KINIT,//初始化
WAIT_HANDLE = 1, KUNHANDLE,//未处理
APPROVE = 2, KAGREED,//同意
REJECT = 3 KREFUSED,//拒绝
KIGNORED//忽略
}
export enum GroupInviteStatus {
INIT,
WAIT_TO_APPROVE,
JOINED,
REFUSED_BY_ADMINI_STRATOR
}
export enum GroupInviteType {
BYBUDDY,
BYGROUPMEMBER,
BYDISCUSSMEMBER
} }
export interface GroupNotify { export interface GroupNotify {
time: number; // 自己添加的字段,时间戳,毫秒, 用于判断收到短时间内收到重复的notify seq: string; // 通知序列号
seq: string; // 唯一标识符转成数字再除以1000应该就是时间戳 type: GroupNotifyMsgType;
type: GroupNotifyTypes; status: GroupNotifyMsgStatus;
status: GroupNotifyStatus; // 0是已忽略1是未处理2是已同意
group: { groupCode: string; groupName: string }; group: { groupCode: string; groupName: string };
user1: { uid: string; nickName: string }; // 被设置管理员的人 user1: { uid: string; nickName: string }; // 被设置管理员的人
user2: { uid: string; nickName: string }; // 操作者 user2: { uid: string; nickName: string }; // 操作者
actionUser: { uid: string; nickName: string }; //未知 actionUser: { uid: string; nickName: string }; //未知
actionTime: string; actionTime: string;
invitationExt: { invitationExt: {
srcType: number; // 0?未知 srcType: GroupInviteType; // 邀请来源
groupCode: string; waitStatus: number groupCode: string;
waitStatus: GroupInviteStatus
}; };
postscript: string; // 加群用户填写的验证信息 postscript: string; // 加群用户填写的验证信息
repeatSeqs: []; repeatSeqs: [];
@@ -64,6 +86,7 @@ export enum BuddyReqType {
} }
export interface FriendRequest { export interface FriendRequest {
isBuddy?: boolean;
isInitiator?: boolean; isInitiator?: boolean;
isDecide: boolean; isDecide: boolean;
friendUid: string; friendUid: string;

View File

@@ -57,7 +57,7 @@ export interface WebApiGroupMemberRet {
export interface WebApiGroupNoticeFeed { export interface WebApiGroupNoticeFeed {
u: number;//发送者 u: number;//发送者
fid: string;//fid fid: string;//fid,notice_id
pubt: number;//时间 pubt: number;//时间
msg: { msg: {
text: string text: string

View File

@@ -7,24 +7,28 @@
"appid": 537240645, "appid": 537240645,
"qua": "V1_LNX_NQ_3.2.12_27206_GW_B" "qua": "V1_LNX_NQ_3.2.12_27206_GW_B"
}, },
"3.2.12-27254":{ "3.2.12-27254": {
"appid": 537240795, "appid": 537240795,
"qua": "V1_LNX_NQ_3.2.12_27254_GW_B" "qua": "V1_LNX_NQ_3.2.12_27254_GW_B"
}, },
"9.9.15-27187":{ "9.9.15-27187": {
"appid": 537240610, "appid": 537240610,
"qua": "V1_WIN_NQ_9.9.15_27187_GW_B" "qua": "V1_WIN_NQ_9.9.15_27187_GW_B"
}, },
"9.9.15-27206":{ "9.9.15-27206": {
"appid": 537240610, "appid": 537240610,
"qua": "V1_WIN_NQ_9.9.15_27206_GW_B" "qua": "V1_WIN_NQ_9.9.15_27206_GW_B"
}, },
"9.9.15-27254":{ "9.9.15-27254": {
"appid": 537240709, "appid": 537240709,
"qua": "V1_WIN_NQ_9.9.15_27254_GW_B" "qua": "V1_WIN_NQ_9.9.15_27254_GW_B"
}, },
"9.9.15-27333": { "9.9.15-27333": {
"appid": 537240709, "appid": 537240709,
"qua": "V1_WIN_NQ_9.9.15_27333_GW_B" "qua": "V1_WIN_NQ_9.9.15_27333_GW_B"
},
"9.9.15-27391": {
"appid": 537240709,
"qua": "V1_WIN_NQ_9.9.15_27333_GW_B"
} }
} }

View File

@@ -1,4 +1,4 @@
import { ConfigBase } from "@/common/utils/ConfigBase"; import { ConfigBase } from '@/common/utils/config-base';
import napCatDefaultConfig from '@/core/external/napcat.json'; import napCatDefaultConfig from '@/core/external/napcat.json';
import { NapCatCore } from '@/core'; import { NapCatCore } from '@/core';
@@ -7,7 +7,7 @@ export type NapCatConfig = typeof napCatDefaultConfig;
// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging // eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
export class NapCatConfigLoader extends ConfigBase<NapCatConfig> { export class NapCatConfigLoader extends ConfigBase<NapCatConfig> {
constructor(coreContext: NapCatCore, configPath: string) { constructor(core: NapCatCore, configPath: string) {
super('napcat', coreContext, configPath); super('napcat', core, configPath);
} }
} }

View File

@@ -1,53 +1,9 @@
import { BuddyCategoryType, FriendRequestNotify } from '@/core/entities'; import { BuddyCategoryType, FriendRequestNotify } from '@/core/entities';
export type OnBuddyChangeParams = BuddyCategoryType[] export type OnBuddyChangeParams = BuddyCategoryType[];
interface IBuddyListener { export class NodeIKernelBuddyListener {
onBuddyListChangedV2(arg: unknown): void,//V2版本 还没兼容
onBuddyListChange(arg: OnBuddyChangeParams): void,
onBuddyInfoChange(arg: unknown): void,
onBuddyDetailInfoChange(arg: unknown): void,
onNickUpdated(arg: unknown): void,
onBuddyRemarkUpdated(arg: unknown): void,
onAvatarUrlUpdated(arg: unknown): void,
onBuddyReqChange(arg: FriendRequestNotify): void,
onBuddyReqUnreadCntChange(arg: unknown): void,
onCheckBuddySettingResult(arg: unknown): void,
onAddBuddyNeedVerify(arg: unknown): void,
onSmartInfos(arg: unknown): void,
onSpacePermissionInfos(arg: unknown): void,
onDoubtBuddyReqChange(arg: unknown): void,
onDoubtBuddyReqUnreadNumChange(arg: unknown): void,
onBlockChanged(arg: unknown): void,
onAddMeSettingChanged(arg: unknown): void,
onDelBatchBuddyInfos(arg: unknown): void
}
export interface NodeIKernelBuddyListener extends IBuddyListener {
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(listener: IBuddyListener): NodeIKernelBuddyListener;
}
export class BuddyListener implements IBuddyListener {
onBuddyListChangedV2(arg: unknown): void { onBuddyListChangedV2(arg: unknown): void {
//throw new Error('Method not implemented.');
} }
onAddBuddyNeedVerify(arg: unknown) { onAddBuddyNeedVerify(arg: unknown) {

View File

@@ -1,21 +1,4 @@
export interface IKernelFileAssistantListener { export class NodeIKernelFileAssistantListener {
onFileStatusChanged(...args: unknown[]): unknown;
onSessionListChanged(...args: unknown[]): unknown;
onSessionChanged(...args: unknown[]): unknown;
onFileListChanged(...args: unknown[]): unknown;
onFileSearch(...args: unknown[]): unknown;
}
export interface NodeIKernelFileAssistantListener extends IKernelFileAssistantListener {
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(adapter: IKernelFileAssistantListener): NodeIKernelFileAssistantListener;
}
export class KernelFileAssistantListener implements IKernelFileAssistantListener {
onFileStatusChanged(...args: unknown[]) { onFileStatusChanged(...args: unknown[]) {
} }

View File

@@ -1,68 +1,6 @@
import { Group, GroupListUpdateType, GroupMember, GroupNotify } from '@/core/entities'; import { DataSource, Group, GroupListUpdateType, GroupMember, GroupNotify } from '@/core/entities';
export interface IGroupListener { export class NodeIKernelGroupListener {
onGroupListUpdate(updateType: GroupListUpdateType, groupList: Group[]): void;
onGroupExtListUpdate(...args: unknown[]): void;
onGroupSingleScreenNotifies(doubt: boolean, seq: string, notifies: GroupNotify[]): void;
onGroupNotifiesUpdated(dboubt: boolean, notifies: GroupNotify[]): void;
onGroupNotifiesUnreadCountUpdated(...args: unknown[]): void;
onGroupDetailInfoChange(...args: unknown[]): void;
onGroupAllInfoChange(...args: unknown[]): void;
onGroupsMsgMaskResult(...args: unknown[]): void;
onGroupConfMemberChange(...args: unknown[]): void;
onGroupBulletinChange(...args: unknown[]): void;
onGetGroupBulletinListResult(...args: unknown[]): void;
onMemberListChange(arg: {
sceneId: string,
ids: string[],
infos: Map<string, GroupMember>,
finish: boolean,
hasRobot: boolean
}): void;
onMemberInfoChange(groupCode: string, changeType: number, members: Map<string, GroupMember>): void;
onSearchMemberChange(...args: unknown[]): void;
onGroupBulletinRichMediaDownloadComplete(...args: unknown[]): void;
onGroupBulletinRichMediaProgressUpdate(...args: unknown[]): void;
onGroupStatisticInfoChange(...args: unknown[]): void;
onJoinGroupNotify(...args: unknown[]): void;
onShutUpMemberListChanged(...args: unknown[]): void;
onGroupBulletinRemindNotify(...args: unknown[]): void;
onGroupFirstBulletinNotify(...args: unknown[]): void;
onJoinGroupNoVerifyFlag(...args: unknown[]): void;
onGroupArkInviteStateResult(...args: unknown[]): void;
// 发现于Win 9.9.9 23159
onGroupMemberLevelInfoChange(...args: unknown[]): void;
}
export interface NodeIKernelGroupListener extends IGroupListener {
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(listener: IGroupListener): NodeIKernelGroupListener;
}
export class GroupListener implements IGroupListener {
// 发现于Win 9.9.9 23159 // 发现于Win 9.9.9 23159
onGroupMemberLevelInfoChange(...args: unknown[]): void { onGroupMemberLevelInfoChange(...args: unknown[]): void {
@@ -125,7 +63,7 @@ export class GroupListener implements IGroupListener {
onJoinGroupNoVerifyFlag(...args: unknown[]) { onJoinGroupNoVerifyFlag(...args: unknown[]) {
} }
onMemberInfoChange(groupCode: string, changeType: number, members: Map<string, GroupMember>) { onMemberInfoChange(groupCode: string, dateSource: DataSource, members: Map<string, GroupMember>) {
} }
onMemberListChange(arg: { onMemberListChange(arg: {
@@ -142,102 +80,4 @@ export class GroupListener implements IGroupListener {
onShutUpMemberListChanged(...args: unknown[]) { onShutUpMemberListChanged(...args: unknown[]) {
} }
} }
export class DebugGroupListener implements IGroupListener {
onGroupMemberLevelInfoChange(...args: unknown[]): void {
console.log('onGroupMemberLevelInfoChange:', ...args);
}
onGetGroupBulletinListResult(...args: unknown[]) {
console.log('onGetGroupBulletinListResult:', ...args);
}
onGroupAllInfoChange(...args: unknown[]) {
console.log('onGroupAllInfoChange:', ...args);
}
onGroupBulletinChange(...args: unknown[]) {
console.log('onGroupBulletinChange:', ...args);
}
onGroupBulletinRemindNotify(...args: unknown[]) {
console.log('onGroupBulletinRemindNotify:', ...args);
}
onGroupArkInviteStateResult(...args: unknown[]) {
console.log('onGroupArkInviteStateResult:', ...args);
}
onGroupBulletinRichMediaDownloadComplete(...args: unknown[]) {
console.log('onGroupBulletinRichMediaDownloadComplete:', ...args);
}
onGroupConfMemberChange(...args: unknown[]) {
console.log('onGroupConfMemberChange:', ...args);
}
onGroupDetailInfoChange(...args: unknown[]) {
console.log('onGroupDetailInfoChange:', ...args);
}
onGroupExtListUpdate(...args: unknown[]) {
console.log('onGroupExtListUpdate:', ...args);
}
onGroupFirstBulletinNotify(...args: unknown[]) {
console.log('onGroupFirstBulletinNotify:', ...args);
}
onGroupListUpdate(...args: unknown[]) {
console.log('onGroupListUpdate:', ...args);
}
onGroupNotifiesUpdated(...args: unknown[]) {
console.log('onGroupNotifiesUpdated:', ...args);
}
onGroupBulletinRichMediaProgressUpdate(...args: unknown[]) {
console.log('onGroupBulletinRichMediaProgressUpdate:', ...args);
}
onGroupNotifiesUnreadCountUpdated(...args: unknown[]) {
console.log('onGroupNotifiesUnreadCountUpdated:', ...args);
}
onGroupSingleScreenNotifies(doubt: boolean, seq: string, notifies: GroupNotify[]) {
console.log('onGroupSingleScreenNotifies:');
}
onGroupsMsgMaskResult(...args: unknown[]) {
console.log('onGroupsMsgMaskResult:', ...args);
}
onGroupStatisticInfoChange(...args: unknown[]) {
console.log('onGroupStatisticInfoChange:', ...args);
}
onJoinGroupNotify(...args: unknown[]) {
console.log('onJoinGroupNotify:', ...args);
}
onJoinGroupNoVerifyFlag(...args: unknown[]) {
console.log('onJoinGroupNoVerifyFlag:', ...args);
}
onMemberInfoChange(groupCode: string, changeType: number, members: Map<string, GroupMember>) {
console.log('onMemberInfoChange:', groupCode, changeType, members);
}
onMemberListChange(...args: unknown[]) {
console.log('onMemberListChange:', ...args);
}
onSearchMemberChange(...args: unknown[]) {
console.log('onSearchMemberChange:', ...args);
}
onShutUpMemberListChanged(...args: unknown[]) {
console.log('onShutUpMemberListChanged:', ...args);
}
}

View File

@@ -1,45 +1,4 @@
export interface IKernelLoginListener { export class NodeIKernelLoginListener {
onLoginConnected(...args: any[]): void;
onLoginDisConnected(...args: any[]): void;
onLoginConnecting(...args: any[]): void;
onQRCodeGetPicture(...args: any[]): void;
onQRCodeLoginPollingStarted(...args: any[]): void;
onQRCodeSessionUserScaned(...args: any[]): void;
onQRCodeLoginSucceed(...args: any[]): void;
onQRCodeSessionFailed(...args: any[]): void;
onLoginFailed(...args: any[]): void;
onLogoutSucceed(...args: any[]): void;
onLogoutFailed(...args: any[]): void;
onUserLoggedIn(...args: any[]): void;
onQRCodeSessionQuickLoginFailed(...args: any[]): void;
onPasswordLoginFailed(...args: any[]): void;
OnConfirmUnusualDeviceFailed(...args: any[]): void;
onQQLoginNumLimited(...args: any[]): void;
onLoginState(...args: any[]): void;
}
export interface NodeIKernelLoginListener {
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(listener: IKernelLoginListener): NodeIKernelLoginListener;
}
export class LoginListener implements IKernelLoginListener {
onLoginConnected(...args: any[]): void { onLoginConnected(...args: any[]): void {
} }

View File

@@ -23,7 +23,7 @@ export interface OnRichMediaDownloadCompleteParams {
userUsedSpacePerDay: unknown | null userUsedSpacePerDay: unknown | null
} }
export interface onGroupFileInfoUpdateParamType { export interface GroupFileInfoUpdateParamType {
retCode: number; retCode: number;
retMsg: string; retMsg: string;
clientWording: string; clientWording: string;
@@ -52,199 +52,7 @@ export interface TempOnRecvParams {
} }
export interface IKernelMsgListener { export class NodeIKernelMsgListener {
onAddSendMsg(msgRecord: RawMessage): void;
onBroadcastHelperDownloadComplete(broadcastHelperTransNotifyInfo: unknown): void;
onBroadcastHelperProgressUpdate(broadcastHelperTransNotifyInfo: unknown): void;
onChannelFreqLimitInfoUpdate(contact: unknown, z: unknown, freqLimitInfo: unknown): void;
onContactUnreadCntUpdate(hashMap: unknown): void;
onCustomWithdrawConfigUpdate(customWithdrawConfig: unknown): void;
onDraftUpdate(contact: unknown, arrayList: unknown, j2: unknown): void;
onEmojiDownloadComplete(emojiNotifyInfo: unknown): void;
onEmojiResourceUpdate(emojiResourceInfo: unknown): void;
onFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown): void;
onFileMsgCome(arrayList: unknown): void;
onFirstViewDirectMsgUpdate(firstViewDirectMsgNotifyInfo: unknown): void;
onFirstViewGroupGuildMapping(arrayList: unknown): void;
onGrabPasswordRedBag(i2: unknown, str: unknown, i3: unknown, recvdOrder: unknown, msgRecord: unknown): void;
onGroupFileInfoAdd(groupItem: unknown): void;
onGroupFileInfoUpdate(groupFileListResult: onGroupFileInfoUpdateParamType): void;
onGroupGuildUpdate(groupGuildNotifyInfo: unknown): void;
onGroupTransferInfoAdd(groupItem: unknown): void;
onGroupTransferInfoUpdate(groupFileListResult: unknown): void;
onGuildInteractiveUpdate(guildInteractiveNotificationItem: unknown): void;
onGuildMsgAbFlagChanged(guildMsgAbFlag: unknown): void;
onGuildNotificationAbstractUpdate(guildNotificationAbstractInfo: unknown): void;
onHitCsRelatedEmojiResult(downloadRelateEmojiResultInfo: unknown): void;
onHitEmojiKeywordResult(hitRelatedEmojiWordsResult: unknown): void;
onHitRelatedEmojiResult(relatedWordEmojiInfo: unknown): void;
onImportOldDbProgressUpdate(importOldDbMsgNotifyInfo: unknown): void;
onInputStatusPush(inputStatusInfo: {
chatType: number;
eventType: number;
fromUin: string;
interval: string;
showTime: string;
statusText: string;
timestamp: string;
toUin: string;
}): void;
onKickedOffLine(kickedInfo: unknown): void;
onLineDev(arrayList: unknown): void;
onLogLevelChanged(j2: unknown): void;
onMsgAbstractUpdate(arrayList: unknown): void;
onMsgBoxChanged(arrayList: unknown): void;
onMsgDelete(contact: unknown, arrayList: unknown): void;
onMsgEventListUpdate(hashMap: unknown): void;
onMsgInfoListAdd(arrayList: unknown): void;
onMsgInfoListUpdate(msgList: RawMessage[]): void;
onMsgQRCodeStatusChanged(i2: unknown): void;
onMsgRecall(i2: unknown, str: unknown, j2: unknown): void;
onMsgSecurityNotify(msgRecord: unknown): void;
onMsgSettingUpdate(msgSetting: unknown): void;
onNtFirstViewMsgSyncEnd(): void;
onNtMsgSyncEnd(): void;
onNtMsgSyncStart(): void;
onReadFeedEventUpdate(firstViewDirectMsgNotifyInfo: unknown): void;
onRecvGroupGuildFlag(i2: unknown): void;
onRecvMsg(...arrayList: unknown[]): void;
onRecvMsgSvrRspTransInfo(j2: unknown, contact: unknown, i2: unknown, i3: unknown, str: unknown, bArr: unknown): void;
onRecvOnlineFileMsg(arrayList: unknown): void;
onRecvS2CMsg(arrayList: unknown): void;
onRecvSysMsg(arrayList: unknown): void;
onRecvUDCFlag(i2: unknown): void;
onRichMediaDownloadComplete(fileTransNotifyInfo: OnRichMediaDownloadCompleteParams): void;
onRichMediaProgerssUpdate(fileTransNotifyInfo: unknown): void;
onRichMediaUploadComplete(fileTransNotifyInfo: unknown): void;
onSearchGroupFileInfoUpdate(searchGroupFileResult:
{
result: {
retCode: number,
retMsg: string,
clientWording: string
},
syncCookie: string,
totalMatchCount: number,
ownerMatchCount: number,
isEnd: boolean,
reqId: number,
item: Array<{
groupCode: string,
groupName: string,
uploaderUin: string,
uploaderName: string,
matchUin: string,
matchWords: Array<unknown>,
fileNameHits: Array<{
start: number,
end: number
}>,
fileModelId: string,
fileId: string,
fileName: string,
fileSize: string,
busId: number,
uploadTime: number,
modifyTime: number,
deadTime: number,
downloadTimes: number,
localPath: string
}>
}): void;
onSendMsgError(j2: unknown, contact: unknown, i2: unknown, str: unknown): void;
onSysMsgNotification(i2: unknown, j2: unknown, j3: unknown, arrayList: unknown): void;
onTempChatInfoUpdate(tempChatInfo: TempOnRecvParams): void;
onUnreadCntAfterFirstView(hashMap: unknown): void;
onUnreadCntUpdate(hashMap: unknown): void;
onUserChannelTabStatusChanged(z: unknown): void;
onUserOnlineStatusChanged(z: unknown): void;
onUserTabStatusChanged(arrayList: unknown): void;
onlineStatusBigIconDownloadPush(i2: unknown, j2: unknown, str: unknown): void;
onlineStatusSmallIconDownloadPush(i2: unknown, j2: unknown, str: unknown): void;
// 第一次发现于Linux
onUserSecQualityChanged(...args: unknown[]): void;
onMsgWithRichLinkInfoUpdate(...args: unknown[]): void;
onRedTouchChanged(...args: unknown[]): void;
// 第一次发现于Win 9.9.9 23159
onBroadcastHelperProgerssUpdate(...args: unknown[]): void;
}
export interface NodeIKernelMsgListener extends IKernelMsgListener {
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(listener: IKernelMsgListener): NodeIKernelMsgListener;
}
export class MsgListener implements IKernelMsgListener {
onAddSendMsg(msgRecord: RawMessage) { onAddSendMsg(msgRecord: RawMessage) {
} }
@@ -305,7 +113,7 @@ export class MsgListener implements IKernelMsgListener {
} }
onGroupFileInfoUpdate(groupFileListResult: onGroupFileInfoUpdateParamType) { onGroupFileInfoUpdate(groupFileListResult: GroupFileInfoUpdateParamType) {
} }
@@ -451,7 +259,7 @@ export class MsgListener implements IKernelMsgListener {
} }
onRecvSysMsg(arrayList: unknown) { onRecvSysMsg(arrayList: Array<number>) {
} }

View File

@@ -1,25 +1,6 @@
import { User, UserDetailInfoListenerArg } from '@/core/entities'; import { User, UserDetailInfoListenerArg } from '@/core/entities';
interface IProfileListener { export class NodeIKernelProfileListener {
onProfileSimpleChanged(...args: unknown[]): void;
onUserDetailInfoChanged(arg: UserDetailInfoListenerArg): void;
onProfileDetailInfoChanged(profile: User): void;
onStatusUpdate(...args: unknown[]): void;
onSelfStatusChanged(...args: unknown[]): void;
onStrangerRemarkChanged(...args: unknown[]): void;
}
export interface NodeIKernelProfileListener extends IProfileListener {
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(listener: IProfileListener): NodeIKernelProfileListener;
}
export class ProfileListener implements IProfileListener {
onUserDetailInfoChanged(arg: UserDetailInfoListenerArg): void { onUserDetailInfoChanged(arg: UserDetailInfoListenerArg): void {
} }
@@ -43,4 +24,48 @@ export class ProfileListener implements IProfileListener {
onStrangerRemarkChanged(...args: unknown[]) { onStrangerRemarkChanged(...args: unknown[]) {
} }
onMemberListChange(...args: unknown[]) {
}
onMemberInfoChange(...args: unknown[]) {
}
onGroupListUpdate(...args: unknown[]) {
}
onGroupAllInfoChange(...args: unknown[]) {
}
onGroupDetailInfoChange(...args: unknown[]) {
}
onGroupConfMemberChange(...args: unknown[]) {
}
onGroupExtListUpdate(...args: unknown[]) {
}
onGroupNotifiesUpdated(...args: unknown[]) {
}
onGroupNotifiesUnreadCountUpdated(...args: unknown[]) {
}
onGroupMemberLevelInfoChange(...args: unknown[]) {
}
onGroupBulletinChange(...args: unknown[]) {
}
} }

View File

@@ -1,28 +1,9 @@
interface IKernelRecentContactListener { export class NodeIKernelRecentContactListener {
onDeletedContactsNotify(...args: unknown[]): unknown;
onRecentContactNotification(...args: unknown[]): unknown;
onMsgUnreadCountUpdate(...args: unknown[]): unknown;
onGuildDisplayRecentContactListChanged(...args: unknown[]): unknown;
onRecentContactListChanged(...args: unknown[]): unknown;
onRecentContactListChangedVer2(...args: unknown[]): unknown;
}
export interface NodeIKernelRecentContactListener extends IKernelRecentContactListener {
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(listener: IKernelRecentContactListener): NodeIKernelRecentContactListener;
}
export class KernelRecentContactListener implements IKernelRecentContactListener {
onDeletedContactsNotify(...args: unknown[]) { onDeletedContactsNotify(...args: unknown[]) {
} }
onRecentContactNotification(...args: unknown[]) { onRecentContactNotification(msgList: any, arg0: { msgListUnreadCnt: string }, arg1: number) {
} }

View File

@@ -1,17 +1,4 @@
export interface IKernelRobotListener { export class NodeIKernelRobotListener {
onRobotFriendListChanged(...args: unknown[]): void;
onRobotListChanged(...args: unknown[]): void;
onRobotProfileChanged(...args: unknown[]): void;
}
export interface NodeIKernelRobotListener extends IKernelRobotListener {
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(adapter: IKernelRobotListener): NodeIKernelRobotListener;
}
export class KernelRobotListener implements IKernelRobotListener {
onRobotFriendListChanged(...args: unknown[]) { onRobotFriendListChanged(...args: unknown[]) {
} }

View File

@@ -0,0 +1,39 @@
import { ChatType } from '@/core';
export interface NodeIKernelSearchListener_Polyfill {
onSearchFileKeywordsResult(params: {
searchId: string,
hasMore: boolean,
resultItems: {
chatType: ChatType,
buddyChatInfo: any[],
discussChatInfo: any[],
groupChatInfo: {
groupCode: string,
isConf: boolean,
hasModifyConfGroupFace: boolean,
hasModifyConfGroupName: boolean,
groupName: string,
remark: string
}[],
dataLineChatInfo: any[],
tmpChatInfo: any[],
msgId: string,
msgSeq: string,
msgTime: string,
senderUid: string,
senderNick: string,
senderRemark: string,
senderCard: string,
elemId: string,
elemType: number,
fileSize: string,
filePath: string,
fileName: string,
hits: {
start: number,
end: number
}[]
}[]
}): void;
}

View File

@@ -1,23 +1,4 @@
export interface ISessionListener { export class NodeIKernelSessionListener {
onNTSessionCreate(args: unknown): void;
onGProSessionCreate(args: unknown): void;
onSessionInitComplete(args: unknown): void;
onOpentelemetryInit(args: unknown): void;
onUserOnlineResult(args: unknown): void;
onGetSelfTinyId(args: unknown): void;
}
export interface NodeIKernelSessionListener extends ISessionListener {
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(adapter: ISessionListener): NodeIKernelSessionListener;
}
export class SessionListener implements ISessionListener {
onNTSessionCreate(args: unknown) { onNTSessionCreate(args: unknown) {
} }

View File

@@ -1,22 +1,4 @@
export interface IStorageCleanListener { export class NodeIKernelStorageCleanListener {
onCleanCacheProgressChanged(args: unknown): void;
onScanCacheProgressChanged(args: unknown): void;
onCleanCacheStorageChanged(args: unknown): void;
onFinishScan(args: unknown): void;
onChatCleanDone(args: unknown): void;
}
export interface NodeIKernelStorageCleanListener extends IStorageCleanListener {
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(adapter: IStorageCleanListener): NodeIKernelStorageCleanListener;
}
export class StorageCleanListener implements IStorageCleanListener {
onCleanCacheProgressChanged(args: unknown) { onCleanCacheProgressChanged(args: unknown) {
} }

View File

@@ -1,10 +1,2 @@
export interface IKernelTicketListener { export class NodeIKernelTicketListener {
}
export interface NodeIKernelTicketListener extends IKernelTicketListener {
// eslint-disable-next-line @typescript-eslint/no-misused-new
new(adapter: IKernelTicketListener): NodeIKernelTicketListener;
}
export class KernelTicketListener implements IKernelTicketListener {
} }

View File

@@ -9,4 +9,32 @@ export * from './NodeIKernelProfileListener';
export * from './NodeIKernelTicketListener'; export * from './NodeIKernelTicketListener';
export * from './NodeIKernelStorageCleanListener'; export * from './NodeIKernelStorageCleanListener';
export * from './NodeIKernelFileAssistantListener'; export * from './NodeIKernelFileAssistantListener';
export * from './NodeIKernelSearchListener_Polyfill';
import type {
NodeIKernelBuddyListener,
NodeIKernelFileAssistantListener,
NodeIKernelGroupListener,
NodeIKernelLoginListener,
NodeIKernelMsgListener,
NodeIKernelProfileListener,
NodeIKernelRobotListener,
NodeIKernelSessionListener,
NodeIKernelStorageCleanListener,
NodeIKernelTicketListener,
NodeIKernelSearchListener_Polyfill,
} from '.';
export type ListenerNamingMapping = {
NodeIKernelSessionListener: NodeIKernelSessionListener;
NodeIKernelLoginListener: NodeIKernelLoginListener;
NodeIKernelMsgListener: NodeIKernelMsgListener;
NodeIKernelGroupListener: NodeIKernelGroupListener;
NodeIKernelBuddyListener: NodeIKernelBuddyListener;
NodeIKernelProfileListener: NodeIKernelProfileListener;
NodeIKernelRobotListener: NodeIKernelRobotListener;
NodeIKernelTicketListener: NodeIKernelTicketListener;
NodeIKernelStorageCleanListener: NodeIKernelStorageCleanListener;
NodeIKernelFileAssistantListener: NodeIKernelFileAssistantListener;
NodeIKernelSearchListener: NodeIKernelSearchListener_Polyfill;
};

View File

@@ -61,11 +61,11 @@ export interface NodeIKernelBuddyService {
getBuddyReqUnreadCnt(): number; getBuddyReqUnreadCnt(): number;
getBuddyReq(): unknown; getBuddyReq(): Promise<GeneralCallResult>;
delBuddyReq(uid: number): void; delBuddyReq(uid: number): void;
clearBuddyReqUnreadCnt(): void; clearBuddyReqUnreadCnt(): Promise<GeneralCallResult>;
reqToAddFriends(uid: number, msg: string): void; reqToAddFriends(uid: number, msg: string): void;

View File

@@ -1,16 +1,25 @@
import { IGroupListener, NodeIKernelGroupListener } from '@/core/listeners/NodeIKernelGroupListener'; import { NodeIKernelGroupListener } from '@/core/listeners/NodeIKernelGroupListener';
import { import {
GroupExt0xEF0InfoFilter,
GroupExtParam, GroupExtParam,
GroupMember, GroupMember,
GroupMemberRole, GroupMemberRole,
GroupNotifyTypes, GroupNotifyMsgType,
GroupRequestOperateTypes, GroupRequestOperateTypes,
KickMemberV2Req,
} from '@/core/entities'; } from '@/core/entities';
import { GeneralCallResult } from '@/core/services/common'; import { GeneralCallResult } from '@/core/services/common';
//高版本的接口不应该随意使用 使用应该严格进行pr审核 同时部分ipc中未出现的接口不要过于依赖 应该做好数据兜底 //高版本的接口不应该随意使用 使用应该严格进行pr审核 同时部分ipc中未出现的接口不要过于依赖 应该做好数据兜底
export interface NodeIKernelGroupService { export interface NodeIKernelGroupService {
//getGroupExt0xEF0Info(this.$enableGroupCodes, this.$bannedGroupCodes, this.$filter, this.$forceFetch
getGroupExt0xEF0Info(enableGroupCodes: string[], bannedGroupCodes: string[], filter: GroupExt0xEF0InfoFilter, forceFetch: boolean):
Promise<GeneralCallResult & { result: { groupExtInfos: Map<string, any> }}>;
kickMemberV2(param: KickMemberV2Req): Promise<GeneralCallResult>;
quitGroupV2(param: { groupCode: string; needDeleteLocalMsg: boolean; }): Promise<GeneralCallResult>;
getMemberCommonInfo(Req: { getMemberCommonInfo(Req: {
groupCode: string, groupCode: string,
startUin: string, startUin: string,
@@ -96,7 +105,7 @@ export interface NodeIKernelGroupService {
uid: string, uid: string,
index: number//0 index: number//0
}>, }>,
infos: {}, infos: unknown,
finish: true, finish: true,
hasRobot: false hasRobot: false
} }
@@ -104,7 +113,7 @@ export interface NodeIKernelGroupService {
setHeader(uid: string, path: string): unknown; setHeader(uid: string, path: string): unknown;
addKernelGroupListener(listener: IGroupListener): number; addKernelGroupListener(listener: NodeIKernelGroupListener): number;
removeKernelGroupListener(listenerId: unknown): void; removeKernelGroupListener(listenerId: unknown): void;
@@ -195,7 +204,7 @@ export interface NodeIKernelGroupService {
operateType: GroupRequestOperateTypes, // 2 拒绝 operateType: GroupRequestOperateTypes, // 2 拒绝
targetMsg: { targetMsg: {
seq: string, // 通知序列号 seq: string, // 通知序列号
type: GroupNotifyTypes, type: GroupNotifyMsgType,
groupCode: string, groupCode: string,
postscript: string postscript: string
} }
@@ -205,7 +214,7 @@ export interface NodeIKernelGroupService {
getGroupBulletin(groupCode: string): unknown; getGroupBulletin(groupCode: string): unknown;
deleteGroupBulletin(groupCode: string, seq: string): void; deleteGroupBulletin(groupCode: string, seq: string, noticeId: string): void;
publishGroupBulletin(groupCode: string, pskey: string, data: any): Promise<GeneralCallResult>; publishGroupBulletin(groupCode: string, pskey: string, data: any): Promise<GeneralCallResult>;

View File

@@ -9,7 +9,7 @@ export interface LoginInitConfig {
hostName: string; hostName: string;
} }
export interface passwordLoginRetType { export interface PasswordLoginRetType {
result: string, result: string,
loginErrorInfo: { loginErrorInfo: {
step: number; step: number;
@@ -23,7 +23,7 @@ export interface passwordLoginRetType {
} }
} }
export interface passwordLoginArgType { export interface PasswordLoginArgType {
uin: string; uin: string;
passwordMd5: string;//passwMD5 passwordMd5: string;//passwMD5
step: number;//猜测是需要二次认证 参数 一次为0 step: number;//猜测是需要二次认证 参数 一次为0
@@ -77,7 +77,7 @@ export interface NodeIKernelLoginService {
quickLoginWithUin(uin: string): Promise<QuickLoginResult>; quickLoginWithUin(uin: string): Promise<QuickLoginResult>;
passwordLogin(param: passwordLoginArgType): Promise<any>; passwordLogin(param: PasswordLoginArgType): Promise<any>;
getQRCodePicture(): boolean; getQRCodePicture(): boolean;
} }

View File

@@ -12,6 +12,7 @@ export interface QueryMsgsParams {
isReverseOrder: boolean, isReverseOrder: boolean,
isIncludeCurrent: boolean isIncludeCurrent: boolean
} }
export interface TmpChatInfoApi { export interface TmpChatInfoApi {
errMsg: string; errMsg: string;
result: number; result: number;
@@ -37,7 +38,7 @@ export interface NodeIKernelMsgService {
recallMsg(peer: Peer, msgIds: string[]): Promise<GeneralCallResult>; recallMsg(peer: Peer, msgIds: string[]): Promise<GeneralCallResult>;
addKernelMsgImportToolListener(arg: Object): unknown; addKernelMsgImportToolListener(arg: unknown): unknown;
removeKernelMsgListener(args: unknown): unknown; removeKernelMsgListener(args: unknown): unknown;
@@ -51,7 +52,7 @@ export interface NodeIKernelMsgService {
getOnLineDev(): void; getOnLineDev(): void;
kickOffLine(DevInfo: Object): unknown; kickOffLine(DevInfo: unknown): unknown;
setStatus(args: { status: number, extStatus: number, batteryStatus: number }): Promise<GeneralCallResult>; setStatus(args: { status: number, extStatus: number, batteryStatus: number }): Promise<GeneralCallResult>;
@@ -80,11 +81,11 @@ export interface NodeIKernelMsgService {
// this.voipToken = bArr2; // this.voipToken = bArr2;
// this.profileId = str; // this.profileId = str;
setToken(arg: Object): unknown; setToken(arg: unknown): unknown;
switchForeGround(): unknown; switchForeGround(): unknown;
switchBackGround(arg: Object): unknown; switchBackGround(arg: unknown): unknown;
//hex //hex
setTokenForMqq(token: string): unknown; setTokenForMqq(token: string): unknown;
@@ -384,7 +385,7 @@ export interface NodeIKernelMsgService {
getFileThumbSavePath(...args: unknown[]): unknown; getFileThumbSavePath(...args: unknown[]): unknown;
//猜测居多 //猜测居多
translatePtt2Text(MsgId: string, Peer: {}, MsgElement: {}): unknown; translatePtt2Text(MsgId: string, Peer: Peer, MsgElement: unknown): unknown;
setPttPlayedState(...args: unknown[]): unknown; setPttPlayedState(...args: unknown[]): unknown;
@@ -511,11 +512,11 @@ export interface NodeIKernelMsgService {
result: number, result: number,
errMsg: string, errMsg: string,
emojiLikesList: emojiLikesList:
Array<{ Array<{
tinyId: string, tinyId: string,
nickName: string, nickName: string,
headUrl: string headUrl: string
}>, }>,
cookie: string, cookie: string,
isLastPage: boolean, isLastPage: boolean,
isFirstPage: boolean isFirstPage: boolean
@@ -668,7 +669,7 @@ export interface NodeIKernelMsgService {
recordEmoji(...args: unknown[]): unknown; recordEmoji(...args: unknown[]): unknown;
fetchGetHitEmotionsByWord(args: Object): Promise<unknown>;//表情推荐? fetchGetHitEmotionsByWord(args: unknown): Promise<unknown>;//表情推荐?
deleteAllRoamMsgs(...args: unknown[]): unknown;//漫游消息? deleteAllRoamMsgs(...args: unknown[]): unknown;//漫游消息?

View File

@@ -1,6 +1,6 @@
import { AnyCnameRecord } from 'node:dns'; import { AnyCnameRecord } from 'node:dns';
import { BizKey, ModifyProfileParams, SimpleInfo, UserDetailInfoByUin } from '../entities'; import { BizKey, ModifyProfileParams, SimpleInfo, UserDetailInfoByUin, UserDetailInfoByUinV2 } from '@/core';
import { NodeIKernelProfileListener, ProfileListener } from '../listeners'; import { NodeIKernelProfileListener } from '@/core';
import { GeneralCallResult } from '@/core/services/common'; import { GeneralCallResult } from '@/core/services/common';
export enum UserDetailSource { export enum UserDetailSource {
@@ -35,7 +35,7 @@ export interface NodeIKernelProfileService {
fetchUserDetailInfo(trace: string, uids: string[], arg2: number, arg3: number[]): Promise<unknown>; fetchUserDetailInfo(trace: string, uids: string[], arg2: number, arg3: number[]): Promise<unknown>;
addKernelProfileListener(listener: ProfileListener): number; addKernelProfileListener(listener: NodeIKernelProfileListener): number;
removeKernelProfileListener(listenerId: number): void; removeKernelProfileListener(listenerId: number): void;
@@ -86,7 +86,7 @@ export interface NodeIKernelProfileService {
getUserDetailInfoWithBizInfo(uid: string, Biz: BizKey[]): Promise<GeneralCallResult>; getUserDetailInfoWithBizInfo(uid: string, Biz: BizKey[]): Promise<GeneralCallResult>;
getUserDetailInfoByUin(uin: string): Promise<UserDetailInfoByUin>; getUserDetailInfoByUin(uin: string): Promise<UserDetailInfoByUinV2>;
getZplanAvatarInfos(args: string[]): Promise<unknown>; getZplanAvatarInfos(args: string[]): Promise<unknown>;

View File

@@ -1,4 +1,4 @@
import { forceFetchClientKeyRetType } from './common'; import { ForceFetchClientKeyRetType } from './common';
export interface NodeIKernelTicketService { export interface NodeIKernelTicketService {
@@ -6,7 +6,7 @@ export interface NodeIKernelTicketService {
removeKernelTicketListener(listenerId: unknown): void; removeKernelTicketListener(listenerId: unknown): void;
forceFetchClientKey(arg: string): Promise<forceFetchClientKeyRetType>; forceFetchClientKey(arg: string): Promise<ForceFetchClientKeyRetType>;
isNull(): boolean; isNull(): boolean;
} }

View File

@@ -8,7 +8,7 @@ export interface GeneralCallResult {
errMsg: string errMsg: string
} }
export interface forceFetchClientKeyRetType extends GeneralCallResult { export interface ForceFetchClientKeyRetType extends GeneralCallResult {
url: string; url: string;
keyIndex: string; keyIndex: string;
clientKey: string; clientKey: string;

View File

@@ -14,3 +14,45 @@ export * from './NodeIKernelRobotService';
export * from './NodeIKernelRichMediaService'; export * from './NodeIKernelRichMediaService';
export * from './NodeIKernelDbToolsService'; export * from './NodeIKernelDbToolsService';
export * from './NodeIKernelTipOffService'; export * from './NodeIKernelTipOffService';
export * from './NodeIKernelSearchService';
export * from './NodeIKernelCollectionService';
import type {
NodeIKernelAvatarService,
NodeIKernelBuddyService,
NodeIKernelDbToolsService,
NodeIKernelFileAssistantService,
NodeIKernelGroupService,
NodeIKernelLoginService,
NodeIKernelMsgService,
NodeIKernelOnlineStatusService,
NodeIKernelProfileLikeService,
NodeIKernelProfileService,
NodeIKernelRichMediaService,
NodeIKernelRobotService,
NodeIKernelStorageCleanService,
NodeIKernelTicketService,
NodeIKernelTipOffService,
NodeIKernelSearchService,
NodeIKernelCollectionService,
} from '.';
export type ServiceNamingMapping = {
NodeIKernelAvatarService: NodeIKernelAvatarService;
NodeIKernelBuddyService: NodeIKernelBuddyService;
NodeIKernelFileAssistantService: NodeIKernelFileAssistantService;
NodeIKernelGroupService: NodeIKernelGroupService;
NodeIKernelLoginService: NodeIKernelLoginService;
NodeIKernelMsgService: NodeIKernelMsgService;
NodeIKernelOnlineStatusService: NodeIKernelOnlineStatusService;
NodeIKernelProfileLikeService: NodeIKernelProfileLikeService;
NodeIKernelProfileService: NodeIKernelProfileService;
NodeIKernelTicketService: NodeIKernelTicketService;
NodeIKernelStorageCleanService: NodeIKernelStorageCleanService;
NodeIKernelRobotService: NodeIKernelRobotService;
NodeIKernelRichMediaService: NodeIKernelRichMediaService;
NodeIKernelDbToolsService: NodeIKernelDbToolsService;
NodeIKernelTipOffService: NodeIKernelTipOffService;
NodeIKernelSearchService: NodeIKernelSearchService,
NodeIKernelCollectionService: NodeIKernelCollectionService;
};

View File

@@ -1,5 +1,5 @@
import { LogWrapper } from '@/common/utils/log'; import { LogWrapper } from '@/common/utils/log';
import { QQBasicInfoWrapper } from '@/common/utils/QQBasicInfo'; import { QQBasicInfoWrapper } from '@/common/utils/qq-basic-info';
import { NapCatCoreWorkingEnv, NodeIKernelLoginService, NodeIQQNTWrapperSession, WrapperNodeApi } from '@/core'; import { NapCatCoreWorkingEnv, NodeIKernelLoginService, NodeIQQNTWrapperSession, WrapperNodeApi } from '@/core';
import { NTQQFileApi, NTQQFriendApi, NTQQGroupApi, NTQQMsgApi, NTQQSystemApi, NTQQUserApi, NTQQWebApi } from '../apis'; import { NTQQFileApi, NTQQFriendApi, NTQQGroupApi, NTQQMsgApi, NTQQSystemApi, NTQQUserApi, NTQQWebApi } from '../apis';
import { NTQQCollectionApi } from '../apis/collection'; import { NTQQCollectionApi } from '../apis/collection';
@@ -15,7 +15,7 @@ export interface InstanceContext {
readonly pathWrapper: NapCatPathWrapper; readonly pathWrapper: NapCatPathWrapper;
} }
export interface NTApiContext { export interface StableNTApiWrapper {
FileApi: NTQQFileApi, FileApi: NTQQFileApi,
SystemApi: NTQQSystemApi, SystemApi: NTQQSystemApi,
CollectionApi: NTQQCollectionApi, CollectionApi: NTQQCollectionApi,

View File

@@ -1,12 +1,5 @@
import { NodeIDependsAdapter, NodeIDispatcherAdapter, NodeIGlobalAdapter } from '../adapters'; import { NodeIDependsAdapter, NodeIDispatcherAdapter, NodeIGlobalAdapter } from '../adapters';
import { import { NodeIKernelSessionListener } from '@/core';
NodeIKernelBuddyListener,
NodeIKernelGroupListener,
NodeIKernelLoginListener,
NodeIKernelMsgListener,
NodeIKernelProfileListener,
NodeIKernelSessionListener,
} from '../listeners';
import { import {
NodeIKernelAvatarService, NodeIKernelAvatarService,
NodeIKernelBuddyService, NodeIKernelBuddyService,
@@ -18,9 +11,9 @@ import {
NodeIKernelRichMediaService, NodeIKernelRichMediaService,
NodeIKernelTicketService, NodeIKernelTicketService,
NodeIKernelTipOffService, NodeIKernelTipOffService,
} from '../services'; } from '@/core';
import { NodeIKernelStorageCleanService } from '../services/NodeIKernelStorageCleanService'; import { NodeIKernelStorageCleanService } from '@/core';
import { NodeIKernelRobotService } from '../services/NodeIKernelRobotService'; import { NodeIKernelRobotService } from '@/core';
import { NodeIKernelNodeMiscService } from '../services/NodeIKernelNodeMiscService'; import { NodeIKernelNodeMiscService } from '../services/NodeIKernelNodeMiscService';
import { NodeIKernelUixConvertService } from '../services/NodeIKernelUixConvertService'; import { NodeIKernelUixConvertService } from '../services/NodeIKernelUixConvertService';
import { NodeIKernelMsgBackupService } from '../services/NodeIKernelMsgBackupService'; import { NodeIKernelMsgBackupService } from '../services/NodeIKernelMsgBackupService';
@@ -36,6 +29,7 @@ import { NodeIKernelECDHService } from '../services/NodeIKernelECDHService';
export interface NodeQQNTWrapperUtil { export interface NodeQQNTWrapperUtil {
get(): unknown; get(): unknown;
// eslint-disable-next-line @typescript-eslint/no-misused-new // eslint-disable-next-line @typescript-eslint/no-misused-new
new(): NodeQQNTWrapperUtil; new(): NodeQQNTWrapperUtil;
@@ -69,9 +63,9 @@ export interface NodeQQNTWrapperUtil {
genFileShaAndMd5Hex(path: string, unknown: number): unknown; //可能是错的 genFileShaAndMd5Hex(path: string, unknown: number): unknown; //可能是错的
setTraceInfo(unknown: Object): unknown; setTraceInfo(unknown: unknown): unknown;
encodeOffLine(unknown: Object): unknown; encodeOffLine(unknown: unknown): unknown;
decodeOffLine(arg: string): unknown; //可能是错的 传递hex decodeOffLine(arg: string): unknown; //可能是错的 传递hex
@@ -89,7 +83,7 @@ export interface NodeQQNTWrapperUtil {
runProcessArgs(arg0: string, arg1: { [key: string]: string }, arg2: boolean): unknown; runProcessArgs(arg0: string, arg1: { [key: string]: string }, arg2: boolean): unknown;
calcThumbSize(arg0: number, arg1: number, arg2: Object): unknown; calcThumbSize(arg0: number, arg1: number, arg2: unknown): unknown;
fullWordToHalfWord(arg0: string): unknown; fullWordToHalfWord(arg0: string): unknown;
@@ -278,20 +272,11 @@ export interface NodeIQQNTWrapperEngine {
export interface WrapperNodeApi { export interface WrapperNodeApi {
[key: string]: any; [key: string]: any;
NodeIKernelBuddyListener: NodeIKernelBuddyListener;
NodeIKernelGroupListener: NodeIKernelGroupListener;
NodeQQNTWrapperUtil: NodeQQNTWrapperUtil; NodeQQNTWrapperUtil: NodeQQNTWrapperUtil;
NodeIQQNTWrapperSession: NodeIQQNTWrapperSession; NodeIQQNTWrapperSession: NodeIQQNTWrapperSession;
NodeIKernelMsgListener: NodeIKernelMsgListener;
NodeIQQNTWrapperEngine: NodeIQQNTWrapperEngine; NodeIQQNTWrapperEngine: NodeIQQNTWrapperEngine;
NodeIGlobalAdapter: NodeIGlobalAdapter;
NodeIDependsAdapter: NodeIDependsAdapter;
NodeIDispatcherAdapter: NodeIDispatcherAdapter;
NodeIKernelSessionListener: NodeIKernelSessionListener;
NodeIKernelLoginService: NodeIKernelLoginService; NodeIKernelLoginService: NodeIKernelLoginService;
NodeIKernelLoginListener: NodeIKernelLoginListener;
NodeIKernelProfileService: NodeIKernelProfileService; NodeIKernelProfileService: NodeIKernelProfileService;
NodeIKernelProfileListener: NodeIKernelProfileListener;
} }
export enum PlatformType { export enum PlatformType {

View File

@@ -1,6 +1,6 @@
//LiteLoader需要提供部分IPC接口以便于其他插件调用 //LiteLoader需要提供部分IPC接口以便于其他插件调用
const { ipcMain } = require('electron'); const { ipcMain } = require('electron');
const napcat= require('./napcat.cjs'); const napcat = require('./napcat.cjs');
ipcMain.handle("napcat_get_webtoken", async (event, arg) => { ipcMain.handle('napcat_get_webtoken', async (event, arg) => {
return napcat.NCgetWebUiUrl(); return napcat.NCgetWebUiUrl();
}); });

View File

@@ -1,11 +1,11 @@
import { NapCatPathWrapper } from '@/common/framework/napcat'; import { NapCatPathWrapper } from '@/common/framework/napcat';
import { LogWrapper } from '@/common/utils/log'; import { LogWrapper } from '@/common/utils/log';
import { proxiedListenerOf } from '@/common/utils/proxy-handler'; import { proxiedListenerOf } from '@/common/utils/proxy-handler';
import { QQBasicInfoWrapper } from '@/common/utils/QQBasicInfo'; import { QQBasicInfoWrapper } from '@/common/utils/qq-basic-info';
import { loadQQWrapper, NapCatCore, NapCatCoreWorkingEnv } from '@/core/core'; import { loadQQWrapper, NapCatCore, NapCatCoreWorkingEnv } from '@/core/core';
import { InstanceContext } from '@/core'; import { InstanceContext } from '@/core';
import { SelfInfo } from '@/core/entities'; import { SelfInfo } from '@/core/entities';
import { LoginListener } from '@/core/listeners'; import { NodeIKernelLoginListener } from '@/core/listeners';
import { NodeIKernelLoginService } from '@/core/services'; import { NodeIKernelLoginService } from '@/core/services';
import { NodeIQQNTWrapperSession, WrapperNodeApi } from '@/core/wrapper/wrapper'; import { NodeIQQNTWrapperSession, WrapperNodeApi } from '@/core/wrapper/wrapper';
import { InitWebUi, WebUiConfig } from '@/webui'; import { InitWebUi, WebUiConfig } from '@/webui';
@@ -14,8 +14,9 @@ import { NapCatOneBot11Adapter } from '@/onebot';
//Framework ES入口文件 //Framework ES入口文件
export async function getWebUiUrl() { export async function getWebUiUrl() {
const WebUiConfigData = (await WebUiConfig.GetWebUIConfig()); const WebUiConfigData = (await WebUiConfig.GetWebUIConfig());
return "http://127.0.0.1:" + WebUiConfigData.port + '/webui/?token=' + WebUiConfigData.token; return 'http://127.0.0.1:' + WebUiConfigData.port + '/webui/?token=' + WebUiConfigData.token;
} }
export async function NCoreInitFramework( export async function NCoreInitFramework(
session: NodeIQQNTWrapperSession, session: NodeIQQNTWrapperSession,
loginService: NodeIKernelLoginService, loginService: NodeIKernelLoginService,
@@ -29,7 +30,7 @@ export async function NCoreInitFramework(
const wrapper = loadQQWrapper(basicInfoWrapper.getFullQQVesion()); const wrapper = loadQQWrapper(basicInfoWrapper.getFullQQVesion());
//直到登录成功后,执行下一步 //直到登录成功后,执行下一步
const selfInfo = await new Promise<SelfInfo>((resolveSelfInfo) => { const selfInfo = await new Promise<SelfInfo>((resolveSelfInfo) => {
const loginListener = new LoginListener(); const loginListener = new NodeIKernelLoginListener();
loginListener.onQRCodeLoginSucceed = async (loginResult) => { loginListener.onQRCodeLoginSucceed = async (loginResult) => {
await new Promise<void>(resolvePendingInit => { await new Promise<void>(resolvePendingInit => {
registerInitCallback(() => resolvePendingInit()); registerInitCallback(() => resolvePendingInit());

View File

@@ -1,11 +1,10 @@
const { contextBridge } = require('electron');
const { contextBridge } = require('electron') const { ipcRenderer } = require('electron');
const { ipcRenderer } = require('electron')
const napcat = { const napcat = {
getWebUiUrl: async () => { getWebUiUrl: async () => {
return ipcRenderer.invoke("napcat_get_webtoken") return ipcRenderer.invoke('napcat_get_webtoken');
} },
} };
// 在window对象下导出只读对象 // 在window对象下导出只读对象
contextBridge.exposeInMainWorld('napcat', napcat) contextBridge.exposeInMainWorld('napcat', napcat);

View File

@@ -1,6 +1,5 @@
export const onSettingWindowCreated = async (view) => { export const onSettingWindowCreated = async (view) => {
// view.style.width = "100%"; // view.style.width = "100%";
// view.style.height = "100%"; // view.style.height = "100%";
// //添加iframe // //添加iframe
@@ -14,7 +13,7 @@ export const onSettingWindowCreated = async (view) => {
// //有滚动条何尝不是一种美 // //有滚动条何尝不是一种美
// view.appendChild(iframe); // view.appendChild(iframe);
let webui = await window.napcat.getWebUiUrl(); let webui = await window.napcat.getWebUiUrl();
let panel = ` view.innerHTML = `
<setting-section data-title=""> <setting-section data-title="">
<setting-panel> <setting-panel>
<setting-list data-direction="column"> <setting-list data-direction="column">
@@ -30,9 +29,8 @@ export const onSettingWindowCreated = async (view) => {
</setting-panel> </setting-panel>
</setting-section> </setting-section>
`; `;
view.innerHTML = panel; view.querySelector('.nc_openwebui').addEventListener('click', () => {
view.querySelector(".nc_openwebui").addEventListener("click", () => { window.open(webui, '_blank');
window.open(webui, "_blank");
}); });
view.querySelector(".nc_webui").innerText = webui; view.querySelector('.nc_webui').innerText = webui;
}; };

View File

@@ -1,4 +0,0 @@
# NewWebui
基于Vue3实现的现代化轻量化NapCat管理面板
## 进度
画饼

View File

@@ -8,19 +8,19 @@ import { NapCatOneBot11Adapter } from '@/onebot';
abstract class BaseAction<PayloadType, ReturnDataType> { abstract class BaseAction<PayloadType, ReturnDataType> {
actionName: ActionName = ActionName.Unknown; actionName: ActionName = ActionName.Unknown;
CoreContext: NapCatCore; core: NapCatCore;
private validate: undefined | ValidateFunction<any> = undefined; private validate: undefined | ValidateFunction<any> = undefined;
PayloadSchema: any = undefined; payloadSchema: any = undefined;
OneBotContext: NapCatOneBot11Adapter; obContext: NapCatOneBot11Adapter;
constructor(onebotContext: NapCatOneBot11Adapter, coreContext: NapCatCore) { constructor(obContext: NapCatOneBot11Adapter, core: NapCatCore) {
this.OneBotContext = onebotContext; this.obContext = obContext;
this.CoreContext = coreContext; this.core = core;
} }
protected async check(payload: PayloadType): Promise<BaseCheckResult> { protected async check(payload: PayloadType): Promise<BaseCheckResult> {
if (this.PayloadSchema) { if (this.payloadSchema) {
this.validate = new Ajv({ allowUnionTypes: true }).compile(this.PayloadSchema); this.validate = new Ajv({ allowUnionTypes: true }).compile(this.payloadSchema);
} }
if (this.validate && !this.validate(payload)) { if (this.validate && !this.validate(payload)) {
const errors = this.validate.errors as ErrorObject[]; const errors = this.validate.errors as ErrorObject[];
@@ -46,7 +46,7 @@ abstract class BaseAction<PayloadType, ReturnDataType> {
const resData = await this._handle(payload); const resData = await this._handle(payload);
return OB11Response.ok(resData); return OB11Response.ok(resData);
} catch (e: any) { } catch (e: any) {
this.CoreContext.context.logger.logError('发生错误', e); this.core.context.logger.logError('发生错误', e);
return OB11Response.error(e?.toString() || e?.stack?.toString() || '未知错误,可能操作超时', 200); return OB11Response.error(e?.toString() || e?.stack?.toString() || '未知错误,可能操作超时', 200);
} }
} }
@@ -60,7 +60,7 @@ abstract class BaseAction<PayloadType, ReturnDataType> {
const resData = await this._handle(payload); const resData = await this._handle(payload);
return OB11Response.ok(resData, echo); return OB11Response.ok(resData, echo);
} catch (e: any) { } catch (e: any) {
this.CoreContext.context.logger.logError('发生错误', e); this.core.context.logger.logError('发生错误', e);
return OB11Response.error(e.stack?.toString() || e.toString(), 1200, echo); return OB11Response.error(e.stack?.toString() || e.toString(), 1200, echo);
} }
} }

View File

@@ -15,13 +15,13 @@ type Payload = FromSchema<typeof SchemaData>;
export class CreateCollection extends BaseAction<Payload, any> { export class CreateCollection extends BaseAction<Payload, any> {
actionName = ActionName.CreateCollection; actionName = ActionName.CreateCollection;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload) { async _handle(payload: Payload) {
return await this.CoreContext.apis.CollectionApi.createCollection( return await this.core.apis.CollectionApi.createCollection(
this.CoreContext.selfInfo.uin, this.core.selfInfo.uin,
this.CoreContext.selfInfo.uid, this.core.selfInfo.uid,
this.CoreContext.selfInfo.nick, this.core.selfInfo.nick,
payload.brief, payload.rawData, payload.brief, payload.rawData,
); );
} }

View File

@@ -13,11 +13,11 @@ type Payload = FromSchema<typeof SchemaData>;
export class FetchCustomFace extends BaseAction<Payload, string[]> { export class FetchCustomFace extends BaseAction<Payload, string[]> {
actionName = ActionName.FetchCustomFace; actionName = ActionName.FetchCustomFace;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload) { async _handle(payload: Payload) {
//48 可能正好是QQ需要的一个页面的数量 Tagged Mlikiowa //48 可能正好是QQ需要的一个页面的数量 Tagged Mlikiowa
const ret = await this.CoreContext.apis.MsgApi.fetchFavEmojiList(parseInt((payload.count || '0').toString()) || 48); const ret = await this.core.apis.MsgApi.fetchFavEmojiList(+(payload.count ?? 48));
return ret.emojiInfoList.map(e => e.url); return ret.emojiInfoList.map(e => e.url);
} }
} }

View File

@@ -2,7 +2,7 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import BaseAction from '../BaseAction'; import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
import { MessageUnique } from '@/common/utils/MessageUnique'; import { MessageUnique } from '@/common/utils/message-unique';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
@@ -21,12 +21,13 @@ type Payload = FromSchema<typeof SchemaData>;
export class FetchEmojiLike extends BaseAction<Payload, any> { export class FetchEmojiLike extends BaseAction<Payload, any> {
actionName = ActionName.FetchEmojiLike; actionName = ActionName.FetchEmojiLike;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload) { async _handle(payload: Payload) {
const NTQQMsgApi = this.CoreContext.apis.MsgApi; const NTQQMsgApi = this.core.apis.MsgApi;
const msgIdPeer = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString())); const msgIdPeer = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString()));
if (!msgIdPeer) throw new Error('消息不存在'); if (!msgIdPeer) throw new Error('消息不存在');
const msg = (await NTQQMsgApi.getMsgsByMsgId(msgIdPeer.Peer, [msgIdPeer.MsgId])).msgList[0]; const msg = (await NTQQMsgApi.getMsgsByMsgId(msgIdPeer.Peer, [msgIdPeer.MsgId])).msgList[0];
return await NTQQMsgApi.getMsgEmojiLikesList(msgIdPeer.Peer, msg.msgSeq, payload.emojiId, payload.emojiType, parseInt((payload.count || '0').toString()) || 20); return await NTQQMsgApi.getMsgEmojiLikesList(msgIdPeer.Peer, msg.msgSeq, payload.emojiId, payload.emojiType, +(payload.count ?? 20));
} }
} }

View File

@@ -15,9 +15,10 @@ type Payload = FromSchema<typeof SchemaData>;
export class GetCollectionList extends BaseAction<Payload, any> { export class GetCollectionList extends BaseAction<Payload, any> {
actionName = ActionName.GetCollectionList; actionName = ActionName.GetCollectionList;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload) { async _handle(payload: Payload) {
const NTQQCollectionApi = this.CoreContext.apis.CollectionApi; const NTQQCollectionApi = this.core.apis.CollectionApi;
return await NTQQCollectionApi.getAllCollection(parseInt(payload.category.toString()), parseInt(payload.count.toString())); return await NTQQCollectionApi.getAllCollection(parseInt(payload.category.toString()), +(payload.count ?? 1));
} }
} }

View File

@@ -1,13 +1,14 @@
import { OB11Constructor } from '@/onebot/helper/converter'; import { OB11Entities } from '@/onebot/helper/entities';
import BaseAction from '../BaseAction'; import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
export class GetFriendWithCategory extends BaseAction<void, any> { export class GetFriendWithCategory extends BaseAction<void, any> {
actionName = ActionName.GetFriendsWithCategory; actionName = ActionName.GetFriendsWithCategory;
async _handle(payload: void) { async _handle(payload: void) {
return (await this.CoreContext.apis.FriendApi.getBuddyV2ExWithCate(true)).map(category => ({ return (await this.core.apis.FriendApi.getBuddyV2ExWithCate(true)).map(category => ({
...category, ...category,
buddyList: OB11Constructor.friendsV2(category.buddyList), buddyList: OB11Entities.friendsV2(category.buddyList),
})); }));
} }
} }

View File

@@ -11,7 +11,7 @@ export default class GetGroupAddRequest extends BaseAction<null, OB11GroupReques
actionName = ActionName.GetGroupIgnoreAddRequest; actionName = ActionName.GetGroupIgnoreAddRequest;
async _handle(payload: null): Promise<OB11GroupRequestNotify[] | null> { async _handle(payload: null): Promise<OB11GroupRequestNotify[] | null> {
const data = await this.CoreContext.apis.GroupApi.getGroupIgnoreNotifies(); const data = await this.core.apis.GroupApi.getGroupIgnoreNotifies();
// log(data); // log(data);
// const notifies: GroupNotify[] = data.notifies.filter(notify => notify.status === GroupNotifyStatus.WAIT_HANDLE); // const notifies: GroupNotify[] = data.notifies.filter(notify => notify.status === GroupNotifyStatus.WAIT_HANDLE);
// const returnData: OB11GroupRequestNotify[] = []; // const returnData: OB11GroupRequestNotify[] = [];

View File

@@ -5,8 +5,8 @@ export class GetProfileLike extends BaseAction<void, any> {
actionName = ActionName.GetProfileLike; actionName = ActionName.GetProfileLike;
async _handle(payload: void) { async _handle(payload: void) {
const NTQQUserApi = this.CoreContext.apis.UserApi; const NTQQUserApi = this.core.apis.UserApi;
const ret = await NTQQUserApi.getProfileLike(this.CoreContext.selfInfo.uid); const ret = await NTQQUserApi.getProfileLike(this.core.selfInfo.uid);
const listdata: any[] = ret.info.userLikeInfos[0].favoriteInfo.userInfos; const listdata: any[] = ret.info.userLikeInfos[0].favoriteInfo.userInfos;
for (let i = 0; i < listdata.length; i++) { for (let i = 0; i < listdata.length; i++) {
listdata[i].uin = parseInt((await NTQQUserApi.getUinByUidV2(listdata[i].uid)) || ''); listdata[i].uin = parseInt((await NTQQUserApi.getUinByUidV2(listdata[i].uid)) || '');

View File

@@ -5,7 +5,7 @@ export class GetRobotUinRange extends BaseAction<void, Array<any>> {
actionName = ActionName.GetRobotUinRange; actionName = ActionName.GetRobotUinRange;
async _handle(payload: void) { async _handle(payload: void) {
const NTQQUserApi = this.CoreContext.apis.UserApi; const NTQQUserApi = this.core.apis.UserApi;
return await NTQQUserApi.getRobotUinRange(); return await NTQQUserApi.getRobotUinRange();
} }
} }

View File

@@ -3,6 +3,7 @@ import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { checkFileReceived, uri2local } from '@/common/utils/file'; import { checkFileReceived, uri2local } from '@/common/utils/file';
import fs from 'fs'; import fs from 'fs';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
@@ -15,11 +16,11 @@ type Payload = FromSchema<typeof SchemaData>;
export class OCRImage extends BaseAction<Payload, any> { export class OCRImage extends BaseAction<Payload, any> {
actionName = ActionName.OCRImage; actionName = ActionName.OCRImage;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload) { async _handle(payload: Payload) {
const NTQQSystemApi = this.CoreContext.apis.SystemApi; const NTQQSystemApi = this.core.apis.SystemApi;
const { path, isLocal, errMsg, success } = (await uri2local(this.CoreContext.NapCatTempPath, payload.image)); const { path, isLocal, success } = (await uri2local(this.core.NapCatTempPath, payload.image));
if (!success) { if (!success) {
throw `OCR ${payload.image}失败,image字段可能格式不正确`; throw `OCR ${payload.image}失败,image字段可能格式不正确`;
} }

View File

@@ -8,7 +8,7 @@ const SchemaData = {
properties: { properties: {
eventType: { type: 'string' }, eventType: { type: 'string' },
group_id: { type: 'string' }, group_id: { type: 'string' },
user_id: { type: 'string' } user_id: { type: 'string' },
}, },
required: ['eventType'], required: ['eventType'],
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
@@ -19,26 +19,25 @@ export class SetInputStatus extends BaseAction<Payload, any> {
actionName = ActionName.SetInputStatus; actionName = ActionName.SetInputStatus;
async _handle(payload: Payload) { async _handle(payload: Payload) {
const NTQQUserApi = this.CoreContext.apis.UserApi; const NTQQUserApi = this.core.apis.UserApi;
const NTQQMsgApi = this.CoreContext.apis.MsgApi; const NTQQMsgApi = this.core.apis.MsgApi;
let peer: Peer; let peer: Peer;
if (payload.group_id) { if (payload.group_id) {
peer = { peer = {
chatType: ChatType.KCHATTYPEGROUP, chatType: ChatType.KCHATTYPEGROUP,
peerUid: payload.group_id peerUid: payload.group_id,
}; };
} else if (payload.user_id) { } else if (payload.user_id) {
const uid = await NTQQUserApi.getUidByUinV2(payload.user_id); const uid = await NTQQUserApi.getUidByUinV2(payload.user_id);
if (!uid) throw new Error('uid is empty'); if (!uid) throw new Error('uid is empty');
peer = { peer = {
chatType: ChatType.KCHATTYPEC2C, chatType: ChatType.KCHATTYPEC2C,
peerUid: uid peerUid: uid,
}; };
} else { } else {
throw new Error('请指定 group_id 或 user_id'); throw new Error('请指定 group_id 或 user_id');
} }
const ret = await NTQQMsgApi.sendShowInputStatusReq(peer, parseInt(payload.eventType)); return await NTQQMsgApi.sendShowInputStatusReq(peer, parseInt(payload.eventType));
return ret;
} }
} }

View File

@@ -14,10 +14,10 @@ type Payload = FromSchema<typeof SchemaData>;
export class SetLongNick extends BaseAction<Payload, any> { export class SetLongNick extends BaseAction<Payload, any> {
actionName = ActionName.SetLongNick; actionName = ActionName.SetLongNick;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload) { async _handle(payload: Payload) {
const NTQQUserApi = this.CoreContext.apis.UserApi; const NTQQUserApi = this.core.apis.UserApi;
const ret = await NTQQUserApi.setLongNick(payload.longNick); const ret = await NTQQUserApi.setLongNick(payload.longNick);
return ret; return ret;
} }

View File

@@ -17,14 +17,14 @@ type Payload = FromSchema<typeof SchemaData>;
export class SetOnlineStatus extends BaseAction<Payload, null> { export class SetOnlineStatus extends BaseAction<Payload, null> {
actionName = ActionName.SetOnlineStatus; actionName = ActionName.SetOnlineStatus;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload) { async _handle(payload: Payload) {
const NTQQUserApi = this.CoreContext.apis.UserApi; const NTQQUserApi = this.core.apis.UserApi;
const ret = await NTQQUserApi.setSelfOnlineStatus( const ret = await NTQQUserApi.setSelfOnlineStatus(
parseInt(payload.status.toString()), parseInt(payload.status.toString()),
parseInt(payload.extStatus.toString()), parseInt(payload.extStatus.toString()),
parseInt(payload.batteryStatus.toString()) parseInt(payload.batteryStatus.toString()),
); );
if (ret.result !== 0) { if (ret.result !== 0) {
throw new Error('设置在线状态失败'); throw new Error('设置在线状态失败');

View File

@@ -24,8 +24,8 @@ export default class SetAvatar extends BaseAction<Payload, null> {
} }
async _handle(payload: Payload): Promise<null> { async _handle(payload: Payload): Promise<null> {
const NTQQUserApi = this.CoreContext.apis.UserApi; const NTQQUserApi = this.core.apis.UserApi;
const { path, isLocal, errMsg, success } = (await uri2local(this.CoreContext.NapCatTempPath, payload.file)); const { path, isLocal, errMsg, success } = (await uri2local(this.core.NapCatTempPath, payload.file));
if (!success) { if (!success) {
throw `头像${payload.file}设置失败,file字段可能格式不正确`; throw `头像${payload.file}设置失败,file字段可能格式不正确`;
} }

View File

@@ -16,11 +16,11 @@ type Payload = FromSchema<typeof SchemaData>;
export class SharePeer extends BaseAction<Payload, any> { export class SharePeer extends BaseAction<Payload, any> {
actionName = ActionName.SharePeer; actionName = ActionName.SharePeer;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload) { async _handle(payload: Payload) {
const NTQQUserApi = this.CoreContext.apis.UserApi; const NTQQUserApi = this.core.apis.UserApi;
const NTQQGroupApi = this.CoreContext.apis.GroupApi; const NTQQGroupApi = this.core.apis.GroupApi;
if (payload.group_id) { if (payload.group_id) {
return await NTQQGroupApi.getGroupRecommendContactArkJson(payload.group_id); return await NTQQGroupApi.getGroupRecommendContactArkJson(payload.group_id);
} else if (payload.user_id) { } else if (payload.user_id) {
@@ -41,10 +41,10 @@ type PayloadGroupEx = FromSchema<typeof SchemaDataGroupEx>;
export class ShareGroupEx extends BaseAction<PayloadGroupEx, any> { export class ShareGroupEx extends BaseAction<PayloadGroupEx, any> {
actionName = ActionName.ShareGroupEx; actionName = ActionName.ShareGroupEx;
PayloadSchema = SchemaDataGroupEx; payloadSchema = SchemaDataGroupEx;
async _handle(payload: PayloadGroupEx) { async _handle(payload: PayloadGroupEx) {
const NTQQGroupApi = this.CoreContext.apis.GroupApi; const NTQQGroupApi = this.core.apis.GroupApi;
return await NTQQGroupApi.getArkJsonGroupShare(payload.group_id); return await NTQQGroupApi.getArkJsonGroupShare(payload.group_id);
} }
} }

View File

@@ -17,10 +17,10 @@ type Payload = FromSchema<typeof SchemaData>;
export class TranslateEnWordToZn extends BaseAction<Payload, Array<any> | null> { export class TranslateEnWordToZn extends BaseAction<Payload, Array<any> | null> {
actionName = ActionName.TranslateEnWordToZn; actionName = ActionName.TranslateEnWordToZn;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload) { async _handle(payload: Payload) {
const NTQQSystemApi = this.CoreContext.apis.SystemApi; const NTQQSystemApi = this.core.apis.SystemApi;
const ret = await NTQQSystemApi.translateEnWordToZn(payload.words); const ret = await NTQQSystemApi.translateEnWordToZn(payload.words);
if (ret.result !== 0) { if (ret.result !== 0) {
throw new Error('翻译失败'); throw new Error('翻译失败');

View File

@@ -15,10 +15,10 @@ type Payload = FromSchema<typeof SchemaData>;
export class DelGroupFile extends BaseAction<Payload, any> { export class DelGroupFile extends BaseAction<Payload, any> {
actionName = ActionName.DelGroupFile; actionName = ActionName.DelGroupFile;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload) { async _handle(payload: Payload) {
const NTQQGroupApi = this.CoreContext.apis.GroupApi; const NTQQGroupApi = this.core.apis.GroupApi;
return await NTQQGroupApi.DelGroupFile(payload.group_id.toString(), [payload.file_id]); return await NTQQGroupApi.DelGroupFile(payload.group_id.toString(), [payload.file_id]);
} }
} }

View File

@@ -15,10 +15,10 @@ type Payload = FromSchema<typeof SchemaData>;
export class DelGroupFileFolder extends BaseAction<Payload, any> { export class DelGroupFileFolder extends BaseAction<Payload, any> {
actionName = ActionName.DelGroupFileFolder; actionName = ActionName.DelGroupFileFolder;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload) { async _handle(payload: Payload) {
const NTQQGroupApi = this.CoreContext.apis.GroupApi; const NTQQGroupApi = this.core.apis.GroupApi;
return (await NTQQGroupApi.DelGroupFileFolder(payload.group_id.toString(), payload.folder_id)).groupFileCommonResult; return (await NTQQGroupApi.DelGroupFileFolder(payload.group_id.toString(), payload.folder_id)).groupFileCommonResult;
} }
} }

View File

@@ -26,14 +26,14 @@ const GetFileBase_PayloadSchema = {
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> { export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
PayloadSchema: any = GetFileBase_PayloadSchema; payloadSchema: any = GetFileBase_PayloadSchema;
async _handle(payload: GetFilePayload): Promise<GetFileResponse> { async _handle(payload: GetFilePayload): Promise<GetFileResponse> {
const NTQQFriendApi = this.CoreContext.apis.FriendApi; const NTQQFriendApi = this.core.apis.FriendApi;
const NTQQUserApi = this.CoreContext.apis.UserApi; const NTQQUserApi = this.core.apis.UserApi;
const NTQQMsgApi = this.CoreContext.apis.MsgApi; const NTQQMsgApi = this.core.apis.MsgApi;
const NTQQGroupApi = this.CoreContext.apis.GroupApi; const NTQQGroupApi = this.core.apis.GroupApi;
const NTQQFileApi = this.CoreContext.apis.FileApi; const NTQQFileApi = this.core.apis.FileApi;
let UuidData: { let UuidData: {
high: string; high: string;
low: string; low: string;
@@ -90,7 +90,7 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
return res; return res;
} }
} catch { } catch {
this.core.context.logger.logDebug('GetFileBase Mode - 1 Error');
} }
const NTSearchNameResult = (await NTQQFileApi.searchfile([payload.file])).resultItems; const NTSearchNameResult = (await NTQQFileApi.searchfile([payload.file])).resultItems;
@@ -210,7 +210,7 @@ interface GetFile_Payload extends GetFile_Payload_Internal {
export default class GetFile extends GetFileBase { export default class GetFile extends GetFileBase {
actionName = ActionName.GetFile; actionName = ActionName.GetFile;
PayloadSchema = GetFile_PayloadSchema; payloadSchema = GetFile_PayloadSchema;
async _handle(payload: GetFile_Payload): Promise<GetFileResponse> { async _handle(payload: GetFile_Payload): Promise<GetFileResponse> {
payload.file = payload.file_id; payload.file = payload.file_id;

View File

@@ -14,10 +14,10 @@ type Payload = FromSchema<typeof SchemaData>;
export class GetGroupFileCount extends BaseAction<Payload, { count: number }> { export class GetGroupFileCount extends BaseAction<Payload, { count: number }> {
actionName = ActionName.GetGroupFileCount; actionName = ActionName.GetGroupFileCount;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload) { async _handle(payload: Payload) {
const NTQQGroupApi = this.CoreContext.apis.GroupApi; const NTQQGroupApi = this.core.apis.GroupApi;
const ret = await NTQQGroupApi.GetGroupFileCount([payload.group_id?.toString()]); const ret = await NTQQGroupApi.GetGroupFileCount([payload.group_id?.toString()]);
return { count: ret.groupFileCounts[0] }; return { count: ret.groupFileCounts[0] };
} }

View File

@@ -16,10 +16,10 @@ type Payload = FromSchema<typeof SchemaData>;
export class GetGroupFileList extends BaseAction<Payload, { FileList: Array<any> }> { export class GetGroupFileList extends BaseAction<Payload, { FileList: Array<any> }> {
actionName = ActionName.GetGroupFileList; actionName = ActionName.GetGroupFileList;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload) { async _handle(payload: Payload) {
const NTQQMsgApi = this.CoreContext.apis.MsgApi; const NTQQMsgApi = this.core.apis.MsgApi;
const ret = await NTQQMsgApi.getGroupFileList(payload.group_id.toString(), { const ret = await NTQQMsgApi.getGroupFileList(payload.group_id.toString(), {
sortType: 1, sortType: 1,
fileCount: payload.file_count, fileCount: payload.file_count,

View File

@@ -15,10 +15,10 @@ type Payload = FromSchema<typeof SchemaData>;
export class SetGroupFileFolder extends BaseAction<Payload, any> { export class SetGroupFileFolder extends BaseAction<Payload, any> {
actionName = ActionName.SetGroupFileFolder; actionName = ActionName.SetGroupFileFolder;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload) { async _handle(payload: Payload) {
const NTQQGroupApi = this.CoreContext.apis.GroupApi; const NTQQGroupApi = this.core.apis.GroupApi;
return (await NTQQGroupApi.CreatGroupFileFolder(payload.group_id.toString(), payload.folder_name)).resultWithGroupItem; return (await NTQQGroupApi.CreatGroupFileFolder(payload.group_id.toString(), payload.folder_name)).resultWithGroupItem;
} }
} }

View File

@@ -30,12 +30,12 @@ type Payload = FromSchema<typeof SchemaData>;
export default class GoCQHTTPDownloadFile extends BaseAction<Payload, FileResponse> { export default class GoCQHTTPDownloadFile extends BaseAction<Payload, FileResponse> {
actionName = ActionName.GoCQHTTP_DownloadFile; actionName = ActionName.GoCQHTTP_DownloadFile;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload): Promise<FileResponse> { async _handle(payload: Payload): Promise<FileResponse> {
const isRandomName = !payload.name; const isRandomName = !payload.name;
const name = payload.name || randomUUID(); const name = payload.name || randomUUID();
const filePath = joinPath(this.CoreContext.NapCatTempPath, name); const filePath = joinPath(this.core.NapCatTempPath, name);
if (payload.base64) { if (payload.base64) {
fs.writeFileSync(filePath, payload.base64, 'base64'); fs.writeFileSync(filePath, payload.base64, 'base64');
@@ -51,7 +51,7 @@ export default class GoCQHTTPDownloadFile extends BaseAction<Payload, FileRespon
if (isRandomName) { if (isRandomName) {
// 默认实现要名称未填写时文件名为文件 md5 // 默认实现要名称未填写时文件名为文件 md5
const md5 = await calculateFileMD5(filePath); const md5 = await calculateFileMD5(filePath);
const newPath = joinPath(this.CoreContext.NapCatTempPath, md5); const newPath = joinPath(this.core.NapCatTempPath, md5);
fs.renameSync(filePath, newPath); fs.renameSync(filePath, newPath);
return { file: newPath }; return { file: newPath };
} }

View File

@@ -1,10 +1,8 @@
import BaseAction from '../BaseAction'; import BaseAction from '../BaseAction';
import { OB11ForwardMessage, OB11Message, OB11MessageData } from '../../types'; import { OB11ForwardMessage } from '@/onebot';
import { OB11Constructor } from '@/onebot/helper/converter';
import { ActionName } from '../types'; import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { MessageUnique } from '@/common/utils/MessageUnique'; import { MessageUnique } from '@/common/utils/message-unique';
import { RawNTMsg2Onebot } from '@/onebot/helper';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
@@ -16,16 +14,12 @@ const SchemaData = {
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
interface Response {
messages: (OB11Message & { content: OB11MessageData })[];
}
export class GoCQHTTPGetForwardMsgAction extends BaseAction<Payload, any> { export class GoCQHTTPGetForwardMsgAction extends BaseAction<Payload, any> {
actionName = ActionName.GoCQHTTP_GetForwardMsg; actionName = ActionName.GoCQHTTP_GetForwardMsg;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload): Promise<any> { async _handle(payload: Payload): Promise<any> {
const NTQQMsgApi = this.CoreContext.apis.MsgApi; const NTQQMsgApi = this.core.apis.MsgApi;
const msgId = payload.message_id || payload.id; const msgId = payload.message_id || payload.id;
if (!msgId) { if (!msgId) {
throw Error('message_id is required'); throw Error('message_id is required');
@@ -41,7 +35,8 @@ export class GoCQHTTPGetForwardMsgAction extends BaseAction<Payload, any> {
} }
const msgList = data.msgList; const msgList = data.msgList;
const messages = (await Promise.all(msgList.map(async msg => { const messages = (await Promise.all(msgList.map(async msg => {
const resMsg = await RawNTMsg2Onebot(this.CoreContext, this.OneBotContext, msg); const resMsg = await this.obContext.apis.MsgApi
.parseMessage(msg);
if (!resMsg) return; if (!resMsg) return;
resMsg.message_id = MessageUnique.createMsg({ resMsg.message_id = MessageUnique.createMsg({
guildId: '', guildId: '',

View File

@@ -1,11 +1,9 @@
import BaseAction from '../BaseAction'; import BaseAction from '../BaseAction';
import { OB11Message } from '../../types'; import { OB11Message } from '@/onebot';
import { ActionName } from '../types'; import { ActionName } from '../types';
import { ChatType, RawMessage } from '@/core/entities'; import { ChatType, RawMessage } from '@/core/entities';
import { OB11Constructor } from '@/onebot/helper/converter';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { MessageUnique } from '@/common/utils/MessageUnique'; import { MessageUnique } from '@/common/utils/message-unique';
import { RawNTMsg2Onebot } from '@/onebot/helper';
interface Response { interface Response {
messages: OB11Message[]; messages: OB11Message[];
@@ -16,8 +14,8 @@ const SchemaData = {
properties: { properties: {
user_id: { type: ['number', 'string'] }, user_id: { type: ['number', 'string'] },
message_seq: { type: 'number' }, message_seq: { type: 'number' },
count: { type: 'number' }, count: { type: ['number', 'string'] },
reverseOrder: { type: 'boolean' }, reverseOrder: { type: ['boolean', 'string'] },
}, },
required: ['user_id'], required: ['user_id'],
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
@@ -26,16 +24,16 @@ type Payload = FromSchema<typeof SchemaData>;
export default class GetFriendMsgHistory extends BaseAction<Payload, Response> { export default class GetFriendMsgHistory extends BaseAction<Payload, Response> {
actionName = ActionName.GetFriendMsgHistory; actionName = ActionName.GetFriendMsgHistory;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload): Promise<Response> { async _handle(payload: Payload): Promise<Response> {
const NTQQUserApi = this.CoreContext.apis.UserApi; const NTQQUserApi = this.core.apis.UserApi;
const NTQQMsgApi = this.CoreContext.apis.MsgApi; const NTQQMsgApi = this.core.apis.MsgApi;
const NTQQFriendApi = this.CoreContext.apis.FriendApi; const NTQQFriendApi = this.core.apis.FriendApi;
//处理参数 //处理参数
const uid = await NTQQUserApi.getUidByUinV2(payload.user_id.toString()); const uid = await NTQQUserApi.getUidByUinV2(payload.user_id.toString());
const MsgCount = payload.count || 20; const MsgCount = +(payload.count ?? 20);
const isReverseOrder = payload.reverseOrder || true; const isReverseOrder = typeof payload.reverseOrder === 'string' ? payload.reverseOrder === 'true' : !!payload.reverseOrder;
if (!uid) throw `记录${payload.user_id}不存在`; if (!uid) throw `记录${payload.user_id}不存在`;
const friend = await NTQQFriendApi.isBuddy(uid); const friend = await NTQQFriendApi.isBuddy(uid);
const peer = { chatType: friend ? ChatType.KCHATTYPEC2C : ChatType.KCHATTYPETEMPC2CFROMGROUP, peerUid: uid }; const peer = { chatType: friend ? ChatType.KCHATTYPEC2C : ChatType.KCHATTYPETEMPC2CFROMGROUP, peerUid: uid };
@@ -54,7 +52,9 @@ export default class GetFriendMsgHistory extends BaseAction<Payload, Response> {
msg.id = MessageUnique.createMsg({ guildId: '', chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId); msg.id = MessageUnique.createMsg({ guildId: '', chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId);
})); }));
//转换消息 //转换消息
const ob11MsgList = (await Promise.all(msgList.map(msg => RawNTMsg2Onebot(this.CoreContext, this.OneBotContext, msg)))).filter(msg => !!msg); const ob11MsgList = (await Promise.all(
msgList.map(msg => this.obContext.apis.MsgApi.parseMessage(msg)))
).filter(msg => msg !== undefined);
return { 'messages': ob11MsgList }; return { 'messages': ob11MsgList };
} }
} }

View File

@@ -16,13 +16,13 @@ type Payload = FromSchema<typeof SchemaData>;
export class GetGroupHonorInfo extends BaseAction<Payload, Array<any>> { export class GetGroupHonorInfo extends BaseAction<Payload, Array<any>> {
actionName = ActionName.GetGroupHonorInfo; actionName = ActionName.GetGroupHonorInfo;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload) { async _handle(payload: Payload) {
if (!payload.type) { if (!payload.type) {
payload.type = WebHonorType.ALL; payload.type = WebHonorType.ALL;
} }
const NTQQWebApi = this.CoreContext.apis.WebApi; const NTQQWebApi = this.core.apis.WebApi;
return await NTQQWebApi.getGroupHonorInfo(payload.group_id.toString(), payload.type); return await NTQQWebApi.getGroupHonorInfo(payload.group_id.toString(), payload.type);
} }
} }

View File

@@ -1,11 +1,9 @@
import BaseAction from '../BaseAction'; import BaseAction from '../BaseAction';
import { OB11Message } from '../../types'; import { OB11Message } from '@/onebot';
import { ActionName } from '../types'; import { ActionName } from '../types';
import { ChatType, Peer, RawMessage } from '@/core/entities'; import { ChatType, Peer, RawMessage } from '@/core/entities';
import { OB11Constructor } from '@/onebot/helper/converter';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { MessageUnique } from '@/common/utils/MessageUnique'; import { MessageUnique } from '@/common/utils/message-unique';
import { RawNTMsg2Onebot } from '@/onebot/helper';
interface Response { interface Response {
messages: OB11Message[]; messages: OB11Message[];
@@ -16,8 +14,8 @@ const SchemaData = {
properties: { properties: {
group_id: { type: ['number', 'string'] }, group_id: { type: ['number', 'string'] },
message_seq: { type: 'number' }, message_seq: { type: 'number' },
count: { type: 'number' }, count: { type: ['number', 'string'] },
reverseOrder: { type: 'boolean' }, reverseOrder: { type: ['boolean', 'string'] },
}, },
required: ['group_id'], required: ['group_id'],
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
@@ -26,13 +24,13 @@ type Payload = FromSchema<typeof SchemaData>;
export default class GoCQHTTPGetGroupMsgHistory extends BaseAction<Payload, Response> { export default class GoCQHTTPGetGroupMsgHistory extends BaseAction<Payload, Response> {
actionName = ActionName.GoCQHTTP_GetGroupMsgHistory; actionName = ActionName.GoCQHTTP_GetGroupMsgHistory;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload): Promise<Response> { async _handle(payload: Payload): Promise<Response> {
const NTQQMsgApi = this.CoreContext.apis.MsgApi; const NTQQMsgApi = this.core.apis.MsgApi;
//处理参数 //处理参数
const isReverseOrder = payload.reverseOrder || true; const isReverseOrder = typeof payload.reverseOrder === 'string' ? payload.reverseOrder === 'true' : !!payload.reverseOrder;
const MsgCount = payload.count || 20; const MsgCount = +(payload.count ?? 20);
const peer: Peer = { chatType: ChatType.KCHATTYPEGROUP, peerUid: payload.group_id.toString() }; const peer: Peer = { chatType: ChatType.KCHATTYPEGROUP, peerUid: payload.group_id.toString() };
//拉取消息 //拉取消息
let msgList: RawMessage[]; let msgList: RawMessage[];
@@ -49,7 +47,9 @@ export default class GoCQHTTPGetGroupMsgHistory extends BaseAction<Payload, Resp
})); }));
//转换消息 //转换消息
const ob11MsgList = (await Promise.all(msgList.map(msg => RawNTMsg2Onebot(this.CoreContext, this.OneBotContext, msg)))).filter(msg => !!msg); const ob11MsgList = (await Promise.all(
msgList.map(msg => this.obContext.apis.MsgApi.parseMessage(msg)))
).filter(msg => msg !== undefined);
return { 'messages': ob11MsgList }; return { 'messages': ob11MsgList };
} }
} }

View File

@@ -15,7 +15,7 @@ export class GetOnlineClient extends BaseAction<void, Array<any>> {
async _handle(payload: void) { async _handle(payload: void) {
//注册监听 //注册监听
const NTQQSystemApi = this.CoreContext.apis.SystemApi; const NTQQSystemApi = this.core.apis.SystemApi;
NTQQSystemApi.getOnlineDev(); NTQQSystemApi.getOnlineDev();
await sleep(500); await sleep(500);

View File

@@ -1,6 +1,6 @@
import BaseAction from '../BaseAction'; import BaseAction from '../BaseAction';
import { OB11User, OB11UserSex } from '../../types'; import { OB11User, OB11UserSex } from '@/onebot';
import { OB11Constructor } from '@/onebot/helper/converter'; import { OB11Entities } from '@/onebot/helper/entities';
import { ActionName } from '../types'; import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { calcQQLevel } from '@/common/utils/helper'; import { calcQQLevel } from '@/common/utils/helper';
@@ -19,12 +19,12 @@ export default class GoCQHTTPGetStrangerInfo extends BaseAction<Payload, OB11Use
actionName = ActionName.GoCQHTTP_GetStrangerInfo; actionName = ActionName.GoCQHTTP_GetStrangerInfo;
async _handle(payload: Payload): Promise<OB11User> { async _handle(payload: Payload): Promise<OB11User> {
const NTQQUserApi = this.CoreContext.apis.UserApi; const NTQQUserApi = this.core.apis.UserApi;
const user_id = payload.user_id.toString(); const user_id = payload.user_id.toString();
const extendData = await NTQQUserApi.getUserDetailInfoByUinV2(user_id); const extendData = await NTQQUserApi.getUserDetailInfoByUinV2(user_id);
const uid = (await NTQQUserApi.getUidByUinV2(user_id))!; const uid = (await NTQQUserApi.getUidByUinV2(user_id))!;
if (!uid || uid.indexOf('*') != -1) { if (!uid || uid.indexOf('*') != -1) {
const ret = { return {
...extendData.detail.simpleInfo.coreInfo, ...extendData.detail.simpleInfo.coreInfo,
...extendData.detail.commonExt, ...extendData.detail.commonExt,
...extendData.detail.simpleInfo.baseInfo, ...extendData.detail.simpleInfo.baseInfo,
@@ -36,11 +36,9 @@ export default class GoCQHTTPGetStrangerInfo extends BaseAction<Payload, OB11Use
qid: extendData.detail.simpleInfo.baseInfo.qid, qid: extendData.detail.simpleInfo.baseInfo.qid,
level: calcQQLevel(extendData.detail.commonExt?.qqLevel ?? 0) || 0, level: calcQQLevel(extendData.detail.commonExt?.qqLevel ?? 0) || 0,
login_days: 0, login_days: 0,
uid: ''
}; };
return ret;
} }
const data = { ...extendData, ...(await NTQQUserApi.getUserDetailInfo(uid)) }; const data = { ...extendData, ...(await NTQQUserApi.getUserDetailInfo(uid)) };
return OB11Constructor.stranger(data); return OB11Entities.stranger(data);
} }
} }

View File

@@ -1,4 +1,3 @@
import { handleQuickOperation } from '@/onebot/helper/quick';
import BaseAction from '../BaseAction'; import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
import { QuickAction, QuickActionEvent } from '@/onebot/types'; import { QuickAction, QuickActionEvent } from '@/onebot/types';
@@ -12,7 +11,9 @@ export class GoCQHTTPHandleQuickAction extends BaseAction<Payload, null> {
actionName = ActionName.GoCQHTTP_HandleQuickAction; actionName = ActionName.GoCQHTTP_HandleQuickAction;
async _handle(payload: Payload): Promise<null> { async _handle(payload: Payload): Promise<null> {
handleQuickOperation(this.CoreContext, this.OneBotContext, payload.context, payload.operation).then().catch(this.CoreContext.context.logger.logError); this.obContext.apis.QuickActionApi
.handleQuickOperation(payload.context, payload.operation)
.catch(this.core.context.logger.logError);
return null; return null;
} }
} }

View File

@@ -10,8 +10,8 @@ const SchemaData = {
group_id: { type: ['number', 'string'] }, group_id: { type: ['number', 'string'] },
content: { type: 'string' }, content: { type: 'string' },
image: { type: 'string' }, image: { type: 'string' },
pinned: { type: 'number' }, pinned: { type: ['number', 'string'] },
confirmRequired: { type: 'number' }, confirmRequired: { type: ['number', 'string'] },
}, },
required: ['group_id', 'content'], required: ['group_id', 'content'],
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
@@ -22,7 +22,7 @@ export class SendGroupNotice extends BaseAction<Payload, null> {
actionName = ActionName.GoCQHTTP_SendGroupNotice; actionName = ActionName.GoCQHTTP_SendGroupNotice;
async _handle(payload: Payload) { async _handle(payload: Payload) {
const NTQQGroupApi = this.CoreContext.apis.GroupApi; const NTQQGroupApi = this.core.apis.GroupApi;
let UploadImage: { id: string, width: number, height: number } | undefined = undefined; let UploadImage: { id: string, width: number, height: number } | undefined = undefined;
if (payload.image) { if (payload.image) {
//公告图逻辑 //公告图逻辑
@@ -31,7 +31,7 @@ export class SendGroupNotice extends BaseAction<Payload, null> {
path, path,
isLocal, isLocal,
success, success,
} = (await uri2local(this.CoreContext.NapCatTempPath, payload.image)); } = (await uri2local(this.core.NapCatTempPath, payload.image));
if (!success) { if (!success) {
throw `群公告${payload.image}设置失败,image字段可能格式不正确`; throw `群公告${payload.image}设置失败,image字段可能格式不正确`;
} }
@@ -49,21 +49,13 @@ export class SendGroupNotice extends BaseAction<Payload, null> {
} }
UploadImage = ImageUploadResult.picInfo; UploadImage = ImageUploadResult.picInfo;
} }
let Notice_Pinned = 0; let Notice_Pinned = +(payload.pinned ?? 0);
let Notice_confirmRequired = 0; let Notice_confirmRequired = +(payload.confirmRequired ?? 0);
if (!payload.pinned) {
Notice_Pinned = 0;
}
if (!payload.confirmRequired) {
Notice_confirmRequired = 0;
}
const PublishGroupBulletinResult = await NTQQGroupApi.publishGroupBulletin(payload.group_id.toString(), payload.content, UploadImage, Notice_Pinned, Notice_confirmRequired); const PublishGroupBulletinResult = await NTQQGroupApi.publishGroupBulletin(payload.group_id.toString(), payload.content, UploadImage, Notice_Pinned, Notice_confirmRequired);
if (PublishGroupBulletinResult.result != 0) { if (PublishGroupBulletinResult.result != 0) {
throw `设置群公告失败,错误信息:${PublishGroupBulletinResult.errMsg}`; throw `设置群公告失败,错误信息:${PublishGroupBulletinResult.errMsg}`;
} }
// 下面实现扬了
//await WebApi.setGroupNotice(payload.group_id, payload.content) ;
return null; return null;
} }
} }

View File

@@ -3,8 +3,6 @@ import { ActionName, BaseCheckResult } from '../types';
import * as fs from 'node:fs'; import * as fs from 'node:fs';
import { checkFileReceived, uri2local } from '@/common/utils/file'; import { checkFileReceived, uri2local } from '@/common/utils/file';
// import { log } from "../../../common/utils";
interface Payload { interface Payload {
file: string, file: string,
group_id: number group_id: number
@@ -27,8 +25,8 @@ export default class SetGroupPortrait extends BaseAction<Payload, any> {
} }
async _handle(payload: Payload): Promise<any> { async _handle(payload: Payload): Promise<any> {
const NTQQGroupApi = this.CoreContext.apis.GroupApi; const NTQQGroupApi = this.core.apis.GroupApi;
const { path, isLocal, errMsg, success } = (await uri2local(this.CoreContext.NapCatTempPath, payload.file)); const { path, isLocal, errMsg, success } = (await uri2local(this.core.NapCatTempPath, payload.file));
if (!success) { if (!success) {
throw `头像${payload.file}设置失败,file字段可能格式不正确`; throw `头像${payload.file}设置失败,file字段可能格式不正确`;
} }
@@ -42,7 +40,6 @@ export default class SetGroupPortrait extends BaseAction<Payload, any> {
if (!ret) { if (!ret) {
throw `头像${payload.file}设置失败,api无返回`; throw `头像${payload.file}设置失败,api无返回`;
} }
// log(`头像设置返回:${JSON.stringify(ret)}`)
if (ret['result'] == 1004022) { if (ret['result'] == 1004022) {
throw `头像${payload.file}设置失败,文件可能不是图片格式或权限不足`; throw `头像${payload.file}设置失败,文件可能不是图片格式或权限不足`;
} else if (ret['result'] != 0) { } else if (ret['result'] != 0) {

View File

@@ -16,19 +16,22 @@ type Payload = FromSchema<typeof SchemaData>;
export class SetQQProfile extends BaseAction<Payload, any | null> { export class SetQQProfile extends BaseAction<Payload, any | null> {
actionName = ActionName.SetQQProfile; actionName = ActionName.SetQQProfile;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload) { async _handle(payload: Payload) {
const NTQQUserApi = this.CoreContext.apis.UserApi; const NTQQUserApi = this.core.apis.UserApi;
const self = this.CoreContext.selfInfo; const self = this.core.selfInfo;
const OldProfile = await NTQQUserApi.getUserDetailInfo(self.uid); const OldProfile = await NTQQUserApi.getUserDetailInfo(self.uid);
const ret = await NTQQUserApi.modifySelfProfile({ return await NTQQUserApi.modifySelfProfile({
nick: payload.nickname, nick: payload.nickname,
longNick: payload?.personal_note ?? OldProfile?.longNick!, longNick: (payload?.personal_note ?? OldProfile?.longNick) || '',
sex: parseInt(payload?.sex ? payload?.sex.toString() : OldProfile?.sex!.toString()), sex: parseInt(payload?.sex ? payload?.sex.toString() : OldProfile?.sex!.toString()),
birthday: { birthday_year: OldProfile?.birthday_year!.toString(), birthday_month: OldProfile?.birthday_month!.toString(), birthday_day: OldProfile?.birthday_day!.toString() }, birthday: {
birthday_year: OldProfile?.birthday_year!.toString(),
birthday_month: OldProfile?.birthday_month!.toString(),
birthday_day: OldProfile?.birthday_day!.toString(),
},
location: undefined, location: undefined,
}); });
return ret;
} }
} }

View File

@@ -1,11 +1,9 @@
import BaseAction from '../BaseAction'; import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
import { ChatType, SendFileElement } from '@/core/entities'; import { ChatType } from '@/core/entities';
import fs from 'fs'; import fs from 'fs';
import { sendMsg } from '@/onebot/action/msg/SendMsg';
import { uri2local } from '@/common/utils/file'; import { uri2local } from '@/common/utils/file';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { SendMsgElementConstructor } from '@/onebot/helper/genMessage';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
@@ -23,19 +21,19 @@ type Payload = FromSchema<typeof SchemaData>;
export default class GoCQHTTPUploadGroupFile extends BaseAction<Payload, null> { export default class GoCQHTTPUploadGroupFile extends BaseAction<Payload, null> {
actionName = ActionName.GoCQHTTP_UploadGroupFile; actionName = ActionName.GoCQHTTP_UploadGroupFile;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload): Promise<null> { async _handle(payload: Payload): Promise<null> {
let file = payload.file; let file = payload.file;
if (fs.existsSync(file)) { if (fs.existsSync(file)) {
file = `file://${file}`; file = `file://${file}`;
} }
const downloadResult = await uri2local(this.CoreContext.NapCatTempPath, file); const downloadResult = await uri2local(this.core.NapCatTempPath, file);
if (!downloadResult.success) { if (!downloadResult.success) {
throw new Error(downloadResult.errMsg); throw new Error(downloadResult.errMsg);
} }
const sendFileEle: SendFileElement = await SendMsgElementConstructor.file(this.CoreContext, downloadResult.path, payload.name, payload.folder_id); const sendFileEle = await this.core.apis.FileApi.createValidSendFileElement(downloadResult.path, payload.name, payload.folder_id);
await sendMsg(this.CoreContext, { await this.obContext.apis.MsgApi.sendMsgWithOb11UniqueId({
chatType: ChatType.KCHATTYPEGROUP, chatType: ChatType.KCHATTYPEGROUP,
peerUid: payload.group_id.toString(), peerUid: payload.group_id.toString(),
}, [sendFileEle], [], true); }, [sendFileEle], [], true);

View File

@@ -2,10 +2,8 @@ import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
import { ChatType, Peer, SendFileElement } from '@/core/entities'; import { ChatType, Peer, SendFileElement } from '@/core/entities';
import fs from 'fs'; import fs from 'fs';
import { sendMsg } from '@/onebot/action/msg/SendMsg';
import { uri2local } from '@/common/utils/file'; import { uri2local } from '@/common/utils/file';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { SendMsgElementConstructor } from '@/onebot/helper/genMessage';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
@@ -21,11 +19,11 @@ type Payload = FromSchema<typeof SchemaData>;
export default class GoCQHTTPUploadPrivateFile extends BaseAction<Payload, null> { export default class GoCQHTTPUploadPrivateFile extends BaseAction<Payload, null> {
actionName = ActionName.GOCQHTTP_UploadPrivateFile; actionName = ActionName.GOCQHTTP_UploadPrivateFile;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async getPeer(payload: Payload): Promise<Peer> { async getPeer(payload: Payload): Promise<Peer> {
const NTQQUserApi = this.CoreContext.apis.UserApi; const NTQQUserApi = this.core.apis.UserApi;
const NTQQFriendApi = this.CoreContext.apis.FriendApi; const NTQQFriendApi = this.core.apis.FriendApi;
if (payload.user_id) { if (payload.user_id) {
const peerUid = await NTQQUserApi.getUidByUinV2(payload.user_id.toString()); const peerUid = await NTQQUserApi.getUidByUinV2(payload.user_id.toString());
if (!peerUid) { if (!peerUid) {
@@ -34,21 +32,20 @@ export default class GoCQHTTPUploadPrivateFile extends BaseAction<Payload, null>
const isBuddy = await NTQQFriendApi.isBuddy(peerUid); const isBuddy = await NTQQFriendApi.isBuddy(peerUid);
return { chatType: isBuddy ? ChatType.KCHATTYPEC2C : ChatType.KCHATTYPETEMPC2CFROMGROUP, peerUid }; return { chatType: isBuddy ? ChatType.KCHATTYPEC2C : ChatType.KCHATTYPETEMPC2CFROMGROUP, peerUid };
} }
throw '缺少参数 user_id'; throw new Error('缺少参数 user_id');
} }
async _handle(payload: Payload): Promise<null> { async _handle(payload: Payload): Promise<null> {
const peer = await this.getPeer(payload);
let file = payload.file; let file = payload.file;
if (fs.existsSync(file)) { if (fs.existsSync(file)) {
file = `file://${file}`; file = `file://${file}`;
} }
const downloadResult = await uri2local(this.CoreContext.NapCatTempPath, file); const downloadResult = await uri2local(this.core.NapCatTempPath, file);
if (!downloadResult.success) { if (!downloadResult.success) {
throw new Error(downloadResult.errMsg); throw new Error(downloadResult.errMsg);
} }
const sendFileEle: SendFileElement = await SendMsgElementConstructor.file(this.CoreContext, downloadResult.path, payload.name); const sendFileEle: SendFileElement = await this.core.apis.FileApi.createValidSendFileElement(downloadResult.path, payload.name);
await sendMsg(this.CoreContext, peer, [sendFileEle], [], true); await this.obContext.apis.MsgApi.sendMsgWithOb11UniqueId(await this.getPeer(payload), [sendFileEle], [], true);
return null; return null;
} }
} }

View File

@@ -1,7 +1,7 @@
import BaseAction from '../BaseAction'; import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { MessageUnique } from '@/common/utils/MessageUnique'; import { MessageUnique } from '@/common/utils/message-unique';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
@@ -15,11 +15,11 @@ type Payload = FromSchema<typeof SchemaData>;
export default class DelEssenceMsg extends BaseAction<Payload, any> { export default class DelEssenceMsg extends BaseAction<Payload, any> {
actionName = ActionName.DelEssenceMsg; actionName = ActionName.DelEssenceMsg;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload): Promise<any> { async _handle(payload: Payload): Promise<any> {
const NTQQGroupApi = this.CoreContext.apis.GroupApi; const NTQQGroupApi = this.core.apis.GroupApi;
const msg = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString())); const msg = MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id);
if (!msg) throw new Error('msg not found'); if (!msg) throw new Error('msg not found');
return await NTQQGroupApi.removeGroupEssence( return await NTQQGroupApi.removeGroupEssence(
msg.Peer.peerUid, msg.Peer.peerUid,

View File

@@ -0,0 +1,27 @@
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
notice_id: { type: 'string' },
},
required: ['group_id', 'notice_id'],
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
export class DelGroupNotice extends BaseAction<Payload, any> {
actionName = ActionName.DelGroupNotice;
payloadSchema = SchemaData;
async _handle(payload: Payload) {
const NTQQGroupApi = this.core.apis.GroupApi;
const group = payload.group_id.toString();
const noticeId = payload.notice_id;
return await NTQQGroupApi.deleteGroupBulletin(group, noticeId);
}
}

View File

@@ -7,7 +7,7 @@ const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
group_id: { type: ['number', 'string'] }, group_id: { type: ['number', 'string'] },
pages: { type: 'number' }, pages: { type: ['number', 'string'] },
}, },
required: ['group_id'], required: ['group_id'],
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
@@ -16,11 +16,11 @@ type Payload = FromSchema<typeof SchemaData>;
export class GetGroupEssence extends BaseAction<Payload, GroupEssenceMsgRet> { export class GetGroupEssence extends BaseAction<Payload, GroupEssenceMsgRet> {
actionName = ActionName.GoCQHTTP_GetEssenceMsg; actionName = ActionName.GoCQHTTP_GetEssenceMsg;
PayloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload) { async _handle(payload: Payload) {
const NTQQWebApi = this.CoreContext.apis.WebApi; const NTQQWebApi = this.core.apis.WebApi;
const ret = await NTQQWebApi.getGroupEssenceMsg(payload.group_id.toString(), (payload.pages || "0").toString()); const ret = await NTQQWebApi.getGroupEssenceMsg(payload.group_id.toString(), (+(payload.pages ?? 0)).toString());
if (!ret) { if (!ret) {
throw new Error('获取失败'); throw new Error('获取失败');
} }

Some files were not shown because too many files have changed in this diff Show More