chore: run eslint --fix in onebot module

This commit is contained in:
Wesley F. Young
2024-08-09 20:35:03 +08:00
parent 714f8327ea
commit 5990e0c2eb
110 changed files with 3832 additions and 3829 deletions

View File

@@ -5,64 +5,64 @@ import Ajv, { ErrorObject, ValidateFunction } from 'ajv';
import { NapCatCore } from '@/core'; import { NapCatCore } from '@/core';
class BaseAction<PayloadType, ReturnDataType> { class BaseAction<PayloadType, ReturnDataType> {
actionName: ActionName = ActionName.Unknown; actionName: ActionName = ActionName.Unknown;
CoreContext: NapCatCore; CoreContext: NapCatCore;
private validate: undefined | ValidateFunction<any> = undefined; private validate: undefined | ValidateFunction<any> = undefined;
PayloadSchema: any = undefined; PayloadSchema: any = undefined;
constructor(context: NapCatCore) { constructor(context: NapCatCore) {
//注入上下文 //注入上下文
this.CoreContext = context; this.CoreContext = context;
}
protected async check(payload: PayloadType): Promise<BaseCheckResult> {
if (this.PayloadSchema) {
this.validate = new Ajv({ allowUnionTypes: true }).compile(this.PayloadSchema);
} }
if (this.validate && !this.validate(payload)) { protected async check(payload: PayloadType): Promise<BaseCheckResult> {
const errors = this.validate.errors as ErrorObject[]; if (this.PayloadSchema) {
const errorMessages: string[] = errors.map((e) => { this.validate = new Ajv({ allowUnionTypes: true }).compile(this.PayloadSchema);
return `Key: ${e.instancePath.split('/').slice(1).join('.')}, Message: ${e.message}`; }
}); if (this.validate && !this.validate(payload)) {
return { const errors = this.validate.errors as ErrorObject[];
valid: false, const errorMessages: string[] = errors.map((e) => {
message: errorMessages.join('\n') as string || '未知错误' return `Key: ${e.instancePath.split('/').slice(1).join('.')}, Message: ${e.message}`;
}; });
return {
valid: false,
message: errorMessages.join('\n') as string || '未知错误'
};
}
return {
valid: true
};
} }
return {
valid: true
};
}
public async handle(payload: PayloadType): Promise<OB11Return<ReturnDataType | null>> { public async handle(payload: PayloadType): Promise<OB11Return<ReturnDataType | null>> {
const result = await this.check(payload); const result = await this.check(payload);
if (!result.valid) { if (!result.valid) {
return OB11Response.error(result.message, 400); return OB11Response.error(result.message, 400);
}
try {
const resData = await this._handle(payload);
return OB11Response.ok(resData);
} catch (e: any) {
this.CoreContext.context.logger.logError('发生错误', e);
return OB11Response.error(e?.toString() || e?.stack?.toString() || '未知错误,可能操作超时', 200);
}
} }
try {
const resData = await this._handle(payload);
return OB11Response.ok(resData);
} catch (e: any) {
this.CoreContext.context.logger.logError('发生错误', e);
return OB11Response.error(e?.toString() || e?.stack?.toString() || '未知错误,可能操作超时', 200);
}
}
public async websocketHandle(payload: PayloadType, echo: any): Promise<OB11Return<ReturnDataType | null>> { public async websocketHandle(payload: PayloadType, echo: any): Promise<OB11Return<ReturnDataType | null>> {
const result = await this.check(payload); const result = await this.check(payload);
if (!result.valid) { if (!result.valid) {
return OB11Response.error(result.message, 1400); return OB11Response.error(result.message, 1400);
}
try {
const resData = await this._handle(payload);
return OB11Response.ok(resData, echo);
} catch (e: any) {
this.CoreContext.context.logger.logError('发生错误', e);
return OB11Response.error(e.stack?.toString() || e.toString(), 1200, echo);
}
} }
try {
const resData = await this._handle(payload);
return OB11Response.ok(resData, echo);
} catch (e: any) {
this.CoreContext.context.logger.logError('发生错误', e);
return OB11Response.error(e.stack?.toString() || e.toString(), 1200, echo);
}
}
protected async _handle(payload: PayloadType): Promise<ReturnDataType> { protected async _handle(payload: PayloadType): Promise<ReturnDataType> {
throw `pleas override ${this.actionName} _handle`; throw `pleas override ${this.actionName} _handle`;
} }
} }
export default BaseAction; export default BaseAction;

View File

@@ -3,30 +3,30 @@ import { OB11Return } from '../types';
import { isNull } from '../../common/utils/helper'; import { isNull } from '../../common/utils/helper';
export class OB11Response { export class OB11Response {
static res<T>(data: T, status: string, retcode: number, message: string = ''): OB11Return<T> { static res<T>(data: T, status: string, retcode: number, message: string = ''): OB11Return<T> {
return { return {
status: status, status: status,
retcode: retcode, retcode: retcode,
data: data, data: data,
message: message, message: message,
wording: message, wording: message,
echo: null echo: null
}; };
}
static ok<T>(data: T, echo: any = null) {
const res = OB11Response.res<T>(data, 'ok', 0);
if (!isNull(echo)) {
res.echo = echo;
} }
return res;
}
static error(err: string, retcode: number, echo: any = null) { static ok<T>(data: T, echo: any = null) {
const res = OB11Response.res(null, 'failed', retcode, err); const res = OB11Response.res<T>(data, 'ok', 0);
if (!isNull(echo)) { if (!isNull(echo)) {
res.echo = echo; res.echo = echo;
}
return res;
}
static error(err: string, retcode: number, echo: any = null) {
const res = OB11Response.res(null, 'failed', retcode, err);
if (!isNull(echo)) {
res.echo = echo;
}
return res;
} }
return res;
}
} }

View File

@@ -2,25 +2,25 @@ import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
rawData: { type: 'string' }, rawData: { type: 'string' },
brief: { type: 'string' } brief: { type: 'string' }
}, },
required: ['brief', 'rawData'], required: ['brief', 'rawData'],
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export class CreateCollection extends BaseAction<Payload, any> { export class CreateCollection extends BaseAction<Payload, any> {
actionName = ActionName.CreateCollection; actionName = ActionName.CreateCollection;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
return await this.CoreContext.getApiContext().CollectionApi.createCollection( return await this.CoreContext.getApiContext().CollectionApi.createCollection(
this.CoreContext.selfInfo.uin, this.CoreContext.selfInfo.uin,
this.CoreContext.selfInfo.uid, this.CoreContext.selfInfo.uid,
this.CoreContext.selfInfo.nick, this.CoreContext.selfInfo.nick,
payload.brief, payload.rawData payload.brief, payload.rawData
); );
} }
} }

View File

@@ -2,20 +2,20 @@ import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import BaseAction from '../BaseAction'; import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
count: { type: 'number' }, count: { type: 'number' },
} }
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export class FetchCustomFace extends BaseAction<Payload, string[]> { export class FetchCustomFace extends BaseAction<Payload, string[]> {
actionName = ActionName.FetchCustomFace; actionName = ActionName.FetchCustomFace;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
//48 可能正好是QQ需要的一个页面的数量 Tagged Mlikiowa //48 可能正好是QQ需要的一个页面的数量 Tagged Mlikiowa
const ret = await this.CoreContext.getApiContext().MsgApi.fetchFavEmojiList(payload.count || 48); const ret = await this.CoreContext.getApiContext().MsgApi.fetchFavEmojiList(payload.count || 48);
return ret.emojiInfoList.map(e => e.url); return ret.emojiInfoList.map(e => e.url);
} }
} }

View File

@@ -4,29 +4,29 @@ import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
import { MessageUnique } from '@/common/utils/MessageUnique'; import { MessageUnique } from '@/common/utils/MessageUnique';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
user_id: { type: 'string' }, user_id: { type: 'string' },
group_id: { type: 'string' }, group_id: { type: 'string' },
emojiId: { type: 'string' }, emojiId: { type: 'string' },
emojiType: { type: 'string' }, emojiType: { type: 'string' },
message_id: { type: ['string', 'number'] }, message_id: { type: ['string', 'number'] },
count: { type: 'number' } count: { type: 'number' }
}, },
required: ['emojiId', 'emojiType', 'message_id'] required: ['emojiId', 'emojiType', 'message_id']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export class FetchEmojioLike extends BaseAction<Payload, any> { export class FetchEmojioLike extends BaseAction<Payload, any> {
actionName = ActionName.FetchEmojioLike; actionName = ActionName.FetchEmojioLike;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi; const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi;
const msgIdPeer = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString())); const msgIdPeer = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString()));
if(!msgIdPeer) throw new Error('消息不存在'); if(!msgIdPeer) throw new Error('消息不存在');
const msg = (await NTQQMsgApi.getMsgsByMsgId(msgIdPeer.Peer, [msgIdPeer.MsgId])).msgList[0]; const msg = (await NTQQMsgApi.getMsgsByMsgId(msgIdPeer.Peer, [msgIdPeer.MsgId])).msgList[0];
const ret = await NTQQMsgApi.getMsgEmojiLikesList(msgIdPeer.Peer,msg.msgSeq,payload.emojiId,payload.emojiType,payload.count); const ret = await NTQQMsgApi.getMsgEmojiLikesList(msgIdPeer.Peer,msg.msgSeq,payload.emojiId,payload.emojiType,payload.count);
return ret; return ret;
} }
} }

View File

@@ -4,21 +4,21 @@ import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
category: { type: 'number' }, category: { type: 'number' },
count: { type: 'number' } count: { type: 'number' }
}, },
required: ['category', 'count'], required: ['category', 'count'],
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export class GetCollectionList extends BaseAction<Payload, any> { export class GetCollectionList extends BaseAction<Payload, any> {
actionName = ActionName.GetCollectionList; actionName = ActionName.GetCollectionList;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const NTQQCollectionApi = this.CoreContext.getApiContext().CollectionApi; const NTQQCollectionApi = this.CoreContext.getApiContext().CollectionApi;
return await NTQQCollectionApi.getAllCollection(payload.category, payload.count); return await NTQQCollectionApi.getAllCollection(payload.category, payload.count);
} }
} }

View File

@@ -4,14 +4,14 @@ import { ActionName } from '../types';
import { OB11Constructor } from '@/onebot/helper/constructor'; import { OB11Constructor } from '@/onebot/helper/constructor';
export class GetFriendWithCategory extends BaseAction<void, any> { export class GetFriendWithCategory extends BaseAction<void, any> {
actionName = ActionName.GetFriendsWithCategory; actionName = ActionName.GetFriendsWithCategory;
protected async _handle(payload: void) { protected async _handle(payload: void) {
if (this.CoreContext.context.basicInfoWrapper.requireMinNTQQBuild('26702')) { if (this.CoreContext.context.basicInfoWrapper.requireMinNTQQBuild('26702')) {
//全新逻辑 //全新逻辑
return OB11Constructor.friendsV2(await this.CoreContext.getApiContext().FriendApi.getBuddyV2ExWithCate(true)); return OB11Constructor.friendsV2(await this.CoreContext.getApiContext().FriendApi.getBuddyV2ExWithCate(true));
} else { } else {
throw new Error('this ntqq version not support, must be 26702 or later'); throw new Error('this ntqq version not support, must be 26702 or later');
}
} }
}
} }

View File

@@ -9,21 +9,21 @@ interface OB11GroupRequestNotify {
} }
export default class GetGroupAddRequest extends BaseAction<null, OB11GroupRequestNotify[] | null> { export default class GetGroupAddRequest extends BaseAction<null, OB11GroupRequestNotify[] | null> {
actionName = ActionName.GetGroupIgnoreAddRequest; actionName = ActionName.GetGroupIgnoreAddRequest;
protected async _handle(payload: null): Promise<OB11GroupRequestNotify[] | null> { protected async _handle(payload: null): Promise<OB11GroupRequestNotify[] | null> {
const data = await this.CoreContext.getApiContext().GroupApi.getGroupIgnoreNotifies(); const data = await this.CoreContext.getApiContext().GroupApi.getGroupIgnoreNotifies();
// log(data); // log(data);
// const notifies: GroupNotify[] = data.notifies.filter(notify => notify.status === GroupNotifyStatus.WAIT_HANDLE); // const notifies: GroupNotify[] = data.notifies.filter(notify => notify.status === GroupNotifyStatus.WAIT_HANDLE);
// const returnData: OB11GroupRequestNotify[] = []; // const returnData: OB11GroupRequestNotify[] = [];
// for (const notify of notifies) { // for (const notify of notifies) {
// const uin = || (await NTQQUserApi.getUserDetailInfo(notify.user1.uid))?.uin; // const uin = || (await NTQQUserApi.getUserDetailInfo(notify.user1.uid))?.uin;
// returnData.push({ // returnData.push({
// group_id: parseInt(notify.group.groupCode), // group_id: parseInt(notify.group.groupCode),
// user_id: parseInt(uin), // user_id: parseInt(uin),
// flag: notify.seq // flag: notify.seq
// }); // });
// } // }
return null; return null;
} }
} }

View File

@@ -1,14 +1,14 @@
import BaseAction from '../BaseAction'; import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
export class GetProfileLike extends BaseAction<void, any> { export class GetProfileLike extends BaseAction<void, any> {
actionName = ActionName.GetProfileLike; actionName = ActionName.GetProfileLike;
protected async _handle(payload: void) { protected async _handle(payload: void) {
const NTQQUserApi = this.CoreContext.getApiContext().UserApi; const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
const ret = await NTQQUserApi.getProfileLike(this.CoreContext.selfInfo.uid); const ret = await NTQQUserApi.getProfileLike(this.CoreContext.selfInfo.uid);
const listdata: any[] = ret.info.userLikeInfos[0].favoriteInfo.userInfos; const listdata: any[] = ret.info.userLikeInfos[0].favoriteInfo.userInfos;
for (let i = 0; i < listdata.length; i++) { for (let i = 0; i < listdata.length; i++) {
listdata[i].uin = parseInt((await NTQQUserApi.getUinByUid(listdata[i].uid)) || ''); listdata[i].uin = parseInt((await NTQQUserApi.getUinByUid(listdata[i].uid)) || '');
}
return listdata;
} }
return listdata;
}
} }

View File

@@ -2,11 +2,11 @@ import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
import { NTQQUserApi } from '@/core/apis'; import { NTQQUserApi } from '@/core/apis';
export class GetRobotUinRange extends BaseAction<void, Array<any>> { export class GetRobotUinRange extends BaseAction<void, Array<any>> {
actionName = ActionName.GetRobotUinRange; actionName = ActionName.GetRobotUinRange;
protected async _handle(payload: void) { protected async _handle(payload: void) {
// console.log(await NTQQUserApi.getRobotUinRange()); // console.log(await NTQQUserApi.getRobotUinRange());
const NTQQUserApi = this.CoreContext.getApiContext().UserApi; const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
return await NTQQUserApi.getRobotUinRange(); return await NTQQUserApi.getRobotUinRange();
} }
} }

View File

@@ -5,41 +5,41 @@ import { checkFileReceived, uri2local } from '@/common/utils/file';
import fs from 'fs'; import fs from 'fs';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
image: { type: 'string' }, image: { type: 'string' },
}, },
required: ['image'] required: ['image']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export class OCRImage extends BaseAction<Payload, any> { export class OCRImage extends BaseAction<Payload, any> {
actionName = ActionName.OCRImage; actionName = ActionName.OCRImage;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const NTQQSystemApi = this.CoreContext.getApiContext().SystemApi; const NTQQSystemApi = this.CoreContext.getApiContext().SystemApi;
const { path, isLocal, errMsg,success } = (await uri2local(this.CoreContext.NapCatTempPath,payload.image)); const { path, isLocal, errMsg,success } = (await uri2local(this.CoreContext.NapCatTempPath,payload.image));
if (!success) { if (!success) {
throw `OCR ${payload.image}失败,image字段可能格式不正确`; throw `OCR ${payload.image}失败,image字段可能格式不正确`;
}
if (path) {
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃需要提前判断
const ret = await NTQQSystemApi.ORCImage(path);
if (!isLocal) {
fs.unlink(path, () => { });
}
if (!ret) {
throw `OCR ${payload.file}失败`;
}
return ret.result;
}
if (!isLocal) {
fs.unlink(path, () => { });
}
throw `OCR ${payload.file}失败,文件可能不存在`;
} }
if (path) {
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃需要提前判断
const ret = await NTQQSystemApi.ORCImage(path);
if (!isLocal) {
fs.unlink(path, () => { });
}
if (!ret) {
throw `OCR ${payload.file}失败`;
}
return ret.result;
}
if (!isLocal) {
fs.unlink(path, () => { });
}
throw `OCR ${payload.file}失败,文件可能不存在`;
}
} }
export class IOCRImage extends OCRImage { export class IOCRImage extends OCRImage {
actionName = ActionName.IOCRImage; actionName = ActionName.IOCRImage;
} }

View File

@@ -11,47 +11,47 @@ interface Payload {
} }
export default class SetGroupHeader extends BaseAction<Payload, any> { export default class SetGroupHeader extends BaseAction<Payload, any> {
actionName = ActionName.SetGroupHeader; actionName = ActionName.SetGroupHeader;
// 用不着复杂检测 // 用不着复杂检测
protected async check(payload: Payload): Promise<BaseCheckResult> { protected async check(payload: Payload): Promise<BaseCheckResult> {
if (!payload.file || typeof payload.file != 'string' || !payload.groupCode || typeof payload.groupCode != 'string') { if (!payload.file || typeof payload.file != 'string' || !payload.groupCode || typeof payload.groupCode != 'string') {
return { return {
valid: false, valid: false,
message: 'file和groupCode字段不能为空或者类型错误', message: 'file和groupCode字段不能为空或者类型错误',
}; };
}
return {
valid: true,
};
} }
return { protected async _handle(payload: Payload): Promise<any> {
valid: true, const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
}; const { path, isLocal, errMsg, success } = (await uri2local(this.CoreContext.NapCatTempPath, payload.file));
} if (!success) {
protected async _handle(payload: Payload): Promise<any> { throw `头像${payload.file}设置失败,file字段可能格式不正确`;
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi; }
const { path, isLocal, errMsg, success } = (await uri2local(this.CoreContext.NapCatTempPath, payload.file)); if (path) {
if (!success) { await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃需要提前判断
throw `头像${payload.file}设置失败,file字段可能格式不正确`; const ret = await NTQQGroupApi.setGroupAvatar(payload.groupCode, path);
if (!isLocal) {
fs.unlink(path, () => { });
}
if (!ret) {
throw `头像${payload.file}设置失败,api无返回`;
}
// log(`头像设置返回:${JSON.stringify(ret)}`)
// if (ret['result'] == 1004022) {
// throw `头像${payload.file}设置失败,文件可能不是图片格式`;
// } else if (ret['result'] != 0) {
// throw `头像${payload.file}设置失败,未知的错误,${ret['result']}:${ret['errMsg']}`;
// }
return ret;
} else {
if (!isLocal) {
fs.unlink(path, () => { });
}
throw `头像${payload.file}设置失败,无法获取头像,文件可能不存在`;
}
return null;
} }
if (path) {
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃需要提前判断
const ret = await NTQQGroupApi.setGroupAvatar(payload.groupCode, path);
if (!isLocal) {
fs.unlink(path, () => { });
}
if (!ret) {
throw `头像${payload.file}设置失败,api无返回`;
}
// log(`头像设置返回:${JSON.stringify(ret)}`)
// if (ret['result'] == 1004022) {
// throw `头像${payload.file}设置失败,文件可能不是图片格式`;
// } else if (ret['result'] != 0) {
// throw `头像${payload.file}设置失败,未知的错误,${ret['result']}:${ret['errMsg']}`;
// }
return ret;
} else {
if (!isLocal) {
fs.unlink(path, () => { });
}
throw `头像${payload.file}设置失败,无法获取头像,文件可能不存在`;
}
return null;
}
} }

View File

@@ -5,21 +5,21 @@ import { NTQQUserApi } from '@/core/apis';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
longNick: { type: 'string' }, longNick: { type: 'string' },
}, },
required: [ 'longNick'], required: [ 'longNick'],
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export class SetLongNick extends BaseAction<Payload, any> { export class SetLongNick extends BaseAction<Payload, any> {
actionName = ActionName.SetLongNick; actionName = ActionName.SetLongNick;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const NTQQUserApi = this.CoreContext.getApiContext().UserApi; const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
const ret = await NTQQUserApi.setLongNick(payload.longNick); const ret = await NTQQUserApi.setLongNick(payload.longNick);
return ret; return ret;
} }
} }

View File

@@ -5,32 +5,32 @@ import { FromSchema, JSONSchema } from 'json-schema-to-ts';
// 设置在线状态 // 设置在线状态
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
status: { type: 'number' }, status: { type: 'number' },
extStatus: { type: 'number' }, extStatus: { type: 'number' },
batteryStatus: { type: 'number' } batteryStatus: { type: 'number' }
}, },
required: ['status', 'extStatus', 'batteryStatus'], required: ['status', 'extStatus', 'batteryStatus'],
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export class SetOnlineStatus extends BaseAction<Payload, null> { export class SetOnlineStatus extends BaseAction<Payload, null> {
actionName = ActionName.SetOnlineStatus; actionName = ActionName.SetOnlineStatus;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
// 可设置状态 // 可设置状态
// { status: 10, extStatus: 1027, batteryStatus: 0 } // { status: 10, extStatus: 1027, batteryStatus: 0 }
// { status: 30, extStatus: 0, batteryStatus: 0 } // { status: 30, extStatus: 0, batteryStatus: 0 }
// { status: 50, extStatus: 0, batteryStatus: 0 } // { status: 50, extStatus: 0, batteryStatus: 0 }
// { status: 60, extStatus: 0, batteryStatus: 0 } // { status: 60, extStatus: 0, batteryStatus: 0 }
// { status: 70, extStatus: 0, batteryStatus: 0 } // { status: 70, extStatus: 0, batteryStatus: 0 }
const NTQQUserApi = this.CoreContext.getApiContext().UserApi; const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
const ret = await NTQQUserApi.setSelfOnlineStatus(payload.status, payload.extStatus, payload.batteryStatus); const ret = await NTQQUserApi.setSelfOnlineStatus(payload.status, payload.extStatus, payload.batteryStatus);
if (ret.result !== 0) { if (ret.result !== 0) {
throw new Error('设置在线状态失败'); throw new Error('设置在线状态失败');
}
return null;
} }
return null;
}
} }

View File

@@ -7,46 +7,46 @@ interface Payload {
} }
export default class SetAvatar extends BaseAction<Payload, null> { export default class SetAvatar extends BaseAction<Payload, null> {
actionName = ActionName.SetQQAvatar; actionName = ActionName.SetQQAvatar;
// 用不着复杂检测 // 用不着复杂检测
protected async check(payload: Payload): Promise<BaseCheckResult> { protected async check(payload: Payload): Promise<BaseCheckResult> {
if (!payload.file || typeof payload.file != 'string') { if (!payload.file || typeof payload.file != 'string') {
return { return {
valid: false, valid: false,
message: 'file字段不能为空或者类型错误', message: 'file字段不能为空或者类型错误',
}; };
}
return {
valid: true,
};
} }
return { protected async _handle(payload: Payload): Promise<null> {
valid: true, const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
}; const { path, isLocal, errMsg, success } = (await uri2local(this.CoreContext.NapCatTempPath, payload.file));
} if (!success) {
protected async _handle(payload: Payload): Promise<null> { throw `头像${payload.file}设置失败,file字段可能格式不正确`;
const NTQQUserApi = this.CoreContext.getApiContext().UserApi; }
const { path, isLocal, errMsg, success } = (await uri2local(this.CoreContext.NapCatTempPath, payload.file)); if (path) {
if (!success) { await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃需要提前判断
throw `头像${payload.file}设置失败,file字段可能格式不正确`; const ret = await NTQQUserApi.setQQAvatar(path);
if (!isLocal) {
fs.unlink(path, () => { });
}
if (!ret) {
throw `头像${payload.file}设置失败,api无返回`;
}
// log(`头像设置返回:${JSON.stringify(ret)}`)
if (ret['result'] == 1004022) {
throw `头像${payload.file}设置失败,文件可能不是图片格式`;
} else if (ret['result'] != 0) {
throw `头像${payload.file}设置失败,未知的错误,${ret['result']}:${ret['errMsg']}`;
}
} else {
if (!isLocal) {
fs.unlink(path, () => { });
}
throw `头像${payload.file}设置失败,无法获取头像,文件可能不存在`;
}
return null;
} }
if (path) {
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃需要提前判断
const ret = await NTQQUserApi.setQQAvatar(path);
if (!isLocal) {
fs.unlink(path, () => { });
}
if (!ret) {
throw `头像${payload.file}设置失败,api无返回`;
}
// log(`头像设置返回:${JSON.stringify(ret)}`)
if (ret['result'] == 1004022) {
throw `头像${payload.file}设置失败,文件可能不是图片格式`;
} else if (ret['result'] != 0) {
throw `头像${payload.file}设置失败,未知的错误,${ret['result']}:${ret['errMsg']}`;
}
} else {
if (!isLocal) {
fs.unlink(path, () => { });
}
throw `头像${payload.file}设置失败,无法获取头像,文件可能不存在`;
}
return null;
}
} }

View File

@@ -4,29 +4,29 @@ import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
nick: { type: 'string' }, nick: { type: 'string' },
longNick: { type: 'string' }, longNick: { type: 'string' },
sex: { type: 'number' }//传Sex值建议传0 sex: { type: 'number' }//传Sex值建议传0
}, },
required: ['nick', 'longNick', 'sex'], required: ['nick', 'longNick', 'sex'],
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export class SetSelfProfile extends BaseAction<Payload, any | null> { export class SetSelfProfile extends BaseAction<Payload, any | null> {
actionName = ActionName.SetSelfProfile; actionName = ActionName.SetSelfProfile;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const NTQQUserApi = this.CoreContext.getApiContext().UserApi; const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
const ret = await NTQQUserApi.modifySelfProfile({ const ret = await NTQQUserApi.modifySelfProfile({
nick: payload.nick, nick: payload.nick,
longNick: payload.longNick, longNick: payload.longNick,
sex: payload.sex, sex: payload.sex,
birthday: { birthday_year: '', birthday_month: '', birthday_day: '' }, birthday: { birthday_year: '', birthday_month: '', birthday_day: '' },
location: undefined location: undefined
}); });
return ret; return ret;
} }
} }

View File

@@ -4,27 +4,27 @@ import { NTQQSystemApi } from '@/core/apis';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
words: { words: {
type: 'array', type: 'array',
items: { type: 'string' } items: { type: 'string' }
} }
}, },
required: ['words'], required: ['words'],
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export class TranslateEnWordToZn extends BaseAction<Payload, Array<any> | null> { export class TranslateEnWordToZn extends BaseAction<Payload, Array<any> | null> {
actionName = ActionName.TranslateEnWordToZn; actionName = ActionName.TranslateEnWordToZn;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const NTQQSystemApi = this.CoreContext.getApiContext().SystemApi; const NTQQSystemApi = this.CoreContext.getApiContext().SystemApi;
const ret = await NTQQSystemApi.translateEnWordToZn(payload.words); const ret = await NTQQSystemApi.translateEnWordToZn(payload.words);
if (ret.result !== 0) { if (ret.result !== 0) {
throw new Error('翻译失败'); throw new Error('翻译失败');
}
return ret.words;
} }
return ret.words;
}
} }

View File

@@ -3,44 +3,44 @@ import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
user_id: { type: 'string' }, user_id: { type: 'string' },
group_id: { type: 'string' }, group_id: { type: 'string' },
phoneNumber: { type: 'string' }, phoneNumber: { type: 'string' },
}, },
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export class sharePeer extends BaseAction<Payload, any> { export class sharePeer extends BaseAction<Payload, any> {
actionName = ActionName.SharePeer; actionName = ActionName.SharePeer;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const NTQQUserApi = this.CoreContext.getApiContext().UserApi; const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi; const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
if (payload.group_id) { if (payload.group_id) {
return await NTQQGroupApi.getGroupRecommendContactArkJson(payload.group_id); return await NTQQGroupApi.getGroupRecommendContactArkJson(payload.group_id);
} else if (payload.user_id) { } else if (payload.user_id) {
return await NTQQUserApi.getBuddyRecommendContactArkJson(payload.user_id, payload.phoneNumber || ''); return await NTQQUserApi.getBuddyRecommendContactArkJson(payload.user_id, payload.phoneNumber || '');
}
} }
}
} }
const SchemaDataGroupEx = { const SchemaDataGroupEx = {
type: 'object', type: 'object',
properties: { properties: {
group_id: { type: 'string' }, group_id: { type: 'string' },
}, },
required: ['group_id'] required: ['group_id']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type PayloadGroupEx = FromSchema<typeof SchemaDataGroupEx>; type PayloadGroupEx = FromSchema<typeof SchemaDataGroupEx>;
export class shareGroupEx extends BaseAction<PayloadGroupEx, any> { export class shareGroupEx extends BaseAction<PayloadGroupEx, any> {
actionName = ActionName.ShareGroupEx; actionName = ActionName.ShareGroupEx;
PayloadSchema = SchemaDataGroupEx; PayloadSchema = SchemaDataGroupEx;
protected async _handle(payload: PayloadGroupEx) { protected async _handle(payload: PayloadGroupEx) {
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi; const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
return await NTQQGroupApi.getArkJsonGroupShare(payload.group_id); return await NTQQGroupApi.getArkJsonGroupShare(payload.group_id);
} }
} }

View File

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

View File

@@ -4,21 +4,21 @@ import { ActionName } from '../types';
import { NTQQGroupApi, NTQQMsgApi, NTQQUserApi } from '@/core/apis'; import { NTQQGroupApi, NTQQMsgApi, NTQQUserApi } from '@/core/apis';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
group_id: { type: ['string', 'number'] }, group_id: { type: ['string', 'number'] },
folder_id: { type: 'string' }, folder_id: { type: 'string' },
}, },
required: ['group_id', 'folder_id'] required: ['group_id', 'folder_id']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export class DelGroupFileFolder extends BaseAction<Payload, any> { export class DelGroupFileFolder extends BaseAction<Payload, any> {
actionName = ActionName.DelGroupFileFolder; actionName = ActionName.DelGroupFileFolder;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi; const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
return (await NTQQGroupApi.DelGroupFileFolder(payload.group_id.toString(), payload.folder_id)).groupFileCommonResult; return (await NTQQGroupApi.DelGroupFileFolder(payload.group_id.toString(), payload.folder_id)).groupFileCommonResult;
} }
} }

View File

@@ -17,170 +17,170 @@ export interface GetFileResponse {
base64?: string; base64?: string;
} }
const GetFileBase_PayloadSchema = { const GetFileBase_PayloadSchema = {
type: 'object', type: 'object',
properties: { properties: {
file: { type: 'string' } file: { type: 'string' }
}, },
required: ['file'] required: ['file']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> { export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
PayloadSchema: any = GetFileBase_PayloadSchema; PayloadSchema: any = GetFileBase_PayloadSchema;
private getElement(msg: RawMessage): { id: string, element: VideoElement | FileElement } { private getElement(msg: RawMessage): { id: string, element: VideoElement | FileElement } {
let element = msg.elements.find(e => e.fileElement); let element = msg.elements.find(e => e.fileElement);
if (!element) { if (!element) {
element = msg.elements.find(e => e.videoElement); element = msg.elements.find(e => e.videoElement);
if (element) { if (element) {
return { id: element.elementId, element: element.videoElement }; return { id: element.elementId, element: element.videoElement };
} else { } else {
throw new Error('找不到文件'); throw new Error('找不到文件');
} }
}
return { id: element.elementId, element: element.fileElement };
} }
return { id: element.elementId, element: element.fileElement }; protected async _handle(payload: GetFilePayload): Promise<GetFileResponse> {
} const NTQQFriendApi = this.CoreContext.getApiContext().FriendApi;
protected async _handle(payload: GetFilePayload): Promise<GetFileResponse> { const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
const NTQQFriendApi = this.CoreContext.getApiContext().FriendApi; const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi;
const NTQQUserApi = this.CoreContext.getApiContext().UserApi; const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi; const NTQQFileApi = this.CoreContext.getApiContext().FileApi;
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi; let UuidData: {
const NTQQFileApi = this.CoreContext.getApiContext().FileApi;
let UuidData: {
high: string; high: string;
low: string; low: string;
} | undefined; } | undefined;
try {
UuidData = UUIDConverter.decode(payload.file);
if (UuidData) {
const peerUin = UuidData.high;
const msgId = UuidData.low;
const isGroup: boolean = !!(await NTQQGroupApi.getGroups(false)).find(e => e.groupCode == peerUin);
let peer: Peer | undefined;
//识别Peer
if (isGroup) {
peer = { chatType: ChatType.group, peerUid: peerUin };
}
const PeerUid = await NTQQUserApi.getUidByUin(peerUin);
if (PeerUid) {
const isBuddy = await NTQQFriendApi.isBuddy(PeerUid);
if (isBuddy) {
peer = { chatType: ChatType.friend, peerUid: PeerUid };
} else {
peer = { chatType: ChatType.temp, peerUid: PeerUid };
}
}
if (!peer) {
throw new Error('chattype not support');
}
const msgList = await NTQQMsgApi.getMsgsByMsgId(peer, [msgId]);
if (msgList.msgList.length == 0) {
throw new Error('msg not found');
}
const msg = msgList.msgList[0];
const findEle = msg.elements.find(e => e.elementType == ElementType.VIDEO || e.elementType == ElementType.FILE || e.elementType == ElementType.PTT);
if (!findEle) {
throw new Error('element not found');
}
const downloadPath = await NTQQFileApi.downloadMedia(msgId, msg.chatType, msg.peerUid, findEle.elementId, '', '');
const fileSize = findEle?.videoElement?.fileSize || findEle?.fileElement?.fileSize || findEle?.pttElement?.fileSize || '0';
const fileName = findEle?.videoElement?.fileName || findEle?.fileElement?.fileName || findEle?.pttElement?.fileName || '';
const res: GetFileResponse = {
file: downloadPath,
url: downloadPath,
file_size: fileSize,
file_name: fileName
};
if (true/*enableLocalFile2Url*/) {
try {
res.base64 = await fs.readFile(downloadPath, 'base64');
} catch (e) {
throw new Error('文件下载失败. ' + e);
}
}
//不手动删除?文件持久化了
return res;
}
} catch {
}
const NTSearchNameResult = (await NTQQFileApi.searchfile([payload.file])).resultItems;
if (NTSearchNameResult.length !== 0) {
const MsgId = NTSearchNameResult[0].msgId;
let peer: Peer | undefined = undefined;
if (NTSearchNameResult[0].chatType == ChatType.group) {
peer = { chatType: ChatType.group, peerUid: NTSearchNameResult[0].groupChatInfo[0].groupCode };
}
if (!peer) {
throw new Error('chattype not support');
}
const msgList: RawMessage[] = (await NTQQMsgApi.getMsgsByMsgId(peer, [MsgId]))?.msgList;
if (!msgList || msgList.length == 0) {
throw new Error('msg not found');
}
const msg = msgList[0];
const file = msg.elements.filter(e => e.elementType == NTSearchNameResult[0].elemType);
if (file.length == 0) {
throw new Error('file not found');
}
const downloadPath = await NTQQFileApi.downloadMedia(msg.msgId, msg.chatType, msg.peerUid, file[0].elementId, '', '');
const res: GetFileResponse = {
file: downloadPath,
url: downloadPath,
file_size: NTSearchNameResult[0].fileSize.toString(),
file_name: NTSearchNameResult[0].fileName
};
if (true/*enableLocalFile2Url*/) {
try { try {
res.base64 = await fs.readFile(downloadPath, 'base64'); UuidData = UUIDConverter.decode(payload.file);
} catch (e) { if (UuidData) {
throw new Error('文件下载失败. ' + e); const peerUin = UuidData.high;
} const msgId = UuidData.low;
} const isGroup: boolean = !!(await NTQQGroupApi.getGroups(false)).find(e => e.groupCode == peerUin);
//不手动删除?文件持久化了 let peer: Peer | undefined;
return res; //识别Peer
} if (isGroup) {
throw new Error('file not found'); peer = { chatType: ChatType.group, peerUid: peerUin };
// let cache = await dbUtil.getFileCacheByName(payload.file); }
// if (!cache) { const PeerUid = await NTQQUserApi.getUidByUin(peerUin);
// cache = await dbUtil.getFileCacheByUuid(payload.file); if (PeerUid) {
// } const isBuddy = await NTQQFriendApi.isBuddy(PeerUid);
// if (!cache) { if (isBuddy) {
// throw new Error('file not found'); peer = { chatType: ChatType.friend, peerUid: PeerUid };
// } } else {
// const { enableLocalFile2Url } = ob11Config; peer = { chatType: ChatType.temp, peerUid: PeerUid };
// try { }
// await fs.access(cache.path, fs.constants.F_OK); }
// } catch (e) { if (!peer) {
// logDebug('local file not found, start download...'); throw new Error('chattype not support');
// // if (cache.url) { }
// // const downloadResult = await uri2local(cache.url); const msgList = await NTQQMsgApi.getMsgsByMsgId(peer, [msgId]);
// // if (downloadResult.success) { if (msgList.msgList.length == 0) {
// // cache.path = downloadResult.path; throw new Error('msg not found');
// // dbUtil.updateFileCache(cache).then(); }
// // } else { const msg = msgList.msgList[0];
// // throw new Error('file download failed. ' + downloadResult.errMsg); const findEle = msg.elements.find(e => e.elementType == ElementType.VIDEO || e.elementType == ElementType.FILE || e.elementType == ElementType.PTT);
// // } if (!findEle) {
// // } else { throw new Error('element not found');
// // // 没有url的可能是私聊文件或者群文件需要自己下载 }
// // log('需要调用 NTQQ 下载文件api'); const downloadPath = await NTQQFileApi.downloadMedia(msgId, msg.chatType, msg.peerUid, findEle.elementId, '', '');
// let peer = MessageUnique.getPeerByMsgId(cache.msgId); const fileSize = findEle?.videoElement?.fileSize || findEle?.fileElement?.fileSize || findEle?.pttElement?.fileSize || '0';
// let msg = await NTQQMsgApi.getMsgsByMsgId(peer?.Peer!,cache.msgId); const fileName = findEle?.videoElement?.fileName || findEle?.fileElement?.fileName || findEle?.pttElement?.fileName || '';
// // log('文件 msg', msg); const res: GetFileResponse = {
// if (msg) { file: downloadPath,
// // 构建下载函数 url: downloadPath,
// const downloadPath = await NTQQFileApi.downloadMedia(msg.msgId, msg.chatType, msg.peerUid, file_size: fileSize,
// cache.elementId, '', ''); file_name: fileName
// // await sleep(1000); };
if (true/*enableLocalFile2Url*/) {
try {
res.base64 = await fs.readFile(downloadPath, 'base64');
} catch (e) {
throw new Error('文件下载失败. ' + e);
}
}
//不手动删除?文件持久化了
return res;
}
} catch {
// // log('download result', downloadPath); }
// let peer = MessageUnique.getPeerByMsgId(cache.msgId);
// msg = await NTQQMsgApi.getMsgsByMsgId(peer?.Peer!,cache.msgId); const NTSearchNameResult = (await NTQQFileApi.searchfile([payload.file])).resultItems;
// // log('下载完成后的msg', msg); if (NTSearchNameResult.length !== 0) {
// cache.path = downloadPath!; const MsgId = NTSearchNameResult[0].msgId;
// dbUtil.updateFileCache(cache).then(); let peer: Peer | undefined = undefined;
// // log('下载完成后的msg', msg); if (NTSearchNameResult[0].chatType == ChatType.group) {
// // } peer = { chatType: ChatType.group, peerUid: NTSearchNameResult[0].groupChatInfo[0].groupCode };
// } }
if (!peer) {
throw new Error('chattype not support');
}
const msgList: RawMessage[] = (await NTQQMsgApi.getMsgsByMsgId(peer, [MsgId]))?.msgList;
if (!msgList || msgList.length == 0) {
throw new Error('msg not found');
}
const msg = msgList[0];
const file = msg.elements.filter(e => e.elementType == NTSearchNameResult[0].elemType);
if (file.length == 0) {
throw new Error('file not found');
}
const downloadPath = await NTQQFileApi.downloadMedia(msg.msgId, msg.chatType, msg.peerUid, file[0].elementId, '', '');
const res: GetFileResponse = {
file: downloadPath,
url: downloadPath,
file_size: NTSearchNameResult[0].fileSize.toString(),
file_name: NTSearchNameResult[0].fileName
};
if (true/*enableLocalFile2Url*/) {
try {
res.base64 = await fs.readFile(downloadPath, 'base64');
} catch (e) {
throw new Error('文件下载失败. ' + e);
}
}
//不手动删除?文件持久化了
return res;
}
throw new Error('file not found');
// let cache = await dbUtil.getFileCacheByName(payload.file);
// if (!cache) {
// cache = await dbUtil.getFileCacheByUuid(payload.file);
// }
// if (!cache) {
// throw new Error('file not found');
// }
// const { enableLocalFile2Url } = ob11Config;
// try {
// await fs.access(cache.path, fs.constants.F_OK);
// } catch (e) {
// logDebug('local file not found, start download...');
// // if (cache.url) {
// // const downloadResult = await uri2local(cache.url);
// // if (downloadResult.success) {
// // cache.path = downloadResult.path;
// // dbUtil.updateFileCache(cache).then();
// // } else {
// // throw new Error('file download failed. ' + downloadResult.errMsg);
// // }
// // } else {
// // // 没有url的可能是私聊文件或者群文件需要自己下载
// // log('需要调用 NTQQ 下载文件api');
// let peer = MessageUnique.getPeerByMsgId(cache.msgId);
// let msg = await NTQQMsgApi.getMsgsByMsgId(peer?.Peer!,cache.msgId);
// // log('文件 msg', msg);
// if (msg) {
// // 构建下载函数
// const downloadPath = await NTQQFileApi.downloadMedia(msg.msgId, msg.chatType, msg.peerUid,
// cache.elementId, '', '');
// // await sleep(1000);
// // log('download result', downloadPath);
// let peer = MessageUnique.getPeerByMsgId(cache.msgId);
// msg = await NTQQMsgApi.getMsgsByMsgId(peer?.Peer!,cache.msgId);
// // log('下载完成后的msg', msg);
// cache.path = downloadPath!;
// dbUtil.updateFileCache(cache).then();
// // log('下载完成后的msg', msg);
// // }
// }
// } // }
// // log('file found', cache); // // log('file found', cache);
@@ -200,16 +200,16 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
// } // }
// } // }
//return res; //return res;
} }
} }
const GetFile_PayloadSchema = { const GetFile_PayloadSchema = {
type: 'object', type: 'object',
properties: { properties: {
file_id: { type: 'string' }, file_id: { type: 'string' },
file: { type: 'string' } file: { type: 'string' }
}, },
required: ['file_id'] required: ['file_id']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type GetFile_Payload_Internal = FromSchema<typeof GetFile_PayloadSchema>; type GetFile_Payload_Internal = FromSchema<typeof GetFile_PayloadSchema>;
@@ -219,10 +219,10 @@ interface GetFile_Payload extends GetFile_Payload_Internal {
} }
export default class GetFile extends GetFileBase { export default class GetFile extends GetFileBase {
actionName = ActionName.GetFile; actionName = ActionName.GetFile;
PayloadSchema = GetFile_PayloadSchema; PayloadSchema = GetFile_PayloadSchema;
protected async _handle(payload: GetFile_Payload): Promise<GetFileResponse> { protected async _handle(payload: GetFile_Payload): Promise<GetFileResponse> {
payload.file = payload.file_id; payload.file = payload.file_id;
return super._handle(payload); return super._handle(payload);
} }
} }

View File

@@ -4,21 +4,21 @@ import { ActionName } from '../types';
import { NTQQGroupApi, NTQQUserApi } from '@/core/apis'; import { NTQQGroupApi, NTQQUserApi } from '@/core/apis';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
group_id: { type: ['string', 'number'] }, group_id: { type: ['string', 'number'] },
}, },
required: ['group_id'] required: ['group_id']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export class GetGroupFileCount extends BaseAction<Payload, { count: number }> { export class GetGroupFileCount extends BaseAction<Payload, { count: number }> {
actionName = ActionName.GetGroupFileCount; actionName = ActionName.GetGroupFileCount;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi; const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
const ret = await NTQQGroupApi.GetGroupFileCount([payload.group_id?.toString()]); const ret = await NTQQGroupApi.GetGroupFileCount([payload.group_id?.toString()]);
return { count: ret.groupFileCounts[0] }; return { count: ret.groupFileCounts[0] };
} }
} }

View File

@@ -2,29 +2,29 @@ import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import BaseAction from '../BaseAction'; import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
group_id: { type: ['string', 'number'] }, group_id: { type: ['string', 'number'] },
start_index: { type: 'number' }, start_index: { type: 'number' },
file_count: { type: 'number' }, file_count: { type: 'number' },
}, },
required: ['group_id', 'start_index', 'file_count'] required: ['group_id', 'start_index', 'file_count']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export class GetGroupFileList extends BaseAction<Payload, { FileList: Array<any> }> { export class GetGroupFileList extends BaseAction<Payload, { FileList: Array<any> }> {
actionName = ActionName.GetGroupFileList; actionName = ActionName.GetGroupFileList;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi; const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi;
const ret = await NTQQMsgApi.getGroupFileList(payload.group_id.toString(), { const ret = await NTQQMsgApi.getGroupFileList(payload.group_id.toString(), {
sortType: 1, sortType: 1,
fileCount: payload.file_count, fileCount: payload.file_count,
startIndex: payload.start_index, startIndex: payload.start_index,
sortOrder: 2, sortOrder: 2,
showOnlinedocFolder: 0 showOnlinedocFolder: 0
}).catch((e) => { return []; }); }).catch((e) => { return []; });
return { FileList: ret }; return { FileList: ret };
} }
} }

View File

@@ -3,5 +3,5 @@ import { ActionName } from '../types';
export default class GetImage extends GetFileBase { export default class GetImage extends GetFileBase {
actionName = ActionName.GetImage; actionName = ActionName.GetImage;
} }

View File

@@ -6,10 +6,10 @@ interface Payload extends GetFilePayload {
} }
export default class GetRecord extends GetFileBase { export default class GetRecord extends GetFileBase {
actionName = ActionName.GetRecord; actionName = ActionName.GetRecord;
protected async _handle(payload: Payload): Promise<GetFileResponse> { protected async _handle(payload: Payload): Promise<GetFileResponse> {
const res = super._handle(payload); const res = super._handle(payload);
return res; return res;
} }
} }

View File

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

View File

@@ -9,74 +9,74 @@ interface FileResponse {
file: string; file: string;
} }
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
thread_count: { type: 'number' }, thread_count: { type: 'number' },
url: { type: 'string' }, url: { type: 'string' },
base64: { type: 'string' }, base64: { type: 'string' },
name: { type: 'string' }, name: { type: 'string' },
headers: { headers: {
type: ['string', 'array'], type: ['string', 'array'],
items: { items: {
type: 'string' type: 'string'
} }
} }
}, },
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export default class GoCQHTTPDownloadFile extends BaseAction<Payload, FileResponse> { export default class GoCQHTTPDownloadFile extends BaseAction<Payload, FileResponse> {
actionName = ActionName.GoCQHTTP_DownloadFile; actionName = ActionName.GoCQHTTP_DownloadFile;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload): Promise<FileResponse> { protected async _handle(payload: Payload): Promise<FileResponse> {
const isRandomName = !payload.name; const isRandomName = !payload.name;
const name = payload.name || randomUUID(); const name = payload.name || randomUUID();
const filePath = joinPath(this.CoreContext.NapCatTempPath, name); const filePath = joinPath(this.CoreContext.NapCatTempPath, name);
if (payload.base64) { if (payload.base64) {
fs.writeFileSync(filePath, payload.base64, 'base64'); fs.writeFileSync(filePath, payload.base64, 'base64');
} else if (payload.url) { } else if (payload.url) {
const headers = this.getHeaders(payload.headers); const headers = this.getHeaders(payload.headers);
const buffer = await httpDownload({ url: payload.url, headers: headers }); const buffer = await httpDownload({ url: payload.url, headers: headers });
fs.writeFileSync(filePath, Buffer.from(buffer), 'binary'); fs.writeFileSync(filePath, Buffer.from(buffer), 'binary');
} else {
throw new Error('不存在任何文件, 无法下载');
}
if (fs.existsSync(filePath)) {
if (isRandomName) {
// 默认实现要名称未填写时文件名为文件 md5
const md5 = await calculateFileMD5(filePath);
const newPath = joinPath(this.CoreContext.NapCatTempPath, md5);
fs.renameSync(filePath, newPath);
return { file: newPath };
}
return { file: filePath };
} else {
throw new Error('文件写入失败, 检查权限');
}
}
getHeaders(headersIn?: string | string[]): Record<string, string> {
const headers: Record<string, string> = {};
if (typeof headersIn == 'string') {
headersIn = headersIn.split('[\\r\\n]');
}
if (Array.isArray(headersIn)) {
for (const headerItem of headersIn) {
const spilt = headerItem.indexOf('=');
if (spilt < 0) {
headers[headerItem] = '';
} else { } else {
const key = headerItem.substring(0, spilt); throw new Error('不存在任何文件, 无法下载');
headers[key] = headerItem.substring(0, spilt + 1); }
if (fs.existsSync(filePath)) {
if (isRandomName) {
// 默认实现要名称未填写时文件名为文件 md5
const md5 = await calculateFileMD5(filePath);
const newPath = joinPath(this.CoreContext.NapCatTempPath, md5);
fs.renameSync(filePath, newPath);
return { file: newPath };
}
return { file: filePath };
} else {
throw new Error('文件写入失败, 检查权限');
} }
}
} }
if (!headers['Content-Type']) {
headers['Content-Type'] = 'application/octet-stream'; getHeaders(headersIn?: string | string[]): Record<string, string> {
const headers: Record<string, string> = {};
if (typeof headersIn == 'string') {
headersIn = headersIn.split('[\\r\\n]');
}
if (Array.isArray(headersIn)) {
for (const headerItem of headersIn) {
const spilt = headerItem.indexOf('=');
if (spilt < 0) {
headers[headerItem] = '';
} else {
const key = headerItem.substring(0, spilt);
headers[key] = headerItem.substring(0, spilt + 1);
}
}
}
if (!headers['Content-Type']) {
headers['Content-Type'] = 'application/octet-stream';
}
return headers;
} }
return headers;
}
} }

View File

@@ -7,11 +7,11 @@ import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { MessageUnique } from '@/common/utils/MessageUnique'; import { MessageUnique } from '@/common/utils/MessageUnique';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
message_id: { type: 'string' }, message_id: { type: 'string' },
id: { type: 'string' } id: { type: 'string' }
}, },
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
@@ -21,33 +21,33 @@ interface Response {
} }
export class GoCQHTTPGetForwardMsgAction extends BaseAction<Payload, any> { export class GoCQHTTPGetForwardMsgAction extends BaseAction<Payload, any> {
actionName = ActionName.GoCQHTTP_GetForwardMsg; actionName = ActionName.GoCQHTTP_GetForwardMsg;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload): Promise<any> { protected async _handle(payload: Payload): Promise<any> {
const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi; const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi;
const msgId = payload.message_id || payload.id; const msgId = payload.message_id || payload.id;
if (!msgId) { if (!msgId) {
throw Error('message_id is required'); throw Error('message_id is required');
}
const rootMsgId = MessageUnique.getShortIdByMsgId(msgId);
const rootMsg = MessageUnique.getMsgIdAndPeerByShortId(rootMsgId || parseInt(msgId));
if (!rootMsg) {
throw Error('msg not found');
}
const data = await NTQQMsgApi.getMultiMsg(rootMsg.Peer, rootMsg.MsgId, rootMsg.MsgId);
if (!data || data.result !== 0) {
throw Error('找不到相关的聊天记录' + data?.errMsg);
}
const msgList = data.msgList;
const messages = await Promise.all(msgList.map(async msg => {
const resMsg = await OB11Constructor.message(this.CoreContext, msg, "array");
resMsg.message_id = MessageUnique.createMsg({ guildId: '', chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId)!;
return resMsg;
}));
messages.map(msg => {
(<OB11ForwardMessage>msg).content = msg.message;
delete (<any>msg).message;
});
return { messages };
} }
const rootMsgId = MessageUnique.getShortIdByMsgId(msgId);
const rootMsg = MessageUnique.getMsgIdAndPeerByShortId(rootMsgId || parseInt(msgId));
if (!rootMsg) {
throw Error('msg not found');
}
const data = await NTQQMsgApi.getMultiMsg(rootMsg.Peer, rootMsg.MsgId, rootMsg.MsgId);
if (!data || data.result !== 0) {
throw Error('找不到相关的聊天记录' + data?.errMsg);
}
const msgList = data.msgList;
const messages = await Promise.all(msgList.map(async msg => {
const resMsg = await OB11Constructor.message(this.CoreContext, msg, "array");
resMsg.message_id = MessageUnique.createMsg({ guildId: '', chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId)!;
return resMsg;
}));
messages.map(msg => {
(<OB11ForwardMessage>msg).content = msg.message;
delete (<any>msg).message;
});
return { messages };
}
} }

View File

@@ -12,48 +12,48 @@ interface Response {
} }
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
user_id: { type: ['number', 'string'] }, user_id: { type: ['number', 'string'] },
message_seq: { type: 'number' }, message_seq: { type: 'number' },
count: { type: 'number' }, count: { type: 'number' },
reverseOrder: { type: 'boolean' } reverseOrder: { type: 'boolean' }
}, },
required: ['user_id'] required: ['user_id']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export default class GetFriendMsgHistory extends BaseAction<Payload, Response> { export default class GetFriendMsgHistory extends BaseAction<Payload, Response> {
actionName = ActionName.GetFriendMsgHistory; actionName = ActionName.GetFriendMsgHistory;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload): Promise<Response> { protected async _handle(payload: Payload): Promise<Response> {
const NTQQUserApi = this.CoreContext.getApiContext().UserApi; const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi; const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi;
const NTQQFriendApi = this.CoreContext.getApiContext().FriendApi; const NTQQFriendApi = this.CoreContext.getApiContext().FriendApi;
//处理参数 //处理参数
const uid = await NTQQUserApi.getUidByUin(payload.user_id.toString()); const uid = await NTQQUserApi.getUidByUin(payload.user_id.toString());
const MsgCount = payload.count || 20; const MsgCount = payload.count || 20;
const isReverseOrder = payload.reverseOrder || true; const isReverseOrder = payload.reverseOrder || true;
if (!uid) throw `记录${payload.user_id}不存在`; if (!uid) throw `记录${payload.user_id}不存在`;
const friend = await NTQQFriendApi.isBuddy(uid); const friend = await NTQQFriendApi.isBuddy(uid);
const peer = { chatType: friend ? ChatType.friend : ChatType.temp, peerUid: uid }; const peer = { chatType: friend ? ChatType.friend : ChatType.temp, peerUid: uid };
//拉取消息 //拉取消息
let msgList: RawMessage[]; let msgList: RawMessage[];
if (!payload.message_seq || payload.message_seq == 0) { if (!payload.message_seq || payload.message_seq == 0) {
msgList = (await NTQQMsgApi.getLastestMsgByUids(peer, MsgCount)).msgList; msgList = (await NTQQMsgApi.getLastestMsgByUids(peer, MsgCount)).msgList;
} else { } else {
const startMsgId = MessageUnique.getMsgIdAndPeerByShortId(payload.message_seq)?.MsgId; const startMsgId = MessageUnique.getMsgIdAndPeerByShortId(payload.message_seq)?.MsgId;
if (!startMsgId) throw `消息${payload.message_seq}不存在`; if (!startMsgId) throw `消息${payload.message_seq}不存在`;
msgList = (await NTQQMsgApi.getMsgHistory(peer, startMsgId, MsgCount)).msgList; msgList = (await NTQQMsgApi.getMsgHistory(peer, startMsgId, MsgCount)).msgList;
}
if (isReverseOrder) msgList.reverse();
await Promise.all(msgList.map(async msg => {
msg.id = MessageUnique.createMsg({ guildId: '', chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId);
}));
//转换消息
const ob11MsgList = await Promise.all(msgList.map(msg => OB11Constructor.message(this.CoreContext, msg, "array")));
return { 'messages': ob11MsgList };
} }
if (isReverseOrder) msgList.reverse();
await Promise.all(msgList.map(async msg => {
msg.id = MessageUnique.createMsg({ guildId: '', chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId);
}));
//转换消息
const ob11MsgList = await Promise.all(msgList.map(msg => OB11Constructor.message(this.CoreContext, msg, "array")));
return { 'messages': ob11MsgList };
}
} }

View File

@@ -4,24 +4,24 @@ import { ActionName } from '../types';
import { WebHonorType } from '@/core/entities'; import { WebHonorType } from '@/core/entities';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
group_id: { type: [ 'number' , 'string' ] }, group_id: { type: [ 'number' , 'string' ] },
type: { enum: [WebHonorType.ALL, WebHonorType.EMOTION, WebHonorType.LEGEND, WebHonorType.PERFORMER, WebHonorType.STRONG_NEWBIE, WebHonorType.TALKATIVE] } type: { enum: [WebHonorType.ALL, WebHonorType.EMOTION, WebHonorType.LEGEND, WebHonorType.PERFORMER, WebHonorType.STRONG_NEWBIE, WebHonorType.TALKATIVE] }
}, },
required: ['group_id'] required: ['group_id']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
// enum是不是有点抽象 // enum是不是有点抽象
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export class GetGroupHonorInfo extends BaseAction<Payload, Array<any>> { export class GetGroupHonorInfo extends BaseAction<Payload, Array<any>> {
actionName = ActionName.GetGroupHonorInfo; actionName = ActionName.GetGroupHonorInfo;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
if (!payload.type) { if (!payload.type) {
payload.type = WebHonorType.ALL; payload.type = WebHonorType.ALL;
}
const NTQQWebApi = this.CoreContext.getApiContext().WebApi;
return await NTQQWebApi.getGroupHonorInfo(payload.group_id.toString(), payload.type);
} }
const NTQQWebApi = this.CoreContext.getApiContext().WebApi;
return await NTQQWebApi.getGroupHonorInfo(payload.group_id.toString(), payload.type);
}
} }

View File

@@ -10,43 +10,43 @@ interface Response {
} }
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
group_id: { type: ['number', 'string'] }, group_id: { type: ['number', 'string'] },
message_seq: { type: 'number' }, message_seq: { type: 'number' },
count: { type: 'number' }, count: { type: 'number' },
reverseOrder: { type: 'boolean' } reverseOrder: { type: 'boolean' }
}, },
required: ['group_id'] required: ['group_id']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export default class GoCQHTTPGetGroupMsgHistory extends BaseAction<Payload, Response> { export default class GoCQHTTPGetGroupMsgHistory extends BaseAction<Payload, Response> {
actionName = ActionName.GoCQHTTP_GetGroupMsgHistory; actionName = ActionName.GoCQHTTP_GetGroupMsgHistory;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload): Promise<Response> { protected async _handle(payload: Payload): Promise<Response> {
const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi; const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi;
//处理参数 //处理参数
const isReverseOrder = payload.reverseOrder || true; const isReverseOrder = payload.reverseOrder || true;
const MsgCount = payload.count || 20; const MsgCount = payload.count || 20;
const peer: Peer = { chatType: ChatType.group, peerUid: payload.group_id.toString() }; const peer: Peer = { chatType: ChatType.group, peerUid: payload.group_id.toString() };
//拉取消息 //拉取消息
let msgList: RawMessage[]; let msgList: RawMessage[];
if (!payload.message_seq || payload.message_seq == 0) { if (!payload.message_seq || payload.message_seq == 0) {
msgList = (await NTQQMsgApi.getLastestMsgByUids(peer, MsgCount)).msgList; msgList = (await NTQQMsgApi.getLastestMsgByUids(peer, MsgCount)).msgList;
} else { } else {
const startMsgId = MessageUnique.getMsgIdAndPeerByShortId(payload.message_seq)?.MsgId; const startMsgId = MessageUnique.getMsgIdAndPeerByShortId(payload.message_seq)?.MsgId;
if (!startMsgId) throw `消息${payload.message_seq}不存在`; if (!startMsgId) throw `消息${payload.message_seq}不存在`;
msgList = (await NTQQMsgApi.getMsgHistory(peer, startMsgId, MsgCount)).msgList; msgList = (await NTQQMsgApi.getMsgHistory(peer, startMsgId, MsgCount)).msgList;
} }
if (isReverseOrder) msgList.reverse(); if (isReverseOrder) msgList.reverse();
await Promise.all(msgList.map(async msg => { await Promise.all(msgList.map(async msg => {
msg.id = MessageUnique.createMsg({ guildId: '', chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId); msg.id = MessageUnique.createMsg({ guildId: '', chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId);
})); }));
//转换消息 //转换消息
const ob11MsgList = await Promise.all(msgList.map(msg => OB11Constructor.message(this.CoreContext, msg, "array"))); const ob11MsgList = await Promise.all(msgList.map(msg => OB11Constructor.message(this.CoreContext, msg, "array")));
return { 'messages': ob11MsgList }; return { 'messages': ob11MsgList };
} }
} }

View File

@@ -4,21 +4,21 @@ import { JSONSchema } from 'json-schema-to-ts';
import { sleep } from '@/common/utils/helper'; import { sleep } from '@/common/utils/helper';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
no_cache: { type: 'boolean' }, no_cache: { type: 'boolean' },
} }
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
export class GetOnlineClient extends BaseAction<void, Array<any>> { export class GetOnlineClient extends BaseAction<void, Array<any>> {
actionName = ActionName.GetOnlineClient; actionName = ActionName.GetOnlineClient;
protected async _handle(payload: void) { protected async _handle(payload: void) {
//注册监听 //注册监听
const NTQQSystemApi = this.CoreContext.getApiContext().SystemApi; const NTQQSystemApi = this.CoreContext.getApiContext().SystemApi;
NTQQSystemApi.getOnlineDev(); NTQQSystemApi.getOnlineDev();
await sleep(500); await sleep(500);
return []; return [];
} }
} }

View File

@@ -5,38 +5,38 @@ import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { calcQQLevel } from '@/common/utils/qqlevel'; import { calcQQLevel } from '@/common/utils/qqlevel';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
user_id: { type: ['number', 'string'] }, user_id: { type: ['number', 'string'] },
}, },
required: ['user_id'] required: ['user_id']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export default class GoCQHTTPGetStrangerInfo extends BaseAction<Payload, OB11User> { export default class GoCQHTTPGetStrangerInfo extends BaseAction<Payload, OB11User> {
actionName = ActionName.GoCQHTTP_GetStrangerInfo; actionName = ActionName.GoCQHTTP_GetStrangerInfo;
protected async _handle(payload: Payload): Promise<OB11User> { protected async _handle(payload: Payload): Promise<OB11User> {
const NTQQUserApi = this.CoreContext.getApiContext().UserApi; const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
const user_id = payload.user_id.toString(); const user_id = payload.user_id.toString();
const extendData = await NTQQUserApi.getUserDetailInfoByUin(user_id); const extendData = await NTQQUserApi.getUserDetailInfoByUin(user_id);
const uid = (await NTQQUserApi.getUidByUin(user_id))!; const uid = (await NTQQUserApi.getUidByUin(user_id))!;
if (!uid || uid.indexOf('*') != -1) { if (!uid || uid.indexOf('*') != -1) {
const ret = { const ret = {
...extendData, ...extendData,
user_id: parseInt(extendData.info.uin) || 0, user_id: parseInt(extendData.info.uin) || 0,
nickname: extendData.info.nick, nickname: extendData.info.nick,
sex: OB11UserSex.unknown, sex: OB11UserSex.unknown,
age: (extendData.info.birthday_year == 0) ? 0 : new Date().getFullYear() - extendData.info.birthday_year, age: (extendData.info.birthday_year == 0) ? 0 : new Date().getFullYear() - extendData.info.birthday_year,
qid: extendData.info.qid, qid: extendData.info.qid,
level: extendData.info.qqLevel && calcQQLevel(extendData.info.qqLevel) || 0, level: extendData.info.qqLevel && calcQQLevel(extendData.info.qqLevel) || 0,
login_days: 0, login_days: 0,
uid: '' uid: ''
}; };
return ret; return ret;
}
const data = { ...extendData, ...(await NTQQUserApi.getUserDetailInfo(uid)) };
return OB11Constructor.stranger(data);
} }
const data = { ...extendData, ...(await NTQQUserApi.getUserDetailInfo(uid)) };
return OB11Constructor.stranger(data);
}
} }

View File

@@ -8,9 +8,9 @@ interface Payload{
} }
export class GoCQHTTPHandleQuickAction extends BaseAction<Payload, null>{ export class GoCQHTTPHandleQuickAction extends BaseAction<Payload, null>{
actionName = ActionName.GoCQHTTP_HandleQuickAction; actionName = ActionName.GoCQHTTP_HandleQuickAction;
protected async _handle(payload: Payload): Promise<null> { protected async _handle(payload: Payload): Promise<null> {
handleQuickOperation(payload.context, payload.operation,this.CoreContext).then().catch(this.CoreContext.context.logger.logError); handleQuickOperation(payload.context, payload.operation,this.CoreContext).then().catch(this.CoreContext.context.logger.logError);
return null; return null;
} }
} }

View File

@@ -3,18 +3,18 @@ import { OB11PostSendMsg } from '../../types';
import { ActionName } from '../types'; import { ActionName } from '../types';
// 未验证 // 未验证
export class GoCQHTTPSendForwardMsg extends SendMsg { export class GoCQHTTPSendForwardMsg extends SendMsg {
actionName = ActionName.GoCQHTTP_SendForwardMsg; actionName = ActionName.GoCQHTTP_SendForwardMsg;
protected async check(payload: OB11PostSendMsg) { protected async check(payload: OB11PostSendMsg) {
if (payload.messages) payload.message = normalize(payload.messages); if (payload.messages) payload.message = normalize(payload.messages);
return super.check(payload); return super.check(payload);
} }
} }
export class GoCQHTTPSendPrivateForwardMsg extends GoCQHTTPSendForwardMsg { export class GoCQHTTPSendPrivateForwardMsg extends GoCQHTTPSendForwardMsg {
actionName = ActionName.GoCQHTTP_SendPrivateForwardMsg; actionName = ActionName.GoCQHTTP_SendPrivateForwardMsg;
} }
export class GoCQHTTPSendGroupForwardMsg extends GoCQHTTPSendForwardMsg { export class GoCQHTTPSendGroupForwardMsg extends GoCQHTTPSendForwardMsg {
actionName = ActionName.GoCQHTTP_SendGroupForwardMsg; actionName = ActionName.GoCQHTTP_SendGroupForwardMsg;
} }

View File

@@ -4,58 +4,58 @@ import { ActionName } from '../types';
import { unlink } from 'node:fs'; import { unlink } from 'node:fs';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
group_id: { type: ['number', 'string'] }, group_id: { type: ['number', 'string'] },
content: { type: 'string' }, content: { type: 'string' },
image: { type: 'string' }, image: { type: 'string' },
pinned: { type: 'number' }, pinned: { type: 'number' },
confirmRequired: { type: 'number' } confirmRequired: { type: 'number' }
}, },
required: ['group_id', 'content'] required: ['group_id', 'content']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export class SendGroupNotice extends BaseAction<Payload, null> { export class SendGroupNotice extends BaseAction<Payload, null> {
actionName = ActionName.GoCQHTTP_SendGroupNotice; actionName = ActionName.GoCQHTTP_SendGroupNotice;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi; const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
let UploadImage: { id: string, width: number, height: number } | undefined = undefined; let UploadImage: { id: string, width: number, height: number } | undefined = undefined;
if (payload.image) { if (payload.image) {
//公告图逻辑 //公告图逻辑
const { errMsg, path, isLocal, success } = (await uri2local(this.CoreContext.NapCatTempPath,payload.image)); const { errMsg, path, isLocal, success } = (await uri2local(this.CoreContext.NapCatTempPath,payload.image));
if (!success) { if (!success) {
throw `群公告${payload.image}设置失败,image字段可能格式不正确`; throw `群公告${payload.image}设置失败,image字段可能格式不正确`;
} }
if (!path) { if (!path) {
throw `群公告${payload.image}设置失败,获取资源失败`; throw `群公告${payload.image}设置失败,获取资源失败`;
} }
await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃需要提前判断 await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃需要提前判断
const ImageUploadResult = await NTQQGroupApi.uploadGroupBulletinPic(payload.group_id.toString(), path); const ImageUploadResult = await NTQQGroupApi.uploadGroupBulletinPic(payload.group_id.toString(), path);
if (ImageUploadResult.errCode != 0) { if (ImageUploadResult.errCode != 0) {
throw `群公告${payload.image}设置失败,图片上传失败`; throw `群公告${payload.image}设置失败,图片上传失败`;
} }
if (!isLocal) { if (!isLocal) {
unlink(path, () => { }); unlink(path, () => { });
} }
UploadImage = ImageUploadResult.picInfo; UploadImage = ImageUploadResult.picInfo;
} }
let Notice_Pinned = 0; let Notice_Pinned = 0;
let Notice_confirmRequired = 0; let Notice_confirmRequired = 0;
if (!payload.pinned) { if (!payload.pinned) {
Notice_Pinned = 0; Notice_Pinned = 0;
} }
if (!payload.confirmRequired) { if (!payload.confirmRequired) {
Notice_confirmRequired = 0; Notice_confirmRequired = 0;
} }
const PublishGroupBulletinResult = await NTQQGroupApi.publishGroupBulletin(payload.group_id.toString(), payload.content, UploadImage, Notice_Pinned, Notice_confirmRequired); const PublishGroupBulletinResult = await NTQQGroupApi.publishGroupBulletin(payload.group_id.toString(), payload.content, UploadImage, Notice_Pinned, Notice_confirmRequired);
if (PublishGroupBulletinResult.result != 0) { if (PublishGroupBulletinResult.result != 0) {
throw `设置群公告失败,错误信息:${PublishGroupBulletinResult.errMsg}`; throw `设置群公告失败,错误信息:${PublishGroupBulletinResult.errMsg}`;
}
// 下面实现扬了
//await WebApi.setGroupNotice(payload.group_id, payload.content) ;
return null;
} }
// 下面实现扬了
//await WebApi.setGroupNotice(payload.group_id, payload.content) ;
return null;
}
} }

View File

@@ -7,33 +7,33 @@ import { uri2local } from '@/common/utils/file';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { SendMsgElementConstructor } from '@/onebot/helper/msg'; import { SendMsgElementConstructor } from '@/onebot/helper/msg';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
group_id: { type: ['number', 'string'] }, group_id: { type: ['number', 'string'] },
file: { type: 'string' }, file: { type: 'string' },
name: { type: 'string' }, name: { type: 'string' },
folder: { type: 'string' }, folder: { type: 'string' },
folder_id: { type: 'string' }//临时扩展 folder_id: { type: 'string' }//临时扩展
}, },
required: ['group_id', 'file', 'name'] required: ['group_id', 'file', 'name']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export default class GoCQHTTPUploadGroupFile extends BaseAction<Payload, null> { export default class GoCQHTTPUploadGroupFile extends BaseAction<Payload, null> {
actionName = ActionName.GoCQHTTP_UploadGroupFile; actionName = ActionName.GoCQHTTP_UploadGroupFile;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload): Promise<null> { protected async _handle(payload: Payload): Promise<null> {
let file = payload.file; let file = payload.file;
if (fs.existsSync(file)) { if (fs.existsSync(file)) {
file = `file://${file}`; file = `file://${file}`;
}
const downloadResult = await uri2local(this.CoreContext.NapCatTempPath, file);
if (!downloadResult.success) {
throw new Error(downloadResult.errMsg);
}
const sendFileEle: SendFileElement = await SendMsgElementConstructor.file(this.CoreContext, downloadResult.path, payload.name, payload.folder_id);
await sendMsg(this.CoreContext, { chatType: ChatType.group, peerUid: payload.group_id.toString() }, [sendFileEle], [], true);
return null;
} }
const downloadResult = await uri2local(this.CoreContext.NapCatTempPath, file);
if (!downloadResult.success) {
throw new Error(downloadResult.errMsg);
}
const sendFileEle: SendFileElement = await SendMsgElementConstructor.file(this.CoreContext, downloadResult.path, payload.name, payload.folder_id);
await sendMsg(this.CoreContext, { chatType: ChatType.group, peerUid: payload.group_id.toString() }, [sendFileEle], [], true);
return null;
}
} }

View File

@@ -1,4 +1,4 @@
import BaseAction from '../BaseAction';; import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
import { ChatType, Peer, SendFileElement } from '@/core/entities'; import { ChatType, Peer, SendFileElement } from '@/core/entities';
import fs from 'fs'; import fs from 'fs';
@@ -7,45 +7,45 @@ import { uri2local } from '@/common/utils/file';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { SendMsgElementConstructor } from '@/onebot/helper/msg'; import { SendMsgElementConstructor } from '@/onebot/helper/msg';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
user_id: { type: ['number', 'string'] }, user_id: { type: ['number', 'string'] },
file: { type: 'string' }, file: { type: 'string' },
name: { type: 'string' } name: { type: 'string' }
}, },
required: ['user_id', 'file', 'name'] required: ['user_id', 'file', 'name']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export default class GoCQHTTPUploadPrivateFile extends BaseAction<Payload, null> { export default class GoCQHTTPUploadPrivateFile extends BaseAction<Payload, null> {
actionName = ActionName.GOCQHTTP_UploadPrivateFile; actionName = ActionName.GOCQHTTP_UploadPrivateFile;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
async getPeer(payload: Payload): Promise<Peer> { async getPeer(payload: Payload): Promise<Peer> {
const NTQQUserApi = this.CoreContext.getApiContext().UserApi; const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
const NTQQFriendApi = this.CoreContext.getApiContext().FriendApi; const NTQQFriendApi = this.CoreContext.getApiContext().FriendApi;
if (payload.user_id) { if (payload.user_id) {
const peerUid = await NTQQUserApi.getUidByUin(payload.user_id.toString()); const peerUid = await NTQQUserApi.getUidByUin(payload.user_id.toString());
if (!peerUid) { if (!peerUid) {
throw `私聊${payload.user_id}不存在`; throw `私聊${payload.user_id}不存在`;
} }
const isBuddy = await NTQQFriendApi.isBuddy(peerUid); const isBuddy = await NTQQFriendApi.isBuddy(peerUid);
return { chatType: isBuddy ? ChatType.friend : ChatType.temp, peerUid }; return { chatType: isBuddy ? ChatType.friend : ChatType.temp, peerUid };
}
throw '缺少参数 user_id';
} }
throw '缺少参数 user_id'; protected async _handle(payload: Payload): Promise<null> {
} const peer = await this.getPeer(payload);
protected async _handle(payload: Payload): Promise<null> { let file = payload.file;
const peer = await this.getPeer(payload); if (fs.existsSync(file)) {
let file = payload.file; file = `file://${file}`;
if (fs.existsSync(file)) { }
file = `file://${file}`; const downloadResult = await uri2local(this.CoreContext.NapCatTempPath, file);
if (!downloadResult.success) {
throw new Error(downloadResult.errMsg);
}
const sendFileEle: SendFileElement = await SendMsgElementConstructor.file(this.CoreContext, downloadResult.path, payload.name);
await sendMsg(this.CoreContext, peer, [sendFileEle], [], true);
return null;
} }
const downloadResult = await uri2local(this.CoreContext.NapCatTempPath, file);
if (!downloadResult.success) {
throw new Error(downloadResult.errMsg);
}
const sendFileEle: SendFileElement = await SendMsgElementConstructor.file(this.CoreContext, downloadResult.path, payload.name);
await sendMsg(this.CoreContext, peer, [sendFileEle], [], true);
return null;
}
} }

View File

@@ -5,27 +5,27 @@ import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { MessageUnique } from '@/common/utils/MessageUnique'; import { MessageUnique } from '@/common/utils/MessageUnique';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
message_id: { type: ['number', 'string'] } message_id: { type: ['number', 'string'] }
}, },
required: ['message_id'] required: ['message_id']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export default class DelEssenceMsg extends BaseAction<Payload, any> { export default class DelEssenceMsg extends BaseAction<Payload, any> {
actionName = ActionName.DelEssenceMsg; actionName = ActionName.DelEssenceMsg;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload): Promise<any> { protected async _handle(payload: Payload): Promise<any> {
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi; const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
const msg = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString())); const msg = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString()));
if (!msg) { if (!msg) {
throw new Error('msg not found'); throw new Error('msg not found');
}
return await NTQQGroupApi.removeGroupEssence(
msg.Peer.peerUid,
msg.MsgId
);
} }
return await NTQQGroupApi.removeGroupEssence(
msg.Peer.peerUid,
msg.MsgId
);
}
} }

View File

@@ -4,25 +4,25 @@ import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
group_id: { type: [ 'number' , 'string' ] }, group_id: { type: [ 'number' , 'string' ] },
pages: { type: 'number' }, pages: { type: 'number' },
}, },
required: ['group_id', 'pages'] required: ['group_id', 'pages']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export class GetGroupEssence extends BaseAction<Payload, GroupEssenceMsgRet> { export class GetGroupEssence extends BaseAction<Payload, GroupEssenceMsgRet> {
actionName = ActionName.GoCQHTTP_GetEssenceMsg; actionName = ActionName.GoCQHTTP_GetEssenceMsg;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const NTQQWebApi = this.CoreContext.getApiContext().WebApi; const NTQQWebApi = this.CoreContext.getApiContext().WebApi;
const ret = await NTQQWebApi.getGroupEssenceMsg(payload.group_id.toString(), payload.pages.toString()); const ret = await NTQQWebApi.getGroupEssenceMsg(payload.group_id.toString(), payload.pages.toString());
if (!ret) { if (!ret) {
throw new Error('获取失败'); throw new Error('获取失败');
}
return ret;
} }
return ret;
}
} }

View File

@@ -5,27 +5,27 @@ import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
group_id: { type: ['number', 'string'] }, group_id: { type: ['number', 'string'] },
}, },
required: ['group_id'] required: ['group_id']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
class GetGroupInfo extends BaseAction<Payload, OB11Group> { class GetGroupInfo extends BaseAction<Payload, OB11Group> {
actionName = ActionName.GetGroupInfo; actionName = ActionName.GetGroupInfo;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi; const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
const group = (await NTQQGroupApi.getGroups()).find(e => e.groupCode == payload.group_id.toString()); const group = (await NTQQGroupApi.getGroups()).find(e => e.groupCode == payload.group_id.toString());
if (group) { if (group) {
return OB11Constructor.group(group); return OB11Constructor.group(group);
} else { } else {
throw `${payload.group_id}不存在`; throw `${payload.group_id}不存在`;
}
} }
}
} }
export default GetGroupInfo; export default GetGroupInfo;

View File

@@ -6,22 +6,22 @@ import { Group } from '@/core/entities';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
// no_cache get时传字符串 // no_cache get时传字符串
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
no_cache: { type: ['boolean', 'string'] }, no_cache: { type: ['boolean', 'string'] },
} }
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
class GetGroupList extends BaseAction<Payload, OB11Group[]> { class GetGroupList extends BaseAction<Payload, OB11Group[]> {
actionName = ActionName.GetGroupList; actionName = ActionName.GetGroupList;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi; const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
const groupList: Group[] = await NTQQGroupApi.getGroups(payload?.no_cache === true || payload.no_cache === 'true'); const groupList: Group[] = await NTQQGroupApi.getGroups(payload?.no_cache === true || payload.no_cache === 'true');
return OB11Constructor.groups(groupList); return OB11Constructor.groups(groupList);
} }
} }
export default GetGroupList; export default GetGroupList;

View File

@@ -4,74 +4,74 @@ import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
group_id: { type: ['number', 'string'] }, group_id: { type: ['number', 'string'] },
user_id: { type: ['number', 'string'] }, user_id: { type: ['number', 'string'] },
no_cache: { type: ['boolean', 'string'] }, no_cache: { type: ['boolean', 'string'] },
}, },
required: ['group_id', 'user_id'] required: ['group_id', 'user_id']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
class GetGroupMemberInfo extends BaseAction<Payload, OB11GroupMember> { class GetGroupMemberInfo extends BaseAction<Payload, OB11GroupMember> {
actionName = ActionName.GetGroupMemberInfo; actionName = ActionName.GetGroupMemberInfo;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const NTQQUserApi = this.CoreContext.getApiContext().UserApi; const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi; const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
const NTQQWebApi = this.CoreContext.getApiContext().WebApi; const NTQQWebApi = this.CoreContext.getApiContext().WebApi;
const isNocache = payload.no_cache == true || payload.no_cache === 'true'; const isNocache = payload.no_cache == true || payload.no_cache === 'true';
const uid = await NTQQUserApi.getUidByUin(payload.user_id.toString()); const uid = await NTQQUserApi.getUidByUin(payload.user_id.toString());
if (!uid) { if (!uid) {
throw (`Uin2Uid Error ${payload.user_id}不存在`); throw (`Uin2Uid Error ${payload.user_id}不存在`);
}
const member = await NTQQGroupApi.getGroupMemberV2(payload.group_id.toString(), uid, isNocache);
if (!member) {
throw (`群(${payload.group_id})成员${payload.user_id}不存在`);
}
try {
const info = (await NTQQUserApi.getUserDetailInfo(member.uid));
this.CoreContext.context.logger.logDebug('群成员详细信息结果', info);
Object.assign(member, info);
} catch (e) {
this.CoreContext.context.logger.logDebug('获取群成员详细信息失败, 只能返回基础信息', e);
}
const date = Math.round(Date.now() / 1000);
const retMember = OB11Constructor.groupMember(payload.group_id.toString(), member);
if (!this.CoreContext.context.basicInfoWrapper.requireMinNTQQBuild('26702')) {
const SelfInfoInGroup = await NTQQGroupApi.getGroupMemberV2(payload.group_id.toString(), this.CoreContext.selfInfo.uid, isNocache);
let isPrivilege = false;
if (SelfInfoInGroup) {
isPrivilege = SelfInfoInGroup.role === 3 || SelfInfoInGroup.role === 4;
}
if (isPrivilege) {
const webGroupMembers = await NTQQWebApi.getGroupMembers(payload.group_id.toString());
for (let i = 0, len = webGroupMembers.length; i < len; i++) {
if (webGroupMembers[i]?.uin && webGroupMembers[i].uin === retMember.user_id) {
retMember.join_time = webGroupMembers[i]?.join_time;
retMember.last_sent_time = webGroupMembers[i]?.last_speak_time;
retMember.qage = webGroupMembers[i]?.qage;
retMember.level = webGroupMembers[i]?.lv.level.toString();
}
} }
} else { const member = await NTQQGroupApi.getGroupMemberV2(payload.group_id.toString(), uid, isNocache);
const LastestMsgList = await NTQQGroupApi.getLatestMsg(payload.group_id.toString(), [payload.user_id.toString()]); if (!member) {
if (LastestMsgList?.msgList?.length && LastestMsgList?.msgList?.length > 0) { throw (`群(${payload.group_id})成员${payload.user_id}不存在`);
const last_send_time = LastestMsgList.msgList[0].msgTime;
if (last_send_time && last_send_time != '0' && last_send_time != '') {
retMember.last_sent_time = parseInt(last_send_time);
retMember.join_time = Math.round(Date.now() / 1000);//兜底数据 防止群管乱杀
}
} }
} try {
} else { const info = (await NTQQUserApi.getUserDetailInfo(member.uid));
// Mlikiowa V2.0.0 Refactor Todo this.CoreContext.context.logger.logDebug('群成员详细信息结果', info);
// retMember.last_sent_time = parseInt((await getGroupMember(payload.group_id.toString(), retMember.user_id))?.lastSpeakTime || date.toString()); Object.assign(member, info);
// retMember.join_time = parseInt((await getGroupMember(payload.group_id.toString(), retMember.user_id))?.joinTime || date.toString()); } catch (e) {
this.CoreContext.context.logger.logDebug('获取群成员详细信息失败, 只能返回基础信息', e);
}
const date = Math.round(Date.now() / 1000);
const retMember = OB11Constructor.groupMember(payload.group_id.toString(), member);
if (!this.CoreContext.context.basicInfoWrapper.requireMinNTQQBuild('26702')) {
const SelfInfoInGroup = await NTQQGroupApi.getGroupMemberV2(payload.group_id.toString(), this.CoreContext.selfInfo.uid, isNocache);
let isPrivilege = false;
if (SelfInfoInGroup) {
isPrivilege = SelfInfoInGroup.role === 3 || SelfInfoInGroup.role === 4;
}
if (isPrivilege) {
const webGroupMembers = await NTQQWebApi.getGroupMembers(payload.group_id.toString());
for (let i = 0, len = webGroupMembers.length; i < len; i++) {
if (webGroupMembers[i]?.uin && webGroupMembers[i].uin === retMember.user_id) {
retMember.join_time = webGroupMembers[i]?.join_time;
retMember.last_sent_time = webGroupMembers[i]?.last_speak_time;
retMember.qage = webGroupMembers[i]?.qage;
retMember.level = webGroupMembers[i]?.lv.level.toString();
}
}
} else {
const LastestMsgList = await NTQQGroupApi.getLatestMsg(payload.group_id.toString(), [payload.user_id.toString()]);
if (LastestMsgList?.msgList?.length && LastestMsgList?.msgList?.length > 0) {
const last_send_time = LastestMsgList.msgList[0].msgTime;
if (last_send_time && last_send_time != '0' && last_send_time != '') {
retMember.last_sent_time = parseInt(last_send_time);
retMember.join_time = Math.round(Date.now() / 1000);//兜底数据 防止群管乱杀
}
}
}
} else {
// Mlikiowa V2.0.0 Refactor Todo
// retMember.last_sent_time = parseInt((await getGroupMember(payload.group_id.toString(), retMember.user_id))?.lastSpeakTime || date.toString());
// retMember.join_time = parseInt((await getGroupMember(payload.group_id.toString(), retMember.user_id))?.joinTime || date.toString());
}
return retMember;
} }
return retMember;
}
} }
export default GetGroupMemberInfo; export default GetGroupMemberInfo;

View File

@@ -5,101 +5,101 @@ import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
group_id: { type: ['number', 'string'] }, group_id: { type: ['number', 'string'] },
no_cache: { type: ['boolean', 'string'] }, no_cache: { type: ['boolean', 'string'] },
}, },
required: ['group_id'] required: ['group_id']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
class GetGroupMemberList extends BaseAction<Payload, OB11GroupMember[]> { class GetGroupMemberList extends BaseAction<Payload, OB11GroupMember[]> {
actionName = ActionName.GetGroupMemberList; actionName = ActionName.GetGroupMemberList;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi; const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
const NTQQWebApi = this.CoreContext.getApiContext().WebApi; const NTQQWebApi = this.CoreContext.getApiContext().WebApi;
const isNocache = payload.no_cache == true || payload.no_cache === 'true'; const isNocache = payload.no_cache == true || payload.no_cache === 'true';
const GroupList = await NTQQGroupApi.getGroups(isNocache); const GroupList = await NTQQGroupApi.getGroups(isNocache);
const group = GroupList.find(item => item.groupCode == payload.group_id); const group = GroupList.find(item => item.groupCode == payload.group_id);
if (!group) { if (!group) {
throw (`${payload.group_id}不存在`); throw (`${payload.group_id}不存在`);
}
const groupMembers = await NTQQGroupApi.getGroupMembers(payload.group_id.toString());
const groupMembersArr = Array.from(groupMembers.values());
const groupMembersUids = groupMembersArr.map(e => e.uid);
let _groupMembers = groupMembersArr.map(item => { return OB11Constructor.groupMember(group.groupCode, item); });
const MemberMap: Map<number, OB11GroupMember> = new Map<number, OB11GroupMember>();
// 转为Map 方便索引
let GroupMemberUids: string[] = [];
const date = Math.round(Date.now() / 1000);
for (let i = 0, len = _groupMembers.length; i < len; i++) {
// 保证基础数据有这个 同时避免群管插件过于依赖这个杀了
_groupMembers[i].join_time = date;
_groupMembers[i].last_sent_time = date;
MemberMap.set(_groupMembers[i].user_id, _groupMembers[i]);
}
if (!this.CoreContext.context.basicInfoWrapper.requireMinNTQQBuild('26702')) {
const selfRole = groupMembers.get(this.CoreContext.selfInfo.uid)?.role;
const isPrivilege = selfRole === 3 || selfRole === 4;
if (isPrivilege) {
const webGroupMembers = await NTQQWebApi.getGroupMembers(payload.group_id.toString());
for (let i = 0, len = webGroupMembers.length; i < len; i++) {
if (!webGroupMembers[i]?.uin) {
continue;
}
const MemberData = MemberMap.get(webGroupMembers[i]?.uin);
if (MemberData) {
MemberData.join_time = webGroupMembers[i]?.join_time;
MemberData.last_sent_time = webGroupMembers[i]?.last_speak_time;
MemberData.qage = webGroupMembers[i]?.qage;
MemberData.level = webGroupMembers[i]?.lv.level.toString();
MemberMap.set(webGroupMembers[i]?.uin, MemberData);
}
} }
} else { const groupMembers = await NTQQGroupApi.getGroupMembers(payload.group_id.toString());
if (isNocache) { const groupMembersArr = Array.from(groupMembers.values());
const DateMap = await NTQQGroupApi.getGroupMemberLatestSendTimeCache(payload.group_id.toString(), groupMembersUids);//开始从本地拉取 const groupMembersUids = groupMembersArr.map(e => e.uid);
for (const DateUin of DateMap.keys()) { let _groupMembers = groupMembersArr.map(item => { return OB11Constructor.groupMember(group.groupCode, item); });
const MemberData = MemberMap.get(parseInt(DateUin));
if (MemberData) { const MemberMap: Map<number, OB11GroupMember> = new Map<number, OB11GroupMember>();
MemberData.last_sent_time = parseInt(DateMap.get(DateUin)!); // 转为Map 方便索引
//join_time 有基础数据兜底 const GroupMemberUids: string[] = [];
const date = Math.round(Date.now() / 1000);
for (let i = 0, len = _groupMembers.length; i < len; i++) {
// 保证基础数据有这个 同时避免群管插件过于依赖这个杀了
_groupMembers[i].join_time = date;
_groupMembers[i].last_sent_time = date;
MemberMap.set(_groupMembers[i].user_id, _groupMembers[i]);
}
if (!this.CoreContext.context.basicInfoWrapper.requireMinNTQQBuild('26702')) {
const selfRole = groupMembers.get(this.CoreContext.selfInfo.uid)?.role;
const isPrivilege = selfRole === 3 || selfRole === 4;
if (isPrivilege) {
const webGroupMembers = await NTQQWebApi.getGroupMembers(payload.group_id.toString());
for (let i = 0, len = webGroupMembers.length; i < len; i++) {
if (!webGroupMembers[i]?.uin) {
continue;
}
const MemberData = MemberMap.get(webGroupMembers[i]?.uin);
if (MemberData) {
MemberData.join_time = webGroupMembers[i]?.join_time;
MemberData.last_sent_time = webGroupMembers[i]?.last_speak_time;
MemberData.qage = webGroupMembers[i]?.qage;
MemberData.level = webGroupMembers[i]?.lv.level.toString();
MemberMap.set(webGroupMembers[i]?.uin, MemberData);
}
}
} else {
if (isNocache) {
const DateMap = await NTQQGroupApi.getGroupMemberLatestSendTimeCache(payload.group_id.toString(), groupMembersUids);//开始从本地拉取
for (const DateUin of DateMap.keys()) {
const MemberData = MemberMap.get(parseInt(DateUin));
if (MemberData) {
MemberData.last_sent_time = parseInt(DateMap.get(DateUin)!);
//join_time 有基础数据兜底
}
}
} else {
_groupMembers.forEach(item => {
item.last_sent_time = date;
item.join_time = date;
});
}
} }
}
} else { } else {
_groupMembers.forEach(item => { // Mlikiowa V2.0.0 Refactor Todo
item.last_sent_time = date; // _groupMembers.forEach(async item => {
item.join_time = date; // item.last_sent_time = parseInt((await getGroupMember(payload.group_id.toString(), item.user_id))?.lastSpeakTime || date.toString());
}); // item.join_time = parseInt((await getGroupMember(payload.group_id.toString(), item.user_id))?.joinTime || date.toString());
// });
} }
} // 还原索引到Array 一同返回
} else {
// Mlikiowa V2.0.0 Refactor Todo // let retData: any[] = [];
// _groupMembers.forEach(async item => { // for (let retMem of MemberMap.values()) {
// item.last_sent_time = parseInt((await getGroupMember(payload.group_id.toString(), item.user_id))?.lastSpeakTime || date.toString()); // retMem.level = TypeConvert.toString(retMem.level) as any;
// item.join_time = parseInt((await getGroupMember(payload.group_id.toString(), item.user_id))?.joinTime || date.toString()); // retData.push(retMem)
// }); // }
// _groupMembers = Array.from(retData);
_groupMembers = Array.from(MemberMap.values());
return _groupMembers;
} }
// 还原索引到Array 一同返回
// let retData: any[] = [];
// for (let retMem of MemberMap.values()) {
// retMem.level = TypeConvert.toString(retMem.level) as any;
// retData.push(retMem)
// }
// _groupMembers = Array.from(retData);
_groupMembers = Array.from(MemberMap.values());
return _groupMembers;
}
} }
export default GetGroupMemberList; export default GetGroupMemberList;

View File

@@ -16,11 +16,11 @@ interface GroupNotice {
} }
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
group_id: { type: [ 'number' , 'string' ] }, group_id: { type: [ 'number' , 'string' ] },
}, },
required: ['group_id'] required: ['group_id']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
@@ -28,33 +28,33 @@ type Payload = FromSchema<typeof SchemaData>;
type ApiGroupNotice = GroupNotice & WebApiGroupNoticeFeed; type ApiGroupNotice = GroupNotice & WebApiGroupNoticeFeed;
export class GetGroupNotice extends BaseAction<Payload, GroupNotice[]> { export class GetGroupNotice extends BaseAction<Payload, GroupNotice[]> {
actionName = ActionName.GoCQHTTP_GetGroupNotice; actionName = ActionName.GoCQHTTP_GetGroupNotice;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const NTQQWebApi = this.CoreContext.getApiContext().WebApi; const NTQQWebApi = this.CoreContext.getApiContext().WebApi;
const group = payload.group_id.toString(); const group = payload.group_id.toString();
const ret = await NTQQWebApi.getGroupNotice(group); const ret = await NTQQWebApi.getGroupNotice(group);
if (!ret) { if (!ret) {
throw new Error('获取公告失败'); throw new Error('获取公告失败');
} }
const retNotices: GroupNotice[] = new Array<ApiGroupNotice>(); const retNotices: GroupNotice[] = new Array<ApiGroupNotice>();
for (const key in ret.feeds) { for (const key in ret.feeds) {
const retApiNotice: WebApiGroupNoticeFeed = ret.feeds[key]; const retApiNotice: WebApiGroupNoticeFeed = ret.feeds[key];
const retNotice: GroupNotice = { const retNotice: GroupNotice = {
// ...ret.feeds[key], // ...ret.feeds[key],
sender_id: retApiNotice.u, sender_id: retApiNotice.u,
publish_time: retApiNotice.pubt, publish_time: retApiNotice.pubt,
message: { message: {
text: retApiNotice.msg.text, text: retApiNotice.msg.text,
image: retApiNotice.msg.pics?.map((pic) => { image: retApiNotice.msg.pics?.map((pic) => {
return { id: pic.id, height: pic.h, width: pic.w }; return { id: pic.id, height: pic.h, width: pic.w };
}) || [] }) || []
}
};
retNotices.push(retNotice);
} }
};
retNotices.push(retNotice);
}
return retNotices; return retNotices;
} }
} }

View File

@@ -3,46 +3,46 @@ import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
group_id: { type: ['number', 'string'] } group_id: { type: ['number', 'string'] }
}, },
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export class GetGroupSystemMsg extends BaseAction<void, any> { export class GetGroupSystemMsg extends BaseAction<void, any> {
actionName = ActionName.GetGroupSystemMsg; actionName = ActionName.GetGroupSystemMsg;
protected async _handle(payload: void) { protected async _handle(payload: void) {
const NTQQUserApi = this.CoreContext.getApiContext().UserApi; const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi; const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
// 默认10条 该api未完整实现 包括响应数据规范化 类型规范化 // 默认10条 该api未完整实现 包括响应数据规范化 类型规范化
const SingleScreenNotifies = await NTQQGroupApi.getSingleScreenNotifies(10); const SingleScreenNotifies = await NTQQGroupApi.getSingleScreenNotifies(10);
const retData: any = { InvitedRequest: [], join_requests: [] }; const retData: any = { InvitedRequest: [], join_requests: [] };
for (const SSNotify of SingleScreenNotifies) { for (const SSNotify of SingleScreenNotifies) {
if (SSNotify.type == 1) { if (SSNotify.type == 1) {
retData.InvitedRequest.push({ retData.InvitedRequest.push({
request_id: SSNotify.seq, request_id: SSNotify.seq,
invitor_uin: await NTQQUserApi.getUinByUid(SSNotify.user1?.uid), invitor_uin: await NTQQUserApi.getUinByUid(SSNotify.user1?.uid),
invitor_nick: SSNotify.user1?.nickName, invitor_nick: SSNotify.user1?.nickName,
group_id: SSNotify.group?.groupCode, group_id: SSNotify.group?.groupCode,
group_name: SSNotify.group?.groupName, group_name: SSNotify.group?.groupName,
checked: SSNotify.status === 1 ? false : true, checked: SSNotify.status === 1 ? false : true,
actor: await NTQQUserApi.getUinByUid(SSNotify.user2?.uid) || 0, actor: await NTQQUserApi.getUinByUid(SSNotify.user2?.uid) || 0,
}); });
} else if (SSNotify.type == 7) { } else if (SSNotify.type == 7) {
retData.join_requests.push({ retData.join_requests.push({
request_id: SSNotify.seq, request_id: SSNotify.seq,
requester_uin: await NTQQUserApi.getUinByUid(SSNotify.user1?.uid), requester_uin: await NTQQUserApi.getUinByUid(SSNotify.user1?.uid),
requester_nick: SSNotify.user1?.nickName, requester_nick: SSNotify.user1?.nickName,
group_id: SSNotify.group?.groupCode, group_id: SSNotify.group?.groupCode,
group_name: SSNotify.group?.groupName, group_name: SSNotify.group?.groupName,
checked: SSNotify.status === 1 ? false : true, checked: SSNotify.status === 1 ? false : true,
actor: await NTQQUserApi.getUinByUid(SSNotify.user2?.uid) || 0, actor: await NTQQUserApi.getUinByUid(SSNotify.user2?.uid) || 0,
}); });
} }
} }
return retData; return retData;
} }
} }

View File

@@ -2,9 +2,9 @@ import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
export default class GetGuildList extends BaseAction<null, null> { export default class GetGuildList extends BaseAction<null, null> {
actionName = ActionName.GetGuildList; actionName = ActionName.GetGuildList;
protected async _handle(payload: null): Promise<null> { protected async _handle(payload: null): Promise<null> {
return null; return null;
} }
} }

View File

@@ -4,14 +4,14 @@ import { OB11PostSendMsg } from '../../types';
// 未检测参数 // 未检测参数
class SendGroupMsg extends SendMsg { class SendGroupMsg extends SendMsg {
actionName = ActionName.SendGroupMsg; actionName = ActionName.SendGroupMsg;
contextMode: ContextMode = ContextMode.Group; contextMode: ContextMode = ContextMode.Group;
protected async check(payload: OB11PostSendMsg): Promise<BaseCheckResult> { protected async check(payload: OB11PostSendMsg): Promise<BaseCheckResult> {
delete payload.user_id; delete payload.user_id;
payload.message_type = 'group'; payload.message_type = 'group';
return super.check(payload); return super.check(payload);
} }
} }
export default SendGroupMsg; export default SendGroupMsg;

View File

@@ -4,27 +4,27 @@ import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { MessageUnique } from '@/common/utils/MessageUnique'; import { MessageUnique } from '@/common/utils/MessageUnique';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
message_id: { type: ['number', 'string'] } message_id: { type: ['number', 'string'] }
}, },
required: ['message_id'] required: ['message_id']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export default class SetEssenceMsg extends BaseAction<Payload, any> { export default class SetEssenceMsg extends BaseAction<Payload, any> {
actionName = ActionName.SetEssenceMsg; actionName = ActionName.SetEssenceMsg;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload): Promise<any> { protected async _handle(payload: Payload): Promise<any> {
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi; const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
const msg = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString())); const msg = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString()));
if (!msg) { if (!msg) {
throw new Error('msg not found'); throw new Error('msg not found');
}
return await NTQQGroupApi.addGroupEssence(
msg.Peer.peerUid,
msg.MsgId
);
} }
return await NTQQGroupApi.addGroupEssence(
msg.Peer.peerUid,
msg.MsgId
);
}
} }

View File

@@ -5,28 +5,28 @@ import { NTQQGroupApi } from '@/core/apis/group';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
flag: { type: 'string' }, flag: { type: 'string' },
approve: { type: ['string', 'boolean'] }, approve: { type: ['string', 'boolean'] },
reason: { type: 'string', nullable: true, } reason: { type: 'string', nullable: true, }
}, },
required: ['flag'], required: ['flag'],
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export default class SetGroupAddRequest extends BaseAction<Payload, null> { export default class SetGroupAddRequest extends BaseAction<Payload, null> {
actionName = ActionName.SetGroupAddRequest; actionName = ActionName.SetGroupAddRequest;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload): Promise<null> { protected async _handle(payload: Payload): Promise<null> {
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi; const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
const flag = payload.flag.toString(); const flag = payload.flag.toString();
const approve = payload.approve?.toString() !== 'false'; const approve = payload.approve?.toString() !== 'false';
await NTQQGroupApi.handleGroupRequest(flag, await NTQQGroupApi.handleGroupRequest(flag,
approve ? GroupRequestOperateTypes.approve : GroupRequestOperateTypes.reject, approve ? GroupRequestOperateTypes.approve : GroupRequestOperateTypes.reject,
payload.reason || " " payload.reason || " "
); );
return null; return null;
} }
} }

View File

@@ -5,26 +5,26 @@ import { NTQQGroupApi } from '@/core/apis/group';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
group_id: { type: [ 'number' , 'string' ] }, group_id: { type: [ 'number' , 'string' ] },
user_id: { type: [ 'number' , 'string' ] }, user_id: { type: [ 'number' , 'string' ] },
enable: { type: 'boolean' } enable: { type: 'boolean' }
}, },
required: ['group_id', 'user_id'] required: ['group_id', 'user_id']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export default class SetGroupAdmin extends BaseAction<Payload, null> { export default class SetGroupAdmin extends BaseAction<Payload, null> {
actionName = ActionName.SetGroupAdmin; actionName = ActionName.SetGroupAdmin;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload): Promise<null> { protected async _handle(payload: Payload): Promise<null> {
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi; const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
const NTQQUserApi = this.CoreContext.getApiContext().UserApi; const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
let uid = await NTQQUserApi.getUidByUin(payload.user_id.toString()) const uid = await NTQQUserApi.getUidByUin(payload.user_id.toString());
if(!uid) throw new Error('get Uid Error') if(!uid) throw new Error('get Uid Error');
await NTQQGroupApi.setMemberRole(payload.group_id.toString(), uid, payload.enable ? GroupMemberRole.admin : GroupMemberRole.normal); await NTQQGroupApi.setMemberRole(payload.group_id.toString(), uid, payload.enable ? GroupMemberRole.admin : GroupMemberRole.normal);
return null; return null;
} }
} }

View File

@@ -3,27 +3,27 @@ import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
group_id: { type: ['number', 'string'] }, group_id: { type: ['number', 'string'] },
user_id: { type: ['number', 'string'] }, user_id: { type: ['number', 'string'] },
duration: { type: ['number', 'string'] } duration: { type: ['number', 'string'] }
}, },
required: ['group_id', 'user_id', 'duration'] required: ['group_id', 'user_id', 'duration']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export default class SetGroupBan extends BaseAction<Payload, null> { export default class SetGroupBan extends BaseAction<Payload, null> {
actionName = ActionName.SetGroupBan; actionName = ActionName.SetGroupBan;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload): Promise<null> { protected async _handle(payload: Payload): Promise<null> {
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi; const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
const NTQQUserApi = this.CoreContext.getApiContext().UserApi; const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
const uid = await NTQQUserApi.getUidByUin(payload.user_id.toString()); const uid = await NTQQUserApi.getUidByUin(payload.user_id.toString());
if(!uid) throw new Error('uid error'); if(!uid) throw new Error('uid error');
await NTQQGroupApi.banMember(payload.group_id.toString(), await NTQQGroupApi.banMember(payload.group_id.toString(),
[{ uid: uid, timeStamp: parseInt(payload.duration.toString()) }]); [{ uid: uid, timeStamp: parseInt(payload.duration.toString()) }]);
return null; return null;
} }
} }

View File

@@ -3,23 +3,23 @@ import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
group_id: { type: [ 'number' , 'string' ] }, group_id: { type: [ 'number' , 'string' ] },
user_id: { type: [ 'number' , 'string' ] }, user_id: { type: [ 'number' , 'string' ] },
card: { type: 'string' } card: { type: 'string' }
}, },
required: ['group_id', 'user_id', 'card'] required: ['group_id', 'user_id', 'card']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export default class SetGroupCard extends BaseAction<Payload, null> { export default class SetGroupCard extends BaseAction<Payload, null> {
actionName = ActionName.SetGroupCard; actionName = ActionName.SetGroupCard;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload): Promise<null> { protected async _handle(payload: Payload): Promise<null> {
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi; const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
await NTQQGroupApi.setMemberCard(payload.group_id.toString(), member.uid, payload.card || ''); await NTQQGroupApi.setMemberCard(payload.group_id.toString(), member.uid, payload.card || '');
return null; return null;
} }
} }

View File

@@ -5,27 +5,27 @@ import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
group_id: { type: [ 'number' , 'string' ] }, group_id: { type: [ 'number' , 'string' ] },
user_id: { type: [ 'number' , 'string' ] }, user_id: { type: [ 'number' , 'string' ] },
reject_add_request: { type: [ 'boolean' , 'string' ] } reject_add_request: { type: [ 'boolean' , 'string' ] }
}, },
required: ['group_id', 'user_id'] required: ['group_id', 'user_id']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export default class SetGroupKick extends BaseAction<Payload, null> { export default class SetGroupKick extends BaseAction<Payload, null> {
actionName = ActionName.SetGroupKick; actionName = ActionName.SetGroupKick;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload): Promise<null> { protected async _handle(payload: Payload): Promise<null> {
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi; const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
const NTQQUserApi = this.CoreContext.getApiContext().UserApi; const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
const rejectReq = payload.reject_add_request?.toString() == 'true'; const rejectReq = payload.reject_add_request?.toString() == 'true';
const uid = await NTQQUserApi.getUidByUin(payload.user_id.toString()); const uid = await NTQQUserApi.getUidByUin(payload.user_id.toString());
if(!uid) throw new Error('get Uid Error') if(!uid) throw new Error('get Uid Error');
await NTQQGroupApi.kickMember(payload.group_id.toString(), [uid], rejectReq); await NTQQGroupApi.kickMember(payload.group_id.toString(), [uid], rejectReq);
return null; return null;
} }
} }

View File

@@ -2,24 +2,20 @@ import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
group_id: { type: [ 'number' , 'string' ] }, group_id: { type: [ 'number' , 'string' ] },
is_dismiss: { type: 'boolean' } is_dismiss: { type: 'boolean' }
}, },
required: ['group_id'] required: ['group_id']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export default class SetGroupLeave extends BaseAction<Payload, any> { export default class SetGroupLeave extends BaseAction<Payload, any> {
actionName = ActionName.SetGroupLeave; actionName = ActionName.SetGroupLeave;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload): Promise<any> { protected async _handle(payload: Payload): Promise<any> {
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi; const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
try { await NTQQGroupApi.quitGroup(payload.group_id.toString());
await NTQQGroupApi.quitGroup(payload.group_id.toString());
} catch (e) {
throw e;
} }
}
} }

View File

@@ -4,21 +4,21 @@ import { ActionName } from '../types';
import { NTQQGroupApi } from '@/core/apis/group'; import { NTQQGroupApi } from '@/core/apis/group';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
group_id: { type: [ 'number' , 'string' ] }, group_id: { type: [ 'number' , 'string' ] },
group_name: { type: 'string' } group_name: { type: 'string' }
}, },
required: ['group_id', 'group_name'] required: ['group_id', 'group_name']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export default class SetGroupName extends BaseAction<Payload, null> { export default class SetGroupName extends BaseAction<Payload, null> {
actionName = ActionName.SetGroupName; actionName = ActionName.SetGroupName;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload): Promise<null> { protected async _handle(payload: Payload): Promise<null> {
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi; const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
await NTQQGroupApi.setGroupName(payload.group_id.toString(), payload.group_name); await NTQQGroupApi.setGroupName(payload.group_id.toString(), payload.group_name);
return null; return null;
} }
} }

View File

@@ -2,23 +2,23 @@ import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import BaseAction from '../BaseAction'; import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
group_id: { type: [ 'number' , 'string' ] }, group_id: { type: [ 'number' , 'string' ] },
enable: { type: ['boolean','string'] } enable: { type: ['boolean','string'] }
}, },
required: ['group_id'] required: ['group_id']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export default class SetGroupWholeBan extends BaseAction<Payload, null> { export default class SetGroupWholeBan extends BaseAction<Payload, null> {
actionName = ActionName.SetGroupWholeBan; actionName = ActionName.SetGroupWholeBan;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload): Promise<null> { protected async _handle(payload: Payload): Promise<null> {
const enable = payload.enable?.toString() !== 'false'; const enable = payload.enable?.toString() !== 'false';
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi; const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
await NTQQGroupApi.banGroup(payload.group_id.toString(), enable); await NTQQGroupApi.banGroup(payload.group_id.toString(), enable);
return null; return null;
} }
} }

View File

@@ -15,9 +15,9 @@ import CanSendRecord from './system/CanSendRecord';
import CanSendImage from './system/CanSendImage'; import CanSendImage from './system/CanSendImage';
import GetStatus from './system/GetStatus'; import GetStatus from './system/GetStatus';
import { import {
GoCQHTTPSendForwardMsg, GoCQHTTPSendForwardMsg,
GoCQHTTPSendGroupForwardMsg, GoCQHTTPSendGroupForwardMsg,
GoCQHTTPSendPrivateForwardMsg GoCQHTTPSendPrivateForwardMsg
} from './go-cqhttp/SendForwardMsg'; } from './go-cqhttp/SendForwardMsg';
import GoCQHTTPGetStrangerInfo from './go-cqhttp/GetStrangerInfo'; import GoCQHTTPGetStrangerInfo from './go-cqhttp/GetStrangerInfo';
import SendLike from './user/SendLike'; import SendLike from './user/SendLike';
@@ -77,94 +77,94 @@ import { FetchEmojioLike } from './extends/FetchEmojioLike';
import { NapCatCore } from '@/core'; import { NapCatCore } from '@/core';
export function createActionMap(context: NapCatCore) { export function createActionMap(context: NapCatCore) {
let actionHandlers = [ const actionHandlers = [
new FetchEmojioLike(context), new FetchEmojioLike(context),
new GetFile(context), new GetFile(context),
new SetSelfProfile(context), new SetSelfProfile(context),
new shareGroupEx(context), new shareGroupEx(context),
new sharePeer(context), new sharePeer(context),
new CreateCollection(context), new CreateCollection(context),
new SetLongNick(context), new SetLongNick(context),
new ForwardFriendSingleMsg(context), new ForwardFriendSingleMsg(context),
new ForwardGroupSingleMsg(context), new ForwardGroupSingleMsg(context),
new MarkGroupMsgAsRead(context), new MarkGroupMsgAsRead(context),
new MarkPrivateMsgAsRead(context), new MarkPrivateMsgAsRead(context),
new SetQQAvatar(context), new SetQQAvatar(context),
new TranslateEnWordToZn(context), new TranslateEnWordToZn(context),
new GetGroupFileCount(context), new GetGroupFileCount(context),
new GetGroupFileList(context), new GetGroupFileList(context),
new SetGroupFileFolder(context), new SetGroupFileFolder(context),
new DelGroupFile(context), new DelGroupFile(context),
new DelGroupFileFolder(context), new DelGroupFileFolder(context),
// onebot11 // onebot11
new SendLike(context), new SendLike(context),
new GetMsg(context), new GetMsg(context),
new GetLoginInfo(context), new GetLoginInfo(context),
new GetFriendList(context), new GetFriendList(context),
new GetGroupList(context), new GetGroupList(context),
new GetGroupInfo(context), new GetGroupInfo(context),
new GetGroupMemberList(context), new GetGroupMemberList(context),
new GetGroupMemberInfo(context), new GetGroupMemberInfo(context),
new SendGroupMsg(context), new SendGroupMsg(context),
new SendPrivateMsg(context), new SendPrivateMsg(context),
new SendMsg(context), new SendMsg(context),
new DeleteMsg(context), new DeleteMsg(context),
new SetGroupAddRequest(context), new SetGroupAddRequest(context),
new SetFriendAddRequest(context), new SetFriendAddRequest(context),
new SetGroupLeave(context), new SetGroupLeave(context),
new GetVersionInfo(context), new GetVersionInfo(context),
new CanSendRecord(context), new CanSendRecord(context),
new CanSendImage(context), new CanSendImage(context),
new GetStatus(context), new GetStatus(context),
new SetGroupWholeBan(context), new SetGroupWholeBan(context),
new SetGroupBan(context), new SetGroupBan(context),
new SetGroupKick(context), new SetGroupKick(context),
new SetGroupAdmin(context), new SetGroupAdmin(context),
new SetGroupName(context), new SetGroupName(context),
new SetGroupCard(context), new SetGroupCard(context),
new GetImage(context), new GetImage(context),
new GetRecord(context), new GetRecord(context),
new SetMsgEmojiLike(context), new SetMsgEmojiLike(context),
new GetCookies(context), new GetCookies(context),
new SetOnlineStatus(context), new SetOnlineStatus(context),
new GetRobotUinRange(context), new GetRobotUinRange(context),
new GetFriendWithCategory(context), new GetFriendWithCategory(context),
//以下为go-cqhttp api //以下为go-cqhttp api
new GetOnlineClient(context), new GetOnlineClient(context),
new OCRImage(context), new OCRImage(context),
new IOCRImage(context), new IOCRImage(context),
new GetGroupHonorInfo(context), new GetGroupHonorInfo(context),
new SendGroupNotice(context), new SendGroupNotice(context),
new GetGroupNotice(context), new GetGroupNotice(context),
new GetGroupEssence(context), new GetGroupEssence(context),
new GoCQHTTPSendForwardMsg(context), new GoCQHTTPSendForwardMsg(context),
new GoCQHTTPSendGroupForwardMsg(context), new GoCQHTTPSendGroupForwardMsg(context),
new GoCQHTTPSendPrivateForwardMsg(context), new GoCQHTTPSendPrivateForwardMsg(context),
new GoCQHTTPGetStrangerInfo(context), new GoCQHTTPGetStrangerInfo(context),
new GoCQHTTPDownloadFile(context), new GoCQHTTPDownloadFile(context),
new GetGuildList(context), new GetGuildList(context),
new GoCQHTTPMarkMsgAsRead(context), new GoCQHTTPMarkMsgAsRead(context),
new GoCQHTTPUploadGroupFile(context), new GoCQHTTPUploadGroupFile(context),
new GoCQHTTPGetGroupMsgHistory(context), new GoCQHTTPGetGroupMsgHistory(context),
new GoCQHTTPGetForwardMsgAction(context), new GoCQHTTPGetForwardMsgAction(context),
new GetFriendMsgHistory(context), new GetFriendMsgHistory(context),
new GoCQHTTPHandleQuickAction(context), new GoCQHTTPHandleQuickAction(context),
new GetGroupSystemMsg(context), new GetGroupSystemMsg(context),
new DelEssenceMsg(context), new DelEssenceMsg(context),
new SetEssenceMsg(context), new SetEssenceMsg(context),
new GetRecentContact(context), new GetRecentContact(context),
new MarkAllMsgAsRead(context), new MarkAllMsgAsRead(context),
new GetProfileLike(context), new GetProfileLike(context),
new SetGroupHeader(context), new SetGroupHeader(context),
new FetchCustomFace(context), new FetchCustomFace(context),
new GoCQHTTPUploadPrivateFile(context) new GoCQHTTPUploadPrivateFile(context)
]; ];
const actionMap = new Map<string, BaseAction<any, any>>(); const actionMap = new Map<string, BaseAction<any, any>>();
for (const action of actionHandlers) { for (const action of actionHandlers) {
actionMap.set(action.actionName, action); actionMap.set(action.actionName, action);
actionMap.set(action.actionName + '_async', action); actionMap.set(action.actionName + '_async', action);
actionMap.set(action.actionName + '_rate_limited', action); actionMap.set(action.actionName + '_rate_limited', action);
} }
return actionMap; return actionMap;
} }

View File

@@ -5,48 +5,48 @@ import { MessageUnique } from '@/common/utils/MessageUnique';
import { NodeIKernelMsgListener } from '@/core'; import { NodeIKernelMsgListener } from '@/core';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
message_id: { message_id: {
oneOf: [ oneOf: [
{ type: 'number' }, { type: 'number' },
{ type: 'string' } { type: 'string' }
] ]
} }
}, },
required: ['message_id'] required: ['message_id']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
class DeleteMsg extends BaseAction<Payload, void> { class DeleteMsg extends BaseAction<Payload, void> {
actionName = ActionName.DeleteMsg; actionName = ActionName.DeleteMsg;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi; const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi;
const msg = MessageUnique.getMsgIdAndPeerByShortId(Number(payload.message_id)); const msg = MessageUnique.getMsgIdAndPeerByShortId(Number(payload.message_id));
if (msg) { if (msg) {
let ret = this.CoreContext.eventWrapper.RegisterListen<NodeIKernelMsgListener['onMsgInfoListUpdate']> const ret = this.CoreContext.eventWrapper.RegisterListen<NodeIKernelMsgListener['onMsgInfoListUpdate']>
( (
'NodeIKernelMsgListener/onMsgInfoListUpdate', 'NodeIKernelMsgListener/onMsgInfoListUpdate',
1, 1,
5000, 5000,
(msgs) => { (msgs) => {
if (msgs.find(m => m.msgId === msg.MsgId && m.recallTime !== '0')) { if (msgs.find(m => m.msgId === msg.MsgId && m.recallTime !== '0')) {
return true; return true;
}
return false;
}
).catch(e => new Promise<undefined>((resolve, reject) => { resolve(undefined); }));
await NTQQMsgApi.recallMsg(msg.Peer, [msg.MsgId]);
const data = await ret;
if (!data) {
throw new Error('Recall failed');
} }
return false; //await sleep(100);
} //await NTQQMsgApi.getMsgsByMsgId(msg.Peer, [msg.MsgId]);
).catch(e => new Promise<undefined>((resolve, reject) => { resolve(undefined) })); }
await NTQQMsgApi.recallMsg(msg.Peer, [msg.MsgId]);
let data = await ret;
if (!data) {
throw new Error('Recall failed');
}
//await sleep(100);
//await NTQQMsgApi.getMsgsByMsgId(msg.Peer, [msg.MsgId]);
} }
}
} }
export default DeleteMsg; export default DeleteMsg;

View File

@@ -5,54 +5,54 @@ import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { MessageUnique } from '@/common/utils/MessageUnique'; import { MessageUnique } from '@/common/utils/MessageUnique';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
message_id: { type: 'number' }, message_id: { type: 'number' },
group_id: { type: ['number', 'string'] }, group_id: { type: ['number', 'string'] },
user_id: { type: ['number', 'string'] } user_id: { type: ['number', 'string'] }
}, },
required: ['message_id'] required: ['message_id']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
class ForwardSingleMsg extends BaseAction<Payload, null> { class ForwardSingleMsg extends BaseAction<Payload, null> {
protected async getTargetPeer(payload: Payload): Promise<Peer> { protected async getTargetPeer(payload: Payload): Promise<Peer> {
const NTQQUserApi = this.CoreContext.getApiContext().UserApi; const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
if (payload.user_id) { if (payload.user_id) {
const peerUid = await NTQQUserApi.getUidByUin(payload.user_id.toString()); const peerUid = await NTQQUserApi.getUidByUin(payload.user_id.toString());
if (!peerUid) { if (!peerUid) {
throw new Error(`无法找到私聊对象${payload.user_id}`); throw new Error(`无法找到私聊对象${payload.user_id}`);
} }
return { chatType: ChatType.friend, peerUid }; return { chatType: ChatType.friend, peerUid };
}
return { chatType: ChatType.group, peerUid: payload.group_id!.toString() };
} }
return { chatType: ChatType.group, peerUid: payload.group_id!.toString() };
}
protected async _handle(payload: Payload): Promise<null> { protected async _handle(payload: Payload): Promise<null> {
const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi; const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi;
const msg = MessageUnique.getMsgIdAndPeerByShortId(payload.message_id); const msg = MessageUnique.getMsgIdAndPeerByShortId(payload.message_id);
if (!msg) { if (!msg) {
throw new Error(`无法找到消息${payload.message_id}`); throw new Error(`无法找到消息${payload.message_id}`);
}
const peer = await this.getTargetPeer(payload);
const ret = await NTQQMsgApi.forwardMsg(msg.Peer,
peer,
[msg.MsgId],
);
if (ret.result !== 0) {
throw new Error(`转发消息失败 ${ret.errMsg}`);
}
return null;
} }
const peer = await this.getTargetPeer(payload);
const ret = await NTQQMsgApi.forwardMsg(msg.Peer,
peer,
[msg.MsgId],
);
if (ret.result !== 0) {
throw new Error(`转发消息失败 ${ret.errMsg}`);
}
return null;
}
} }
export class ForwardFriendSingleMsg extends ForwardSingleMsg { export class ForwardFriendSingleMsg extends ForwardSingleMsg {
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
actionName = ActionName.ForwardFriendSingleMsg; actionName = ActionName.ForwardFriendSingleMsg;
} }
export class ForwardGroupSingleMsg extends ForwardSingleMsg { export class ForwardGroupSingleMsg extends ForwardSingleMsg {
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
actionName = ActionName.ForwardGroupSingleMsg; actionName = ActionName.ForwardGroupSingleMsg;
} }

View File

@@ -9,42 +9,42 @@ import { MessageUnique } from '@/common/utils/MessageUnique';
export type ReturnDataType = OB11Message export type ReturnDataType = OB11Message
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
message_id: { type: ['number', 'string'] }, message_id: { type: ['number', 'string'] },
}, },
required: ['message_id'] required: ['message_id']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
class GetMsg extends BaseAction<Payload, OB11Message> { class GetMsg extends BaseAction<Payload, OB11Message> {
actionName = ActionName.GetMsg; actionName = ActionName.GetMsg;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi; const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi;
// log("history msg ids", Object.keys(msgHistory)); // log("history msg ids", Object.keys(msgHistory));
if (!payload.message_id) { if (!payload.message_id) {
throw Error('参数message_id不能为空'); throw Error('参数message_id不能为空');
}
const MsgShortId = await MessageUnique.getShortIdByMsgId(payload.message_id.toString());
const msgIdWithPeer = await MessageUnique.getMsgIdAndPeerByShortId(MsgShortId || parseInt(payload.message_id.toString()));
if (!msgIdWithPeer) {
throw ('消息不存在');
}
const peer = { guildId: '', peerUid: msgIdWithPeer?.Peer.peerUid, chatType: msgIdWithPeer.Peer.chatType };
const msg = await NTQQMsgApi.getMsgsByMsgId(
peer,
[msgIdWithPeer?.MsgId || payload.message_id.toString()]);
const retMsg = await OB11Constructor.message(this.CoreContext, msg.msgList[0], "array");
try {
retMsg.message_id = MessageUnique.createMsg(peer, msg.msgList[0].msgId)!;
retMsg.message_seq = retMsg.message_id;
retMsg.real_id = retMsg.message_id;
} catch (e) {
}
return retMsg;
} }
const MsgShortId = await MessageUnique.getShortIdByMsgId(payload.message_id.toString());
const msgIdWithPeer = await MessageUnique.getMsgIdAndPeerByShortId(MsgShortId || parseInt(payload.message_id.toString()));
if (!msgIdWithPeer) {
throw ('消息不存在');
}
const peer = { guildId: '', peerUid: msgIdWithPeer?.Peer.peerUid, chatType: msgIdWithPeer.Peer.chatType };
const msg = await NTQQMsgApi.getMsgsByMsgId(
peer,
[msgIdWithPeer?.MsgId || payload.message_id.toString()]);
const retMsg = await OB11Constructor.message(this.CoreContext, msg.msgList[0], "array");
try {
retMsg.message_id = MessageUnique.createMsg(peer, msg.msgList[0].msgId)!;
retMsg.message_seq = retMsg.message_id;
retMsg.real_id = retMsg.message_id;
} catch (e) {
}
return retMsg;
}
} }
export default GetMsg; export default GetMsg;

View File

@@ -5,50 +5,50 @@ import { NTQQFriendApi, NTQQMsgApi, NTQQUserApi } from '@/core/apis';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
user_id: { type: ['number', 'string'] }, user_id: { type: ['number', 'string'] },
group_id: { type: ['number', 'string'] } group_id: { type: ['number', 'string'] }
} }
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type PlayloadType = FromSchema<typeof SchemaData>; type PlayloadType = FromSchema<typeof SchemaData>;
class MarkMsgAsRead extends BaseAction<PlayloadType, null> { class MarkMsgAsRead extends BaseAction<PlayloadType, null> {
async getPeer(payload: PlayloadType): Promise<Peer> { async getPeer(payload: PlayloadType): Promise<Peer> {
const NTQQUserApi = this.CoreContext.getApiContext().UserApi; const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
const NTQQFriendApi = this.CoreContext.getApiContext().FriendApi; const NTQQFriendApi = this.CoreContext.getApiContext().FriendApi;
if (payload.user_id) { if (payload.user_id) {
const peerUid = await NTQQUserApi.getUidByUin(payload.user_id.toString()); const peerUid = await NTQQUserApi.getUidByUin(payload.user_id.toString());
if (!peerUid) { if (!peerUid) {
throw `私聊${payload.user_id}不存在`; throw `私聊${payload.user_id}不存在`;
} }
const isBuddy = await NTQQFriendApi.isBuddy(peerUid); const isBuddy = await NTQQFriendApi.isBuddy(peerUid);
return { chatType: isBuddy ? ChatType.friend : ChatType.temp, peerUid }; return { chatType: isBuddy ? ChatType.friend : ChatType.temp, peerUid };
}
if (!payload.group_id) {
throw '缺少参数 group_id 或 user_id';
}
return { chatType: ChatType.group, peerUid: payload.group_id.toString() };
} }
if (!payload.group_id) { protected async _handle(payload: PlayloadType): Promise<null> {
throw '缺少参数 group_id 或 user_id'; const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi;
// 调用API
const ret = await NTQQMsgApi.setMsgRead(await this.getPeer(payload));
if (ret.result != 0) {
throw ('设置已读失败,' + ret.errMsg);
}
return null;
} }
return { chatType: ChatType.group, peerUid: payload.group_id.toString() };
}
protected async _handle(payload: PlayloadType): Promise<null> {
const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi;
// 调用API
const ret = await NTQQMsgApi.setMsgRead(await this.getPeer(payload));
if (ret.result != 0) {
throw ('设置已读失败,' + ret.errMsg);
}
return null;
}
} }
// 以下为非标准实现 // 以下为非标准实现
export class MarkPrivateMsgAsRead extends MarkMsgAsRead { export class MarkPrivateMsgAsRead extends MarkMsgAsRead {
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
actionName = ActionName.MarkPrivateMsgAsRead; actionName = ActionName.MarkPrivateMsgAsRead;
} }
export class MarkGroupMsgAsRead extends MarkMsgAsRead { export class MarkGroupMsgAsRead extends MarkMsgAsRead {
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
actionName = ActionName.MarkGroupMsgAsRead; actionName = ActionName.MarkGroupMsgAsRead;
} }
@@ -57,19 +57,19 @@ interface Payload {
} }
export class GoCQHTTPMarkMsgAsRead extends BaseAction<Payload, null> { export class GoCQHTTPMarkMsgAsRead extends BaseAction<Payload, null> {
actionName = ActionName.GoCQHTTP_MarkMsgAsRead; actionName = ActionName.GoCQHTTP_MarkMsgAsRead;
protected async _handle(payload: Payload): Promise<null> { protected async _handle(payload: Payload): Promise<null> {
return null; return null;
} }
} }
export class MarkAllMsgAsRead extends BaseAction<Payload, null> { export class MarkAllMsgAsRead extends BaseAction<Payload, null> {
actionName = ActionName._MarkAllMsgAsRead; actionName = ActionName._MarkAllMsgAsRead;
protected async _handle(payload: Payload): Promise<null> { protected async _handle(payload: Payload): Promise<null> {
const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi; const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi;
await NTQQMsgApi.markallMsgAsRead(); await NTQQMsgApi.markallMsgAsRead();
return null; return null;
} }
} }

View File

@@ -1,36 +1,36 @@
import { OB11MessageData } from '@/onebot/types'; import { OB11MessageData } from '@/onebot/types';
function checkSendMessage(sendMsgList: OB11MessageData[]) { function checkSendMessage(sendMsgList: OB11MessageData[]) {
function checkUri(uri: string): boolean { function checkUri(uri: string): boolean {
const pattern = /^(file:\/\/|http:\/\/|https:\/\/|base64:\/\/)/; const pattern = /^(file:\/\/|http:\/\/|https:\/\/|base64:\/\/)/;
return pattern.test(uri); return pattern.test(uri);
}
for (const msg of sendMsgList) {
if (msg['type'] && msg['data']) {
const type = msg['type'];
const data = msg['data'];
if (type === 'text' && !data['text']) {
return 400;
} else if (['image', 'voice', 'record'].includes(type)) {
if (!data['file']) {
return 400;
} else {
if (checkUri(data['file'])) {
return 200;
} else {
return 400;
}
}
} else if (type === 'at' && !data['qq']) {
return 400;
} else if (type === 'reply' && !data['id']) {
return 400;
}
} else {
return 400;
} }
}
return 200; for (const msg of sendMsgList) {
if (msg['type'] && msg['data']) {
const type = msg['type'];
const data = msg['data'];
if (type === 'text' && !data['text']) {
return 400;
} else if (['image', 'voice', 'record'].includes(type)) {
if (!data['file']) {
return 400;
} else {
if (checkUri(data['file'])) {
return 200;
} else {
return 400;
}
}
} else if (type === 'at' && !data['qq']) {
return 400;
} else if (type === 'reply' && !data['id']) {
return 400;
}
} else {
return 400;
}
}
return 200;
} }

View File

@@ -10,23 +10,23 @@ export type MessageContext = {
peer: Peer peer: Peer
} }
async function handleOb11FileLikeMessage( async function handleOb11FileLikeMessage(
coreContext: NapCatCore, coreContext: NapCatCore,
{ data: inputdata }: OB11MessageFileBase, { data: inputdata }: OB11MessageFileBase,
{ deleteAfterSentFiles }: MessageContext { deleteAfterSentFiles }: MessageContext
) { ) {
//有的奇怪的框架将url作为参数 而不是file 此时优先url 同时注意可能传入的是非file://开头的目录 By Mlikiowa //有的奇怪的框架将url作为参数 而不是file 此时优先url 同时注意可能传入的是非file://开头的目录 By Mlikiowa
const { path, isLocal, fileName, errMsg, success } = (await uri2local(coreContext.NapCatTempPath, inputdata?.url || inputdata.file)); const { path, isLocal, fileName, errMsg, success } = (await uri2local(coreContext.NapCatTempPath, inputdata?.url || inputdata.file));
if (!success) { if (!success) {
coreContext.context.logger.logError('文件下载失败', errMsg); coreContext.context.logger.logError('文件下载失败', errMsg);
throw Error('文件下载失败' + errMsg); throw Error('文件下载失败' + errMsg);
} }
if (!isLocal) { // 只删除http和base64转过来的文件 if (!isLocal) { // 只删除http和base64转过来的文件
deleteAfterSentFiles.push(path); deleteAfterSentFiles.push(path);
} }
return { path, fileName: inputdata.name || fileName }; return { path, fileName: inputdata.name || fileName };
} }
const _handlers: { const _handlers: {
@@ -38,149 +38,150 @@ const _handlers: {
context: MessageContext context: MessageContext
) => Promise<SendMessageElement | undefined> ) => Promise<SendMessageElement | undefined>
} = { } = {
[OB11MessageDataType.text]: async (coreContext, { data: { text } }) => SendMsgElementConstructor.text(coreContext, text), [OB11MessageDataType.text]: async (coreContext, { data: { text } }) => SendMsgElementConstructor.text(coreContext, text),
[OB11MessageDataType.at]: async (coreContext, { data: { qq: atQQ } }, context) => { [OB11MessageDataType.at]: async (coreContext, { data: { qq: atQQ } }, context) => {
if (!context.peer) return undefined; if (!context.peer) return undefined;
if (atQQ === 'all') return SendMsgElementConstructor.at(coreContext, atQQ, atQQ, AtType.atAll, '全体成员'); if (atQQ === 'all') return SendMsgElementConstructor.at(coreContext, atQQ, atQQ, AtType.atAll, '全体成员');
// then the qq is a group member // then the qq is a group member
// Mlikiowa V2.0.0 Refactor Todo // Mlikiowa V2.0.0 Refactor Todo
let uid = await coreContext.getApiContext().UserApi.getUidByUin(atQQ); const uid = await coreContext.getApiContext().UserApi.getUidByUin(atQQ);
if (!uid) throw new Error('Get Uid Error') if (!uid) throw new Error('Get Uid Error');
return SendMsgElementConstructor.at(coreContext, atQQ, uid, AtType.atUser, ""); return SendMsgElementConstructor.at(coreContext, atQQ, uid, AtType.atUser, "");
}, },
[OB11MessageDataType.reply]: async (coreContext, { data: { id } }) => { [OB11MessageDataType.reply]: async (coreContext, { data: { id } }) => {
const replyMsgM = MessageUnique.getMsgIdAndPeerByShortId(parseInt(id)); const replyMsgM = MessageUnique.getMsgIdAndPeerByShortId(parseInt(id));
if (!replyMsgM) { if (!replyMsgM) {
coreContext.context.logger.logWarn('回复消息不存在', id); coreContext.context.logger.logWarn('回复消息不存在', id);
return undefined; return undefined;
} }
const NTQQMsgApi = coreContext.getApiContext().MsgApi; const NTQQMsgApi = coreContext.getApiContext().MsgApi;
const replyMsg = (await NTQQMsgApi.getMsgsByMsgId(replyMsgM?.Peer!, [replyMsgM?.MsgId!])).msgList[0]; const replyMsg = (await NTQQMsgApi.getMsgsByMsgId(
return replyMsg ? replyMsgM.Peer, [replyMsgM.MsgId!])).msgList[0];
SendMsgElementConstructor.reply(coreContext, replyMsg.msgSeq, replyMsg.msgId, replyMsg.senderUin!, replyMsg.senderUin!) : return replyMsg ?
undefined; SendMsgElementConstructor.reply(coreContext, replyMsg.msgSeq, replyMsg.msgId, replyMsg.senderUin!, replyMsg.senderUin!) :
}, undefined;
},
[OB11MessageDataType.face]: async (coreContext, { data: { id } }) => SendMsgElementConstructor.face(coreContext, parseInt(id)), [OB11MessageDataType.face]: async (coreContext, { data: { id } }) => SendMsgElementConstructor.face(coreContext, parseInt(id)),
[OB11MessageDataType.mface]: async (coreContext, { [OB11MessageDataType.mface]: async (coreContext, {
data: { data: {
emoji_package_id, emoji_id, key, summary emoji_package_id, emoji_id, key, summary
} }
}) => SendMsgElementConstructor.mface(coreContext, emoji_package_id, emoji_id, key, summary), }) => SendMsgElementConstructor.mface(coreContext, emoji_package_id, emoji_id, key, summary),
// File service // File service
[OB11MessageDataType.image]: async (coreContext, sendMsg, context) => { [OB11MessageDataType.image]: async (coreContext, sendMsg, context) => {
const PicEle = await SendMsgElementConstructor.pic( const PicEle = await SendMsgElementConstructor.pic(
coreContext, coreContext,
(await handleOb11FileLikeMessage(coreContext, sendMsg, context)).path, (await handleOb11FileLikeMessage(coreContext, sendMsg, context)).path,
sendMsg.data.summary || '', sendMsg.data.summary || '',
sendMsg.data.subType || 0 sendMsg.data.subType || 0
); );
context.deleteAfterSentFiles.push(PicEle.picElement.sourcePath); context.deleteAfterSentFiles.push(PicEle.picElement.sourcePath);
return PicEle; return PicEle;
}, // currently not supported }, // currently not supported
[OB11MessageDataType.file]: async (coreContext, sendMsg, context) => { [OB11MessageDataType.file]: async (coreContext, sendMsg, context) => {
const { path, fileName } = await handleOb11FileLikeMessage(coreContext, sendMsg, context); const { path, fileName } = await handleOb11FileLikeMessage(coreContext, sendMsg, context);
//logDebug('发送文件', path, fileName); //logDebug('发送文件', path, fileName);
const FileEle = await SendMsgElementConstructor.file(coreContext, path, fileName); const FileEle = await SendMsgElementConstructor.file(coreContext, path, fileName);
// 清除Upload的应该 // 清除Upload的应该
// context.deleteAfterSentFiles.push(fileName || FileEle.fileElement.filePath); // context.deleteAfterSentFiles.push(fileName || FileEle.fileElement.filePath);
return FileEle; return FileEle;
}, },
[OB11MessageDataType.video]: async (coreContext, sendMsg, context) => { [OB11MessageDataType.video]: async (coreContext, sendMsg, context) => {
const { path, fileName } = await handleOb11FileLikeMessage(coreContext, sendMsg, context); const { path, fileName } = await handleOb11FileLikeMessage(coreContext, sendMsg, context);
//logDebug('发送视频', path, fileName); //logDebug('发送视频', path, fileName);
let thumb = sendMsg.data.thumb; let thumb = sendMsg.data.thumb;
if (thumb) { if (thumb) {
const uri2LocalRes = await uri2local(coreContext.NapCatTempPath, thumb); const uri2LocalRes = await uri2local(coreContext.NapCatTempPath, thumb);
if (uri2LocalRes.success) thumb = uri2LocalRes.path; if (uri2LocalRes.success) thumb = uri2LocalRes.path;
} }
const videoEle = await SendMsgElementConstructor.video(coreContext, path, fileName, thumb); const videoEle = await SendMsgElementConstructor.video(coreContext, path, fileName, thumb);
//未测试 //未测试
context.deleteAfterSentFiles.push(videoEle.videoElement.filePath); context.deleteAfterSentFiles.push(videoEle.videoElement.filePath);
return videoEle; return videoEle;
}, },
[OB11MessageDataType.voice]: async (coreContext, sendMsg, context) => SendMsgElementConstructor.ptt(coreContext, (await handleOb11FileLikeMessage(coreContext, sendMsg, context)).path), [OB11MessageDataType.voice]: async (coreContext, sendMsg, context) => SendMsgElementConstructor.ptt(coreContext, (await handleOb11FileLikeMessage(coreContext, sendMsg, context)).path),
[OB11MessageDataType.json]: async (coreContext, { data: { data } }) => SendMsgElementConstructor.ark(coreContext, data), [OB11MessageDataType.json]: async (coreContext, { data: { data } }) => SendMsgElementConstructor.ark(coreContext, data),
[OB11MessageDataType.dice]: async (coreContext, { data: { result } }) => SendMsgElementConstructor.dice(coreContext, result), [OB11MessageDataType.dice]: async (coreContext, { data: { result } }) => SendMsgElementConstructor.dice(coreContext, result),
[OB11MessageDataType.RPS]: async (coreContext, { data: { result } }) => SendMsgElementConstructor.rps(coreContext, result), [OB11MessageDataType.RPS]: async (coreContext, { data: { result } }) => SendMsgElementConstructor.rps(coreContext, result),
[OB11MessageDataType.markdown]: async (coreContext, { data: { content } }) => SendMsgElementConstructor.markdown(coreContext, content), [OB11MessageDataType.markdown]: async (coreContext, { data: { content } }) => SendMsgElementConstructor.markdown(coreContext, content),
[OB11MessageDataType.music]: async (coreContext, { data }) => { [OB11MessageDataType.music]: async (coreContext, { data }) => {
// 保留, 直到...找到更好的解决方案 // 保留, 直到...找到更好的解决方案
if (data.type === 'custom') { if (data.type === 'custom') {
if (!data.url) { if (!data.url) {
coreContext.context.logger.logError('自定义音卡缺少参数url'); coreContext.context.logger.logError('自定义音卡缺少参数url');
return undefined; return undefined;
} }
if (!data.audio) { if (!data.audio) {
coreContext.context.logger.logError('自定义音卡缺少参数audio'); coreContext.context.logger.logError('自定义音卡缺少参数audio');
return undefined; return undefined;
} }
if (!data.title) { if (!data.title) {
coreContext.context.logger.logError('自定义音卡缺少参数title'); coreContext.context.logger.logError('自定义音卡缺少参数title');
return undefined; return undefined;
} }
} else { } else {
if (!['qq', '163'].includes(data.type)) { if (!['qq', '163'].includes(data.type)) {
coreContext.context.logger.logError('音乐卡片type错误, 只支持qq、163、custom当前type:', data.type); coreContext.context.logger.logError('音乐卡片type错误, 只支持qq、163、custom当前type:', data.type);
return undefined; return undefined;
} }
if (!data.id) { if (!data.id) {
coreContext.context.logger.logError('音乐卡片缺少参数id'); coreContext.context.logger.logError('音乐卡片缺少参数id');
return undefined; return undefined;
} }
}
let postData: IdMusicSignPostData | CustomMusicSignPostData;
if (data.type === 'custom' && data.content) {
const { content, ...others } = data;
postData = { singer: content, ...others };
} else {
postData = data;
}
// Mlikiowa V2.0.0 Refactor Todo
const signUrl = "";
if (!signUrl) {
if (data.type === 'qq') {
//const musicJson = (await SignMusicWrapper(data.id.toString())).data.arkResult.slice(0, -1);
//return SendMsgElementConstructor.ark(musicJson);
}
throw Error('音乐消息签名地址未配置');
}
try {
const musicJson = await RequestUtil.HttpGetJson<any>(signUrl, 'POST', postData);
return SendMsgElementConstructor.ark(coreContext, musicJson);
} catch (e) {
coreContext.context.logger.logError('生成音乐消息失败', e);
}
},
[OB11MessageDataType.node]: async (coreContext) => undefined,
[OB11MessageDataType.forward]: async (coreContext) => undefined,
[OB11MessageDataType.xml]: async (coreContext) => undefined,
[OB11MessageDataType.poke]: async (coreContext) => undefined,
[OB11MessageDataType.Location]: async (coreContext) => {
return SendMsgElementConstructor.location(coreContext);
},
[OB11MessageDataType.miniapp]: function (CoreContext: NapCatCore, sendMsg: never, context: MessageContext): Promise<SendMessageElement | undefined> {
throw new Error('Function not implemented.');
} }
let postData: IdMusicSignPostData | CustomMusicSignPostData;
if (data.type === 'custom' && data.content) {
const { content, ...others } = data;
postData = { singer: content, ...others };
} else {
postData = data;
}
// Mlikiowa V2.0.0 Refactor Todo
const signUrl = "";
if (!signUrl) {
if (data.type === 'qq') {
//const musicJson = (await SignMusicWrapper(data.id.toString())).data.arkResult.slice(0, -1);
//return SendMsgElementConstructor.ark(musicJson);
}
throw Error('音乐消息签名地址未配置');
}
try {
const musicJson = await RequestUtil.HttpGetJson<any>(signUrl, 'POST', postData);
return SendMsgElementConstructor.ark(coreContext, musicJson);
} catch (e) {
coreContext.context.logger.logError('生成音乐消息失败', e);
}
},
[OB11MessageDataType.node]: async (coreContext) => undefined,
[OB11MessageDataType.forward]: async (coreContext) => undefined,
[OB11MessageDataType.xml]: async (coreContext) => undefined,
[OB11MessageDataType.poke]: async (coreContext) => undefined,
[OB11MessageDataType.Location]: async (coreContext) => {
return SendMsgElementConstructor.location(coreContext);
},
[OB11MessageDataType.miniapp]: function (CoreContext: NapCatCore, sendMsg: never, context: MessageContext): Promise<SendMessageElement | undefined> {
throw new Error('Function not implemented.');
}
}; };
const handlers = <{ const handlers = <{
@@ -192,46 +193,46 @@ const handlers = <{
}>_handlers; }>_handlers;
export default async function createSendElements( export default async function createSendElements(
CoreContext: NapCatCore, CoreContext: NapCatCore,
messageData: OB11MessageData[], messageData: OB11MessageData[],
peer: Peer, peer: Peer,
ignoreTypes: OB11MessageDataType[] = [] ignoreTypes: OB11MessageDataType[] = []
) { ) {
const deleteAfterSentFiles: string[] = []; const deleteAfterSentFiles: string[] = [];
const callResultList: Array<Promise<SendMessageElement | undefined>> = []; const callResultList: Array<Promise<SendMessageElement | undefined>> = [];
for (const sendMsg of messageData) { for (const sendMsg of messageData) {
if (ignoreTypes.includes(sendMsg.type)) { if (ignoreTypes.includes(sendMsg.type)) {
continue; continue;
}
const callResult = handlers[sendMsg.type](
CoreContext,
sendMsg,
{ peer, deleteAfterSentFiles }
)?.catch(undefined);
callResultList.push(callResult);
} }
const callResult = handlers[sendMsg.type]( const ret = await Promise.all(callResultList);
CoreContext, const sendElements: SendMessageElement[] = ret.filter(ele => ele) as SendMessageElement[];
sendMsg, return { sendElements, deleteAfterSentFiles };
{ peer, deleteAfterSentFiles }
)?.catch(undefined);
callResultList.push(callResult);
}
const ret = await Promise.all(callResultList);
const sendElements: SendMessageElement[] = ret.filter(ele => ele) as SendMessageElement[];
return { sendElements, deleteAfterSentFiles };
} }
export async function createSendElementsParallel( export async function createSendElementsParallel(
CoreContext: NapCatCore, CoreContext: NapCatCore,
messageData: OB11MessageData[], messageData: OB11MessageData[],
peer: Peer, peer: Peer,
ignoreTypes: OB11MessageDataType[] = [] ignoreTypes: OB11MessageDataType[] = []
) { ) {
const deleteAfterSentFiles: string[] = []; const deleteAfterSentFiles: string[] = [];
const sendElements = <SendMessageElement[]>( const sendElements = <SendMessageElement[]>(
await Promise.all( await Promise.all(
messageData.map(async sendMsg => ignoreTypes.includes(sendMsg.type) ? messageData.map(async sendMsg => ignoreTypes.includes(sendMsg.type) ?
undefined : undefined :
handlers[sendMsg.type](CoreContext, sendMsg, { peer, deleteAfterSentFiles })) handlers[sendMsg.type](CoreContext, sendMsg, { peer, deleteAfterSentFiles }))
).then( ).then(
results => results.filter( results => results.filter(
element => element !== undefined element => element !== undefined
) )
) )
); );
return { sendElements, deleteAfterSentFiles }; return { sendElements, deleteAfterSentFiles };
} }

View File

@@ -2,118 +2,118 @@ import { ChatType, ElementType, NapCatCore, Peer, RawMessage, SendMessageElement
import { MessageUnique } from '@/common/utils/MessageUnique'; import { MessageUnique } from '@/common/utils/MessageUnique';
import { OB11MessageDataType, OB11MessageNode } from '@/onebot/types'; import { OB11MessageDataType, OB11MessageNode } from '@/onebot/types';
import createSendElements from './create-send-elements'; import createSendElements from './create-send-elements';
import { normalize, sendMsg } from "../SendMsg/index" import { normalize, sendMsg } from "../SendMsg/index";
async function cloneMsg(coreContext: NapCatCore, msg: RawMessage): Promise<RawMessage | undefined> { async function cloneMsg(coreContext: NapCatCore, msg: RawMessage): Promise<RawMessage | undefined> {
const selfPeer = { const selfPeer = {
chatType: ChatType.friend, chatType: ChatType.friend,
peerUid: coreContext.selfInfo.uid peerUid: coreContext.selfInfo.uid
}; };
const logger = coreContext.context.logger; const logger = coreContext.context.logger;
const NTQQMsgApi = coreContext.getApiContext().MsgApi; const NTQQMsgApi = coreContext.getApiContext().MsgApi;
//logDebug('克隆的目标消息', msg); //logDebug('克隆的目标消息', msg);
const sendElements: SendMessageElement[] = []; const sendElements: SendMessageElement[] = [];
for (const element of msg.elements) { for (const element of msg.elements) {
sendElements.push(element as SendMessageElement); sendElements.push(element as SendMessageElement);
} }
if (sendElements.length === 0) { if (sendElements.length === 0) {
logger.logDebug('需要clone的消息无法解析将会忽略掉', msg); logger.logDebug('需要clone的消息无法解析将会忽略掉', msg);
} }
try { try {
const nodeMsg = await NTQQMsgApi.sendMsg(selfPeer, sendElements, true); const nodeMsg = await NTQQMsgApi.sendMsg(selfPeer, sendElements, true);
return nodeMsg; return nodeMsg;
} catch (e) { } catch (e) {
logger.logError(e, '克隆转发消息失败,将忽略本条消息', msg); logger.logError(e, '克隆转发消息失败,将忽略本条消息', msg);
} }
} }
export async function handleForwardNode(coreContext: NapCatCore, destPeer: Peer, messageNodes: OB11MessageNode[]): Promise<RawMessage | null> { export async function handleForwardNode(coreContext: NapCatCore, destPeer: Peer, messageNodes: OB11MessageNode[]): Promise<RawMessage | null> {
const NTQQMsgApi = coreContext.getApiContext().MsgApi; const NTQQMsgApi = coreContext.getApiContext().MsgApi;
const selfPeer = { const selfPeer = {
chatType: ChatType.friend, chatType: ChatType.friend,
peerUid: coreContext.selfInfo.uid peerUid: coreContext.selfInfo.uid
}; };
let nodeMsgIds: string[] = []; let nodeMsgIds: string[] = [];
const logger = coreContext.context.logger; const logger = coreContext.context.logger;
for (const messageNode of messageNodes) { for (const messageNode of messageNodes) {
const nodeId = messageNode.data.id; const nodeId = messageNode.data.id;
if (nodeId) { if (nodeId) {
//对Mgsid和OB11ID混用情况兜底 //对Mgsid和OB11ID混用情况兜底
const nodeMsg = MessageUnique.getMsgIdAndPeerByShortId(parseInt(nodeId)) || MessageUnique.getPeerByMsgId(nodeId); const nodeMsg = MessageUnique.getMsgIdAndPeerByShortId(parseInt(nodeId)) || MessageUnique.getPeerByMsgId(nodeId);
if (!nodeMsg) { if (!nodeMsg) {
logger.logError('转发消息失败,未找到消息', nodeId); logger.logError('转发消息失败,未找到消息', nodeId);
continue; continue;
} }
nodeMsgIds.push(nodeMsg.MsgId); nodeMsgIds.push(nodeMsg.MsgId);
} else {
// 自定义的消息
try {
const OB11Data = normalize(messageNode.data.content);
//筛选node消息
const isNodeMsg = OB11Data.filter(e => e.type === OB11MessageDataType.node).length;//找到子转发消息
if (isNodeMsg !== 0) {
if (isNodeMsg !== OB11Data.length) { logger.logError('子消息中包含非node消息 跳过不合法部分'); continue; }
const nodeMsg = await handleForwardNode(coreContext, selfPeer, OB11Data.filter(e => e.type === OB11MessageDataType.node));
if (nodeMsg) { nodeMsgIds.push(nodeMsg.msgId); MessageUnique.createMsg(selfPeer, nodeMsg.msgId); }
//完成子卡片生成跳过后续
continue;
}
const { sendElements } = await createSendElements(coreContext,OB11Data, destPeer);
//拆分消息
const MixElement = sendElements.filter(element => element.elementType !== ElementType.FILE && element.elementType !== ElementType.VIDEO);
const SingleElement = sendElements.filter(element => element.elementType === ElementType.FILE || element.elementType === ElementType.VIDEO).map(e => [e]);
const AllElement: SendMessageElement[][] = [MixElement, ...SingleElement].filter(e => e !== undefined && e.length !== 0);
const MsgNodeList: Promise<RawMessage | undefined>[] = [];
for (const sendElementsSplitElement of AllElement) {
MsgNodeList.push(sendMsg(coreContext,selfPeer, sendElementsSplitElement, [], true).catch(e => new Promise((resolve, reject) => { resolve(undefined); })));
}
(await Promise.allSettled(MsgNodeList)).map((result) => {
if (result.status === 'fulfilled' && result.value) {
nodeMsgIds.push(result.value.msgId);
MessageUnique.createMsg(selfPeer, result.value.msgId);
}
});
} catch (e) {
logger.logDebug('生成转发消息节点失败', e);
}
}
}
const nodeMsgArray: Array<RawMessage> = [];
let srcPeer: Peer | undefined = undefined;
let needSendSelf = false;
//检测是否处于同一个Peer 不在同一个peer则全部消息由自身发送
for (const msgId of nodeMsgIds) {
const nodeMsgPeer = MessageUnique.getPeerByMsgId(msgId);
if (!nodeMsgPeer) {
logger.logError('转发消息失败,未找到消息', msgId);
continue;
}
const nodeMsg = (await NTQQMsgApi.getMsgsByMsgId(nodeMsgPeer.Peer, [msgId])).msgList[0];
srcPeer = srcPeer ?? { chatType: nodeMsg.chatType, peerUid: nodeMsg.peerUid };
if (srcPeer.peerUid !== nodeMsg.peerUid) {
needSendSelf = true;
}
nodeMsgArray.push(nodeMsg);
}
nodeMsgIds = nodeMsgArray.map(msg => msg.msgId);
let retMsgIds: string[] = [];
if (needSendSelf) {
for (const [index, msg] of nodeMsgArray.entries()) {
if (msg.peerUid === coreContext.selfInfo.uid) continue;
const ClonedMsg = await cloneMsg(coreContext, msg);
if (ClonedMsg) retMsgIds.push(ClonedMsg.msgId);
}
} else { } else {
// 自定义的消息 retMsgIds = nodeMsgIds;
try {
let OB11Data = normalize(messageNode.data.content);
//筛选node消息
let isNodeMsg = OB11Data.filter(e => e.type === OB11MessageDataType.node).length;//找到子转发消息
if (isNodeMsg !== 0) {
if (isNodeMsg !== OB11Data.length) { logger.logError('子消息中包含非node消息 跳过不合法部分'); continue; }
const nodeMsg = await handleForwardNode(coreContext, selfPeer, OB11Data.filter(e => e.type === OB11MessageDataType.node));
if (nodeMsg) { nodeMsgIds.push(nodeMsg.msgId); MessageUnique.createMsg(selfPeer, nodeMsg.msgId) };
//完成子卡片生成跳过后续
continue;
}
const { sendElements } = await createSendElements(coreContext,OB11Data, destPeer);
//拆分消息
let MixElement = sendElements.filter(element => element.elementType !== ElementType.FILE && element.elementType !== ElementType.VIDEO);
let SingleElement = sendElements.filter(element => element.elementType === ElementType.FILE || element.elementType === ElementType.VIDEO).map(e => [e]);
let AllElement: SendMessageElement[][] = [MixElement, ...SingleElement].filter(e => e !== undefined && e.length !== 0);
const MsgNodeList: Promise<RawMessage | undefined>[] = [];
for (const sendElementsSplitElement of AllElement) {
MsgNodeList.push(sendMsg(coreContext,selfPeer, sendElementsSplitElement, [], true).catch(e => new Promise((resolve, reject) => { resolve(undefined) })));
}
(await Promise.allSettled(MsgNodeList)).map((result) => {
if (result.status === 'fulfilled' && result.value) {
nodeMsgIds.push(result.value.msgId);
MessageUnique.createMsg(selfPeer, result.value.msgId);
}
});
} catch (e) {
logger.logDebug('生成转发消息节点失败', e);
}
} }
} if (nodeMsgIds.length === 0) throw Error('转发消息失败,生成节点为空');
const nodeMsgArray: Array<RawMessage> = []; try {
let srcPeer: Peer | undefined = undefined; logger.logDebug('开发转发', srcPeer, destPeer, nodeMsgIds);
let needSendSelf = false; return await NTQQMsgApi.multiForwardMsg(srcPeer!, destPeer, nodeMsgIds);
//检测是否处于同一个Peer 不在同一个peer则全部消息由自身发送 } catch (e) {
for (let msgId of nodeMsgIds) { logger.logError('forward failed', e);
const nodeMsgPeer = MessageUnique.getPeerByMsgId(msgId); return null;
if (!nodeMsgPeer) {
logger.logError('转发消息失败,未找到消息', msgId);
continue;
} }
const nodeMsg = (await NTQQMsgApi.getMsgsByMsgId(nodeMsgPeer.Peer, [msgId])).msgList[0];
srcPeer = srcPeer ?? { chatType: nodeMsg.chatType, peerUid: nodeMsg.peerUid };
if (srcPeer.peerUid !== nodeMsg.peerUid) {
needSendSelf = true;
}
nodeMsgArray.push(nodeMsg);
}
nodeMsgIds = nodeMsgArray.map(msg => msg.msgId);
let retMsgIds: string[] = [];
if (needSendSelf) {
for (const [index, msg] of nodeMsgArray.entries()) {
if (msg.peerUid === coreContext.selfInfo.uid) continue;
const ClonedMsg = await cloneMsg(coreContext, msg);
if (ClonedMsg) retMsgIds.push(ClonedMsg.msgId);
}
} else {
retMsgIds = nodeMsgIds;
}
if (nodeMsgIds.length === 0) throw Error('转发消息失败,生成节点为空');
try {
logger.logDebug('开发转发', srcPeer, destPeer, nodeMsgIds);
return await NTQQMsgApi.multiForwardMsg(srcPeer!, destPeer, nodeMsgIds);
} catch (e) {
logger.logError('forward failed', e);
return null;
}
} }

View File

@@ -1,10 +1,10 @@
import { import {
OB11MessageData, OB11MessageData,
OB11MessageDataType, OB11MessageDataType,
OB11MessageMixType, OB11MessageMixType,
OB11MessageNode, OB11MessageNode,
OB11PostSendMsg OB11PostSendMsg
} from '@/onebot/types'; } from '@/onebot/types';
import { ActionName, BaseCheckResult } from '@/onebot/action/types'; import { ActionName, BaseCheckResult } from '@/onebot/action/types';
import fs from 'node:fs'; import fs from 'node:fs';
@@ -26,147 +26,147 @@ export enum ContextMode {
} }
// Normalizes a mixed type (CQCode/a single segment/segment array) into a segment array. // Normalizes a mixed type (CQCode/a single segment/segment array) into a segment array.
export function normalize(message: OB11MessageMixType, autoEscape = false): OB11MessageData[] { export function normalize(message: OB11MessageMixType, autoEscape = false): OB11MessageData[] {
return typeof message === 'string' ? ( return typeof message === 'string' ? (
autoEscape ? autoEscape ?
[{ type: OB11MessageDataType.text, data: { text: message } }] : [{ type: OB11MessageDataType.text, data: { text: message } }] :
decodeCQCode(message) decodeCQCode(message)
) : Array.isArray(message) ? message : [message]; ) : Array.isArray(message) ? message : [message];
} }
export { createSendElements }; export { createSendElements };
export async function sendMsg(coreContext: NapCatCore, peer: Peer, sendElements: SendMessageElement[], deleteAfterSentFiles: string[], waitComplete = true) { export async function sendMsg(coreContext: NapCatCore, peer: Peer, sendElements: SendMessageElement[], deleteAfterSentFiles: string[], waitComplete = true) {
const NTQQMsgApi = coreContext.getApiContext().MsgApi; const NTQQMsgApi = coreContext.getApiContext().MsgApi;
const logger = coreContext.context.logger; const logger = coreContext.context.logger;
if (!sendElements.length) { if (!sendElements.length) {
throw ('消息体无法解析, 请检查是否发送了不支持的消息类型'); throw ('消息体无法解析, 请检查是否发送了不支持的消息类型');
}
let totalSize = 0;
let timeout = 10000;
try {
for (const fileElement of sendElements) {
if (fileElement.elementType === ElementType.PTT) {
totalSize += fs.statSync(fileElement.pttElement.filePath).size;
}
if (fileElement.elementType === ElementType.FILE) {
totalSize += fs.statSync(fileElement.fileElement.filePath).size;
}
if (fileElement.elementType === ElementType.VIDEO) {
totalSize += fs.statSync(fileElement.videoElement.filePath).size;
}
if (fileElement.elementType === ElementType.PIC) {
totalSize += fs.statSync(fileElement.picElement.sourcePath).size;
}
} }
//且 PredictTime ((totalSize / 1024 / 512) * 1000)不等于Nan let totalSize = 0;
const PredictTime = totalSize / 1024 / 256 * 1000; let timeout = 10000;
if (!Number.isNaN(PredictTime)) { try {
timeout += PredictTime;// 10S Basic Timeout + PredictTime( For File 512kb/s ) for (const fileElement of sendElements) {
if (fileElement.elementType === ElementType.PTT) {
totalSize += fs.statSync(fileElement.pttElement.filePath).size;
}
if (fileElement.elementType === ElementType.FILE) {
totalSize += fs.statSync(fileElement.fileElement.filePath).size;
}
if (fileElement.elementType === ElementType.VIDEO) {
totalSize += fs.statSync(fileElement.videoElement.filePath).size;
}
if (fileElement.elementType === ElementType.PIC) {
totalSize += fs.statSync(fileElement.picElement.sourcePath).size;
}
}
//且 PredictTime ((totalSize / 1024 / 512) * 1000)不等于Nan
const PredictTime = totalSize / 1024 / 256 * 1000;
if (!Number.isNaN(PredictTime)) {
timeout += PredictTime;// 10S Basic Timeout + PredictTime( For File 512kb/s )
}
} catch (e) {
logger.logError('发送消息计算预计时间异常', e);
} }
} catch (e) { const returnMsg = await NTQQMsgApi.sendMsg(peer, sendElements, waitComplete, timeout);
logger.logError('发送消息计算预计时间异常', e); try {
}
const returnMsg = await NTQQMsgApi.sendMsg(peer, sendElements, waitComplete, timeout);
try {
returnMsg!.id = MessageUnique.createMsg({ chatType: peer.chatType, guildId: '', peerUid: peer.peerUid }, returnMsg!.msgId); returnMsg!.id = MessageUnique.createMsg({ chatType: peer.chatType, guildId: '', peerUid: peer.peerUid }, returnMsg!.msgId);
} catch (e: any) { } catch (e: any) {
logger.logDebug('发送消息id获取失败', e); logger.logDebug('发送消息id获取失败', e);
returnMsg!.id = 0; returnMsg!.id = 0;
} }
deleteAfterSentFiles.map((f) => { fsPromise.unlink(f).then().catch(e => logger.logError('发送消息删除文件失败', e)); }); deleteAfterSentFiles.map((f) => { fsPromise.unlink(f).then().catch(e => logger.logError('发送消息删除文件失败', e)); });
return returnMsg; return returnMsg;
} }
async function createContext(coreContext: NapCatCore, payload: OB11PostSendMsg, contextMode: ContextMode): Promise<Peer> { async function createContext(coreContext: NapCatCore, payload: OB11PostSendMsg, contextMode: ContextMode): Promise<Peer> {
// This function determines the type of message by the existence of user_id / group_id, // This function determines the type of message by the existence of user_id / group_id,
// not message_type. // not message_type.
// This redundant design of Ob11 here should be blamed. // This redundant design of Ob11 here should be blamed.
const NTQQGroupApi = coreContext.getApiContext().GroupApi; const NTQQGroupApi = coreContext.getApiContext().GroupApi;
const NTQQFriendApi = coreContext.getApiContext().FriendApi; const NTQQFriendApi = coreContext.getApiContext().FriendApi;
const NTQQUserApi = coreContext.getApiContext().UserApi; const NTQQUserApi = coreContext.getApiContext().UserApi;
if ((contextMode === ContextMode.Group || contextMode === ContextMode.Normal) && payload.group_id) { if ((contextMode === ContextMode.Group || contextMode === ContextMode.Normal) && payload.group_id) {
const group = (await NTQQGroupApi.getGroups()).find(e => e.groupCode == payload.group_id?.toString()) const group = (await NTQQGroupApi.getGroups()).find(e => e.groupCode == payload.group_id?.toString());
return { return {
chatType: ChatType.group, chatType: ChatType.group,
peerUid: payload.group_id.toString() peerUid: payload.group_id.toString()
}; };
} }
if ((contextMode === ContextMode.Private || contextMode === ContextMode.Normal) && payload.user_id) { if ((contextMode === ContextMode.Private || contextMode === ContextMode.Normal) && payload.user_id) {
const Uid = await NTQQUserApi.getUidByUin(payload.user_id.toString()); const Uid = await NTQQUserApi.getUidByUin(payload.user_id.toString());
const isBuddy = await NTQQFriendApi.isBuddy(Uid!); const isBuddy = await NTQQFriendApi.isBuddy(Uid!);
//console.log("[调试代码] UIN:", payload.user_id, " UID:", Uid, " IsBuddy:", isBuddy); //console.log("[调试代码] UIN:", payload.user_id, " UID:", Uid, " IsBuddy:", isBuddy);
return { return {
chatType: isBuddy ? ChatType.friend : ChatType.temp, chatType: isBuddy ? ChatType.friend : ChatType.temp,
peerUid: Uid! peerUid: Uid!
}; };
} }
throw '请指定 group_id 或 user_id'; throw '请指定 group_id 或 user_id';
} }
function getSpecialMsgNum(payload: OB11PostSendMsg, msgType: OB11MessageDataType): number { function getSpecialMsgNum(payload: OB11PostSendMsg, msgType: OB11MessageDataType): number {
if (Array.isArray(payload.message)) { if (Array.isArray(payload.message)) {
return payload.message.filter(msg => msg.type == msgType).length; return payload.message.filter(msg => msg.type == msgType).length;
} }
return 0; return 0;
} }
export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> { export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
actionName = ActionName.SendMsg; actionName = ActionName.SendMsg;
contextMode = ContextMode.Normal; contextMode = ContextMode.Normal;
protected async check(payload: OB11PostSendMsg): Promise<BaseCheckResult> { protected async check(payload: OB11PostSendMsg): Promise<BaseCheckResult> {
const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi; const NTQQGroupApi = this.CoreContext.getApiContext().GroupApi;
const NTQQFriendApi = this.CoreContext.getApiContext().FriendApi; const NTQQFriendApi = this.CoreContext.getApiContext().FriendApi;
const NTQQUserApi = this.CoreContext.getApiContext().UserApi; const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
const messages = normalize(payload.message); const messages = normalize(payload.message);
const nodeElementLength = getSpecialMsgNum(payload, OB11MessageDataType.node); const nodeElementLength = getSpecialMsgNum(payload, OB11MessageDataType.node);
if (nodeElementLength > 0 && nodeElementLength != messages.length) { if (nodeElementLength > 0 && nodeElementLength != messages.length) {
return { valid: false, message: '转发消息不能和普通消息混在一起发送,转发需要保证message只有type为node的元素' }; return { valid: false, message: '转发消息不能和普通消息混在一起发送,转发需要保证message只有type为node的元素' };
}
// if (payload.message_type !== 'private' && payload.group_id && !(await getGroup(payload.group_id))) {
// return { valid: false, message: `群${payload.group_id}不存在` };
// }
if (payload.user_id && payload.message_type !== 'group') {
const uid = await NTQQUserApi.getUidByUin(payload.user_id.toString());
const isBuddy = await NTQQFriendApi.isBuddy(uid!);
// 此处有问题
if (!isBuddy) {
//return { valid: false, message: '异常消息' };
}
}
return { valid: true };
} }
// if (payload.message_type !== 'private' && payload.group_id && !(await getGroup(payload.group_id))) {
// return { valid: false, message: `群${payload.group_id}不存在` }; protected async _handle(payload: OB11PostSendMsg): Promise<{ message_id: number }> {
// } const peer = await createContext(this.CoreContext, payload, this.contextMode);
if (payload.user_id && payload.message_type !== 'group') {
const uid = await NTQQUserApi.getUidByUin(payload.user_id.toString()); const messages = normalize(
const isBuddy = await NTQQFriendApi.isBuddy(uid!); payload.message,
// 此处有问题 payload.auto_escape === true || payload.auto_escape === 'true'
if (!isBuddy) { );
//return { valid: false, message: '异常消息' };
} if (getSpecialMsgNum(payload, OB11MessageDataType.node)) {
const returnMsg = await handleForwardNode(this.CoreContext,peer, messages as OB11MessageNode[]);
if (returnMsg) {
const msgShortId = MessageUnique.createMsg({ guildId: '', peerUid: peer.peerUid, chatType: peer.chatType }, returnMsg!.msgId);
return { message_id: msgShortId! };
} else {
throw Error('发送转发消息失败');
}
} else {
// if (getSpecialMsgNum(payload, OB11MessageDataType.music)) {
// const music: OB11MessageCustomMusic = messages[0] as OB11MessageCustomMusic;
// if (music) {
// }
// }
}
// log("send msg:", peer, sendElements)
const { sendElements, deleteAfterSentFiles } = await createSendElements(this.CoreContext, messages, peer);
//console.log(peer, JSON.stringify(sendElements,null,2));
const returnMsg = await sendMsg(this.CoreContext, peer, sendElements, deleteAfterSentFiles);
return { message_id: returnMsg!.id! };
} }
return { valid: true };
}
protected async _handle(payload: OB11PostSendMsg): Promise<{ message_id: number }> {
const peer = await createContext(this.CoreContext, payload, this.contextMode);
const messages = normalize(
payload.message,
payload.auto_escape === true || payload.auto_escape === 'true'
);
if (getSpecialMsgNum(payload, OB11MessageDataType.node)) {
const returnMsg = await handleForwardNode(this.CoreContext,peer, messages as OB11MessageNode[]);
if (returnMsg) {
const msgShortId = MessageUnique.createMsg({ guildId: '', peerUid: peer.peerUid, chatType: peer.chatType }, returnMsg!.msgId);
return { message_id: msgShortId! };
} else {
throw Error('发送转发消息失败');
}
} else {
// if (getSpecialMsgNum(payload, OB11MessageDataType.music)) {
// const music: OB11MessageCustomMusic = messages[0] as OB11MessageCustomMusic;
// if (music) {
// }
// }
}
// log("send msg:", peer, sendElements)
const { sendElements, deleteAfterSentFiles } = await createSendElements(this.CoreContext, messages, peer);
//console.log(peer, JSON.stringify(sendElements,null,2));
const returnMsg = await sendMsg(this.CoreContext, peer, sendElements, deleteAfterSentFiles);
return { message_id: returnMsg!.id! };
}
} }
export default SendMsg; export default SendMsg;

View File

@@ -3,13 +3,13 @@ import { ActionName, BaseCheckResult } from '../types';
import { OB11PostSendMsg } from '../../types'; import { OB11PostSendMsg } from '../../types';
// 未检测参数 // 未检测参数
class SendPrivateMsg extends SendMsg { class SendPrivateMsg extends SendMsg {
actionName = ActionName.SendPrivateMsg; actionName = ActionName.SendPrivateMsg;
contextMode: ContextMode = ContextMode.Private; contextMode: ContextMode = ContextMode.Private;
protected async check(payload: OB11PostSendMsg): Promise<BaseCheckResult> { protected async check(payload: OB11PostSendMsg): Promise<BaseCheckResult> {
payload.message_type = 'private'; payload.message_type = 'private';
return super.check(payload); return super.check(payload);
} }
} }
export default SendPrivateMsg; export default SendPrivateMsg;

View File

@@ -5,32 +5,32 @@ import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { MessageUnique } from '@/common/utils/MessageUnique'; import { MessageUnique } from '@/common/utils/MessageUnique';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
message_id: { type: ['string', 'number'] }, message_id: { type: ['string', 'number'] },
emoji_id: { type: ['string', 'number'] } emoji_id: { type: ['string', 'number'] }
}, },
required: ['message_id', 'emoji_id'] required: ['message_id', 'emoji_id']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export class SetMsgEmojiLike extends BaseAction<Payload, any> { export class SetMsgEmojiLike extends BaseAction<Payload, any> {
actionName = ActionName.SetMsgEmojiLike; actionName = ActionName.SetMsgEmojiLike;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi; const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi;
const msg = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString())); const msg = MessageUnique.getMsgIdAndPeerByShortId(parseInt(payload.message_id.toString()));
if (!msg) { if (!msg) {
throw new Error('msg not found'); throw new Error('msg not found');
}
if (!payload.emoji_id) {
throw new Error('emojiId not found');
}
const msgData = (await NTQQMsgApi.getMsgsByMsgId(msg.Peer, [msg.MsgId])).msgList;
if (!msgData || msgData.length == 0 || !msgData[0].msgSeq) {
throw new Error('find msg by msgid error');
}
return await NTQQMsgApi.setEmojiLike(msg.Peer, msgData[0].msgSeq, payload.emoji_id.toString(), true);
} }
if (!payload.emoji_id) {
throw new Error('emojiId not found');
}
const msgData = (await NTQQMsgApi.getMsgsByMsgId(msg.Peer, [msg.MsgId])).msgList;
if (!msgData || msgData.length == 0 || !msgData[0].msgSeq) {
throw new Error('find msg by msgid error');
}
return await NTQQMsgApi.setEmojiLike(msg.Peer, msgData[0].msgSeq, payload.emoji_id.toString(), true);
}
} }

View File

@@ -6,5 +6,5 @@ interface ReturnType {
} }
export default class CanSendImage extends CanSendRecord { export default class CanSendImage extends CanSendRecord {
actionName = ActionName.CanSendImage; actionName = ActionName.CanSendImage;
} }

View File

@@ -6,11 +6,11 @@ interface ReturnType {
} }
export default class CanSendRecord extends BaseAction<any, ReturnType> { export default class CanSendRecord extends BaseAction<any, ReturnType> {
actionName = ActionName.CanSendRecord; actionName = ActionName.CanSendRecord;
protected async _handle(_payload: void): Promise<ReturnType> { protected async _handle(_payload: void): Promise<ReturnType> {
return { return {
yes: true yes: true
}; };
} }
} }

View File

@@ -5,11 +5,11 @@ import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
class GetLoginInfo extends BaseAction<null, OB11User> { class GetLoginInfo extends BaseAction<null, OB11User> {
actionName = ActionName.GetLoginInfo; actionName = ActionName.GetLoginInfo;
protected async _handle(payload: null) { protected async _handle(payload: null) {
return OB11Constructor.selfInfo(this.CoreContext.selfInfo); return OB11Constructor.selfInfo(this.CoreContext.selfInfo);
} }
} }
export default GetLoginInfo; export default GetLoginInfo;

View File

@@ -2,13 +2,13 @@ import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
export default class GetStatus extends BaseAction<any, any> { export default class GetStatus extends BaseAction<any, any> {
actionName = ActionName.GetStatus; actionName = ActionName.GetStatus;
protected async _handle(payload: any): Promise<any> { protected async _handle(payload: any): Promise<any> {
return { return {
online: !!this.CoreContext.selfInfo.online, online: !!this.CoreContext.selfInfo.online,
good: true, good: true,
stat:{} stat:{}
}; };
} }
} }

View File

@@ -3,13 +3,13 @@ import { ActionName } from '../types';
import { napcat_version } from '@/common/framework/napcat'; import { napcat_version } from '@/common/framework/napcat';
export default class GetVersionInfo extends BaseAction<any, any> { export default class GetVersionInfo extends BaseAction<any, any> {
actionName = ActionName.GetVersionInfo; actionName = ActionName.GetVersionInfo;
protected async _handle(payload: any): Promise<any> { protected async _handle(payload: any): Promise<any> {
return { return {
app_name: 'NapCat.Onebot', app_name: 'NapCat.Onebot',
protocol_version: 'v11', protocol_version: 'v11',
app_version: napcat_version app_version: napcat_version
}; };
} }
} }

View File

@@ -7,65 +7,65 @@ interface Response {
bkn: string bkn: string
} }
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
domain: { type: 'string' } domain: { type: 'string' }
}, },
required: ['domain'] required: ['domain']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export class GetCookies extends BaseAction<Payload, Response> { export class GetCookies extends BaseAction<Payload, Response> {
actionName = ActionName.GetCookies; actionName = ActionName.GetCookies;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const NTQQUserApi = this.CoreContext.getApiContext().UserApi; const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
const NTQQWebApi = this.CoreContext.getApiContext().WebApi; const NTQQWebApi = this.CoreContext.getApiContext().WebApi;
// if (!payload.domain) { // if (!payload.domain) {
// throw new Error('缺少参数 domain'); // throw new Error('缺少参数 domain');
// } // }
// if (payload.domain.endsWith('qzone.qq.com')) { // if (payload.domain.endsWith('qzone.qq.com')) {
// // 兼容整个 *.qzone.qq.com // // 兼容整个 *.qzone.qq.com
// const data = (await NTQQUserApi.getQzoneCookies()); // const data = (await NTQQUserApi.getQzoneCookies());
// const Bkn = WebApi.genBkn(data.p_skey); // const Bkn = WebApi.genBkn(data.p_skey);
// const CookieValue = 'p_skey=' + data.p_skey + '; skey=' + data.skey + '; p_uin=o' + selfInfo.uin + '; uin=o' + selfInfo.uin; // const CookieValue = 'p_skey=' + data.p_skey + '; skey=' + data.skey + '; p_uin=o' + selfInfo.uin + '; uin=o' + selfInfo.uin;
// return { cookies: CookieValue }; // return { cookies: CookieValue };
// } // }
// // 取Skey // // 取Skey
// // 先NodeIKernelTicketService.forceFetchClientKey('') // // 先NodeIKernelTicketService.forceFetchClientKey('')
// // 返回值 // // 返回值
// // { // // {
// // result: 0, // // result: 0,
// // errMsg: '', // // errMsg: '',
// // url: '', // // url: '',
// // keyIndex: '19', // // keyIndex: '19',
// // clientKey: 'clientKey', // // clientKey: 'clientKey',
// // expireTime: '7200' // // expireTime: '7200'
// // } // // }
// // request https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=1627126029&clientkey=key // // request https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=1627126029&clientkey=key
// // &u1=https%3A%2F%2Fh5.qzone.qq.com%2Fqqnt%2Fqzoneinpcqq%2Ffriend%3Frefresh%3D0%26clientuin%3D0%26darkMode%3D0&keyindex=keyIndex // // &u1=https%3A%2F%2Fh5.qzone.qq.com%2Fqqnt%2Fqzoneinpcqq%2Ffriend%3Frefresh%3D0%26clientuin%3D0%26darkMode%3D0&keyindex=keyIndex
// const _PSkey = (await NTQQUserApi.getPSkey([payload.domain]))[payload.domain]; // const _PSkey = (await NTQQUserApi.getPSkey([payload.domain]))[payload.domain];
// // 取Pskey // // 取Pskey
// // NodeIKernelTipOffService.getPskey([ 'qun.qq.com' ], true ) // // NodeIKernelTipOffService.getPskey([ 'qun.qq.com' ], true )
// // { // // {
// // domainPskeyMap: 0, // // domainPskeyMap: 0,
// // errMsg: 'success', // // errMsg: 'success',
// // domainPskeyMap: Map(1) { // // domainPskeyMap: Map(1) {
// // 'qun.qq.com' => 'pskey' // // 'qun.qq.com' => 'pskey'
// // } // // }
// // } // // }
// if (!_PSkey || !_Skey) { // if (!_PSkey || !_Skey) {
// throw new Error('获取Cookies失败'); // throw new Error('获取Cookies失败');
// } // }
// const cookies = `p_skey=${_PSkey}; skey=${_Skey}; p_uin=o${selfInfo.uin}; uin=o${selfInfo.uin}`; // const cookies = `p_skey=${_PSkey}; skey=${_Skey}; p_uin=o${selfInfo.uin}; uin=o${selfInfo.uin}`;
// return { // return {
// cookies // cookies
// }; // };
const cookiesObject = await NTQQUserApi.getCookies(payload.domain); const cookiesObject = await NTQQUserApi.getCookies(payload.domain);
//把获取到的cookiesObject转换成 k=v; 格式字符串拼接在一起 //把获取到的cookiesObject转换成 k=v; 格式字符串拼接在一起
const cookies = Object.entries(cookiesObject).map(([key, value]) => `${key}=${value}`).join('; '); const cookies = Object.entries(cookiesObject).map(([key, value]) => `${key}=${value}`).join('; ');
const bkn = NTQQWebApi.getBknFromCookie(cookiesObject.p_skey); const bkn = NTQQWebApi.getBknFromCookie(cookiesObject.p_skey);
return { cookies, bkn }; return { cookies, bkn };
} }
} }

View File

@@ -6,19 +6,19 @@ import { FromSchema, JSONSchema } from 'json-schema-to-ts';
// no_cache get时传字符串 // no_cache get时传字符串
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
no_cache: { type: ['boolean', 'string'] }, no_cache: { type: ['boolean', 'string'] },
} }
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export default class GetFriendList extends BaseAction<Payload, OB11User[]> { export default class GetFriendList extends BaseAction<Payload, OB11User[]> {
actionName = ActionName.GetFriendList; actionName = ActionName.GetFriendList;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
//全新逻辑 //全新逻辑
const NTQQFriendApi = this.CoreContext.getApiContext().FriendApi; const NTQQFriendApi = this.CoreContext.getApiContext().FriendApi;
return OB11Constructor.friendsV2(await NTQQFriendApi.getBuddyV2(payload?.no_cache === true || payload?.no_cache === 'true')); return OB11Constructor.friendsV2(await NTQQFriendApi.getBuddyV2(payload?.no_cache === true || payload?.no_cache === 'true'));
} }
} }

View File

@@ -5,49 +5,49 @@ import { ActionName } from '../types';
import { OB11Constructor } from '@/onebot/helper/data'; import { OB11Constructor } from '@/onebot/helper/data';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
count: { type: ['number', 'string'] } count: { type: ['number', 'string'] }
} }
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export default class GetRecentContact extends BaseAction<Payload, any> { export default class GetRecentContact extends BaseAction<Payload, any> {
actionName = ActionName.GetRecentContact; actionName = ActionName.GetRecentContact;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const NTQQUserApi = this.CoreContext.getApiContext().UserApi; const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi; const NTQQMsgApi = this.CoreContext.getApiContext().MsgApi;
const ret = await NTQQUserApi.getRecentContactListSnapShot(parseInt((payload.count || 10).toString())); const ret = await NTQQUserApi.getRecentContactListSnapShot(parseInt((payload.count || 10).toString()));
const data = await Promise.all(ret.info.changedList.map(async (t) => { const data = await Promise.all(ret.info.changedList.map(async (t) => {
const FastMsg = await NTQQMsgApi.getMsgsByMsgId({ chatType: t.chatType, peerUid: t.peerUid }, [t.msgId]); const FastMsg = await NTQQMsgApi.getMsgsByMsgId({ chatType: t.chatType, peerUid: t.peerUid }, [t.msgId]);
if (FastMsg.msgList.length > 0) { if (FastMsg.msgList.length > 0) {
//扩展ret.info.changedList //扩展ret.info.changedList
const lastestMsg = await OB11Constructor.message(this.CoreContext, FastMsg.msgList[0], "array"); const lastestMsg = await OB11Constructor.message(this.CoreContext, FastMsg.msgList[0], "array");
return { return {
lastestMsg: lastestMsg, lastestMsg: lastestMsg,
peerUin: t.peerUin, peerUin: t.peerUin,
remark: t.remark, remark: t.remark,
msgTime: t.msgTime, msgTime: t.msgTime,
chatType: t.chatType, chatType: t.chatType,
msgId: t.msgId, msgId: t.msgId,
sendNickName: t.sendNickName, sendNickName: t.sendNickName,
sendMemberName: t.sendMemberName, sendMemberName: t.sendMemberName,
peerName: t.peerName peerName: t.peerName
}; };
} }
return { return {
peerUin: t.peerUin, peerUin: t.peerUin,
remark: t.remark, remark: t.remark,
msgTime: t.msgTime, msgTime: t.msgTime,
chatType: t.chatType, chatType: t.chatType,
msgId: t.msgId, msgId: t.msgId,
sendNickName: t.sendNickName, sendNickName: t.sendNickName,
sendMemberName: t.sendMemberName, sendMemberName: t.sendMemberName,
peerName: t.peerName peerName: t.peerName
}; };
})); }));
return data; return data;
} }
} }

View File

@@ -4,33 +4,33 @@ import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
user_id: { type: ['number', 'string'] }, user_id: { type: ['number', 'string'] },
times: { type: ['number', 'string'] } times: { type: ['number', 'string'] }
}, },
required: ['user_id', 'times'] required: ['user_id', 'times']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export default class SendLike extends BaseAction<Payload, null> { export default class SendLike extends BaseAction<Payload, null> {
actionName = ActionName.SendLike; actionName = ActionName.SendLike;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload): Promise<null> { protected async _handle(payload: Payload): Promise<null> {
const NTQQUserApi = this.CoreContext.getApiContext().UserApi; const NTQQUserApi = this.CoreContext.getApiContext().UserApi;
//logDebug('点赞参数', payload); //logDebug('点赞参数', payload);
try { try {
const qq = payload.user_id.toString(); const qq = payload.user_id.toString();
const uid: string = await NTQQUserApi.getUidByUin(qq) || ''; const uid: string = await NTQQUserApi.getUidByUin(qq) || '';
const result = await NTQQUserApi.like(uid, parseInt(payload.times?.toString()) || 1); const result = await NTQQUserApi.like(uid, parseInt(payload.times?.toString()) || 1);
//logDebug('点赞结果', result); //logDebug('点赞结果', result);
if (result.result !== 0) { if (result.result !== 0) {
throw Error(result.errMsg); throw Error(result.errMsg);
} }
} catch (e) { } catch (e) {
throw `点赞失败 ${e}`; throw `点赞失败 ${e}`;
}
return null;
} }
return null;
}
} }

View File

@@ -4,24 +4,24 @@ import { ActionName } from '../types';
import { NTQQFriendApi } from '@/core/apis/friend'; import { NTQQFriendApi } from '@/core/apis/friend';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
properties: { properties: {
flag: { type: 'string' }, flag: { type: 'string' },
approve: { type: ['string', 'boolean'] }, approve: { type: ['string', 'boolean'] },
remark: { type: 'string' } remark: { type: 'string' }
}, },
required: ['flag'] required: ['flag']
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>; type Payload = FromSchema<typeof SchemaData>;
export default class SetFriendAddRequest extends BaseAction<Payload, null> { export default class SetFriendAddRequest extends BaseAction<Payload, null> {
actionName = ActionName.SetFriendAddRequest; actionName = ActionName.SetFriendAddRequest;
PayloadSchema = SchemaData; PayloadSchema = SchemaData;
protected async _handle(payload: Payload): Promise<null> { protected async _handle(payload: Payload): Promise<null> {
const NTQQFriendApi = this.CoreContext.getApiContext().FriendApi; const NTQQFriendApi = this.CoreContext.getApiContext().FriendApi;
const approve = payload.approve?.toString() !== 'false'; const approve = payload.approve?.toString() !== 'false';
await NTQQFriendApi.handleFriendRequest(payload.flag, approve); await NTQQFriendApi.handleFriendRequest(payload.flag, approve);
return null; return null;
} }
} }

View File

@@ -10,7 +10,7 @@ export enum EventType {
export abstract class OB11BaseEvent { export abstract class OB11BaseEvent {
time = Math.floor(Date.now() / 1000); time = Math.floor(Date.now() / 1000);
self_id = parseInt(selfInfo.uin); self_id = parseInt(selfInfo.uin);
post_type: EventType = EventType.META; post_type: EventType = EventType.META;
} }

View File

@@ -1,5 +1,5 @@
import { EventType, OB11BaseEvent } from '../OB11BaseEvent'; import { EventType, OB11BaseEvent } from '../OB11BaseEvent';
export abstract class OB11BaseMessageEvent extends OB11BaseEvent { export abstract class OB11BaseMessageEvent extends OB11BaseEvent {
post_type = EventType.MESSAGE; post_type = EventType.MESSAGE;
} }

View File

@@ -1,6 +1,6 @@
import { EventType, OB11BaseEvent } from '../OB11BaseEvent'; import { EventType, OB11BaseEvent } from '../OB11BaseEvent';
export abstract class OB11BaseMetaEvent extends OB11BaseEvent { export abstract class OB11BaseMetaEvent extends OB11BaseEvent {
post_type = EventType.META; post_type = EventType.META;
meta_event_type: string; meta_event_type: string;
} }

View File

@@ -6,16 +6,16 @@ interface HeartbeatStatus {
} }
export class OB11HeartbeatEvent extends OB11BaseMetaEvent { export class OB11HeartbeatEvent extends OB11BaseMetaEvent {
meta_event_type = 'heartbeat'; meta_event_type = 'heartbeat';
status: HeartbeatStatus; status: HeartbeatStatus;
interval: number; interval: number;
public constructor(isOnline: boolean, isGood: boolean, interval: number) { public constructor(isOnline: boolean, isGood: boolean, interval: number) {
super(); super();
this.interval = interval; this.interval = interval;
this.status = { this.status = {
online: isOnline, online: isOnline,
good: isGood good: isGood
}; };
} }
} }

View File

@@ -7,11 +7,11 @@ export enum LifeCycleSubType {
} }
export class OB11LifeCycleEvent extends OB11BaseMetaEvent { export class OB11LifeCycleEvent extends OB11BaseMetaEvent {
meta_event_type = 'lifecycle'; meta_event_type = 'lifecycle';
sub_type: LifeCycleSubType; sub_type: LifeCycleSubType;
public constructor(subType: LifeCycleSubType) { public constructor(subType: LifeCycleSubType) {
super(); super();
this.sub_type = subType; this.sub_type = subType;
} }
} }

View File

@@ -1,5 +1,5 @@
import { EventType, OB11BaseEvent } from '../OB11BaseEvent'; import { EventType, OB11BaseEvent } from '../OB11BaseEvent';
export abstract class OB11BaseNoticeEvent extends OB11BaseEvent { export abstract class OB11BaseNoticeEvent extends OB11BaseEvent {
post_type = EventType.NOTICE; post_type = EventType.NOTICE;
} }

View File

@@ -1,11 +1,11 @@
import { OB11BaseNoticeEvent } from './OB11BaseNoticeEvent'; import { OB11BaseNoticeEvent } from './OB11BaseNoticeEvent';
export class OB11FriendAddNoticeEvent extends OB11BaseNoticeEvent { export class OB11FriendAddNoticeEvent extends OB11BaseNoticeEvent {
notice_type = 'friend_add'; notice_type = 'friend_add';
user_id: number; user_id: number;
public constructor(user_Id: number) { public constructor(user_Id: number) {
super(); super();
this.user_id = user_Id; this.user_id = user_Id;
} }
} }

View File

@@ -1,13 +1,13 @@
import { OB11BaseNoticeEvent } from './OB11BaseNoticeEvent'; import { OB11BaseNoticeEvent } from './OB11BaseNoticeEvent';
export class OB11FriendRecallNoticeEvent extends OB11BaseNoticeEvent { export class OB11FriendRecallNoticeEvent extends OB11BaseNoticeEvent {
notice_type = 'friend_recall'; notice_type = 'friend_recall';
user_id: number; user_id: number;
message_id: number; message_id: number;
public constructor(userId: number, messageId: number) { public constructor(userId: number, messageId: number) {
super(); super();
this.user_id = userId; this.user_id = userId;
this.message_id = messageId; this.message_id = messageId;
} }
} }

View File

@@ -1,6 +1,6 @@
import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent'; import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent';
export class OB11GroupAdminNoticeEvent extends OB11GroupNoticeEvent { export class OB11GroupAdminNoticeEvent extends OB11GroupNoticeEvent {
notice_type = 'group_admin'; notice_type = 'group_admin';
sub_type: 'set' | 'unset' = "set"; // "set" | "unset" sub_type: 'set' | 'unset' = "set"; // "set" | "unset"
} }

View File

@@ -1,17 +1,17 @@
import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent'; import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent';
export class OB11GroupBanEvent extends OB11GroupNoticeEvent { export class OB11GroupBanEvent extends OB11GroupNoticeEvent {
notice_type = 'group_ban'; notice_type = 'group_ban';
operator_id: number; operator_id: number;
duration: number; duration: number;
sub_type: 'ban' | 'lift_ban'; sub_type: 'ban' | 'lift_ban';
constructor(groupId: number, userId: number, operatorId: number, duration: number, sub_type: 'ban' | 'lift_ban') { constructor(groupId: number, userId: number, operatorId: number, duration: number, sub_type: 'ban' | 'lift_ban') {
super(); super();
this.group_id = groupId; this.group_id = groupId;
this.operator_id = operatorId; this.operator_id = operatorId;
this.user_id = userId; this.user_id = userId;
this.duration = duration; this.duration = duration;
this.sub_type = sub_type; this.sub_type = sub_type;
} }
} }

View File

@@ -1,16 +1,16 @@
import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent'; import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent';
export class OB11GroupCardEvent extends OB11GroupNoticeEvent { export class OB11GroupCardEvent extends OB11GroupNoticeEvent {
notice_type = 'group_card'; notice_type = 'group_card';
card_new: string; card_new: string;
card_old: string; card_old: string;
constructor(groupId: number, userId: number, cardNew: string, cardOld: string) { constructor(groupId: number, userId: number, cardNew: string, cardOld: string) {
super(); super();
this.group_id = groupId; this.group_id = groupId;
this.user_id = userId; this.user_id = userId;
this.card_new = cardNew; this.card_new = cardNew;
this.card_old = cardOld; this.card_old = cardOld;
} }
} }

View File

@@ -3,15 +3,15 @@ import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent';
export type GroupDecreaseSubType = 'leave' | 'kick' | 'kick_me'; export type GroupDecreaseSubType = 'leave' | 'kick' | 'kick_me';
export class OB11GroupDecreaseEvent extends OB11GroupNoticeEvent { export class OB11GroupDecreaseEvent extends OB11GroupNoticeEvent {
notice_type = 'group_decrease'; notice_type = 'group_decrease';
sub_type: GroupDecreaseSubType = 'leave'; // TODO: 实现其他几种子类型的识别 ("leave" | "kick" | "kick_me") sub_type: GroupDecreaseSubType = 'leave'; // TODO: 实现其他几种子类型的识别 ("leave" | "kick" | "kick_me")
operator_id: number; operator_id: number;
constructor(groupId: number, userId: number, operatorId: number, subType: GroupDecreaseSubType = 'leave') { constructor(groupId: number, userId: number, operatorId: number, subType: GroupDecreaseSubType = 'leave') {
super(); super();
this.group_id = groupId; this.group_id = groupId;
this.operator_id = operatorId; // 实际上不应该这么实现,但是现在还没有办法识别用户是被踢出的,还是自己主动退出的 this.operator_id = operatorId; // 实际上不应该这么实现,但是现在还没有办法识别用户是被踢出的,还是自己主动退出的
this.user_id = userId; this.user_id = userId;
this.sub_type = subType; this.sub_type = subType;
} }
} }

View File

@@ -1,14 +1,14 @@
import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent'; import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent';
export class OB11GroupEssenceEvent extends OB11GroupNoticeEvent { export class OB11GroupEssenceEvent extends OB11GroupNoticeEvent {
notice_type = 'essence'; notice_type = 'essence';
message_id: number; message_id: number;
sender_id: number; sender_id: number;
sub_type: 'add' | 'delete' = 'add'; sub_type: 'add' | 'delete' = 'add';
constructor(groupId: number, message_id: number, sender_id: number) { constructor(groupId: number, message_id: number, sender_id: number) {
super(); super();
this.group_id = groupId; this.group_id = groupId;
this.message_id = message_id; this.message_id = message_id;
this.sender_id = sender_id; this.sender_id = sender_id;
} }
} }

View File

@@ -2,14 +2,14 @@ import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent';
type GroupIncreaseSubType = 'approve' | 'invite'; type GroupIncreaseSubType = 'approve' | 'invite';
export class OB11GroupIncreaseEvent extends OB11GroupNoticeEvent { export class OB11GroupIncreaseEvent extends OB11GroupNoticeEvent {
notice_type = 'group_increase'; notice_type = 'group_increase';
operator_id: number; operator_id: number;
sub_type: GroupIncreaseSubType; sub_type: GroupIncreaseSubType;
constructor(groupId: number, userId: number, operatorId: number, subType: GroupIncreaseSubType = 'approve') { constructor(groupId: number, userId: number, operatorId: number, subType: GroupIncreaseSubType = 'approve') {
super(); super();
this.group_id = groupId; this.group_id = groupId;
this.operator_id = operatorId; this.operator_id = operatorId;
this.user_id = userId; this.user_id = userId;
this.sub_type = subType; this.sub_type = subType;
} }
} }

View File

@@ -1,6 +1,6 @@
import { OB11BaseNoticeEvent } from './OB11BaseNoticeEvent'; import { OB11BaseNoticeEvent } from './OB11BaseNoticeEvent';
export abstract class OB11GroupNoticeEvent extends OB11BaseNoticeEvent { export abstract class OB11GroupNoticeEvent extends OB11BaseNoticeEvent {
group_id: number = 0; group_id: number = 0;
user_id: number = 0; user_id: number = 0;
} }

View File

@@ -1,15 +1,15 @@
import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent'; import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent';
export class OB11GroupRecallNoticeEvent extends OB11GroupNoticeEvent { export class OB11GroupRecallNoticeEvent extends OB11GroupNoticeEvent {
notice_type = 'group_recall'; notice_type = 'group_recall';
operator_id: number; operator_id: number;
message_id: number; message_id: number;
constructor(groupId: number, userId: number, operatorId: number, messageId: number) { constructor(groupId: number, userId: number, operatorId: number, messageId: number) {
super(); super();
this.group_id = groupId; this.group_id = groupId;
this.user_id = userId; this.user_id = userId;
this.operator_id = operatorId; this.operator_id = operatorId;
this.message_id = messageId; this.message_id = messageId;
} }
} }

View File

@@ -1,15 +1,15 @@
import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent'; import { OB11GroupNoticeEvent } from './OB11GroupNoticeEvent';
export class OB11GroupTitleEvent extends OB11GroupNoticeEvent { export class OB11GroupTitleEvent extends OB11GroupNoticeEvent {
notice_type = 'notify'; notice_type = 'notify';
sub_type = 'title'; sub_type = 'title';
title: string; title: string;
constructor(groupId: number, userId: number, title: string) { constructor(groupId: number, userId: number, title: string) {
super(); super();
this.group_id = groupId; this.group_id = groupId;
this.user_id = userId; this.user_id = userId;
this.title = title; this.title = title;
} }
} }

View File

@@ -8,13 +8,13 @@ export interface GroupUploadFile{
} }
export class OB11GroupUploadNoticeEvent extends OB11GroupNoticeEvent { export class OB11GroupUploadNoticeEvent extends OB11GroupNoticeEvent {
notice_type = 'group_upload'; notice_type = 'group_upload';
file: GroupUploadFile; file: GroupUploadFile;
constructor(groupId: number, userId: number, file: GroupUploadFile) { constructor(groupId: number, userId: number, file: GroupUploadFile) {
super(); super();
this.group_id = groupId; this.group_id = groupId;
this.user_id = userId; this.user_id = userId;
this.file = file; this.file = file;
} }
} }

View File

@@ -1,16 +1,16 @@
import { OB11BaseNoticeEvent } from './OB11BaseNoticeEvent'; import { OB11BaseNoticeEvent } from './OB11BaseNoticeEvent';
//输入状态事件 初步完成 Mlikio wa Todo 需要做一些过滤 //输入状态事件 初步完成 Mlikio wa Todo 需要做一些过滤
export class OB11InputStatusEvent extends OB11BaseNoticeEvent { export class OB11InputStatusEvent extends OB11BaseNoticeEvent {
notice_type = 'notify'; notice_type = 'notify';
sub_type = 'input_status'; sub_type = 'input_status';
status_text = "对方正在输入..." status_text = "对方正在输入...";
eventType = 1; eventType = 1;
user_id = 0; user_id = 0;
constructor(user_id: number, eventType: number, status_text: string) { constructor(user_id: number, eventType: number, status_text: string) {
super(); super();
this.user_id = user_id; this.user_id = user_id;
this.eventType = eventType; this.eventType = eventType;
this.status_text = status_text; this.status_text = status_text;
} }
} }

View File

@@ -6,15 +6,15 @@ export interface MsgEmojiLike {
} }
export class OB11GroupMsgEmojiLikeEvent extends OB11GroupNoticeEvent { export class OB11GroupMsgEmojiLikeEvent extends OB11GroupNoticeEvent {
notice_type = 'group_msg_emoji_like'; notice_type = 'group_msg_emoji_like';
message_id: number; message_id: number;
likes: MsgEmojiLike[]; likes: MsgEmojiLike[];
constructor(groupId: number, userId: number, messageId: number, likes: MsgEmojiLike[]) { constructor(groupId: number, userId: number, messageId: number, likes: MsgEmojiLike[]) {
super(); super();
this.group_id = groupId; this.group_id = groupId;
this.user_id = userId; // 可为空表示是对别人的消息操作如果是对bot自己的消息则不为空 this.user_id = userId; // 可为空表示是对别人的消息操作如果是对bot自己的消息则不为空
this.message_id = messageId; this.message_id = messageId;
this.likes = likes; this.likes = likes;
} }
} }

View File

@@ -1,32 +1,32 @@
import { OB11BaseNoticeEvent } from './OB11BaseNoticeEvent'; import { OB11BaseNoticeEvent } from './OB11BaseNoticeEvent';
class OB11PokeEvent extends OB11BaseNoticeEvent { class OB11PokeEvent extends OB11BaseNoticeEvent {
notice_type = 'notify'; notice_type = 'notify';
sub_type = 'poke'; sub_type = 'poke';
target_id = 0; target_id = 0;
user_id = 0; user_id = 0;
} }
export class OB11FriendPokeEvent extends OB11PokeEvent { export class OB11FriendPokeEvent extends OB11PokeEvent {
raw_info: any; raw_info: any;
//raw_message nb等框架标准为string //raw_message nb等框架标准为string
constructor(user_id: number, target_id: number, raw_message: any) { constructor(user_id: number, target_id: number, raw_message: any) {
super(); super();
this.target_id = target_id; this.target_id = target_id;
this.user_id = user_id; this.user_id = user_id;
this.raw_info = raw_message; this.raw_info = raw_message;
} }
} }
export class OB11GroupPokeEvent extends OB11PokeEvent { export class OB11GroupPokeEvent extends OB11PokeEvent {
group_id: number; group_id: number;
raw_info: any; raw_info: any;
//raw_message nb等框架标准为string //raw_message nb等框架标准为string
constructor(group_id: number, user_id: number = 0, target_id: number = 0, raw_message: any) { constructor(group_id: number, user_id: number = 0, target_id: number = 0, raw_message: any) {
super(); super();
this.group_id = group_id; this.group_id = group_id;
this.target_id = target_id; this.target_id = target_id;
this.user_id = user_id; this.user_id = user_id;
this.raw_info = raw_message; this.raw_info = raw_message;
} }
} }

View File

@@ -3,9 +3,9 @@ import { EventType } from '../OB11BaseEvent';
export class OB11FriendRequestEvent extends OB11BaseNoticeEvent { export class OB11FriendRequestEvent extends OB11BaseNoticeEvent {
post_type = EventType.REQUEST; post_type = EventType.REQUEST;
user_id: number = 0; user_id: number = 0;
request_type = 'friend' as const; request_type = 'friend' as const;
comment: string = ''; comment: string = '';
flag: string = ''; flag: string = '';
} }

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