Compare commits

...

33 Commits

Author SHA1 Message Date
手瓜一十雪
1d2e2b6e5c release: 2.2.44 2024-09-03 21:33:48 +08:00
手瓜一十雪
31d963c4d1 Merge pull request #336 from hguandl/feat/macos
feat: 支持 macOS
2024-09-03 21:16:03 +08:00
Hao Guan
7e96118cdc feat: support macOS 2024-09-03 20:17:10 +08:00
Hao Guan
709a0744bd chore: refactor path config 2024-09-03 20:14:35 +08:00
手瓜一十雪
f59248cc5a release: 2.2.43 2024-09-03 18:49:45 +08:00
手瓜一十雪
8647c5c607 fix: echo丢失问题 2024-09-03 18:37:28 +08:00
手瓜一十雪
6699ff38a1 Revert "fix: Error Handle"
This reverts commit d79b98bd55.
2024-09-03 18:36:20 +08:00
手瓜一十雪
d79b98bd55 fix: Error Handle 2024-09-03 18:34:33 +08:00
手瓜一十雪
5065a052fb release: 2.2.42 2024-09-03 18:12:59 +08:00
Wesley F. Young
45603bb78c fix(docs): unexpected spaces 2024-09-03 15:48:08 +08:00
手瓜一十雪
40948995b4 build: test 2024-09-03 14:09:17 +08:00
手瓜一十雪
4ccdd8d1d3 docs: update 2024-09-03 13:37:19 +08:00
手瓜一十雪
30d0174f47 fix: #334 2024-09-03 13:20:10 +08:00
手瓜一十雪
5a986ba25c release: 2.2.40 2024-09-03 13:01:37 +08:00
手瓜一十雪
fe63c24ac3 release: 2.2.39 2024-09-03 12:40:13 +08:00
手瓜一十雪
c384bd6875 release: 2.2.38 2024-09-02 17:31:27 +08:00
手瓜一十雪
dcbff3f569 release: 2.2.37 2024-09-02 16:31:42 +08:00
手瓜一十雪
7d91e05a69 fix: #332 2024-09-02 16:31:18 +08:00
手瓜一十雪
a5ce424a40 release: 2.2.36 2024-09-01 18:44:23 +08:00
手瓜一十雪
47c36ca062 release: 2.2.35 2024-09-01 18:24:49 +08:00
手瓜一十雪
c4c5b3bf8b fix: remark 2024-09-01 18:24:29 +08:00
手瓜一十雪
b1a81b0d12 release: 2.2.32 2024-09-01 16:32:13 +08:00
手瓜一十雪
ad9fe64850 release: 2.2.32 2024-09-01 16:13:41 +08:00
手瓜一十雪
f236349dc6 Revert "release:2.2.31"
This reverts commit 309d8a9f18.
2024-09-01 16:13:14 +08:00
手瓜一十雪
5f56c8a7d4 fix 2024-09-01 16:10:16 +08:00
手瓜一十雪
309d8a9f18 release:2.2.31 2024-09-01 15:59:02 +08:00
手瓜一十雪
2981799803 fix: file api 2024-09-01 14:11:28 +08:00
手瓜一十雪
00f8e1c0da Revert "fix: fileId"
This reverts commit ae009f98c1.
2024-09-01 13:41:19 +08:00
手瓜一十雪
e9482e2ec4 Revert "fix: encode fileId"
This reverts commit 9bff327377.
2024-09-01 13:41:14 +08:00
手瓜一十雪
9bff327377 fix: encode fileId 2024-09-01 12:17:42 +08:00
手瓜一十雪
ae009f98c1 fix: fileId 2024-09-01 12:17:17 +08:00
手瓜一十雪
77505a6f5b release: 2.2.31 2024-09-01 09:31:59 +08:00
手瓜一十雪
19c729aa23 chore: appid 2024-09-01 09:30:38 +08:00
39 changed files with 285 additions and 508 deletions

View File

@@ -7,10 +7,12 @@
NapCatQQ (aka 猫猫框架) 是现代化的基于 NTQQ 的 Bot 协议端实现。
## 猫猫技能
- [x] **高性能**1K+ 群聊数目、20 线程并行发送消息毫无压力
- [x] **多种启动方式**支持以无头、LiteLoader 插件、仅 QQ GUI 三种方式启动
- [x] **低占用**:无头模式占用资源极低,适合在服务器上运行
- [x] **超多接口**实现大部分Onebot接口上扩展了一套私有API
- [x] **超多接口**:实现大部分 OneBot 和 go-cqhttp 接口,超多扩展 API
- [x] **WebUI**:自带 WebUI 支持,远程管理更加便捷
- [x] **低故障率**:快速适配最新版本,日常保证 0 Issue
## 使用猫猫

View File

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

View File

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

Binary file not shown.

View File

@@ -22,9 +22,14 @@ export abstract class ConfigBase<T> {
}
getConfigPath(pathName: string | undefined): string {
const suffix = pathName ? `_${pathName}` : '';
const filename = `${this.name}${suffix}.json`;
return path.join(this.configPath, filename);
if (!pathName) {
const filename = `${this.name}.json`;
const mainPath = this.core.context.pathWrapper.binaryPath;
return path.join(mainPath, 'config', filename);
} else {
const filename = `${this.name}_${pathName}.json`;
return path.join(this.configPath, filename);
}
}
read(): T {

View File

@@ -25,29 +25,31 @@ export async function solveAsyncProblem<T extends (...args: any[]) => Promise<an
}
export class FileNapCatOneBotUUID {
static encodeModelId(peer: Peer, modelId: string): string {
return `NapCatOneBot-ModelIdFile-${peer.chatType}-${peer.peerUid}-${modelId}`;
static encodeModelId(peer: Peer, modelId: string, fileId: string): string {
return `NapCatOneBot|ModelIdFile|${peer.chatType}|${peer.peerUid}|${modelId}|${fileId}`;
}
static decodeModelId(uuid: string): undefined | {
peer: Peer,
modelId: string
modelId: string,
fileId: string
} {
if (!uuid.startsWith('NapCatOneBot-ModelIdFile-')) return undefined;
const data = uuid.split('-');
if (data.length !== 5) return undefined;
const [, , chatType, peerUid, modelId] = data;
if (!uuid.startsWith('NapCatOneBot|ModelIdFile|')) return undefined;
const data = uuid.split('|');
if (data.length !== 6) return undefined;
const [, , chatType, peerUid, modelId, fileId] = data;
return {
peer: {
chatType: chatType as any,
peerUid: peerUid,
},
modelId,
fileId
};
}
static encode(peer: Peer, msgId: string, elementId: string): string {
return `NapCatOneBot-MsgFile-${peer.chatType}-${peer.peerUid}-${msgId}-${elementId}`;
return `NapCatOneBot|MsgFile|${peer.chatType}|${peer.peerUid}|${msgId}|${elementId}`;
}
static decode(uuid: string): undefined | {
@@ -55,8 +57,8 @@ export class FileNapCatOneBotUUID {
msgId: string,
elementId: string
} {
if (!uuid.startsWith('NapCatOneBot-MsgFile-')) return undefined;
const data = uuid.split('-');
if (!uuid.startsWith('NapCatOneBot|MsgFile|')) return undefined;
const data = uuid.split('|');
if (data.length !== 6) return undefined;
const [, , chatType, peerUid, msgId, elementId] = data;
return {
@@ -138,26 +140,38 @@ export function isEqual(obj1: any, obj2: any) {
export function getDefaultQQVersionConfigInfo(): QQVersionConfigType {
if (os.platform() === 'linux') {
return {
baseVersion: '3.2.12-27254',
curVersion: '3.2.12-27254',
baseVersion: '3.2.12-27597',
curVersion: '3.2.12-27597',
prevVersion: '',
onErrorVersions: [],
buildId: '27254',
buildId: '27597',
};
}
return {
baseVersion: '9.9.15-27391',
curVersion: '9.9.15-27391',
baseVersion: '9.9.15-27597',
curVersion: '9.9.15-27597',
prevVersion: '',
onErrorVersions: [],
buildId: '27391',
buildId: '27597',
};
}
export function getQQPackageInfoPath(exePath: string = ''): string {
if (os.platform() === 'darwin') {
return path.join(path.dirname(exePath), '..', 'Resources', 'app', 'package.json');
} else {
return path.join(path.dirname(exePath), 'resources', 'app', 'package.json');
}
}
export function getQQVersionConfigPath(exePath: string = ''): string | undefined {
let configVersionInfoPath;
if (os.platform() !== 'linux') {
if (os.platform() === 'win32') {
configVersionInfoPath = path.join(path.dirname(exePath), 'resources', 'app', 'versions', 'config.json');
} else if (os.platform() === 'darwin') {
const userPath = os.homedir();
const appDataPath = path.resolve(userPath, './Library/Application Support/QQ');
configVersionInfoPath = path.resolve(appDataPath, './versions/config.json');
} else {
const userPath = os.homedir();
const appDataPath = path.resolve(userPath, './.config/QQ');

View File

@@ -1,6 +1,7 @@
import path, { dirname } from 'path';
import { fileURLToPath } from 'url';
import fs from 'fs';
import os from 'os';
export class NapCatPathWrapper {
binaryPath: string;
@@ -11,17 +12,23 @@ export class NapCatPathWrapper {
constructor(mainPath: string = dirname(fileURLToPath(import.meta.url))) {
this.binaryPath = mainPath;
this.logsPath = path.join(this.binaryPath, 'logs');
this.configPath = path.join(this.binaryPath, 'config');
this.cachePath = path.join(this.binaryPath, 'cache');
let writePath: string;
if (os.platform() === 'darwin') {
writePath = path.join(os.homedir(), 'Library', 'Application Support', 'QQ', 'NapCat');
} else {
writePath = this.binaryPath;
}
this.logsPath = path.join(writePath, 'logs');
this.configPath = path.join(writePath, 'config');
this.cachePath = path.join(writePath, 'cache');
this.staticPath = path.join(this.binaryPath, 'static');
if (fs.existsSync(this.logsPath)) {
if (!fs.existsSync(this.logsPath)) {
fs.mkdirSync(this.logsPath, { recursive: true });
}
if (fs.existsSync(this.configPath)) {
if (!fs.existsSync(this.configPath)) {
fs.mkdirSync(this.configPath, { recursive: true });
}
if (fs.existsSync(this.cachePath)) {
if (!fs.existsSync(this.cachePath)) {
fs.mkdirSync(this.cachePath, { recursive: true });
}
}

View File

@@ -1,7 +1,6 @@
import path from 'node:path';
import fs from 'node:fs';
import { systemPlatform } from '@/common/system';
import { getDefaultQQVersionConfigInfo, getQQVersionConfigPath } from './helper';
import { getDefaultQQVersionConfigInfo, getQQPackageInfoPath, getQQVersionConfigPath } from './helper';
import AppidTable from '@/core/external/appid.json';
import { LogWrapper } from './log';
@@ -20,7 +19,7 @@ export class QQBasicInfoWrapper {
//基础目录获取
this.context = context;
this.QQMainPath = process.execPath;
this.QQPackageInfoPath = path.join(path.dirname(this.QQMainPath), 'resources', 'app', 'package.json');
this.QQPackageInfoPath = getQQPackageInfoPath(this.QQMainPath);
this.QQVersionConfigPath = getQQVersionConfigPath(this.QQMainPath);
//基础信息获取 无快更则启用默认模板填充
@@ -53,9 +52,25 @@ export class QQBasicInfoWrapper {
//此方法不要直接使用
getQUAInternal() {
return systemPlatform === 'linux'
? `V1_LNX_NQ_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B`
: `V1_WIN_NQ_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B`;
switch (systemPlatform) {
case 'linux':
return `V1_LNX_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B`;
case 'darwin':
return `V1_MAC_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B`;
default:
return `V1_WIN_${this.getFullQQVesion()}_${this.getQQBuildStr()}_GW_B`;
}
}
getAppidInternal() {
switch (systemPlatform) {
case 'linux':
return '537243600';
case 'darwin':
return '537243441';
default:
return '537243538';
}
}
getAppidV2(): { appid: string; qua: string } {
@@ -71,6 +86,6 @@ export class QQBasicInfoWrapper {
// else
this.context.logger.log(`[QQ版本兼容性检测] 获取Appid异常 请检测NapCat/QQNT是否正常`);
this.context.logger.log(`[QQ版本兼容性检测] ${fullVersion} 版本兼容性不佳,可能会导致一些功能无法正常使用`,);
return { appid: systemPlatform === 'linux' ? '537240795' : '537240709', qua: this.getQUAInternal() };
return { appid: this.getAppidInternal(), qua: this.getQUAInternal() };
}
}

View File

@@ -1 +1 @@
export const napCatVersion = '2.2.30';
export const napCatVersion = '2.2.44';

View File

@@ -121,51 +121,6 @@ export class NTQQGroupApi {
return group;
}
async getGroupMemberLatestSendTimeCache(GroupCode: string, uids: string[]) {
return this.getGroupMemberLatestSendTime(GroupCode, uids);
}
async getGroupMemberLatestSendTime(GroupCode: string, uids: string[]) {
const getData = async (uid: string) => {
const msgListWrapper = await this.getLatestMsgByUids(GroupCode, [uid]);
if (msgListWrapper.result !== 0 && msgListWrapper.msgList.length < 1) {
return undefined;
}
return { sendUin: msgListWrapper.msgList[0].senderUin, sendTime: msgListWrapper.msgList[0].msgTime };
};
const PromiseData: Promise<({
sendUin: string;
sendTime: string;
} | undefined)>[] = [];
const ret: Map<string, string> = new Map();
for (const uid of uids) {
PromiseData.push(getData(uid).catch(() => undefined));
}
const allRet = await runAllWithTimeout(PromiseData, 2500);
for (const PromiseDo of allRet) {
if (PromiseDo) {
ret.set(PromiseDo.sendUin, PromiseDo.sendTime);
}
}
return ret;
}
async getLatestMsgByUids(GroupCode: string, uids: string[]) {
return await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', '0', {
chatInfo: {
peerUid: GroupCode,
chatType: ChatType.KCHATTYPEGROUP,
},
filterMsgType: [],
filterSendersUid: uids,
filterMsgToTime: '0',
filterMsgFromTime: '0',
isReverseOrder: false,
isIncludeCurrent: true,
pageLimit: 1,
});
}
async getGroupMemberAll(GroupCode: string, forced = false) {
return this.context.session.getGroupService().getAllMemberList(GroupCode, forced);
}
@@ -202,30 +157,6 @@ export class NTQQGroupApi {
}
return member;
}
async getLatestMsg(GroupCode: string, uins: string[]) {
const uids: Array<string> = [];
for (const uin of uins) {
const uid = await this.core.apis.UserApi.getUidByUinV2(uin);
if (uid) {
uids.push(uid);
}
}
return await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', '0', {
chatInfo: {
peerUid: GroupCode,
chatType: ChatType.KCHATTYPEGROUP,
},
filterMsgType: [],
filterSendersUid: uids,
filterMsgToTime: '0',
filterMsgFromTime: '0',
isReverseOrder: false,
isIncludeCurrent: true,
pageLimit: 1,
});
}
async getGroupRecommendContactArkJson(GroupCode: string) {
return this.context.session.getGroupService().getGroupRecommendContactArkJson(GroupCode);
}
@@ -383,9 +314,6 @@ export class NTQQGroupApi {
return this.context.session.getRichMediaService().batchGetGroupFileCount(Gids);
}
async getGroupIgnoreNotifies() {
}
async getArkJsonGroupShare(GroupCode: string) {
const ret = await this.core.eventWrapper.callNoListenerEvent(
'NodeIKernelGroupService/getGroupRecommendContactArkJson',

View File

@@ -54,19 +54,6 @@ export class NTQQMsgApi {
return this.context.session.getMsgService().forwardMsg(msgIds, peer, [peer], new Map());
}
async getLatestMsgByUids(peer: Peer, count: number = 20, isReverseOrder: boolean = false) {
return await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', '0', {
chatInfo: peer,
filterMsgType: [],
filterSendersUid: [],
filterMsgToTime: '0',
filterMsgFromTime: '0',
isReverseOrder: isReverseOrder,//此参数有点离谱 注意不是本次查询的排序 而是全部消历史信息的排序 默认false 从新消息拉取到旧消息
isIncludeCurrent: true,
pageLimit: count,
});
}
async getMsgsByMsgId(peer: Peer | undefined, msgIds: string[] | undefined) {
if (!peer) throw new Error('peer is not allowed');
if (!msgIds) throw new Error('msgIds is not allowed');
@@ -94,11 +81,41 @@ export class NTQQMsgApi {
pageLimit: 1,
});
}
async queryMsgsWithFilterExWithSeqV2(peer: Peer, msgSeq: string, MsgTime: string, SendersUid: string[]) {
return await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', msgSeq, {
chatInfo: peer,
filterMsgType: [],
filterSendersUid: SendersUid,
filterMsgToTime: MsgTime,
filterMsgFromTime: MsgTime,
isReverseOrder: false,
isIncludeCurrent: true,
pageLimit: 1,
});
}
async queryFirstMsgBySeq(peer: Peer, msgSeq: string) {
return await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', msgSeq, {
chatInfo: peer,
filterMsgType: [],
filterSendersUid: [],
filterMsgToTime: '0',
filterMsgFromTime: '0',
isReverseOrder: true,
isIncludeCurrent: true,
pageLimit: 1,
});
}
async getMsgsBySeqAndCount(peer: Peer, seq: string, count: number, desc: boolean, z: boolean) {
return await this.context.session.getMsgService().getMsgsBySeqAndCount(peer, seq, count, desc, z);
}
async getMsgBySeqList(peer: Peer, msgSeqList: string[]) {
//坏的
return await this.context.session.getMsgService().getMsgsBySeqList(peer, msgSeqList);
}
async getMsgBySeqExFirstMsg(peer: Peer, rootMsgId: string, replyMsgId: string) {
let reply = await this.context.session.getMsgService().getSourceOfReplyMsgV2(peer, rootMsgId, replyMsgId);
console.log(reply);
}
async getMsgExBySeq(peer: Peer, msgSeq: string) {
const DateNow = Math.floor(Date.now() / 1000);
const filterMsgFromTime = (DateNow - 300).toString();
@@ -233,7 +250,7 @@ export class NTQQMsgApi {
() => true,
(msgRecords) => msgRecords.some(
msgRecord => msgRecord.peerUid === destPeer.peerUid
&& msgRecord.senderUid === this.core.selfInfo.uid
&& msgRecord.senderUid === this.core.selfInfo.uid
),
);
for (const msg of msgList) {

View File

@@ -370,7 +370,8 @@ export interface ReplyElement {
replayMsgSeq: string;
replayMsgId: string;
senderUin: string;
senderUinStr: string;
senderUidStr?: string;
replyMsgTime?: string;
}
export interface SendReplyElement {

View File

@@ -1,42 +1,14 @@
{
"3.2.12-27187": {
"appid": 537240645,
"qua": "V1_LNX_NQ_3.2.12_27187_GW_B"
},
"3.2.12-27206": {
"appid": 537240645,
"qua": "V1_LNX_NQ_3.2.12_27206_GW_B"
},
"3.2.12-27254": {
"appid": 537240795,
"qua": "V1_LNX_NQ_3.2.12_27254_GW_B"
},
"3.2.12-27556": {
"3.2.12-27597": {
"appid": 537243600,
"qua": "V1_LNX_NQ_3.2.12_27556_GW_B"
},
"9.9.15-27187": {
"appid": 537240610,
"qua": "V1_WIN_NQ_9.9.15_27187_GW_B"
},
"9.9.15-27206": {
"appid": 537240610,
"qua": "V1_WIN_NQ_9.9.15_27206_GW_B"
},
"9.9.15-27254": {
"appid": 537240709,
"qua": "V1_WIN_NQ_9.9.15_27254_GW_B"
},
"9.9.15-27333": {
"appid": 537240709,
"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"
"qua": "V1_LNX_NQ_3.2.12_27597_GW_B"
},
"9.9.15-27597": {
"appid": 537243441,
"qua": "V1_WIN_NQ_9.9.15_27597_GW_B"
},
"6.9.53-27597": {
"appid": 537243538,
"qua": "V1_MAC_NQ_6.9.53_27597_GW_B"
}
}

View File

@@ -24,7 +24,7 @@ import path from 'node:path';
import fs from 'node:fs';
import { getMachineId, hostname, systemName, systemVersion } from '@/common/system';
import { NTEventWrapper } from '@/common/event';
import { DataSource, GroupMember, SelfInfo } from '@/core/entities';
import { DataSource, GroupMember, KickedOffLineInfo, SelfInfo, SelfStatusInfo } from '@/core/entities';
import { NapCatConfigLoader } from '@/core/helper/config';
import os from 'node:os';
import { NodeIKernelGroupListener, NodeIKernelMsgListener, NodeIKernelProfileListener } from '@/core/listeners';
@@ -42,9 +42,15 @@ export enum NapCatCoreWorkingEnv {
}
export function loadQQWrapper(QQVersion: string): WrapperNodeApi {
let wrapperNodePath = path.resolve(path.dirname(process.execPath), './resources/app/wrapper.node');
let appPath;
if (os.platform() === 'darwin') {
appPath = path.resolve(path.dirname(process.execPath), '../Resources/app');
} else {
appPath = path.resolve(path.dirname(process.execPath), './resources/app');
}
let wrapperNodePath = path.resolve(appPath, 'wrapper.node');
if (!fs.existsSync(wrapperNodePath)) {
wrapperNodePath = path.join(path.dirname(process.execPath), `resources/app/versions/${QQVersion}/wrapper.node`);
wrapperNodePath = path.join(appPath, `versions/${QQVersion}/wrapper.node`);
}
const nativemodule: any = { exports: {} };
process.dlopen(nativemodule, wrapperNodePath);
@@ -113,6 +119,11 @@ export class NapCatCore {
// Renamed from 'InitDataListener'
async initNapCatCoreListeners() {
const msgListener = new NodeIKernelMsgListener();
msgListener.onKickedOffLine = (Info: KickedOffLineInfo) => {
// 下线通知
this.context.logger.logError('[KickedOffLine] [' + Info.tipsTitle + '] ' + Info.tipsDesc);
this.selfInfo.online = false;
};
msgListener.onRecvMsg = (msgs) => {
msgs.forEach(msg => this.context.logger.logMessage(msg, this.selfInfo));
};
@@ -130,10 +141,12 @@ export class NapCatCore {
Object.assign(this.selfInfo, profile);
}
};
profileListener.onSelfStatusChanged = (/* Info: SelfStatusInfo */) => {
// if (Info.status == 20) {
// log("账号状态变更为离线")
// }
profileListener.onSelfStatusChanged = (Info: SelfStatusInfo) => {
if (Info.status == 20) {
this.selfInfo.online = false;
this.context.logger.log("账号状态变更为离线");
}
this.selfInfo.online = true;
};
this.context.session.getProfileService().addKernelProfileListener(
proxiedListenerOf(profileListener, this.context.logger),

View File

@@ -54,7 +54,7 @@ abstract class BaseAction<PayloadType, ReturnDataType> {
public async websocketHandle(payload: PayloadType, echo: any): Promise<OB11Return<ReturnDataType | null>> {
const result = await this.check(payload);
if (!result.valid) {
return OB11Response.error(result.message, 1400);
return OB11Response.error(result.message, 1400, echo);
}
try {
const resData = await this._handle(payload);

View File

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

View File

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

View File

@@ -3,6 +3,7 @@ import fs from 'fs/promises';
import { FileNapCatOneBotUUID } from '@/common/helper';
import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { OB11MessageImage, OB11MessageVideo } from '@/onebot/types';
export interface GetFilePayload {
file: string; // 文件名或者fileUuid
@@ -33,16 +34,27 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
if (contextMsgFile) {
const { peer, msgId, elementId } = contextMsgFile;
const downloadPath = await this.core.apis.FileApi.downloadMedia(msgId, peer.chatType, peer.peerUid, elementId, '', '');
const mixElement = (await this.core.apis.MsgApi.getMsgsByMsgId(peer, [msgId]))?.msgList
.find(msg => msg.msgId === msgId)?.elements.find(e => e.elementId === elementId);
const rawMessage = (await this.core.apis.MsgApi.getMsgsByMsgId(peer, [msgId]))?.msgList
.find(msg => msg.msgId === msgId);
const mixElement = rawMessage?.elements.find(e => e.elementId === elementId);
const mixElementInner = mixElement?.videoElement ?? mixElement?.fileElement ?? mixElement?.pttElement ?? mixElement?.picElement;
if (!mixElementInner) throw new Error('element not found');
const fileSize = mixElementInner.fileSize?.toString() ?? '';
const fileName = mixElementInner.fileName ?? '';
let url = '';
if (mixElement?.picElement && rawMessage) {
let tempData =
await this.obContext.apis.MsgApi.rawToOb11Converters.picElement?.(mixElement?.picElement, rawMessage, mixElement) as OB11MessageImage | undefined;
url = tempData?.data.url ?? '';
}
if (mixElement?.videoElement && rawMessage) {
let tempData =
await this.obContext.apis.MsgApi.rawToOb11Converters.videoElement?.(mixElement?.videoElement, rawMessage, mixElement) as OB11MessageVideo | undefined;
url = tempData?.data.url ?? '';
}
const res: GetFileResponse = {
file: downloadPath,
url: downloadPath,
url: url !== '' ? url : downloadPath,
file_size: fileSize,
file_name: fileName,
};

View File

@@ -1,23 +0,0 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['string', 'number'] },
},
required: ['group_id'],
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
export class GetGroupFileCount extends BaseAction<Payload, { count: number }> {
actionName = ActionName.GetGroupFileCount;
payloadSchema = SchemaData;
async _handle(payload: Payload) {
const ret = await this.core.apis.GroupApi.getGroupFileCount([payload.group_id?.toString()]);
return { count: ret.groupFileCounts[0] };
}
}

View File

@@ -1,50 +0,0 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { FileNapCatOneBotUUID } from '@/common/helper';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['string', 'number'] },
start_index: { type: ['string', 'number'] },
file_count: { type: ['string', 'number'] },
folder_id: { type: ['string', 'number'] },
},
required: ['group_id', 'start_index', 'file_count'],
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
export class GetGroupFileList extends BaseAction<Payload, { FileList: Array<any> }> {
actionName = ActionName.GetGroupFileList;
payloadSchema = SchemaData;
async _handle(payload: Payload) {
let param = {};
if (payload.folder_id) {
param = {
folderId: payload.folder_id.toString(),
};
}
const ret = await this.core.apis.MsgApi.getGroupFileList(payload.group_id.toString(), {
sortType: 1,
fileCount: +payload.file_count,
startIndex: +payload.start_index,
sortOrder: 2,
showOnlinedocFolder: 0,
...param
}).catch(() => {
return [];
});
ret.forEach((e) => {
const fileModelId = e?.fileInfo?.fileModelId;
if (fileModelId)
e.fileInfo!.fileId = FileNapCatOneBotUUID.encodeModelId({
chatType: 2,
peerUid: payload.group_id.toString()
}, fileModelId);
});
return { FileList: ret };
}
}

View File

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

View File

@@ -1,10 +1,6 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { NapCatOneBot11Adapter } from '@/onebot';
import { NapCatCore } from '@/core';
import { SetGroupFileFolder } from '@/onebot/action/file/SetGroupFileFolder';
const SchemaData = {
type: 'object',
properties: {
@@ -16,17 +12,10 @@ const SchemaData = {
type Payload = FromSchema<typeof SchemaData>;
export class CreateGroupFileFolder extends BaseAction<Payload, null> {
export class CreateGroupFileFolder extends BaseAction<Payload, any> {
actionName = ActionName.GoCQHTTP_CreateGroupFileFolder;
payloadSchema = SchemaData;
constructor(obContext: NapCatOneBot11Adapter, core: NapCatCore,
private ncSetGroupFileFolderImpl: SetGroupFileFolder) {
super(obContext, core);
}
async _handle(payload: Payload) {
await this.ncSetGroupFileFolderImpl._handle(payload);
return null;
return (await this.core.apis.GroupApi.CreatGroupFileFolder(payload.group_id.toString(), payload.folder_name)).resultWithGroupItem;
}
}

View File

@@ -1,10 +1,7 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { NapCatCore } from '@/core';
import { NapCatOneBot11Adapter } from '@/onebot';
import { DelGroupFile } from '@/onebot/action/file/DelGroupFile';
import { FileNapCatOneBotUUID } from '@/common/helper';
const SchemaData = {
type: 'object',
properties: {
@@ -16,17 +13,12 @@ const SchemaData = {
type Payload = FromSchema<typeof SchemaData>;
export class DeleteGroupFile extends BaseAction<Payload, null> {
export class DeleteGroupFile extends BaseAction<Payload, any> {
actionName = ActionName.GOCQHTTP_DeleteGroupFile;
payloadSchema = SchemaData;
constructor(obContext: NapCatOneBot11Adapter, core: NapCatCore,
private ncDelGroupFileImpl: DelGroupFile) {
super(obContext, core);
}
async _handle(payload: Payload) {
await this.ncDelGroupFileImpl._handle(payload);
return null;
const data = FileNapCatOneBotUUID.decodeModelId(payload.file_id);
if (!data) throw new Error('Invalid file_id');
return await this.core.apis.GroupApi.DelGroupFile(payload.group_id.toString(), [data.fileId]);
}
}

View File

@@ -1,9 +1,6 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { NapCatCore } from '@/core';
import { NapCatOneBot11Adapter } from '@/onebot';
import { DelGroupFileFolder } from '@/onebot/action/file/DelGroupFileFolder';
import BaseAction from '../BaseAction';
const SchemaData = {
type: 'object',
@@ -16,17 +13,11 @@ const SchemaData = {
type Payload = FromSchema<typeof SchemaData>;
export class DeleteGroupFileFolder extends BaseAction<Payload, null> {
export class DeleteGroupFileFolder extends BaseAction<Payload, any> {
actionName = ActionName.GoCQHTTP_DeleteGroupFileFolder;
payloadSchema = SchemaData;
constructor(obContext: NapCatOneBot11Adapter, core: NapCatCore,
private ncDelGroupFileFolderImpl: DelGroupFileFolder) {
super(obContext, core);
}
async _handle(payload: Payload) {
await this.ncDelGroupFileFolderImpl._handle(payload);
return null;
return (await this.core.apis.GroupApi.DelGroupFileFolder(
payload.group_id.toString(), payload.folder_id)).groupFileCommonResult;
}
}

View File

@@ -1,43 +1,27 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { NapCatOneBot11Adapter, OB11GroupFile } from '@/onebot';
import { NapCatCore } from '@/core';
import { GetGroupRootFiles } from '@/onebot/action/go-cqhttp/GetGroupRootFiles';
import { OB11Entities } from '@/onebot/entities';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['string', 'number'] },
folder_id: { type: 'string' },
file_count: { type: ['string', 'number'] },
},
required: ['group_id', 'folder_id'],
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
export class GetGroupFilesByFolder extends BaseAction<Payload, {
files: OB11GroupFile[],
folders: [] // QQ does not allow nested folders
}> {
export class GetGroupFilesByFolder extends BaseAction<any, any> {
actionName = ActionName.GoCQHTTP_GetGroupFilesByFolder;
payloadSchema = SchemaData;
constructor(obContext: NapCatOneBot11Adapter, core: NapCatCore,
private getGroupRootFilesImpl: GetGroupRootFiles) {
super(obContext, core);
}
async _handle(payload: Payload) {
const folder = (await this.getGroupRootFilesImpl._handle({ group_id: payload.group_id }))
.folders.find(folder => folder.folder_id === payload.folder_id);
if (!folder) {
throw new Error('Folder not found');
}
const ret = await this.core.apis.MsgApi.getGroupFileList(payload.group_id.toString(), {
sortType: 1,
fileCount: folder.total_file_count,
fileCount: +(payload.file_count ?? 50),
startIndex: 0,
sortOrder: 2,
showOnlinedocFolder: 0,

View File

@@ -1,15 +1,14 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { NapCatOneBot11Adapter, OB11GroupFile, OB11GroupFileFolder } from '@/onebot';
import { NapCatCore } from '@/core';
import { GetGroupFileCount } from '@/onebot/action/file/GetGroupFileCount';
import { OB11GroupFile, OB11GroupFileFolder } from '@/onebot';
import { OB11Entities } from '@/onebot/entities';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['string', 'number'] },
file_count: { type: ['string', 'number'] },
},
required: ['group_id'],
} as const satisfies JSONSchema;
@@ -22,16 +21,10 @@ export class GetGroupRootFiles extends BaseAction<Payload, {
}> {
actionName = ActionName.GoCQHTTP_GetGroupRootFiles;
payloadSchema = SchemaData;
constructor(obContext: NapCatOneBot11Adapter, core: NapCatCore,
private ncGetGroupFileCountImpl: GetGroupFileCount) {
super(obContext, core);
}
async _handle(payload: Payload) {
const ret = await this.core.apis.MsgApi.getGroupFileList(payload.group_id.toString(), {
sortType: 1,
fileCount: (await this.ncGetGroupFileCountImpl._handle({ group_id: payload.group_id.toString() })).count,
fileCount: +(payload.file_count ?? 50),
startIndex: 0,
sortOrder: 2,
showOnlinedocFolder: 0,

View File

@@ -55,12 +55,7 @@ import { GoCQHTTPHandleQuickAction } from './go-cqhttp/QuickAction';
import { GetGroupIgnoredNotifies } from './group/GetGroupIgnoredNotifies';
import { GetOnlineClient } from './go-cqhttp/GetOnlineClient';
import { IOCRImage, OCRImage } from './extends/OCRImage';
import { GetGroupFileCount } from './file/GetGroupFileCount';
import { GetGroupFileList } from './file/GetGroupFileList';
import { TranslateEnWordToZn } from './extends/TranslateEnWordToZn';
import { SetGroupFileFolder } from './file/SetGroupFileFolder';
import { DelGroupFile } from './file/DelGroupFile';
import { DelGroupFileFolder } from './file/DelGroupFileFolder';
import { SetQQProfile } from './go-cqhttp/SetQQProfile';
import { ShareGroupEx, SharePeer } from './extends/ShareContact';
import { CreateCollection } from './extends/CreateCollection';
@@ -92,11 +87,6 @@ import { GetGroupFilesByFolder } from '@/onebot/action/go-cqhttp/GetGroupFilesBy
export type ActionMap = Map<string, BaseAction<any, any>>;
export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCore): ActionMap {
const ncDelGroupFile = new DelGroupFile(obContext, core);
const ncSetGroupFileFolder = new SetGroupFileFolder(obContext, core);
const ncDelGroupFileFolder = new DelGroupFileFolder(obContext, core);
const ncGetGroupFileCount = new GetGroupFileCount(obContext, core);
const goCqHttpGetGroupRootFiles = new GetGroupRootFiles(obContext, core, ncGetGroupFileCount);
const actionHandlers = [
new GetGroupInfoEx(obContext, core),
@@ -113,11 +103,7 @@ export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCo
new MarkPrivateMsgAsRead(obContext, core),
new SetQQAvatar(obContext, core),
new TranslateEnWordToZn(obContext, core),
ncGetGroupFileCount,
new GetGroupFileList(obContext, core),
ncSetGroupFileFolder,
ncDelGroupFile,
ncDelGroupFileFolder,
new GetGroupRootFiles(obContext, core),
// onebot11
new SendLike(obContext, core),
new GetMsg(obContext, core),
@@ -185,12 +171,11 @@ export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCo
new SetInputStatus(obContext, core),
new GetCSRF(obContext, core),
new DelGroupNotice(obContext, core),
new DeleteGroupFile(obContext, core, ncDelGroupFile),
new CreateGroupFileFolder(obContext, core, ncSetGroupFileFolder),
new DeleteGroupFileFolder(obContext, core, ncDelGroupFileFolder),
new DeleteGroupFile(obContext, core),
new CreateGroupFileFolder(obContext, core),
new DeleteGroupFileFolder(obContext, core),
new GetGroupFileSystemInfo(obContext, core),
goCqHttpGetGroupRootFiles,
new GetGroupFilesByFolder(obContext, core, goCqHttpGetGroupRootFiles),
new GetGroupFilesByFolder(obContext, core),
];
const actionMap = new Map();
for (const action of actionHandlers) {

View File

@@ -28,18 +28,14 @@ class DeleteMsg extends BaseAction<Payload, void> {
const ret = this.core.eventWrapper.registerListen(
'NodeIKernelMsgListener/onMsgInfoListUpdate',
1,
5000,
1000,
(msgs) => !!msgs.find(m => m.msgId === msg.MsgId && m.recallTime !== '0'),
).catch(() => new Promise<undefined>((resolve) => {
resolve(undefined);
}));
).catch(() => undefined);
await this.core.apis.MsgApi.recallMsg(msg.Peer, [msg.MsgId]);
const data = await ret;
if (!data) {
//throw new Error('Recall failed');
}
//await sleep(100);
//await NTQQMsgApi.getMsgsByMsgId(msg.Peer, [msg.MsgId]);
if (!data) throw new Error('Recall failed');
} else {
throw new Error('Recall failed');
}
}
}

View File

@@ -173,9 +173,18 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
}
const { sendElements } = await this.obContext.apis.MsgApi
.createSendElements(OB11Data, destPeer);
//拆分消息
const MixElement = sendElements.filter(element => element.elementType !== ElementType.FILE && element.elementType !== ElementType.VIDEO);
const SingleElement = sendElements.filter(element => element.elementType === ElementType.FILE || element.elementType === ElementType.VIDEO).map(e => [e]);
const MixElement = sendElements.filter(
element =>
element.elementType !== ElementType.FILE && element.elementType !== ElementType.VIDEO && element.elementType !== ElementType.ARK
);
const SingleElement = sendElements.filter(
element =>
element.elementType === ElementType.FILE || element.elementType === ElementType.VIDEO || element.elementType === ElementType.ARK
).map(e => [e]);
const AllElement: SendMessageElement[][] = [MixElement, ...SingleElement].filter(e => e !== undefined && e.length !== 0);
const MsgNodeList: Promise<RawMessage | undefined>[] = [];
for (const sendElementsSplitElement of AllElement) {

View File

@@ -213,7 +213,7 @@ export class OneBotGroupApi {
async parseGroupMemberIncreaseEvent(GroupCode: string, grayTipElement: GrayTipElement) {
const groupElement = grayTipElement?.groupElement;
if (!groupElement) return undefined;
const member = await this.core.apis.GroupApi.getGroupMember(GroupCode, groupElement.memberUid);
const member = await this.core.apis.UserApi.getUserDetailInfo(groupElement.memberUid);
const memberUin = member?.uin;
const adminMember = await this.core.apis.GroupApi.getGroupMember(GroupCode, groupElement.adminUid);
if (memberUin) {
@@ -271,14 +271,11 @@ export class OneBotGroupApi {
guildId: '',
peerUid: groupCode,
};
const replyMsgList = (await this.core.apis.MsgApi.getMsgExBySeq(peer, msgSeq)).msgList;
const replyMsgList = (await this.core.apis.MsgApi.queryFirstMsgBySeq(peer, msgSeq)).msgList;
if (replyMsgList.length < 1) {
return;
}
const replyMsg = replyMsgList
.filter(e => e.msgSeq == msgSeq)
.sort((a, b) => parseInt(a.msgTime) - parseInt(b.msgTime))[0];
//console.log("表情回应消息长度检测", msgSeq, replyMsg.elements);
const replyMsg = replyMsgList[0];
if (!replyMsg) {
this.core.context.logger.logError('解析表情回应消息失败: 未找到回应消息');
return undefined;

View File

@@ -219,7 +219,7 @@ export class OneBotMsgApi {
peerUid: msg.peerUid,
guildId: '',
};
if (!records) {
if (!records || !element.replyMsgTime || !element.senderUidStr) {
this.core.context.logger.logError('获取不到引用的消息', element.replayMsgSeq);
return null;
}
@@ -234,29 +234,13 @@ export class OneBotMsgApi {
if (records.peerUin === '284840486') {
return createReplyData(records.msgId);
}
let replyMsg: RawMessage | undefined;
// Attempt 1
replyMsg = (await this.core.apis.MsgApi.getMsgsBySeqAndCount(peer,element.replayMsgSeq, 1, true, true))
.msgList
.find(msg => msg.msgRandom === records.msgRandom);
let replyMsg = (await this.core.apis.MsgApi.queryMsgsWithFilterExWithSeqV2(peer, element.replayMsgSeq, element.replyMsgTime, [element.senderUidStr]))
.msgList.find(msg => msg.msgRandom === records.msgRandom);
if (!replyMsg || records.msgRandom !== replyMsg.msgRandom) {
// Attempt 2
replyMsg = (await this.core.apis.MsgApi.getSingleMsg(peer, element.replayMsgSeq)).msgList[0];
if (!replyMsg || records.msgRandom !== replyMsg.msgRandom) {
// Attempt 3
const replyMsgList = (await this.core.apis.MsgApi.getMsgExBySeq(peer, records.msgSeq)).msgList;
if (replyMsgList.length < 1) {
this.core.context.logger.logError('回复消息消息验证失败', element.replayMsgSeq);
return null;
}
replyMsg = replyMsgList.filter(e => e.msgSeq == records.msgSeq)
.sort((a, b) => parseInt(a.msgTime) - parseInt(b.msgTime))[0];
}
this.core.context.logger.logError('获取不到引用的消息', element.replayMsgSeq);
return null;
}
return createReplyData(replyMsg.msgId);
},
@@ -725,6 +709,9 @@ export class OneBotMsgApi {
message_format: messagePostFormat === 'string' ? 'string' : 'array',
post_type: this.core.selfInfo.uin == msg.senderUin ? EventType.MESSAGE_SENT : EventType.MESSAGE,
};
if (this.core.selfInfo.uin == msg.senderUin) {
resMsg.message_sent_type = 'self';
}
if (msg.chatType == ChatType.KCHATTYPEGROUP) {
resMsg.sub_type = 'normal'; // 这里go-cqhttp是group而onebot11标准是normal, 蛋疼
resMsg.group_id = parseInt(msg.peerUin);

View File

@@ -24,7 +24,7 @@ export class OB11Entities {
...rawFriend.coreInfo,
user_id: parseInt(rawFriend.coreInfo.uin),
nickname: rawFriend.coreInfo.nick,
remark: rawFriend.coreInfo.nick,
remark: rawFriend.coreInfo.remark ?? rawFriend.coreInfo.nick,
sex: this.sex(rawFriend.baseInfo.sex!),
level: 0,
}));
@@ -109,7 +109,7 @@ export class OB11Entities {
static file(peerId: string, file: Exclude<GroupFileInfoUpdateParamType['item'][0]['fileInfo'], undefined>): OB11GroupFile {
return {
group_id: parseInt(peerId),
file_id: FileNapCatOneBotUUID.encodeModelId({ chatType: 2, peerUid: peerId }, file.fileModelId),
file_id: FileNapCatOneBotUUID.encodeModelId({ chatType: 2, peerUid: peerId }, file.fileModelId, file.fileId),
file_name: file.fileName,
busid: file.busId,
size: parseInt(file.fileSize),

View File

@@ -242,31 +242,31 @@ export class NapCatOneBot11Adapter {
const msgListener = new NodeIKernelMsgListener();
msgListener.onRecvSysMsg = async msg => {
const sysMsg = SysMessage.fromBinary(Uint8Array.from(msg));
if (sysMsg.msgSpec.length === 0) {
return;
}
const { msgType, subType, subSubType } = sysMsg.msgSpec[0];
if (msgType === 732 && subType === 16 && subSubType === 16) {
const greyTip = GreyTipWrapper.fromBinary(Uint8Array.from(sysMsg.bodyWrapper!.wrappedBody.slice(7)));
if (greyTip.subTypeId === 36) {
const emojiLikeToOthers = EmojiLikeToOthersWrapper1
.fromBinary(greyTip.rest)
.wrapper!
.body!;
if (emojiLikeToOthers.attributes?.operation !== 1) { // Un-like
return;
}
const eventOrEmpty = await this.apis.GroupApi.createGroupEmojiLikeEvent(
greyTip.groupCode.toString(),
await this.core.apis.UserApi.getUinByUidV2(emojiLikeToOthers.attributes!.senderUid),
emojiLikeToOthers.msgSpec!.msgSeq.toString(),
emojiLikeToOthers.attributes!.emojiId,
);
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
eventOrEmpty && await this.networkManager.emitEvent(eventOrEmpty);
}
}
// const sysMsg = SysMessage.fromBinary(Uint8Array.from(msg));
// if (sysMsg.msgSpec.length === 0) {
// return;
// }
// const { msgType, subType, subSubType } = sysMsg.msgSpec[0];
// if (msgType === 732 && subType === 16 && subSubType === 16) {
// const greyTip = GreyTipWrapper.fromBinary(Uint8Array.from(sysMsg.bodyWrapper!.wrappedBody.slice(7)));
// if (greyTip.subTypeId === 36) {
// const emojiLikeToOthers = EmojiLikeToOthersWrapper1
// .fromBinary(greyTip.rest)
// .wrapper!
// .body!;
// if (emojiLikeToOthers.attributes?.operation !== 1) { // Un-like
// return;
// }
// const eventOrEmpty = await this.apis.GroupApi.createGroupEmojiLikeEvent(
// greyTip.groupCode.toString(),
// await this.core.apis.UserApi.getUinByUidV2(emojiLikeToOthers.attributes!.senderUid),
// emojiLikeToOthers.msgSpec!.msgSeq.toString(),
// emojiLikeToOthers.attributes!.emojiId,
// );
// // eslint-disable-next-line @typescript-eslint/no-unused-expressions
// eventOrEmpty && await this.networkManager.emitEvent(eventOrEmpty);
// }
// }
};
msgListener.onInputStatusPush = async data => {

View File

@@ -131,23 +131,24 @@ export class OB11ActiveWebSocketAdapter implements IOB11NetworkAdapter {
private async handleMessage(message: any) {
let receiveData: { action: ActionName, params?: any, echo?: any } = { action: ActionName.Unknown, params: {} };
let echo = undefined;
try {
try {
receiveData = JSON.parse(message.toString());
echo = receiveData.echo;
this.logger.logDebug('[OneBot] [WebSocket Client] 收到正向Websocket消息', receiveData);
} catch (e) {
this.checkStateAndReply<any>(OB11Response.error('json解析失败,请检查数据格式', 1400, echo));
return;
}
receiveData.params = (receiveData?.params) ? receiveData.params : {};//兼容类型验证
const retdata = await this.actions.get(receiveData.action)
?.websocketHandle(receiveData.params, echo ?? '');
const packet = Object.assign({}, retdata);
this.checkStateAndReply<any>(packet);
receiveData = JSON.parse(message.toString());
echo = receiveData.echo;
this.logger.logDebug('[OneBot] [WebSocket Client] 收到正向Websocket消息', receiveData);
} catch (e) {
this.logger.logError('[OneBot] [WebSocket Client] 发生错误', e);
this.checkStateAndReply<any>(OB11Response.error('不支持的api ' + receiveData.action, 1404, echo));
this.checkStateAndReply<any>(OB11Response.error('json解析失败,请检查数据格式', 1400, echo));
return;
}
receiveData.params = (receiveData?.params) ? receiveData.params : {};//兼容类型验证
const action = this.actions.get(receiveData.action);
if (!action) {
this.logger.logError('[OneBot] [WebSocket Client] 发生错误', '不支持的api ' + receiveData.action);
this.checkStateAndReply<any>(OB11Response.error('不支持的api ' + receiveData.action, 1404, echo));
return;
}
const retdata = await action.websocketHandle(receiveData.params, echo ?? '');
const packet = Object.assign({}, retdata);
this.checkStateAndReply<any>(packet);
}
}

View File

@@ -146,22 +146,23 @@ export class OB11PassiveWebSocketAdapter implements IOB11NetworkAdapter {
let receiveData: { action: ActionName, params?: any, echo?: any } = { action: ActionName.Unknown, params: {} };
let echo = undefined;
try {
try {
receiveData = JSON.parse(message.toString());
echo = receiveData.echo;
//this.logger.logDebug('收到正向Websocket消息', receiveData);
} catch (e) {
this.checkStateAndReply<any>(OB11Response.error('json解析失败,请检查数据格式', 1400, echo), wsClient);
return;
}
receiveData.params = (receiveData?.params) ? receiveData.params : {};//兼容类型验证
const retdata = await this.actions.get(receiveData.action)?.websocketHandle(receiveData.params, echo ?? '');
const packet = Object.assign({}, retdata);
this.checkStateAndReply<any>(packet, wsClient);
receiveData = JSON.parse(message.toString());
echo = receiveData.echo;
//this.logger.logDebug('收到正向Websocket消息', receiveData);
} catch (e) {
this.checkStateAndReply<any>(OB11Response.error('不支持的api ' + receiveData.action, 1404, echo), wsClient);
this.checkStateAndReply<any>(OB11Response.error('json解析失败,请检查数据格式', 1400, echo), wsClient);
return;
}
receiveData.params = (receiveData?.params) ? receiveData.params : {};//兼容类型验证
const action = this.actions.get(receiveData.action);
if (!action) {
this.logger.logError('[OneBot] [WebSocket Client] 发生错误', '不支持的api ' + receiveData.action);
this.checkStateAndReply<any>(OB11Response.error('不支持的api ' + receiveData.action, 1404, echo), wsClient);
return;
}
const retdata = await action.websocketHandle(receiveData.params, echo ?? '');
const packet = Object.assign({}, retdata);
this.checkStateAndReply<any>(packet, wsClient);
}
}

View File

@@ -8,6 +8,7 @@ export enum OB11MessageType {
}
export interface OB11Message {
message_sent_type?: string;
target_id?: number; // 自己发送的消息才有此字段
self_id?: number,
time: number,

View File

@@ -49,12 +49,20 @@ export async function NCoreInitShell() {
const session = new wrapper.NodeIQQNTWrapperSession();
// from get dataPath
let dataPath = wrapper.NodeQQNTWrapperUtil.getNTUserDataInfoConfig();
if (!dataPath) {
dataPath = path.resolve(os.homedir(), './.config/QQ');
fs.mkdirSync(dataPath, { recursive: true });
}
const dataPathGlobal = path.resolve(dataPath, './nt_qq/global');
const [dataPath, dataPathGlobal] = (() => {
if (os.platform() === 'darwin') {
const userPath = os.homedir();
const appDataPath = path.resolve(userPath, './Library/Application Support/QQ');
return [appDataPath, path.join(appDataPath, 'global')];
}
let dataPath = wrapper.NodeQQNTWrapperUtil.getNTUserDataInfoConfig();
if (!dataPath) {
dataPath = path.resolve(os.homedir(), './.config/QQ');
fs.mkdirSync(dataPath, { recursive: true });
}
const dataPathGlobal = path.resolve(dataPath, './nt_qq/global');
return [dataPath, dataPathGlobal];
})();
// from initConfig
engine.initWithDeskTopConfig(
@@ -115,7 +123,7 @@ export async function NCoreInitShell() {
const realBase64 = pngBase64QrcodeData.replace(/^data:image\/\w+;base64,/, '');
const buffer = Buffer.from(realBase64, 'base64');
logger.logWarn('请扫描下面的二维码然后在手Q上授权登录');
const qrcodePath = path.join(pathWrapper.binaryPath, 'qrcode.png');
const qrcodePath = path.join(pathWrapper.cachePath, 'qrcode.png');
qrcode.generate(qrcodeUrl, { small: true }, (res) => {
logger.logWarn([
'\n',
@@ -191,7 +199,7 @@ export async function NCoreInitShell() {
logger.log(`可用于快速登录的 QQ\n${historyLoginList
.map((u, index) => `${index + 1}. ${u.uin} ${u.nickName}`)
.join('\n')
}`);
}`);
}
loginService.getQRCodePicture();
}

View File

@@ -30,7 +30,7 @@ async function onSettingWindowCreated(view: Element) {
SettingItem(
'<span id="napcat-update-title">Napcat</span>',
undefined,
SettingButton('V2.2.30', 'napcat-update-button', 'secondary'),
SettingButton('V2.2.44', 'napcat-update-button', 'secondary'),
),
]),
SettingList([

View File

@@ -164,7 +164,7 @@ async function onSettingWindowCreated(view) {
SettingItem(
'<span id="napcat-update-title">Napcat</span>',
void 0,
SettingButton("V2.2.30", "napcat-update-button", "secondary")
SettingButton("V2.2.44", "napcat-update-button", "secondary")
)
]),
SettingList([