Compare commits

...

32 Commits

Author SHA1 Message Date
手瓜一十雪
05043f8dfc fix: code 2024-12-03 21:41:53 +08:00
手瓜一十雪
dc2b45fa00 fix: 优化处理 2024-12-03 21:36:55 +08:00
手瓜一十雪
cc70fc766a fix 2024-12-03 21:14:18 +08:00
手瓜一十雪
d2e9db5571 fix: 临时的抽象方案 2024-12-03 20:55:24 +08:00
手瓜一十雪
8e01638a36 fix: error 2024-12-03 19:50:47 +08:00
手瓜一十雪
e8b8eae8a9 refactor: GroupAdminChange 2024-12-03 19:44:38 +08:00
手瓜一十雪
0f0275243b feat: 迁移事件解析原理 2024-12-03 19:28:51 +08:00
手瓜一十雪
eeb27d38bc fix: 清理旧的脚本 2024-12-03 17:33:13 +08:00
Mlikiowa
491a79ec96 release: v4.2.12 2024-12-03 09:22:43 +00:00
手瓜一十雪
f429db61af fix: #594 2024-12-03 17:16:58 +08:00
Mlikiowa
2881099602 release: v4.2.11 2024-12-02 14:08:36 +00:00
手瓜一十雪
672ae8decf fix: Once处理空格目录 中文目录 2024-12-02 22:08:08 +08:00
手瓜一十雪
2abc7e541d fix: 空格目录启动问题 2024-12-02 21:23:13 +08:00
手瓜一十雪
45b1f369ac style: 异步实现 2024-12-02 11:44:37 +08:00
手瓜一十雪
3b5d2c8f6f style: 简化写法 2024-12-02 11:16:12 +08:00
Mlikiowa
5376e16c9f release: v4.2.10 2024-12-01 11:12:10 +00:00
bietiaop
af052242fa feat:带等级的实时日志 2024-12-01 15:19:23 +08:00
手瓜一十雪
85e0b71545 chore: daily -> weekly 2024-12-01 13:26:56 +08:00
手瓜一十雪
1206d1fcf6 chore: bug report 2024-12-01 13:25:36 +08:00
手瓜一十雪
f7534dc438 fix: 自动迁移 2024-12-01 13:20:20 +08:00
手瓜一十雪
97f317254e fix: MiniApp type check 2024-12-01 13:11:56 +08:00
手瓜一十雪
9eaf51e15f fix: nullable 2024-12-01 13:04:00 +08:00
手瓜一十雪
7221f4ac02 fix: type-check 2024-12-01 12:50:13 +08:00
手瓜一十雪
1bb6dce239 refactor: type-check (#586)
* refactor: type-check

* fix: default

* refactor: type-check
2024-12-01 12:41:51 +08:00
bietiaop
d13db5e8eb feat: 实时日志 (#584)
* feat: 历史日志

* feat: 实时日志

* fix: EventEmitter实现事件监听
2024-12-01 09:31:47 +08:00
Mlikiowa
040b5535f3 release: v4.2.9 2024-11-30 06:12:44 +00:00
手瓜一十雪
b44e1618fb fix: quick error 2024-11-30 14:12:23 +08:00
手瓜一十雪
1e13483bc3 fix: type 2024-11-30 13:32:21 +08:00
手瓜一十雪
f9519d3923 style: lint 2024-11-30 13:29:10 +08:00
手瓜一十雪
86cdfbb79b feat: 取消上报 pic_type 2024-11-30 12:11:33 +08:00
手瓜一十雪
a70585e854 feat: 处理失败的情况 2024-11-30 12:08:58 +08:00
Mlikiowa
040d0a8635 release: v4.2.8 2024-11-30 01:39:59 +00:00
106 changed files with 876 additions and 1572 deletions

View File

@@ -10,13 +10,12 @@ body:
在提交新的 Bug 反馈前,请确保您:
* 已经搜索了现有的 issues并且没有找到可以解决您问题的方法
* 不与现有的某一 issue 重复
* 不涉及[已经停止维护的特性](https://github.com/NapNeko/NapCatQQ?tab=readme-ov-file#挥别昨日),例如 CQ 码
- type: input
id: system-version
attributes:
label: 系统版本
description: 运行 QQNT 的系统版本
placeholder: Windows 10 Pro Workstation 22H2
placeholder: Windows 11 24H2
validations:
required: true
- type: input
@@ -24,7 +23,7 @@ body:
attributes:
label: QQNT 版本
description: 可在 QQNT 的「关于」的设置页中找到
placeholder: 9.9.7-21804
placeholder: 9.9.16-29927
validations:
required: true
- type: input
@@ -40,21 +39,21 @@ body:
attributes:
label: OneBot 客户端
description: 连接至 NapCat 的客户端版本信息
placeholder: Overflow 2.16.0-2cf7991-SNAPSHOT
placeholder: Karin 1.0.0
validations:
required: true
- type: textarea
id: what-happened
attributes:
label: 发生了什么?
description: 填写你认为的 NapCat 的不正常行为
description: 填写你认为的 NapCat 的常行为
validations:
required: true
- type: textarea
id: how-reproduce
attributes:
label: 如何复现
description: 填写应当如何操作才能触发这个不正常行为
description: 填写应当如何操作才能触发这个常行为
placeholder: |
1. xxx
2. xxx

View File

@@ -1,11 +1,6 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2
updates:
- package-ecosystem: "npm" # See documentation for possible values
directory: "/" # Location of package manifests
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
interval: "weekly"

Binary file not shown.

Binary file not shown.

View File

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

View File

@@ -2,7 +2,7 @@
"name": "napcat",
"private": true,
"type": "module",
"version": "4.2.7",
"version": "4.2.12",
"scripts": {
"build:universal": "npm run build:webui && vite build --mode universal || exit 1",
"build:framework": "npm run build:webui && vite build --mode framework || exit 1",
@@ -43,13 +43,13 @@
"file-type": "^19.0.0",
"globals": "^15.12.0",
"image-size": "^1.1.1",
"json-schema-to-ts": "^3.1.1",
"typescript": "^5.3.3",
"typescript-eslint": "^8.13.0",
"vite": "^6.0.1",
"vite-plugin-cp": "^4.0.8",
"vite-tsconfig-paths": "^5.1.0",
"winston": "^3.17.0"
"winston": "^3.17.0",
"@sinclair/typebox": "^0.34.9"
},
"dependencies": {
"express": "^5.0.0",

View File

@@ -1,9 +1,9 @@
import winston, { format, transports } from 'winston';
import { truncateString } from '@/common/helper';
import path from 'node:path';
import fs from 'node:fs';
import fs from 'node:fs/promises';
import { NTMsgAtType, ChatType, ElementType, MessageElement, RawMessage, SelfInfo } from '@/core';
import EventEmitter from 'node:events';
export enum LogLevel {
DEBUG = 'debug',
INFO = 'info',
@@ -24,6 +24,36 @@ function getFormattedTimestamp() {
return `${year}-${month}-${day}_${hours}-${minutes}-${seconds}.${milliseconds}`;
}
const logEmitter = new EventEmitter();
export type LogListener = (msg: string) => void;
class Subscription {
public static MAX_HISTORY = 100;
public static history: string[] = [];
subscribe(listener: LogListener) {
for (const history of Subscription.history) {
try {
listener(history);
} catch (_) {
// ignore
}
}
logEmitter.on('log', listener);
}
unsubscribe(listener: LogListener) {
logEmitter.off('log', listener);
}
notify(msg: string) {
logEmitter.emit('log', msg);
if (Subscription.history.length >= Subscription.MAX_HISTORY) {
Subscription.history.shift();
}
Subscription.history.push(msg);
}
}
export const logSubscription = new Subscription();
export class LogWrapper {
fileLogEnabled = true;
consoleLogEnabled = true;
@@ -47,7 +77,7 @@ export class LogWrapper {
filename: logPath,
level: 'debug',
maxsize: 5 * 1024 * 1024, // 5MB
maxFiles: 5
maxFiles: 5,
}),
new transports.Console({
format: format.combine(
@@ -56,9 +86,9 @@ export class LogWrapper {
const userInfo = meta.userInfo ? `${meta.userInfo} | ` : '';
return `${timestamp} [${level}] ${userInfo}${message}`;
})
)
})
]
),
}),
],
});
this.setLogSelfInfo({ nick: '', uid: '' });
@@ -67,26 +97,20 @@ export class LogWrapper {
cleanOldLogs(logDir: string) {
const oneWeekAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;
fs.readdir(logDir, (err, files) => {
if (err) {
this.logger.error('Failed to read log directory', err);
return;
}
files.forEach(file => {
fs.readdir(logDir).then((files) => {
files.forEach((file) => {
const filePath = path.join(logDir, file);
this.deleteOldLogFile(filePath, oneWeekAgo);
});
}).catch((err) => {
this.logger.error('Failed to read log directory', err);
});
}
private deleteOldLogFile(filePath: string, oneWeekAgo: number) {
fs.stat(filePath, (err, stats) => {
if (err) {
this.logger.error('Failed to get file stats', err);
return;
}
fs.stat(filePath).then((stats) => {
if (stats.mtime.getTime() < oneWeekAgo) {
fs.unlink(filePath, err => {
fs.unlink(filePath).catch((err) => {
if (err) {
if (err.code === 'ENOENT') {
this.logger.warn(`File already deleted: ${filePath}`);
@@ -98,6 +122,8 @@ export class LogWrapper {
}
});
}
}).catch((err) => {
this.logger.error('Failed to get file stats', err);
});
}
@@ -111,7 +137,7 @@ export class LogWrapper {
});
}
setLogSelfInfo(selfInfo: { nick: string, uid: string }) {
setLogSelfInfo(selfInfo: { nick: string; uid: string }) {
const userInfo = `${selfInfo.nick}`;
this.logger.defaultMeta = { userInfo };
}
@@ -135,14 +161,16 @@ export class LogWrapper {
}
formatMsg(msg: any[]) {
return msg.map(msgItem => {
if (msgItem instanceof Error) {
return msgItem.stack;
} else if (typeof msgItem === 'object') {
return JSON.stringify(truncateString(JSON.parse(JSON.stringify(msgItem, null, 2))));
}
return msgItem;
}).join(' ');
return msg
.map((msgItem) => {
if (msgItem instanceof Error) {
return msgItem.stack;
} else if (typeof msgItem === 'object') {
return JSON.stringify(truncateString(JSON.parse(JSON.stringify(msgItem, null, 2))));
}
return msgItem;
})
.join(' ');
}
_log(level: LogLevel, ...args: any[]) {
@@ -155,6 +183,7 @@ export class LogWrapper {
// eslint-disable-next-line no-control-regex
this.logger.log(level, message.replace(/\x1B[@-_][0-?]*[ -/]*[@-~]/g, ''));
}
logSubscription.notify(JSON.stringify({ level, message }));
}
log(...args: any[]) {
@@ -282,13 +311,9 @@ function textElementToText(textElement: any): string {
}
function replyElementToText(replyElement: any, msg: RawMessage, recursiveLevel: number): string {
const recordMsgOrNull = msg.records.find(
record => replyElement.sourceMsgIdInRecords === record.msgId,
);
return `[回复消息 ${recordMsgOrNull &&
recordMsgOrNull.peerUin != '284840486' && recordMsgOrNull.peerUin != '1094950020'
?
rawMessageToText(recordMsgOrNull, recursiveLevel + 1) :
`未找到消息记录 (MsgId = ${replyElement.sourceMsgIdInRecords})`
}]`;
}
const recordMsgOrNull = msg.records.find((record) => replyElement.sourceMsgIdInRecords === record.msgId);
return `[回复消息 ${recordMsgOrNull && recordMsgOrNull.peerUin != '284840486' && recordMsgOrNull.peerUin != '1094950020'
? rawMessageToText(recordMsgOrNull, recursiveLevel + 1)
: `未找到消息记录 (MsgId = ${replyElement.sourceMsgIdInRecords})`
}]`;
}

View File

@@ -1,6 +1,5 @@
import https from 'node:https';
import http from 'node:http';
import { readFileSync } from 'node:fs';
export class RequestUtil {
// 适用于获取服务器下发cookies时获取仅GET
@@ -69,7 +68,7 @@ export class RequestUtil {
// 'Content-Length': Buffer.byteLength(postData),
// },
return new Promise((resolve, reject) => {
const req = protocol.request(options, (res: any) => {
const req = protocol.request(options, (res: http.IncomingMessage) => {
let responseBody = '';
res.on('data', (chunk: string | Buffer) => {
responseBody += chunk.toString();
@@ -112,24 +111,4 @@ export class RequestUtil {
static async HttpGetText(url: string, method: string = 'GET', data?: any, headers: { [key: string]: string } = {}) {
return this.HttpGetJson<string>(url, method, data, headers, false, false);
}
static async createFormData(boundary: string, filePath: string): Promise<Buffer> {
let type = 'image/png';
if (filePath.endsWith('.jpg')) {
type = 'image/jpeg';
}
const formDataParts = [
`------${boundary}\r\n`,
`Content-Disposition: form-data; name="share_image"; filename="${filePath}"\r\n`,
'Content-Type: ' + type + '\r\n\r\n',
];
const fileContent = readFileSync(filePath);
const footer = `\r\n------${boundary}--`;
return Buffer.concat([
Buffer.from(formDataParts.join(''), 'utf8'),
fileContent,
Buffer.from(footer, 'utf8'),
]);
}
}

View File

@@ -1 +1 @@
export const napCatVersion = '4.2.7';
export const napCatVersion = '4.2.12';

View File

@@ -33,6 +33,7 @@ export class NTQQGroupApi {
this.groups = await this.getGroups();
for (const group of this.groups) {
this.groupCache.set(group.groupCode, group);
this.refreshGroupMemberCache(group.groupCode).then().catch(e => this.context.logger.logError(e));
}
this.context.logger.logDebug(`加载${this.groups.length}个群组缓存完成`);
// process.pid 调试点
@@ -54,11 +55,13 @@ export class NTQQGroupApi {
pageLimit: 300,
}, pskey);
}
async getGroupShutUpMemberList(groupCode: string) {
const data = this.core.eventWrapper.registerListen('NodeIKernelGroupListener/onShutUpMemberListChanged', (group_id) => group_id === groupCode, 1, 1000);
this.context.session.getGroupService().getGroupShutUpMemberList(groupCode);
return (await data)[1];
}
async clearGroupNotifiesUnreadCount(uk: boolean) {
return this.context.session.getGroupService().clearGroupNotifiesUnreadCount(uk);
}
@@ -140,18 +143,44 @@ export class NTQQGroupApi {
return this.context.session.getGroupService().getAllMemberList(groupCode, forced);
}
async refreshGroupMemberCache(groupCode: string) {
try {
const members = await this.getGroupMemberAll(groupCode, true);
// 首先填入基础信息
const existingMembers = this.groupMemberCache.get(groupCode) ?? new Map<string, GroupMember>();
members.result.infos.forEach((value, key) => {
existingMembers.set(value.uid, { ...value, ...existingMembers.get(value.uid) });
});
// 后台补全复杂信息
let event = (async () => {
let data = (await Promise.allSettled(members.result.ids.map(e => this.core.apis.UserApi.getUserDetailInfo(e.uid)))).filter(e => e.status === 'fulfilled').map(e => e.value);
data.forEach(e => {
const existingMember = members.result.infos.get(e.uid);
if (existingMember) {
members.result.infos.set(e.uid, { ...existingMember, ...e });
}
});
this.groupMemberCache.set(groupCode, members.result.infos);
})().then().catch(e => this.context.logger.logError(e));
// 处理首次空缺
if (!this.groupMemberCache.get(groupCode)) {
await event;
}
} catch (e) {
this.context.logger.logError(`刷新群成员缓存失败, ${e}`);
}
}
async getGroupMember(groupCode: string | number, memberUinOrUid: string | number) {
const groupCodeStr = groupCode.toString();
const memberUinOrUidStr = memberUinOrUid.toString();
// 检查群缓存
let members = this.groupMemberCache.get(groupCodeStr);
if (!members) {
try {
members = await this.getGroupMembers(groupCodeStr);
this.groupMemberCache.set(groupCodeStr, members);
} catch (e) {
return null;
}
await this.refreshGroupMemberCache(groupCodeStr);
}
function getMember() {
let member: GroupMember | undefined;
if (isNumeric(memberUinOrUidStr)) {
@@ -162,9 +191,11 @@ export class NTQQGroupApi {
return member;
}
let member = getMember();
// 不存在群友缓存 尝试刷新
if (!member) {
members = await this.getGroupMembers(groupCodeStr);
await this.refreshGroupMemberCache(groupCode.toString());
member = getMember();
}
return member;
@@ -253,29 +284,6 @@ export class NTQQGroupApi {
return notifies;
}
async getGroupMemberV2(GroupCode: string, uid: string, forced = false) {
const Listener = this.core.eventWrapper.registerListen(
'NodeIKernelGroupListener/onMemberInfoChange',
(params, _, members) => params === GroupCode && members.size > 0,
1,
forced ? 5000 : 250,
);
const retData = await (
this.core.eventWrapper
.createEventFunction('NodeIKernelGroupService/getMemberInfo')
)!(GroupCode, [uid], forced);
if (retData.result !== 0) {
throw new Error(`${retData.errMsg}`);
}
const result = await Listener as unknown;
let member: GroupMember | undefined;
if (Array.isArray(result) && result?.[2] instanceof Map) {
const members = result[2] as Map<string, GroupMember>;
member = members.get(uid);
}
return member;
}
async searchGroup(groupCode: string) {
const [, ret] = await this.core.eventWrapper.callNormalEventV2(
'NodeIKernelSearchService/searchGroup',
@@ -316,89 +324,6 @@ export class NTQQGroupApi {
return undefined;
}
async tryGetGroupMembersV2(groupQQ: string, modeListener = false, num = 30, timeout = 100): Promise<{
infos: Map<string, GroupMember>;
finish: boolean;
hasNext: boolean | undefined;
}> {
const sceneId = this.context.session.getGroupService().createMemberListScene(groupQQ, 'groupMemberList_MainWindow_1');
const once = this.core.eventWrapper.registerListen('NodeIKernelGroupListener/onMemberListChange', (params) => params.sceneId === sceneId, 0, timeout)
.catch(() => { });
const result = await this.context.session.getGroupService().getNextMemberList(sceneId, undefined, num);
if (result.errCode !== 0) {
throw new Error('获取群成员列表出错,' + result.errMsg);
}
let resMode2;
if (modeListener) {
const ret = (await once)?.[0];
if (ret) {
resMode2 = ret;
}
}
this.context.session.getGroupService().destroyMemberListScene(sceneId);
return {
infos: new Map([...(resMode2?.infos ?? []), ...result.result.infos]),
finish: result.result.finish,
hasNext: resMode2?.hasNext,
};
}
async GetGroupMembersV3(groupQQ: string, num = 3000, timeout = 2500): Promise<{
infos: Map<string, GroupMember>;
finish: boolean;
hasNext: boolean | undefined;
listenerMode: boolean;
}> {
const sceneId = this.context.session.getGroupService().createMemberListScene(groupQQ, 'groupMemberList_MainWindow_1');
const once = this.core.eventWrapper.registerListen('NodeIKernelGroupListener/onMemberListChange', (params) => params.sceneId === sceneId, 0, timeout)
.catch(() => { });
const result = await this.context.session.getGroupService().getNextMemberList(sceneId, undefined, num);
if (result.errCode !== 0) {
throw new Error('获取群成员列表出错,' + result.errMsg);
}
let resMode2;
if (result.result.finish && result.result.infos.size === 0) {
const ret = (await once)?.[0];
if (ret) {
resMode2 = ret;
}
}
this.context.session.getGroupService().destroyMemberListScene(sceneId);
return {
infos: new Map([...(resMode2?.infos ?? []), ...result.result.infos]),
finish: result.result.finish,
hasNext: resMode2?.hasNext,
listenerMode: resMode2?.hasNext !== undefined
};
}
async getGroupMembersV2(groupQQ: string, num = 3000, no_cache: boolean = false): Promise<Map<string, GroupMember>> {
if (no_cache) {
return (await this.getGroupMemberAll(groupQQ, true)).result.infos;
}
let res = await this.GetGroupMembersV3(groupQQ, num);
let ret = res.infos;
if (res.infos.size === 0 && !res.listenerMode) {
res = await this.GetGroupMembersV3(groupQQ, num);
ret = res.infos;
}
if (res.infos.size === 0) {
ret = (await this.getGroupMemberAll(groupQQ)).result.infos;
}
return ret;
}
async getGroupMembers(groupQQ: string, num = 3000): Promise<Map<string, GroupMember>> {
const groupService = this.context.session.getGroupService();
const sceneId = groupService.createMemberListScene(groupQQ, 'groupMemberList_MainWindow');
const result = await groupService.getNextMemberList(sceneId, undefined, num);
if (result.errCode !== 0) {
throw new Error('获取群成员列表出错,' + result.errMsg);
}
this.context.logger.logDebug(`获取群(${groupQQ})成员列表结果:`, `members: ${result.result.infos.size}`);
return result.result.infos;
}
async getGroupFileCount(group_ids: Array<string>) {
return this.context.session.getRichMediaService().batchGetGroupFileCount(group_ids);
}

View File

@@ -90,7 +90,7 @@ export class NTQQUserApi {
};
return RetUser;
}
async getUserDetailInfo(uid: string): Promise<User> {
let retUser = await solveAsyncProblem(async (uid) => this.fetchUserDetailInfo(uid, UserDetailSource.KDB), uid);
if (retUser && retUser.uin !== '0') {
@@ -181,13 +181,13 @@ export class NTQQUserApi {
//后期改成流水线处理
async getUinByUidV2(Uid: string) {
let uin = (await this.context.session.getGroupService().getUinByUids([Uid])).uins.get(Uid);
if (uin) return uin;
if (uin && uin !== '0') return uin;
uin = (await this.context.session.getProfileService().getUinByUid('FriendsServiceImpl', [Uid])).get(Uid);
if (uin) return uin;
if (uin && uin !== '0') return uin;
uin = (await this.context.session.getUixConvertService().getUin([Uid])).uinInfo.get(Uid);
if (uin) return uin;
if (uin && uin !== '0') return uin;
uin = (await this.core.apis.FriendApi.getBuddyIdMap(true)).getKey(Uid);
if (uin) return uin;
if (uin && uin !== '0') return uin;
uin = (await this.getUserDetailInfo(Uid)).uin; //从QQ Native 转换
return uin;
}

View File

@@ -24,10 +24,10 @@ import path from 'node:path';
import fs from 'node:fs';
import { hostname, systemName, systemVersion } from '@/common/system';
import { NTEventWrapper } from '@/common/event';
import { DataSource, GroupMember, KickedOffLineInfo, SelfInfo, SelfStatusInfo } from '@/core/types';
import { GroupMember, KickedOffLineInfo, SelfInfo, SelfStatusInfo } from '@/core/types';
import { NapCatConfigLoader } from '@/core/helper/config';
import os from 'node:os';
import { NodeIKernelGroupListener, NodeIKernelMsgListener, NodeIKernelProfileListener } from '@/core/listeners';
import { NodeIKernelMsgListener, NodeIKernelProfileListener } from '@/core/listeners';
import { proxiedListenerOf } from '@/common/proxy-handler';
import { NTQQPacketApi } from './apis/packet';
export * from './wrapper';
@@ -163,7 +163,6 @@ export class NapCatCore {
msgListener.onAddSendMsg = (msg) => {
this.context.logger.logMessage(msg, this.selfInfo);
};
//await sleep(2500);
this.context.session.getMsgService().addKernelMsgListener(
proxiedListenerOf(msgListener, this.context.logger),
);
@@ -185,92 +184,6 @@ export class NapCatCore {
this.context.session.getProfileService().addKernelProfileListener(
proxiedListenerOf(profileListener, this.context.logger),
);
// 群相关
const groupListener = new NodeIKernelGroupListener();
groupListener.onGroupListUpdate = (updateType, groupList) => {
// console.log("onGroupListUpdate", updateType, groupList)
groupList.map(g => {
const existGroup = this.apis.GroupApi.groupCache.get(g.groupCode);
//群成员数量变化 应该刷新缓存
if (existGroup && g.memberCount === existGroup.memberCount) {
Object.assign(existGroup, g);
} else {
this.apis.GroupApi.groupCache.set(g.groupCode, g);
// 获取群成员
}
const sceneId = this.context.session.getGroupService().createMemberListScene(g.groupCode, 'groupMemberList_MainWindow');
this.context.session.getGroupService().getNextMemberList(sceneId, undefined, 3000).then( /* r => {
// console.log(`get group ${g.groupCode} members`, r);
// r.result.infos.forEach(member => {
// });
// groupMembers.set(g.groupCode, r.result.infos);
} */);
this.context.session.getGroupService().destroyMemberListScene(sceneId);
});
};
groupListener.onMemberListChange = (arg) => {
// TODO: 应该加一个内部自己维护的成员变动callback用于判断成员变化通知
const groupCode = arg.sceneId.split('_')[0];
if (this.apis.GroupApi.groupMemberCache.has(groupCode)) {
const existMembers = this.apis.GroupApi.groupMemberCache.get(groupCode)!;
arg.infos.forEach((member, uid) => {
//console.log('onMemberListChange', member);
const existMember = existMembers.get(uid);
if (existMember) {
Object.assign(existMember, member);
} else {
existMembers.set(uid, member);
}
//移除成员
if (member.isDelete) {
existMembers.delete(uid);
}
});
} else {
this.apis.GroupApi.groupMemberCache.set(groupCode, arg.infos);
}
};
groupListener.onMemberInfoChange = (groupCode, dataSource, members) => {
if (dataSource === DataSource.LOCAL && members.get(this.selfInfo.uid)?.isDelete) {
// 自身退群或者被踢退群 5s用于Api操作 之后不再出现
setTimeout(() => {
this.apis.GroupApi.groupCache.delete(groupCode);
}, 5000);
}
const existMembers = this.apis.GroupApi.groupMemberCache.get(groupCode);
if (existMembers) {
members.forEach((member, uid) => {
const existMember = existMembers.get(uid);
if (existMember) {
// 检查管理变动
member.isChangeRole = this.checkAdminEvent(groupCode, member, existMember);
// 更新成员信息
Object.assign(existMember, member);
} else {
existMembers.set(uid, member);
}
//移除成员
if (member.isDelete) {
existMembers.delete(uid);
}
});
} else {
this.apis.GroupApi.groupMemberCache.set(groupCode, members);
}
};
this.context.session.getGroupService().addKernelGroupListener(
proxiedListenerOf(groupListener, this.context.logger),
);
}
checkAdminEvent(groupCode: string, memberNew: GroupMember, memberOld: GroupMember | undefined): boolean {
if (memberNew.role !== memberOld?.role) {
this.context.logger.logDebug(`${groupCode} ${memberNew.nick} 角色变更为 ${memberNew.role === 3 ? '管理员' : '群员'}`);
return true;
}
return false;
}
}

View File

@@ -0,0 +1,18 @@
import { ProtoField, ScalarType } from "@napneko/nap-proto-core";
export const GroupAdminExtra = {
adminUid: ProtoField(1, ScalarType.STRING),
isPromote: ProtoField(2, ScalarType.BOOL),
}
export const GroupAdminBody = {
extraDisable: ProtoField(1, () => GroupAdminExtra),
extraEnable: ProtoField(2, () => GroupAdminExtra),
}
export const GroupAdmin = {
groupUin: ProtoField(1, ScalarType.UINT32),
flag: ProtoField(2, ScalarType.UINT32),
isPromote: ProtoField(3, ScalarType.BOOL),
body: ProtoField(4, () => GroupAdminBody),
}

View File

@@ -163,7 +163,7 @@ export interface NodeIKernelGroupService {
getGroupPortrait(): void;
modifyGroupName(groupCode: string, groupName: string, arg: false): void;
modifyGroupName(groupCode: string, groupName: string, isNormalMember: boolean): Promise<GeneralCallResult>;
modifyGroupRemark(groupCode: string, remark: string): void;

View File

@@ -42,7 +42,7 @@ export abstract class OneBotAction<PayloadType, ReturnDataType> {
protected async check(payload: PayloadType): Promise<BaseCheckResult> {
if (this.payloadSchema) {
this.validate = new Ajv({ allowUnionTypes: true }).compile(this.payloadSchema);
this.validate = new Ajv({ allowUnionTypes: true, useDefaults: true }).compile(this.payloadSchema);
}
if (this.validate && !this.validate(payload)) {
const errors = this.validate.errors as ErrorObject[];

View File

@@ -1,17 +1,13 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Type, Static } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
rawData: { type: 'string' },
brief: { type: 'string' },
},
required: ['brief', 'rawData'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
rawData: Type.String(),
brief: Type.String(),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class CreateCollection extends OneBotAction<Payload, any> {
actionName = ActionName.CreateCollection;
@@ -25,4 +21,4 @@ export class CreateCollection extends OneBotAction<Payload, any> {
payload.brief, payload.rawData,
);
}
}
}

View File

@@ -1,23 +1,19 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Type, Static } from '@sinclair/typebox';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
const SchemaData = {
type: 'object',
properties: {
count: { type: ['number', 'string'] },
},
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
count: Type.Union([Type.Number(), Type.String()], { default: 48 }),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class FetchCustomFace extends OneBotAction<Payload, string[]> {
actionName = ActionName.FetchCustomFace;
payloadSchema = SchemaData;
async _handle(payload: Payload) {
//48 可能正好是QQ需要的一个页面的数量 Tagged Mlikiowa
const ret = await this.core.apis.MsgApi.fetchFavEmojiList(+(payload.count ?? 48));
const ret = await this.core.apis.MsgApi.fetchFavEmojiList(+payload.count);
return ret.emojiInfoList.map(e => e.url);
}
}
}

View File

@@ -1,32 +1,27 @@
//getMsgEmojiLikesList
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Type, Static } from '@sinclair/typebox';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { MessageUnique } from '@/common/message-unique';
const SchemaData = {
type: 'object',
properties: {
user_id: { type: 'string' },
group_id: { type: 'string' },
emojiId: { type: 'string' },
emojiType: { type: 'string' },
message_id: { type: ['string', 'number'] },
count: { type: ['string', 'number'] },
},
required: ['emojiId', 'emojiType', 'message_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
message_id: Type.Union([Type.Number(), Type.String()]),
emojiId: Type.Union([Type.Number(), Type.String()]),
emojiType: Type.Union([Type.Number(), Type.String()]),
count: Type.Union([Type.Number(), Type.String()], { default: 20 }),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class FetchEmojiLike extends OneBotAction<Payload, any> {
actionName = ActionName.FetchEmojiLike;
payloadSchema = SchemaData;
async _handle(payload: Payload) {
const msgIdPeer = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString()));
const msgIdPeer = MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id);
if (!msgIdPeer) throw new Error('消息不存在');
const msg = (await this.core.apis.MsgApi.getMsgsByMsgId(msgIdPeer.Peer, [msgIdPeer.MsgId])).msgList[0];
return await this.core.apis.MsgApi.getMsgEmojiLikesList(msgIdPeer.Peer, msg.msgSeq, payload.emojiId, payload.emojiType, +(payload.count ?? 20));
return await this.core.apis.MsgApi.getMsgEmojiLikesList(
msgIdPeer.Peer, msg.msgSeq, payload.emojiId.toString(), payload.emojiType.toString(), +payload.count
);
}
}

View File

@@ -1,11 +1,17 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { Type, Static } from '@sinclair/typebox';
export class FetchUserProfileLike extends OneBotAction<{ qq: number }, any> {
const SchemaData = Type.Object({
user_id: Type.Union([Type.Number(), Type.String()]),
});
type Payload = Static<typeof SchemaData>;
export class FetchUserProfileLike extends OneBotAction<Payload, any> {
actionName = ActionName.FetchUserProfileLike;
async _handle(payload: { qq: number }) {
if (!payload.qq) throw new Error('qq is required');
return await this.core.apis.UserApi.getUidByUinV2(payload.qq.toString());
async _handle(payload: Payload) {
return await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
}
}

View File

@@ -1,18 +1,14 @@
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
import { AIVoiceChatType } from "@/core/packet/entities/aiChat";
import { Type, Static } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
chat_type: { type: ['number', 'string'] },
},
required: ['group_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
chat_type: Type.Union([Type.Union([Type.Number(), Type.String()])], { default: 1 }),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
interface GetAiCharactersResponse {
type: string;
@@ -28,7 +24,7 @@ export class GetAiCharacters extends GetPacketStatusDepends<Payload, GetAiCharac
payloadSchema = SchemaData;
async _handle(payload: Payload) {
const rawList = await this.core.apis.PacketApi.pkt.operation.FetchAiVoiceList(+payload.group_id, +(payload.chat_type ?? 1) as AIVoiceChatType);
const rawList = await this.core.apis.PacketApi.pkt.operation.FetchAiVoiceList(+payload.group_id, +payload.chat_type as AIVoiceChatType);
return rawList?.map((item) => ({
type: item.category,
characters: item.voices.map((voice) => ({

View File

@@ -1,23 +1,19 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Type, Static } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
category: { type: ['number', 'string'] },
count: { type: ['number', 'string'] },
},
required: ['category', 'count'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
category: Type.Union([Type.Number(), Type.String()]),
count: Type.Union([Type.Union([Type.Number(), Type.String()])], { default: 1 }),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class GetCollectionList extends OneBotAction<Payload, any> {
actionName = ActionName.GetCollectionList;
payloadSchema = SchemaData;
async _handle(payload: Payload) {
return await this.core.apis.CollectionApi.getAllCollection(parseInt(payload.category.toString()), +(payload.count ?? 1));
return await this.core.apis.CollectionApi.getAllCollection(+payload.category, +payload.count);
}
}

View File

@@ -1,16 +1,11 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Type, Static } from '@sinclair/typebox';
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
});
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
},
required: ['group_id'],
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class GetGroupInfoEx extends OneBotAction<Payload, any> {
actionName = ActionName.GetGroupInfoEx;

View File

@@ -1,47 +1,37 @@
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
import { MiniAppInfo, MiniAppInfoHelper } from "@/core/packet/utils/helper/miniAppHelper";
import { MiniAppData, MiniAppRawData, MiniAppReqCustomParams, MiniAppReqParams } from "@/core/packet/entities/miniApp";
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
type: {
type: 'string',
enum: ['bili', 'weibo']
},
title: { type: 'string' },
desc: { type: 'string' },
picUrl: { type: 'string' },
jumpUrl: { type: 'string' },
iconUrl: { type: 'string' },
sdkId: { type: 'string' },
appId: { type: 'string' },
scene: { type: ['number', 'string'] },
templateType: { type: ['number', 'string'] },
businessType: { type: ['number', 'string'] },
verType: { type: ['number', 'string'] },
shareType: { type: ['number', 'string'] },
versionId: { type: 'string' },
withShareTicket: { type: ['number', 'string'] },
rawArkData: { type: ['boolean', 'string'] }
},
oneOf: [
{
required: ['type', 'title', 'desc', 'picUrl', 'jumpUrl']
},
{
required: [
'title', 'desc', 'picUrl', 'jumpUrl',
'iconUrl', 'appId', 'scene', 'templateType', 'businessType',
'verType', 'shareType', 'versionId', 'withShareTicket'
]
}
]
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
const SchemaData = Type.Union([
Type.Object({
type: Type.Union([Type.Literal('bili'), Type.Literal('weibo')]),
title: Type.String(),
desc: Type.String(),
picUrl: Type.String(),
jumpUrl: Type.String(),
rawArkData: Type.Optional(Type.Union([Type.Boolean(), Type.String()]))
}),
Type.Object({
title: Type.String(),
desc: Type.String(),
picUrl: Type.String(),
jumpUrl: Type.String(),
iconUrl: Type.String(),
appId: Type.String(),
scene: Type.Union([Type.Number(), Type.String()]),
templateType: Type.Union([Type.Number(), Type.String()]),
businessType: Type.Union([Type.Number(), Type.String()]),
verType: Type.Union([Type.Number(), Type.String()]),
shareType: Type.Union([Type.Number(), Type.String()]),
versionId: Type.String(),
sdkId: Type.String(),
withShareTicket: Type.Union([Type.Number(), Type.String()]),
rawArkData: Type.Optional(Type.Union([Type.Boolean(), Type.String()]))
})
]);
type Payload = Static<typeof SchemaData>;
export class GetMiniAppArk extends GetPacketStatusDepends<Payload, {
data: MiniAppData | MiniAppRawData
@@ -57,7 +47,7 @@ export class GetMiniAppArk extends GetPacketStatusDepends<Payload, {
picUrl: payload.picUrl,
jumpUrl: payload.jumpUrl
} as MiniAppReqCustomParams;
if (payload.type) {
if ('type' in payload) {
reqParam = MiniAppInfoHelper.generateReq(customParams, MiniAppInfo.get(payload.type)!.template);
} else {
const { appId, scene, iconUrl, templateType, businessType, verType, shareType, versionId, withShareTicket } = payload;

View File

@@ -1,34 +1,28 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Type, Static } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
user_id: { type: ['number', 'string'] },
start: { type: ['number', 'string'] },
count: { type: ['number', 'string'] },
type: { type: ['number', 'string'] },
},
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
user_id: Type.Optional(Type.Union([Type.Number(), Type.String()])),
start: Type.Union([Type.Number(), Type.String()], { default: 0 }),
count: Type.Union([Type.Number(), Type.String()], { default: 10 }),
type: Type.Union([Type.Number(), Type.String()], { default: 2 }),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class GetProfileLike extends OneBotAction<Payload, any> {
actionName = ActionName.GetProfileLike;
payloadSchema = SchemaData;
async _handle(payload: Payload) {
const start = payload.start ? Number(payload.start) : 0;
const count = payload.count ? Number(payload.count) : 10;
const type = payload.count ? Number(payload.count) : 2;
const user_uid =
this.core.selfInfo.uin === payload.user_id || !payload.user_id ?
this.core.selfInfo.uid :
await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
const ret = await this.core.apis.UserApi.getProfileLike(user_uid ?? this.core.selfInfo.uid, start, count, type);
const ret = await this.core.apis.UserApi.getProfileLike(user_uid ?? this.core.selfInfo.uid, +payload.start, +payload.count, +payload.type);
const listdata = ret.info.userLikeInfos[0].voteInfo.userInfos;
for (const item of listdata) {
item.uin = parseInt((await this.core.apis.UserApi.getUinByUidV2(item.uid)) || '');
item.uin = +((await this.core.apis.UserApi.getUinByUidV2(item.uid)) ?? '');
}
return ret.info.userLikeInfos[0].voteInfo;
}

View File

@@ -1,8 +1,7 @@
import { ActionName } from '@/onebot/action/router';
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
export class GetRkey extends GetPacketStatusDepends<null, Array<any>> {
export class GetRkey extends GetPacketStatusDepends<void, Array<any>> {
actionName = ActionName.GetRkey;
async _handle() {

View File

@@ -4,7 +4,7 @@ import { ActionName } from '@/onebot/action/router';
export class GetRobotUinRange extends OneBotAction<void, Array<any>> {
actionName = ActionName.GetRobotUinRange;
async _handle(payload: void) {
async _handle() {
return await this.core.apis.UserApi.getRobotUinRange();
}
}

View File

@@ -1,16 +1,12 @@
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
// no_cache get时传字符串
const SchemaData = {
type: 'object',
properties: {
user_id: { type: ['number', 'string'] },
},
required: ['user_id'],
} as const satisfies JSONSchema;
import { Static, Type } from '@sinclair/typebox';
type Payload = FromSchema<typeof SchemaData>;
const SchemaData = Type.Object({
user_id: Type.Union([Type.Number(), Type.String()]),
});
type Payload = Static<typeof SchemaData>;
export class GetUserStatus extends GetPacketStatusDepends<Payload, { status: number; ext_status: number; } | undefined> {
actionName = ActionName.GetUserStatus;

View File

@@ -1,18 +1,14 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { checkFileExist, uri2local } from '@/common/file';
import fs from 'fs';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
image: { type: 'string' },
},
required: ['image'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
image: Type.String(),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class OCRImage extends OneBotAction<Payload, any> {
actionName = ActionName.OCRImage;
@@ -29,12 +25,12 @@ export class OCRImage extends OneBotAction<Payload, any> {
fs.unlink(path, () => { });
if (!ret) {
throw new Error(`OCR ${payload.file}失败`);
throw new Error(`OCR ${payload.image}失败`);
}
return ret.result;
}
fs.unlink(path, () => { });
throw new Error(`OCR ${payload.file}失败,文件可能不存在`);
throw new Error(`OCR ${payload.image}失败,文件可能不存在`);
}
}

View File

@@ -1,16 +1,12 @@
import { GetPacketStatusDepends } from '@/onebot/action/packet/GetPacketStatus';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['string', 'number'] },
},
required: ['group_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class SetGroupSign extends GetPacketStatusDepends<Payload, any> {
actionName = ActionName.SetGroupSign;

View File

@@ -1,18 +1,14 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { ChatType } from '@/core';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
event_type: { type: 'number' },
user_id: { type: ['number', 'string'] },
},
required: ['event_type', 'user_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
user_id: Type.Union([Type.Number(), Type.String()]),
event_type: Type.Number(),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class SetInputStatus extends OneBotAction<Payload, any> {
actionName = ActionName.SetInputStatus;

View File

@@ -1,16 +1,12 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
longNick: { type: 'string' },
},
required: ['longNick'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
longNick: Type.String(),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class SetLongNick extends OneBotAction<Payload, any> {
actionName = ActionName.SetLongNick;

View File

@@ -1,19 +1,14 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
// 设置在线状态
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
status: { type: ['number', 'string'] },
ext_status: { type: ['number', 'string'] },
battery_status: { type: ['number', 'string'] },
},
required: ['status', 'ext_status', 'battery_status'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
status: Type.Union([Type.Number(), Type.String()]),
ext_status: Type.Union([Type.Number(), Type.String()]),
battery_status: Type.Union([Type.Number(), Type.String()]),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class SetOnlineStatus extends OneBotAction<Payload, null> {
actionName = ActionName.SetOnlineStatus;
@@ -21,9 +16,9 @@ export class SetOnlineStatus extends OneBotAction<Payload, null> {
async _handle(payload: Payload) {
const ret = await this.core.apis.UserApi.setSelfOnlineStatus(
parseInt(payload.status.toString()),
parseInt(payload.ext_status.toString()),
parseInt(payload.battery_status.toString()),
+payload.status,
+payload.ext_status,
+payload.battery_status,
);
if (ret.result !== 0) {
throw new Error('设置在线状态失败');

View File

@@ -1,28 +1,18 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName, BaseCheckResult } from '@/onebot/action/router';
import * as fs from 'node:fs';
import { ActionName } from '@/onebot/action/router';
import fs from 'node:fs/promises';
import { checkFileExist, uri2local } from '@/common/file';
import { Static, Type } from '@sinclair/typebox';
interface Payload {
file: string;
}
const SchemaData = Type.Object({
file: Type.String(),
});
type Payload = Static<typeof SchemaData>;
export default class SetAvatar extends OneBotAction<Payload, null> {
actionName = ActionName.SetQQAvatar;
// 用不着复杂检测
protected async check(payload: Payload): Promise<BaseCheckResult> {
if (!payload.file || typeof payload.file != 'string') {
return {
valid: false,
message: 'file字段不能为空或者类型错误',
};
}
return {
valid: true,
};
}
payloadSchema = SchemaData;
async _handle(payload: Payload): Promise<null> {
const { path, success } = (await uri2local(this.core.NapCatTempPath, payload.file));
if (!success) {
@@ -31,9 +21,7 @@ export default class SetAvatar extends OneBotAction<Payload, null> {
if (path) {
await checkFileExist(path, 5000);// 避免崩溃
const ret = await this.core.apis.UserApi.setQQAvatar(path);
fs.unlink(path, () => {
});
fs.unlink(path).catch(() => { });
if (!ret) {
throw new Error(`头像${payload.file}设置失败,api无返回`);
}
@@ -44,8 +32,7 @@ export default class SetAvatar extends OneBotAction<Payload, null> {
throw new Error(`头像${payload.file}设置失败,未知的错误,${ret.result}:${ret.errMsg}`);
}
} else {
fs.unlink(path, () => { });
fs.unlink(path).catch(() => { });
throw new Error(`头像${payload.file}设置失败,无法获取头像,文件可能不存在`);
}
return null;

View File

@@ -1,17 +1,14 @@
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
user_id: { type: ['number', 'string'] },
special_title: { type: 'string' },
},
required: ['group_id', 'user_id', 'special_title'],
} as const satisfies JSONSchema;
import { Static, Type } from '@sinclair/typebox';
type Payload = FromSchema<typeof SchemaData>;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
user_id: Type.Union([Type.Number(), Type.String()]),
special_title: Type.String(),
});
type Payload = Static<typeof SchemaData>;
export class SetSpecialTittle extends GetPacketStatusDepends<Payload, any> {
actionName = ActionName.SetSpecialTittle;

View File

@@ -1,18 +1,14 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
user_id: { type: 'string' },
group_id: { type: 'string' },
phoneNumber: { type: 'string' },
},
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
const SchemaData = Type.Object({
user_id: Type.Optional(Type.Union([Type.Number(), Type.String()])),
group_id: Type.Optional(Type.Union([Type.Number(), Type.String()])),
phoneNumber: Type.String({ default: '' }),
});
type Payload = Static<typeof SchemaData>;
export class SharePeer extends OneBotAction<Payload, any> {
actionName = ActionName.SharePeer;
@@ -20,28 +16,24 @@ export class SharePeer extends OneBotAction<Payload, any> {
async _handle(payload: Payload) {
if (payload.group_id) {
return await this.core.apis.GroupApi.getGroupRecommendContactArkJson(payload.group_id);
return await this.core.apis.GroupApi.getGroupRecommendContactArkJson(payload.group_id.toString());
} else if (payload.user_id) {
return await this.core.apis.UserApi.getBuddyRecommendContactArkJson(payload.user_id, payload.phoneNumber || '');
return await this.core.apis.UserApi.getBuddyRecommendContactArkJson(payload.user_id.toString(), payload.phoneNumber);
}
}
}
const SchemaDataGroupEx = {
type: 'object',
properties: {
group_id: { type: 'string' },
},
required: ['group_id'],
} as const satisfies JSONSchema;
const SchemaDataGroupEx = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
});
type PayloadGroupEx = FromSchema<typeof SchemaDataGroupEx>;
type PayloadGroupEx = Static<typeof SchemaDataGroupEx>;
export class ShareGroupEx extends OneBotAction<PayloadGroupEx, any> {
actionName = ActionName.ShareGroupEx;
payloadSchema = SchemaDataGroupEx;
async _handle(payload: PayloadGroupEx) {
return await this.core.apis.GroupApi.getArkJsonGroupShare(payload.group_id);
return await this.core.apis.GroupApi.getArkJsonGroupShare(payload.group_id.toString());
}
}

View File

@@ -1,19 +1,12 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
words: {
type: 'array',
items: { type: 'string' },
},
},
required: ['words'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
words: Type.Array(Type.String()),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class TranslateEnWordToZn extends OneBotAction<Payload, Array<any> | null> {
actionName = ActionName.TranslateEnWordToZn;

View File

@@ -2,12 +2,8 @@ import { OneBotAction } from '@/onebot/action/OneBotAction';
import fs from 'fs/promises';
import { FileNapCatOneBotUUID } from '@/common/helper';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { OB11MessageImage, OB11MessageVideo } from '@/onebot/types';
// interface GetFilePayload {
// file: string; // 文件名或者fileUuid
// }
import { Static, Type } from '@sinclair/typebox';
export interface GetFileResponse {
file?: string; // path
@@ -16,19 +12,14 @@ export interface GetFileResponse {
file_name?: string;
base64?: string;
}
const GetFileBase_PayloadSchema = {
type: 'object',
properties: {
file: { type: 'string' },
file_id: { type: 'string' }
},
oneOf: [
{ required: ['file'] },
{ required: ['file_id'] }
]
} as const satisfies JSONSchema;
export type GetFilePayload = FromSchema<typeof GetFileBase_PayloadSchema>;
const GetFileBase_PayloadSchema = Type.Object({
file: Type.Optional(Type.String()),
file_id: Type.Optional(Type.String())
});
export type GetFilePayload = Static<typeof GetFileBase_PayloadSchema>;
export class GetFileBase extends OneBotAction<GetFilePayload, GetFileResponse> {
payloadSchema = GetFileBase_PayloadSchema;
@@ -50,12 +41,12 @@ export class GetFileBase extends OneBotAction<GetFilePayload, GetFileResponse> {
let url = '';
if (mixElement?.picElement && rawMessage) {
const tempData =
await this.obContext.apis.MsgApi.rawToOb11Converters.picElement?.(mixElement?.picElement, rawMessage, mixElement) as OB11MessageImage | undefined;
await this.obContext.apis.MsgApi.rawToOb11Converters.picElement?.(mixElement?.picElement, rawMessage, mixElement, { parseMultMsg: false }) as OB11MessageImage | undefined;
url = tempData?.data.url ?? '';
}
if (mixElement?.videoElement && rawMessage) {
const tempData =
await this.obContext.apis.MsgApi.rawToOb11Converters.videoElement?.(mixElement?.videoElement, rawMessage, mixElement) as OB11MessageVideo | undefined;
await this.obContext.apis.MsgApi.rawToOb11Converters.videoElement?.(mixElement?.videoElement, rawMessage, mixElement, { parseMultMsg: false }) as OB11MessageVideo | undefined;
url = tempData?.data.url ?? '';
}
const res: GetFileResponse = {

View File

@@ -1,18 +1,14 @@
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { FileNapCatOneBotUUID } from "@/common/helper";
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
file_id: { type: ['string'] },
},
required: ['group_id', 'file_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
file_id: Type.String(),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
interface GetGroupFileUrlResponse {
url?: string;

View File

@@ -1,17 +1,13 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['string', 'number'] },
folder_name: { type: 'string' },
},
required: ['group_id', 'folder_name'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
folder_name: Type.String(),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class CreateGroupFileFolder extends OneBotAction<Payload, any> {
actionName = ActionName.GoCQHTTP_CreateGroupFileFolder;

View File

@@ -1,18 +1,15 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FileNapCatOneBotUUID } from '@/common/helper';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['string', 'number'] },
file_id: { type: 'string' },
},
required: ['group_id', 'file_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
file_id: Type.String(),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class DeleteGroupFile extends OneBotAction<Payload, any> {
actionName = ActionName.GOCQHTTP_DeleteGroupFile;

View File

@@ -1,18 +1,14 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { ActionName } from '@/onebot/action/router';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['string', 'number'] },
folder_id: { type: 'string' },
folder: { type: 'string' }
},
required: ['group_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
folder_id: Type.Optional(Type.String()),
folder: Type.Optional(Type.String()),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class DeleteGroupFileFolder extends OneBotAction<Payload, any> {
actionName = ActionName.GoCQHTTP_DeleteGroupFileFolder;

View File

@@ -4,29 +4,20 @@ import fs from 'fs';
import { join as joinPath } from 'node:path';
import { calculateFileMD5, httpDownload } from '@/common/file';
import { randomUUID } from 'crypto';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
interface FileResponse {
file: string;
}
const SchemaData = {
type: 'object',
properties: {
thread_count: { type: ['number', 'string'] },
url: { type: 'string' },
base64: { type: 'string' },
name: { type: 'string' },
headers: {
type: ['string', 'array'],
items: {
type: 'string',
},
},
},
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
url: Type.Optional(Type.String()),
base64: Type.Optional(Type.String()),
name: Type.Optional(Type.String()),
headers: Type.Optional(Type.Union([Type.String(), Type.Array(Type.String())])),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export default class GoCQHTTPDownloadFile extends OneBotAction<Payload, FileResponse> {
actionName = ActionName.GoCQHTTP_DownloadFile;

View File

@@ -1,20 +1,15 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { OB11Message, OB11MessageData, OB11MessageDataType, OB11MessageForward, OB11MessageNodePlain as OB11MessageNode } from '@/onebot';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { MessageUnique } from '@/common/message-unique';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = Type.Object({
message_id: Type.Optional(Type.Union([Type.Number(), Type.String()])),
id: Type.Optional(Type.Union([Type.Number(), Type.String()])),
});
const SchemaData = {
type: 'object',
properties: {
message_id: { type: 'string' },
id: { type: 'string' },
},
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class GoCQHTTPGetForwardMsgAction extends OneBotAction<Payload, any> {
actionName = ActionName.GoCQHTTP_GetForwardMsg;
@@ -60,7 +55,7 @@ export class GoCQHTTPGetForwardMsgAction extends OneBotAction<Payload, any> {
throw new Error('message_id is required');
}
const rootMsgId = MessageUnique.getShortIdByMsgId(msgId);
const rootMsgId = MessageUnique.getShortIdByMsgId(msgId.toString());
const rootMsg = MessageUnique.getMsgIdAndPeerByShortId(rootMsgId ?? +msgId);
if (!rootMsg) {
throw new Error('msg not found');

View File

@@ -2,26 +2,22 @@ import { OneBotAction } from '@/onebot/action/OneBotAction';
import { OB11Message } from '@/onebot';
import { ActionName } from '@/onebot/action/router';
import { ChatType } from '@/core/types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { MessageUnique } from '@/common/message-unique';
import { AdapterConfigWrap } from '@/onebot/config/config';
import { Static, Type } from '@sinclair/typebox';
interface Response {
messages: OB11Message[];
}
const SchemaData = Type.Object({
user_id: Type.Union([Type.Number(), Type.String()]),
message_seq: Type.Optional(Type.Union([Type.Number(), Type.String()])),
count: Type.Union([Type.Number(), Type.String()], { default: 20 }),
reverseOrder: Type.Optional(Type.Union([Type.Boolean(), Type.String()]))
});
const SchemaData = {
type: 'object',
properties: {
user_id: { type: ['number', 'string'] },
message_seq: { type: ['number', 'string'] },
count: { type: ['number', 'string'] },
reverseOrder: { type: ['boolean', 'string'] },
},
required: ['user_id'],
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export default class GetFriendMsgHistory extends OneBotAction<Payload, Response> {
actionName = ActionName.GetFriendMsgHistory;
@@ -30,7 +26,7 @@ export default class GetFriendMsgHistory extends OneBotAction<Payload, Response>
async _handle(payload: Payload, adapter: string): Promise<Response> {
//处理参数
const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
const MsgCount = +(payload.count ?? 20);
const isReverseOrder = typeof payload.reverseOrder === 'string' ? payload.reverseOrder === 'true' : !!payload.reverseOrder;
if (!uid) throw new Error(`记录${payload.user_id}不存在`);
const friend = await this.core.apis.FriendApi.isBuddy(uid);
@@ -38,7 +34,7 @@ export default class GetFriendMsgHistory extends OneBotAction<Payload, Response>
const hasMessageSeq = !payload.message_seq ? !!payload.message_seq : !(payload.message_seq?.toString() === '' || payload.message_seq?.toString() === '0');
const startMsgId = hasMessageSeq ? (MessageUnique.getMsgIdAndPeerByShortId(+payload.message_seq!)?.MsgId ?? payload.message_seq!.toString()) : '0';
const msgList = hasMessageSeq ?
(await this.core.apis.MsgApi.getMsgHistory(peer, startMsgId, MsgCount)).msgList : (await this.core.apis.MsgApi.getAioFirstViewLatestMsgs(peer, MsgCount)).msgList;
(await this.core.apis.MsgApi.getMsgHistory(peer, startMsgId, +payload.count)).msgList : (await this.core.apis.MsgApi.getAioFirstViewLatestMsgs(peer, +payload.count)).msgList;
if (msgList.length === 0) throw new Error(`消息${payload.message_seq}不存在`);
//翻转消息
if (isReverseOrder) msgList.reverse();

View File

@@ -1,15 +1,12 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] }
},
required: ['group_id'],
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()])
});
type Payload = Static<typeof SchemaData>;
export class GoCQHTTPGetGroupAtAllRemain extends OneBotAction<Payload, any> {
actionName = ActionName.GoCQHTTP_GetGroupAtAllRemain;

View File

@@ -1,16 +1,12 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['string', 'number'] },
},
required: ['group_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()])
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class GetGroupFileSystemInfo extends OneBotAction<Payload, {
file_count: number,

View File

@@ -1,20 +1,17 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { OB11Construct } from '@/onebot/helper/data';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['string', 'number'] },
folder_id: { type: 'string' },
folder: { type: 'string' },
file_count: { type: ['string', 'number'] },
},
required: ['group_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
folder_id: Type.Optional(Type.String()),
folder: Type.Optional(Type.String()),
file_count: Type.Union([Type.Number(), Type.String()], { default: 50 }),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class GetGroupFilesByFolder extends OneBotAction<any, any> {
actionName = ActionName.GoCQHTTP_GetGroupFilesByFolder;
@@ -23,7 +20,7 @@ export class GetGroupFilesByFolder extends OneBotAction<any, any> {
const ret = await this.core.apis.MsgApi.getGroupFileList(payload.group_id.toString(), {
sortType: 1,
fileCount: +(payload.file_count ?? 50),
fileCount: +payload.file_count,
startIndex: 0,
sortOrder: 2,
showOnlinedocFolder: 0,

View File

@@ -1,18 +1,14 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { WebHonorType } from '@/core/types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
type: { enum: [WebHonorType.ALL, WebHonorType.EMOTION, WebHonorType.LEGEND, WebHonorType.PERFORMER, WebHonorType.STRONG_NEWBIE, WebHonorType.TALKATIVE] },
},
required: ['group_id'],
} as const satisfies JSONSchema;
// enum是不是有点抽象
type Payload = FromSchema<typeof SchemaData>;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
type: Type.Optional(Type.Enum(WebHonorType))
});
type Payload = Static<typeof SchemaData>;
export class GetGroupHonorInfo extends OneBotAction<Payload, Array<any>> {
actionName = ActionName.GetGroupHonorInfo;

View File

@@ -2,26 +2,24 @@ import { OneBotAction } from '@/onebot/action/OneBotAction';
import { OB11Message } from '@/onebot';
import { ActionName } from '@/onebot/action/router';
import { ChatType, Peer } from '@/core/types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { MessageUnique } from '@/common/message-unique';
import { AdapterConfigWrap } from '@/onebot/config/config';
import { Static, Type } from '@sinclair/typebox';
interface Response {
messages: OB11Message[];
}
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
message_seq: { type: ['number', 'string'] },
count: { type: ['number', 'string'] },
reverseOrder: { type: ['boolean', 'string'] },
},
required: ['group_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
message_seq: Type.Optional(Type.Union([Type.Number(), Type.String()])),
count: Type.Union([Type.Number(), Type.String()], { default: 20 }),
reverseOrder: Type.Optional(Type.Union([Type.Boolean(), Type.String()]))
});
type Payload = Static<typeof SchemaData>;
type Payload = FromSchema<typeof SchemaData>;
export default class GoCQHTTPGetGroupMsgHistory extends OneBotAction<Payload, Response> {
actionName = ActionName.GoCQHTTP_GetGroupMsgHistory;
@@ -30,13 +28,12 @@ export default class GoCQHTTPGetGroupMsgHistory extends OneBotAction<Payload, Re
async _handle(payload: Payload, adapter: string): Promise<Response> {
//处理参数
const isReverseOrder = typeof payload.reverseOrder === 'string' ? payload.reverseOrder === 'true' : !!payload.reverseOrder;
const MsgCount = +(payload.count ?? 20);
const peer: Peer = { chatType: ChatType.KCHATTYPEGROUP, peerUid: payload.group_id.toString() };
const hasMessageSeq = !payload.message_seq ? !!payload.message_seq : !(payload.message_seq?.toString() === '' || payload.message_seq?.toString() === '0');
//拉取消息
const startMsgId = hasMessageSeq ? (MessageUnique.getMsgIdAndPeerByShortId(+payload.message_seq!)?.MsgId ?? payload.message_seq!.toString()) : '0';
const msgList = hasMessageSeq ?
(await this.core.apis.MsgApi.getMsgHistory(peer, startMsgId, MsgCount)).msgList : (await this.core.apis.MsgApi.getAioFirstViewLatestMsgs(peer, MsgCount)).msgList;
(await this.core.apis.MsgApi.getMsgHistory(peer, startMsgId, +payload.count)).msgList : (await this.core.apis.MsgApi.getAioFirstViewLatestMsgs(peer, +payload.count)).msgList;
if (msgList.length === 0) throw new Error(`消息${payload.message_seq}不存在`);
//翻转消息
if (isReverseOrder) msgList.reverse();

View File

@@ -1,19 +1,16 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { OB11GroupFile, OB11GroupFileFolder } from '@/onebot';
import { OB11Construct } from '@/onebot/helper/data';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['string', 'number'] },
file_count: { type: ['string', 'number'] },
},
required: ['group_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
file_count: Type.Union([Type.Number(), Type.String()], { default: 50 }),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class GetGroupRootFiles extends OneBotAction<Payload, {
files: OB11GroupFile[],
@@ -24,7 +21,7 @@ export class GetGroupRootFiles extends OneBotAction<Payload, {
async _handle(payload: Payload) {
const ret = await this.core.apis.MsgApi.getGroupFileList(payload.group_id.toString(), {
sortType: 1,
fileCount: +(payload.file_count ?? 50),
fileCount: +payload.file_count,
startIndex: 0,
sortOrder: 2,
showOnlinedocFolder: 0,

View File

@@ -1,15 +1,7 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { JSONSchema } from 'json-schema-to-ts';
import { sleep } from '@/common/helper';
const SchemaData = {
type: 'object',
properties: {
no_cache: { type: 'boolean' },
},
} as const satisfies JSONSchema;
export class GetOnlineClient extends OneBotAction<void, Array<any>> {
actionName = ActionName.GetOnlineClient;

View File

@@ -2,18 +2,14 @@ import { OneBotAction } from '@/onebot/action/OneBotAction';
import { OB11User, OB11UserSex } from '@/onebot';
import { OB11Construct } from '@/onebot/helper/data';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { calcQQLevel } from '@/common/helper';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
user_id: { type: ['number', 'string'] },
},
required: ['user_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
user_id: Type.Union([Type.Number(), Type.String()]),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export default class GoCQHTTPGetStrangerInfo extends OneBotAction<Payload, OB11User> {
actionName = ActionName.GoCQHTTP_GetStrangerInfo;

View File

@@ -1,15 +1,12 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
url: { type: 'string' },
},
required: ['url'],
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
const SchemaData = Type.Object({
url: Type.String(),
});
type Payload = Static<typeof SchemaData>;
export class GoCQHTTPCheckUrlSafely extends OneBotAction<Payload, any> {
actionName = ActionName.GoCQHTTP_CheckUrlSafely;

View File

@@ -1,22 +1,15 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
friend_id: { type: ['string', 'number'] },
user_id: { type: ['string', 'number'] },
temp_block: { type: 'boolean' },
temp_both_del: { type: 'boolean' },
},
oneOf: [
{ required: ['friend_id'] },
{ required: ['user_id'] },
],
const SchemaData = Type.Object({
friend_id: Type.Optional(Type.Union([Type.String(), Type.Number()])),
user_id: Type.Optional(Type.Union([Type.String(), Type.Number()])),
temp_block: Type.Optional(Type.Boolean()),
temp_both_del: Type.Optional(Type.Boolean()),
});
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class GoCQHTTPDeleteFriend extends OneBotAction<Payload, any> {
actionName = ActionName.GoCQHTTP_DeleteFriend;

View File

@@ -1,14 +1,12 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
model: { type: 'string' },
}
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
const SchemaData = Type.Object({
model: Type.String(),
});
type Payload = Static<typeof SchemaData>;
export class GoCQHTTPGetModelShow extends OneBotAction<Payload, any> {
actionName = ActionName.GoCQHTTP_GetModelShow;

View File

@@ -1,19 +1,10 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = {
type: 'object',
properties: {},
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
//兼容性代码
export class GoCQHTTPSetModelShow extends OneBotAction<Payload, any> {
export class GoCQHTTPSetModelShow extends OneBotAction<void, any> {
actionName = ActionName.GoCQHTTP_SetModelShow;
payloadSchema = SchemaData;
async _handle(payload: Payload) {
async _handle(payload: void) {
return null;
}
}

View File

@@ -1,25 +1,21 @@
import { checkFileExist, uri2local } from '@/common/file';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { unlink } from 'node:fs';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { unlink } from 'node:fs/promises';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
content: { type: 'string' },
image: { type: 'string' },
pinned: { type: ['number', 'string'] },
type: { type: ['number', 'string'] },
confirm_required: { type: ['number', 'string'] },
is_show_edit_card: { type: ['number', 'string'] },
tip_window_type: { type: ['number', 'string'] },
},
required: ['group_id', 'content'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
content: Type.String(),
image: Type.Optional(Type.String()),
pinned: Type.Union([Type.Number(), Type.String()], { default: 0 }),
type: Type.Union([Type.Number(), Type.String()], { default: 1 }),
confirm_required: Type.Union([Type.Number(), Type.String()], { default: 1 }),
is_show_edit_card: Type.Union([Type.Number(), Type.String()], { default: 0 }),
tip_window_type: Type.Union([Type.Number(), Type.String()], { default: 0 })
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class SendGroupNotice extends OneBotAction<Payload, null> {
actionName = ActionName.GoCQHTTP_SendGroupNotice;
@@ -45,26 +41,18 @@ export class SendGroupNotice extends OneBotAction<Payload, null> {
throw new Error(`群公告${payload.image}设置失败,图片上传失败`);
}
unlink(path, () => {
});
unlink(path).catch(() => { });
UploadImage = ImageUploadResult.picInfo;
}
const noticeType = +(payload.type ?? 1);
const noticePinned = +(payload.pinned ?? 0);
const noticeShowEditCard = +(payload.is_show_edit_card ?? 0);
const noticeTipWindowType = +(payload.tip_window_type ?? 0);
const noticeConfirmRequired = +(payload.confirm_required ?? 1);
const publishGroupBulletinResult = await this.core.apis.WebApi.setGroupNotice(
payload.group_id.toString(),
payload.content,
noticePinned,
noticeType,
noticeShowEditCard,
noticeTipWindowType,
noticeConfirmRequired,
+payload.pinned,
+payload.type,
+payload.is_show_edit_card,
+payload.tip_window_type,
+payload.confirm_required,
UploadImage?.id,
UploadImage?.width,
UploadImage?.height

View File

@@ -1,28 +1,18 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName, BaseCheckResult } from '@/onebot/action/router';
import * as fs from 'node:fs';
import { ActionName } from '@/onebot/action/router';
import { checkFileExistV2, uri2local } from '@/common/file';
import { Static, Type } from '@sinclair/typebox';
import fs from 'node:fs/promises';
const SchemaData = Type.Object({
file: Type.String(),
group_id: Type.Union([Type.Number(), Type.String()])
});
interface Payload {
file: string,
group_id: number
}
type Payload = Static<typeof SchemaData>;
export default class SetGroupPortrait extends OneBotAction<Payload, any> {
actionName = ActionName.SetGroupPortrait;
// 用不着复杂检测
protected async check(payload: Payload): Promise<BaseCheckResult> {
if (!payload.file || typeof payload.file != 'string' || !payload.group_id || typeof payload.group_id != 'number') {
return {
valid: false,
message: 'file和group_id字段不能为空或者类型错误',
};
}
return {
valid: true,
};
}
payloadSchema = SchemaData;
async _handle(payload: Payload): Promise<any> {
const { path, success } = (await uri2local(this.core.NapCatTempPath, payload.file));
@@ -32,7 +22,7 @@ export default class SetGroupPortrait extends OneBotAction<Payload, any> {
if (path) {
await checkFileExistV2(path, 5000); // 文件不存在QQ会崩溃需要提前判断
const ret = await this.core.apis.GroupApi.setGroupAvatar(payload.group_id.toString(), path);
fs.unlink(path, () => { });
fs.unlink(path).catch(() => { });
if (!ret) {
throw new Error(`头像${payload.file}设置失败,api无返回`);
}
@@ -43,7 +33,7 @@ export default class SetGroupPortrait extends OneBotAction<Payload, any> {
}
return ret;
} else {
fs.unlink(path, () => { });
fs.unlink(path).catch(() => { });
throw new Error(`头像${payload.file}设置失败,无法获取头像,文件可能不存在`);
}
}

View File

@@ -1,18 +1,14 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
nickname: { type: 'string' },
personal_note: { type: 'string' },
sex: { type: ['number', 'string'] },//传Sex值建议传0
},
required: ['nickname'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
nickname: Type.String(),
personal_note: Type.Optional(Type.String()),
sex: Type.Optional(Type.Union([Type.Number(), Type.String()])), // 传Sex值建议传0
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class SetQQProfile extends OneBotAction<Payload, any> {
actionName = ActionName.SetQQProfile;

View File

@@ -3,22 +3,18 @@ import { ActionName } from '@/onebot/action/router';
import { ChatType, Peer } from '@/core/types';
import fs from 'fs';
import { uri2local } from '@/common/file';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { MessageContext } from '@/onebot/api';
import { SendMessageContext } from '@/onebot/api';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
file: { type: 'string' },
name: { type: 'string' },
folder: { type: 'string' },
folder_id: { type: 'string' },//临时扩展
},
required: ['group_id', 'file', 'name'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
file: Type.String(),
name: Type.String(),
folder: Type.Optional(Type.String()),
folder_id: Type.Optional(Type.String()),//临时扩展
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export default class GoCQHTTPUploadGroupFile extends OneBotAction<Payload, null> {
actionName = ActionName.GoCQHTTP_UploadGroupFile;
@@ -37,7 +33,7 @@ export default class GoCQHTTPUploadGroupFile extends OneBotAction<Payload, null>
if (!downloadResult.success) {
throw new Error(downloadResult.errMsg);
}
const msgContext: MessageContext = {
const msgContext: SendMessageContext = {
peer: peer,
deleteAfterSentFiles: []
};

View File

@@ -3,21 +3,17 @@ import { ActionName } from '@/onebot/action/router';
import { ChatType, Peer, SendFileElement } from '@/core/types';
import fs from 'fs';
import { uri2local } from '@/common/file';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { MessageContext } from '@/onebot/api';
import { SendMessageContext } from '@/onebot/api';
import { ContextMode, createContext } from '@/onebot/action/msg/SendMsg';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
user_id: { type: ['number', 'string'] },
file: { type: 'string' },
name: { type: 'string' },
},
required: ['user_id', 'file', 'name'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
user_id: Type.Union([Type.Number(), Type.String()]),
file: Type.String(),
name: Type.String(),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export default class GoCQHTTPUploadPrivateFile extends OneBotAction<Payload, null> {
actionName = ActionName.GOCQHTTP_UploadPrivateFile;
@@ -45,7 +41,7 @@ export default class GoCQHTTPUploadPrivateFile extends OneBotAction<Payload, nul
throw new Error(downloadResult.errMsg);
}
const msgContext: MessageContext = {
const msgContext: SendMessageContext = {
peer: await createContext(this.core, {
user_id: payload.user_id.toString(),
group_id: undefined,

View File

@@ -1,17 +1,13 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { MessageUnique } from '@/common/message-unique';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
message_id: { type: ['number', 'string'] },
},
required: ['message_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
message_id: Type.Union([Type.Number(), Type.String()]),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export default class DelEssenceMsg extends OneBotAction<Payload, any> {
actionName = ActionName.DelEssenceMsg;

View File

@@ -1,18 +1,13 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
notice_id: Type.String()
});
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>;
type Payload = Static<typeof SchemaData>;
export class DelGroupNotice extends OneBotAction<Payload, any> {
actionName = ActionName.DelGroupNotice;

View File

@@ -1,19 +1,15 @@
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
import { AIVoiceChatType } from "@/core/packet/entities/aiChat";
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
character: { type: ['string'] },
group_id: { type: ['number', 'string'] },
text: { type: 'string' },
},
required: ['character', 'group_id', 'text'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
character: Type.String(),
group_id: Type.Union([Type.Number(), Type.String()]),
text: Type.String(),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class GetAiRecord extends GetPacketStatusDepends<Payload, string> {
actionName = ActionName.GetAiRecord;

View File

@@ -1,20 +1,16 @@
import { ChatType, Peer } from '@/core';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { MessageUnique } from '@/common/message-unique';
import crypto from 'crypto';
import { AdapterConfigWrap } from '@/onebot/config/config';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] }
},
required: ['group_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class GetGroupEssence extends OneBotAction<Payload, any> {
actionName = ActionName.GoCQHTTP_GetEssenceMsg;

View File

@@ -1,17 +1,6 @@
import { GroupNotifyMsgStatus } from '@/core';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
},
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
export class GetGroupIgnoredNotifies extends OneBotAction<void, any> {
actionName = ActionName.GetGroupIgnoredNotifies;

View File

@@ -2,17 +2,13 @@ import { OB11Group } from '@/onebot';
import { OB11Construct } from '@/onebot/helper/data';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
},
required: ['group_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
class GetGroupInfo extends OneBotAction<Payload, OB11Group> {
actionName = ActionName.GetGroupInfo;

View File

@@ -2,16 +2,13 @@ import { OB11Group } from '@/onebot';
import { OB11Construct } from '@/onebot/helper/data';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
// no_cache get时传字符串
const SchemaData = {
type: 'object',
properties: {
no_cache: { type: ['boolean', 'string'] },
},
} as const satisfies JSONSchema;
import { Static, Type } from '@sinclair/typebox';
type Payload = FromSchema<typeof SchemaData>;
const SchemaData = Type.Object({
no_cache: Type.Optional(Type.Union([Type.Boolean(), Type.String()])),
});
type Payload = Static<typeof SchemaData>;
class GetGroupList extends OneBotAction<Payload, OB11Group[]> {
actionName = ActionName.GetGroupList;

View File

@@ -2,19 +2,15 @@ import { OB11GroupMember } from '@/onebot';
import { OB11Construct } from '@/onebot/helper/data';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
user_id: { type: ['number', 'string'] },
no_cache: { type: ['boolean', 'string'] },
},
required: ['group_id', 'user_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
user_id: Type.Union([Type.Number(), Type.String()]),
no_cache: Type.Optional(Type.Union([Type.Boolean(), Type.String()])),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
class GetGroupMemberInfo extends OneBotAction<Payload, OB11GroupMember> {
actionName = ActionName.GetGroupMemberInfo;

View File

@@ -2,18 +2,14 @@ import { OB11GroupMember } from '@/onebot';
import { OB11Construct } from '@/onebot/helper/data';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
no_cache: { type: ['boolean', 'string'] },
},
required: ['group_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
no_cache: Type.Optional(Type.Union([Type.Boolean(), Type.String()]))
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class GetGroupMemberList extends OneBotAction<Payload, OB11GroupMember[]> {
actionName = ActionName.GetGroupMemberList;
@@ -23,11 +19,13 @@ export class GetGroupMemberList extends OneBotAction<Payload, OB11GroupMember[]>
const groupIdStr = payload.group_id.toString();
const noCache = payload.no_cache ? this.stringToBoolean(payload.no_cache) : false;
const memberCache = this.core.apis.GroupApi.groupMemberCache;
let groupMembers;
try {
groupMembers = await this.core.apis.GroupApi.getGroupMembersV2(groupIdStr, 3000, noCache);
} catch (error) {
groupMembers = memberCache.get(groupIdStr) ?? await this.core.apis.GroupApi.getGroupMembersV2(groupIdStr);
let groupMembers = memberCache.get(groupIdStr);
if (noCache || !groupMembers) {
await this.core.apis.GroupApi.refreshGroupMemberCache(groupIdStr);
groupMembers = memberCache.get(groupIdStr);
if (!groupMembers) {
throw new Error(`Failed to get group member list for group ${groupIdStr}`);
}
}
const memberPromises = Array.from(groupMembers.values()).map(item =>
OB11Construct.groupMember(groupIdStr, item)

View File

@@ -1,8 +1,7 @@
import { WebApiGroupNoticeFeed } from '@/core';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
interface GroupNotice {
sender_id: number;
publish_time: number;
@@ -17,15 +16,11 @@ interface GroupNotice {
};
}
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
},
required: ['group_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
type ApiGroupNotice = GroupNotice & WebApiGroupNoticeFeed;

View File

@@ -1,16 +1,12 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
},
required: ['group_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class GetGroupShutList extends OneBotAction<Payload, any> {
actionName = ActionName.GetGroupShutList;

View File

@@ -1,17 +1,13 @@
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
// no_cache get时传字符串
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
user_id: { type: ['number', 'string'] },
},
required: ['group_id', 'user_id'],
} as const satisfies JSONSchema;
import { Static, Type } from '@sinclair/typebox';
type Payload = FromSchema<typeof SchemaData>;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
user_id: Type.Union([Type.Number(), Type.String()]),
});
type Payload = Static<typeof SchemaData>;
export class GroupPoke extends GetPacketStatusDepends<Payload, any> {
actionName = ActionName.GroupPoke;

View File

@@ -1,21 +1,18 @@
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
import { uri2local } from "@/common/file";
import { ChatType, Peer } from "@/core";
import { AIVoiceChatType } from "@/core/packet/entities/aiChat";
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
character: { type: ['string'] },
group_id: { type: ['number', 'string'] },
text: { type: 'string' },
},
required: ['character', 'group_id', 'text'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
character: Type.String(),
group_id: Type.Union([Type.Number(), Type.String()]),
text: Type.String(),
});
type Payload = Static<typeof SchemaData>;
type Payload = FromSchema<typeof SchemaData>;
export class SendGroupAiRecord extends GetPacketStatusDepends<Payload, {
message_id: number

View File

@@ -1,24 +1,20 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { MessageUnique } from '@/common/message-unique';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
message_id: { type: ['number', 'string'] },
},
required: ['message_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
message_id: Type.Union([Type.Number(), Type.String()]),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export default class SetEssenceMsg extends OneBotAction<Payload, any> {
actionName = ActionName.SetEssenceMsg;
payloadSchema = SchemaData;
async _handle(payload: Payload): Promise<any> {
const msg = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString()));
const msg = MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id);
if (!msg) {
throw new Error('msg not found');
}

View File

@@ -1,19 +1,15 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { NTGroupRequestOperateTypes } from '@/core/types';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
flag: { type: 'string' },
approve: { type: ['string', 'boolean'] },
reason: { type: 'string', nullable: true },
},
required: ['flag'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
flag: Type.String(),
approve: Type.Optional(Type.Union([Type.Boolean(), Type.String()])),
reason: Type.Union([Type.String({ default: ' ' }), Type.Null()]),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export default class SetGroupAddRequest extends OneBotAction<Payload, null> {
actionName = ActionName.SetGroupAddRequest;

View File

@@ -1,19 +1,15 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { NTGroupMemberRole } from '@/core/types';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
user_id: { type: ['number', 'string'] },
enable: { type: ['boolean', 'string'] },
},
required: ['group_id', 'user_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
user_id: Type.Union([Type.Number(), Type.String()]),
enable: Type.Optional(Type.Union([Type.Boolean(), Type.String()])),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export default class SetGroupAdmin extends OneBotAction<Payload, null> {
actionName = ActionName.SetGroupAdmin;

View File

@@ -1,18 +1,14 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
user_id: { type: ['number', 'string'] },
duration: { type: ['number', 'string'] },
},
required: ['group_id', 'user_id', 'duration'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
user_id: Type.Union([Type.Number(), Type.String()]),
duration: Type.Union([Type.Number(), Type.String()], { default: 0 }),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export default class SetGroupBan extends OneBotAction<Payload, null> {
actionName = ActionName.SetGroupBan;
@@ -22,7 +18,7 @@ export default class SetGroupBan extends OneBotAction<Payload, null> {
const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
if (!uid) throw new Error('uid error');
await this.core.apis.GroupApi.banMember(payload.group_id.toString(),
[{ uid: uid, timeStamp: parseInt(payload.duration.toString()) }]);
[{ uid: uid, timeStamp: +payload.duration}]);
return null;
}
}

View File

@@ -1,18 +1,14 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
user_id: { type: ['number', 'string'] },
card: { type: 'string' },
},
required: ['group_id', 'user_id', 'card'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
user_id: Type.Union([Type.Number(), Type.String()]),
card: Type.Optional(Type.String())
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export default class SetGroupCard extends OneBotAction<Payload, null> {
actionName = ActionName.SetGroupCard;

View File

@@ -1,19 +1,14 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
user_id: Type.Union([Type.Number(), Type.String()]),
reject_add_request: Type.Optional(Type.Union([Type.Boolean(), Type.String()])),
});
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
user_id: { type: ['number', 'string'] },
reject_add_request: { type: ['boolean', 'string'] },
},
required: ['group_id', 'user_id'],
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export default class SetGroupKick extends OneBotAction<Payload, null> {
actionName = ActionName.SetGroupKick;

View File

@@ -1,17 +1,14 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
is_dismiss: { type: ['boolean', 'string'] },
},
required: ['group_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
is_dismiss: Type.Optional(Type.Union([Type.Boolean(), Type.String()])),
});
type Payload = Static<typeof SchemaData>;
type Payload = FromSchema<typeof SchemaData>;
export default class SetGroupLeave extends OneBotAction<Payload, any> {
actionName = ActionName.SetGroupLeave;
payloadSchema = SchemaData;

View File

@@ -1,23 +1,24 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
group_name: { type: 'string' },
},
required: ['group_id', 'group_name'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
group_name: Type.String(),
});
type Payload = Static<typeof SchemaData>;
type Payload = FromSchema<typeof SchemaData>;
export default class SetGroupName extends OneBotAction<Payload, null> {
actionName = ActionName.SetGroupName;
payloadSchema = SchemaData;
async _handle(payload: Payload): Promise<null> {
await this.core.apis.GroupApi.setGroupName(payload.group_id.toString(), payload.group_name);
const ret = await this.core.apis.GroupApi.setGroupName(payload.group_id.toString(), payload.group_name);
if (ret.result !== 0) {
throw new Error(`设置群名称失败 ErrCode: ${ret.result} ErrMsg: ${ret.errMsg}`);
}
return null;
}
}

View File

@@ -1,17 +1,13 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
enable: { type: ['boolean', 'string'] },
},
required: ['group_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]),
enable: Type.Optional(Type.Union([Type.Boolean(), Type.String()])),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export default class SetGroupWholeBan extends OneBotAction<Payload, null> {
actionName = ActionName.SetGroupWholeBan;

View File

@@ -1,22 +1,13 @@
import { ActionName } from '@/onebot/action/router';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { MessageUnique } from '@/common/message-unique';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
message_id: {
oneOf: [
{ type: 'number' },
{ type: 'string' },
],
},
},
required: ['message_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
message_id: Type.Union([Type.Number(), Type.String()]),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
class DeleteMsg extends OneBotAction<Payload, void> {
actionName = ActionName.DeleteMsg;

View File

@@ -1,20 +1,16 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ChatType, Peer } from '@/core/types';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { MessageUnique } from '@/common/message-unique';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
message_id: { type: ['number', 'string'] },
group_id: { type: ['number', 'string'] },
user_id: { type: ['number', 'string'] },
},
required: ['message_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
message_id: Type.Union([Type.Number(), Type.String()]),
group_id: Type.Optional(Type.Union([Type.Number(), Type.String()])),
user_id: Type.Optional(Type.Union([Type.Number(), Type.String()])),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
class ForwardSingleMsg extends OneBotAction<Payload, null> {
protected async getTargetPeer(payload: Payload): Promise<Peer> {
@@ -29,7 +25,7 @@ class ForwardSingleMsg extends OneBotAction<Payload, null> {
}
async _handle(payload: Payload): Promise<null> {
const msg = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString()));
const msg = MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id);
if (!msg) {
throw new Error(`无法找到消息${payload.message_id}`);
}

View File

@@ -1,23 +1,18 @@
import { OB11Message } from '@/onebot';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { MessageUnique } from '@/common/message-unique';
import { RawMessage } from '@/core';
import { AdapterConfigWrap } from '@/onebot/config/config';
import { Static, Type } from '@sinclair/typebox';
export type ReturnDataType = OB11Message
const SchemaData = {
type: 'object',
properties: {
message_id: { type: ['number', 'string'] },
},
required: ['message_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
message_id: Type.Union([Type.Number(), Type.String()]),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
class GetMsg extends OneBotAction<Payload, OB11Message> {
actionName = ActionName.GetMsg;

View File

@@ -1,19 +1,16 @@
import { ChatType, Peer } from '@/core/types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { MessageUnique } from '@/common/message-unique';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
user_id: { type: ['number', 'string'] },
group_id: { type: ['number', 'string'] },
message_id: { type: ['number', 'string'] },
},
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
user_id: Type.Optional(Type.Union([Type.String(), Type.Number()])),
group_id: Type.Optional(Type.Union([Type.String(), Type.Number()])),
message_id: Type.Optional(Type.Union([Type.String(), Type.Number()])),
});
type PlayloadType = FromSchema<typeof SchemaData>;
type PlayloadType = Static<typeof SchemaData>;
class MarkMsgAsRead extends OneBotAction<PlayloadType, null> {
async getPeer(payload: PlayloadType): Promise<Peer> {

View File

@@ -1,26 +1,22 @@
import { ActionName } from '@/onebot/action/router';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { MessageUnique } from '@/common/message-unique';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
message_id: { type: ['string', 'number'] },
emoji_id: { type: ['string', 'number'] },
set: { type: ['boolean', 'string'] }
},
required: ['message_id', 'emoji_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
message_id: Type.Union([Type.Number(), Type.String()]),
emoji_id: Type.Union([Type.Number(), Type.String()]),
set: Type.Optional(Type.Union([Type.Boolean(), Type.String()]))
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class SetMsgEmojiLike extends OneBotAction<Payload, any> {
actionName = ActionName.SetMsgEmojiLike;
payloadSchema = SchemaData;
async _handle(payload: Payload) {
const msg = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString()));
const msg = MessageUnique.getMsgIdAndPeerByShortId(+payload.message_id);
if (!msg) {
throw new Error('msg not found');
}

View File

@@ -1,21 +1,18 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
interface Response {
cookies: string,
token: number
}
const SchemaData = {
type: 'object',
properties: {
domain: { type: 'string' },
},
required: ['domain'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
domain: Type.String()
});
type Payload = Static<typeof SchemaData>;
type Payload = FromSchema<typeof SchemaData>;
export class GetCredentials extends OneBotAction<Payload, Response> {
actionName = ActionName.GetCredentials;

View File

@@ -1,21 +1,10 @@
import { GroupNotifyMsgStatus } from '@/core';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: ['number', 'string'] },
},
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
export class GetGroupSystemMsg extends OneBotAction<void, any> {
actionName = ActionName.GetGroupSystemMsg;
async _handle(payload: void) {
async _handle() {
const NTQQUserApi = this.core.apis.UserApi;
const NTQQGroupApi = this.core.apis.GroupApi;
// 默认10条 该api未完整实现 包括响应数据规范化 类型规范化

View File

@@ -1,16 +1,12 @@
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
user_id: { type: ['number', 'string'] },
},
required: ['user_id'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
user_id: Type.Union([Type.Number(), Type.String()])
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class FriendPoke extends GetPacketStatusDepends<Payload, any> {
actionName = ActionName.FriendPoke;

View File

@@ -1,21 +1,16 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
interface Response {
cookies: string,
bkn: string
}
const SchemaData = {
type: 'object',
properties: {
domain: { type: 'string' },
},
required: ['domain'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
domain: Type.String()
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export class GetCookies extends OneBotAction<Payload, Response> {
actionName = ActionName.GetCookies;

View File

@@ -2,17 +2,14 @@ import { OB11User } from '@/onebot';
import { OB11Construct } from '@/onebot/helper/data';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
// no_cache get时传字符串
const SchemaData = {
type: 'object',
properties: {
no_cache: { type: ['boolean', 'string'] },
},
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
no_cache: Type.Optional(Type.Union([Type.Boolean(), Type.String()])),
});
type Payload = Static<typeof SchemaData>;
type Payload = FromSchema<typeof SchemaData>;
export default class GetFriendList extends OneBotAction<Payload, OB11User[]> {
actionName = ActionName.GetFriendList;
payloadSchema = SchemaData;

View File

@@ -1,23 +1,21 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { AdapterConfigWrap } from '@/onebot/config/config';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
count: { type: ['number', 'string'] },
},
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
count: Type.Union([Type.Number(), Type.String()], { default: 10 }),
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export default class GetRecentContact extends OneBotAction<Payload, any> {
actionName = ActionName.GetRecentContact;
payloadSchema = SchemaData;
async _handle(payload: Payload, adapter: string) {
const ret = await this.core.apis.UserApi.getRecentContactListSnapShot(+(payload.count || 10));
const ret = await this.core.apis.UserApi.getRecentContactListSnapShot(+payload.count);
const network = Object.values(this.obContext.configLoader.configData.network) as Array<AdapterConfigWrap>;
//烘焙消息
const msgFormat = network.flat().find(e => e.name === adapter)?.messagePostFormat ?? 'array';

View File

@@ -1,17 +1,13 @@
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
user_id: { type: ['number', 'string'] },
times: { type: ['number', 'string'] },
},
required: ['user_id', 'times'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
times: Type.Union([Type.Number(), Type.String()], { default: 1 }),
user_id: Type.Union([Type.Number(), Type.String()])
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export default class SendLike extends OneBotAction<Payload, null> {
actionName = ActionName.SendLike;
@@ -20,7 +16,7 @@ export default class SendLike extends OneBotAction<Payload, null> {
async _handle(payload: Payload): Promise<null> {
const qq = payload.user_id.toString();
const uid: string = await this.core.apis.UserApi.getUidByUinV2(qq) ?? '';
const result = await this.core.apis.UserApi.like(uid, parseInt(payload.times?.toString()) || 1);
const result = await this.core.apis.UserApi.like(uid, +payload.times);
if (result.result !== 0) {
throw new Error(`点赞失败 ${result.errMsg}`);
}

View File

@@ -1,18 +1,14 @@
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router';
import { Static, Type } from '@sinclair/typebox';
const SchemaData = {
type: 'object',
properties: {
flag: { type: 'string' },
approve: { type: ['string', 'boolean'] },
remark: { type: 'string' },
},
required: ['flag'],
} as const satisfies JSONSchema;
const SchemaData = Type.Object({
flag: Type.String(),
approve: Type.Optional(Type.Union([Type.String(), Type.Boolean()])),
remark: Type.Optional(Type.String())
});
type Payload = FromSchema<typeof SchemaData>;
type Payload = Static<typeof SchemaData>;
export default class SetFriendAddRequest extends OneBotAction<Payload, null> {
actionName = ActionName.SetFriendAddRequest;

View File

@@ -7,15 +7,10 @@ import {
MessageElement,
NapCatCore,
NTGrayTipElementSubTypeV2,
NTMsgType,
RawMessage,
TipGroupElement,
TipGroupElementType,
} from '@/core';
import { NapCatOneBot11Adapter } from '@/onebot';
import { OB11GroupBanEvent } from '@/onebot/event/notice/OB11GroupBanEvent';
import { OB11GroupIncreaseEvent } from '@/onebot/event/notice/OB11GroupIncreaseEvent';
import { OB11GroupDecreaseEvent } from '@/onebot/event/notice/OB11GroupDecreaseEvent';
import fastXmlParser from 'fast-xml-parser';
import { OB11GroupMsgEmojiLikeEvent } from '@/onebot/event/notice/OB11MsgEmojiLikeEvent';
import { MessageUnique } from '@/common/message-unique';
@@ -66,67 +61,6 @@ export class OneBotGroupApi {
return undefined;
}
// async parseGroupIncreaseEvent(GroupCode: string, grayTipElement: GrayTipElement) {
// this.core.context.logger.logDebug('收到新人被邀请进群消息', grayTipElement);
// const xmlElement = grayTipElement.xmlElement;
// if (xmlElement?.content) {
// const regex = /jp="(\d+)"/g;
// const matches = [];
// let match = null;
// while ((match = regex.exec(xmlElement.content)) !== null) {
// matches.push(match[1]);
// }
// if (matches.length === 2) {
// const [inviter, invitee] = matches;
// return new OB11GroupIncreaseEvent(
// this.core,
// parseInt(GroupCode),
// parseInt(invitee),
// parseInt(inviter),
// 'invite',
// );
// }
// }
// return undefined;
// }
// async parseGroupMemberIncreaseEvent(GroupCode: string, grayTipElement: GrayTipElement) {
// const groupElement = grayTipElement?.groupElement;
// if (!groupElement) return undefined;
// 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) {
// const operatorUin = adminMember?.uin ?? memberUin;
// return new OB11GroupIncreaseEvent(
// this.core,
// parseInt(GroupCode),
// parseInt(memberUin),
// parseInt(operatorUin),
// );
// } else {
// return undefined;
// }
// }
// async parseGroupKickEvent(GroupCode: string, grayTipElement: GrayTipElement) {
// const groupElement = grayTipElement?.groupElement;
// if (!groupElement) return undefined;
// const adminUin = (await this.core.apis.GroupApi.getGroupMember(GroupCode, groupElement.adminUid))?.uin ?? (await this.core.apis.UserApi.getUidByUinV2(groupElement.adminUid));
// if (adminUin) {
// return new OB11GroupDecreaseEvent(
// this.core,
// parseInt(GroupCode),
// parseInt(this.core.selfInfo.uin),
// parseInt(adminUin),
// 'kick_me',
// );
// }
// return undefined;
// }
async parseGroupEmojiLikeEventByGrayTip(
groupCode: string,
grayTipElement: GrayTipElement
@@ -187,31 +121,6 @@ export class OneBotGroupApi {
return undefined;
}
// async parseGroupElement(msg: RawMessage, groupElement: TipGroupElement, elementWrapper: GrayTipElement) {
// if (groupElement.type == TipGroupElementType.KMEMBERADD) {
// const MemberIncreaseEvent = await this.obContext.apis.GroupApi.parseGroupMemberIncreaseEvent(msg.peerUid, elementWrapper);
// if (MemberIncreaseEvent) return MemberIncreaseEvent;
// } else if (groupElement.type === TipGroupElementType.KSHUTUP) {
// const BanEvent = await this.obContext.apis.GroupApi.parseGroupBanEvent(msg.peerUid, elementWrapper);
// if (BanEvent) return BanEvent;
// } else if (groupElement.type == TipGroupElementType.KQUITTE) {
// this.core.apis.GroupApi.quitGroup(msg.peerUid).then();
// try {
// const KickEvent = await this.obContext.apis.GroupApi.parseGroupKickEvent(msg.peerUid, elementWrapper);
// if (KickEvent) return KickEvent;
// } catch (e) {
// return new OB11GroupDecreaseEvent(
// this.core,
// parseInt(msg.peerUid),
// parseInt(this.core.selfInfo.uin),
// 0,
// 'leave',
// );
// }
// }
// return undefined;
// }
async parsePaiYiPai(msg: RawMessage, jsonStr: string) {
const json = JSON.parse(jsonStr);

View File

@@ -1,8 +1,8 @@
import { OneBotFriendApi } from '@/onebot/api/friend';
import { OneBotUserApi } from '@/onebot/api/user';
import { OneBotGroupApi } from '@/onebot/api/group';
import { OneBotMsgApi } from '@/onebot/api/msg';
import { OneBotQuickActionApi } from '@/onebot/api/quick-action';
import type { OneBotFriendApi } from '@/onebot/api/friend';
import type { OneBotUserApi } from '@/onebot/api/user';
import type { OneBotGroupApi } from '@/onebot/api/group';
import type { OneBotMsgApi } from '@/onebot/api/msg';
import type { OneBotQuickActionApi } from '@/onebot/api/quick-action';
export * from './friend';
export * from './group';

View File

@@ -15,7 +15,6 @@ import {
RawMessage,
SendMessageElement,
SendTextElement,
BaseEmojiType,
FaceType,
GrayTipElement,
} from '@/core';
@@ -26,16 +25,15 @@ import { EventType } from '@/onebot/event/OneBotEvent';
import { encodeCQCode } from '@/onebot/helper/cqcode';
import { uri2local } from '@/common/file';
import { RequestUtil } from '@/common/request';
import fs from 'node:fs';
import fsPromise from 'node:fs/promises';
import fsPromise, { constants } from 'node:fs/promises';
import { OB11FriendAddNoticeEvent } from '@/onebot/event/notice/OB11FriendAddNoticeEvent';
// import { decodeSysMessage } from '@/core/packet/proto/old/ProfileLike';
import { ForwardMsgBuilder } from "@/common/forward-msg-builder";
import { decodeSysMessage } from "@/core/helper/adaptDecoder";
import { GroupChange, PushMsgBody } from "@/core/packet/transformer/proto";
import { NapProtoMsg } from '@napneko/nap-proto-core';
import { OB11GroupIncreaseEvent } from '../event/notice/OB11GroupIncreaseEvent';
import { OB11GroupDecreaseEvent, GroupDecreaseSubType } from '../event/notice/OB11GroupDecreaseEvent';
import { GroupAdmin } from '@/core/packet/transformer/proto/message/groupAdmin';
import { OB11GroupAdminNoticeEvent } from '../event/notice/OB11GroupAdminNoticeEvent';
type RawToOb11Converters = {
[Key in keyof MessageElement as Key extends `${string}Element` ? Key : never]: (
@@ -118,7 +116,6 @@ export class OneBotMsgApi {
return {
type: OB11MessageDataType.image,
data: {
pic_type: element.picType,
summary: element.summary,
file: encodedFileId,
sub_type: element.picSubType,
@@ -453,7 +450,7 @@ export class OneBotMsgApi {
},
[OB11MessageDataType.face]: async ({ data: { id } }) => {
let parsedFaceId = parseInt(id);
let parsedFaceId = +id;
// 从face_config.json中获取表情名称
const sysFaces = faceConfig.sysface;
const face: any = sysFaces.find((systemFace) => systemFace.QSid === parsedFaceId.toString());
@@ -461,7 +458,6 @@ export class OneBotMsgApi {
this.core.context.logger.logError('不支持的ID', id);
return undefined;
}
parsedFaceId = parseInt(parsedFaceId.toString());
let faceType = 1;
if (parsedFaceId >= 222) {
faceType = 2;
@@ -889,16 +885,16 @@ export class OneBotMsgApi {
try {
for (const fileElement of sendElements) {
if (fileElement.elementType === ElementType.PTT) {
totalSize += fs.statSync(fileElement.pttElement.filePath).size;
totalSize += (await fsPromise.stat(fileElement.pttElement.filePath)).size;
}
if (fileElement.elementType === ElementType.FILE) {
totalSize += fs.statSync(fileElement.fileElement.filePath).size;
totalSize += (await fsPromise.stat(fileElement.fileElement.filePath)).size;
}
if (fileElement.elementType === ElementType.VIDEO) {
totalSize += fs.statSync(fileElement.videoElement.filePath).size;
totalSize += (await fsPromise.stat(fileElement.videoElement.filePath)).size;
}
if (fileElement.elementType === ElementType.PIC) {
totalSize += fs.statSync(fileElement.picElement.sourcePath).size;
totalSize += (await fsPromise.stat(fileElement.picElement.sourcePath)).size;
}
}
//且 PredictTime ((totalSize / 1024 / 512) * 1000)不等于Nan
@@ -918,9 +914,9 @@ export class OneBotMsgApi {
}, returnMsg.msgId);
setTimeout(() => {
deleteAfterSentFiles.forEach(file => {
deleteAfterSentFiles.forEach(async file => {
try {
if (fs.existsSync(file)) {
if (await fsPromise.access(file, constants.W_OK).then(() => true).catch(() => false)) {
fsPromise.unlink(file).then().catch(e => this.core.context.logger.logError('发送消息删除文件失败', e));
}
} catch (error) {
@@ -959,23 +955,22 @@ export class OneBotMsgApi {
}
groupChangDecreseType2String(type: number): GroupDecreaseSubType {
switch (type) {
case 130:
return 'leave';
case 131:
return 'kick';
case 3:
return 'kick_me';
default:
return 'kick';
case 130:
return 'leave';
case 131:
return 'kick';
case 3:
return 'kick_me';
default:
return 'kick';
}
}
async parseSysMessage(msg: number[]) {
// Todo Refactor
const SysMessage = new NapProtoMsg(PushMsgBody).decode(Uint8Array.from(msg));
if (SysMessage.contentHead.type == 33 && SysMessage.body?.msgContent) {
const groupChange = new NapProtoMsg(GroupChange).decode(SysMessage.body.msgContent);
console.log(JSON.stringify(groupChange));
this.core.apis.GroupApi.refreshGroupMemberCache(groupChange.groupUin.toString()).then().catch();
return new OB11GroupIncreaseEvent(
this.core,
groupChange.groupUin,
@@ -985,6 +980,7 @@ export class OneBotMsgApi {
);
} else if (SysMessage.contentHead.type == 34 && SysMessage.body?.msgContent) {
const groupChange = new NapProtoMsg(GroupChange).decode(SysMessage.body.msgContent);
this.core.apis.GroupApi.refreshGroupMemberCache(groupChange.groupUin.toString()).then().catch();
return new OB11GroupDecreaseEvent(
this.core,
groupChange.groupUin,
@@ -992,31 +988,26 @@ export class OneBotMsgApi {
groupChange.operatorUid ? +await this.core.apis.UserApi.getUinByUidV2(groupChange.operatorUid) : 0,
this.groupChangDecreseType2String(groupChange.decreaseType),
);
} else if (SysMessage.contentHead.type == 44 && SysMessage.body?.msgContent) {
const groupAmin = new NapProtoMsg(GroupAdmin).decode(SysMessage.body.msgContent);
this.core.apis.GroupApi.refreshGroupMemberCache(groupAmin.groupUin.toString()).then().catch();
let enabled = false;
let uid = '';
if (groupAmin.body.extraEnable != null) {
uid = groupAmin.body.extraEnable.adminUid;
enabled = true;
} else if (groupAmin.body.extraDisable != null) {
uid = groupAmin.body.extraDisable.adminUid;
enabled = false;
}
return new OB11GroupAdminNoticeEvent(
this.core,
groupAmin.groupUin,
+await this.core.apis.UserApi.getUinByUidV2(uid),
enabled ? 'set' : 'unset'
);
} else if (SysMessage.contentHead.type == 528 && SysMessage.contentHead.subType == 39 && SysMessage.body?.msgContent) {
return await this.obContext.apis.UserApi.parseLikeEvent(SysMessage.body?.msgContent);
}
/*
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);
}
}
*/
}
}

View File

@@ -1,4 +1,4 @@
import {
import type {
NapCatOneBot11Adapter,
OB11Message,
OB11MessageAt,
@@ -10,17 +10,19 @@ import {
QuickActionGroupMessage,
QuickActionGroupRequest,
} from '@/onebot';
import { NTGroupRequestOperateTypes, NapCatCore, Peer } from '@/core';
import { OB11FriendRequestEvent } from '@/onebot/event/request/OB11FriendRequest';
import { OB11GroupRequestEvent } from '@/onebot/event/request/OB11GroupRequest';
import { NTGroupRequestOperateTypes, type NapCatCore, type Peer } from '@/core';
import type { OB11FriendRequestEvent } from '@/onebot/event/request/OB11FriendRequest';
import type { OB11GroupRequestEvent } from '@/onebot/event/request/OB11GroupRequest';
import { ContextMode, createContext, normalize } from '@/onebot/action/msg/SendMsg';
import { isNull } from '@/common/helper';
export class OneBotQuickActionApi {
constructor(
public obContext: NapCatOneBot11Adapter,
public core: NapCatCore,
) {
private obContext: NapCatOneBot11Adapter;
private core: NapCatCore;
constructor(obContext: NapCatOneBot11Adapter, core: NapCatCore) {
this.obContext = obContext;
this.core = core;
}
async handleQuickOperation(eventContext: QuickActionEvent, quickAction: QuickAction) {

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