kt-template-online-api/src/qqbot/send/qqbot-send.service.ts

179 lines
5.4 KiB
TypeScript

import { Injectable } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { throwVbenError } from '@/common';
import { QqbotAccountService } from '../account/qqbot-account.service';
import type { QqbotReverseWsService } from '../connection/qqbot-reverse-ws.service';
import { QQBOT_MQTT_TOPICS } from '../qqbot.constants';
import { QqbotBusService } from '../mqtt/qqbot-bus.service';
import { QqbotMessageService } from '../message/qqbot-message.service';
import type { QqbotMessageType } from '../qqbot.types';
import { getPageParams } from '../qqbot.utils';
import { QqbotRateLimitService } from './qqbot-rate-limit.service';
import { QqbotSendLog } from './qqbot-send-log.entity';
import type {
QqbotSendGroupDto,
QqbotSendLogQueryDto,
QqbotSendPrivateDto,
} from './qqbot-send.dto';
@Injectable()
export class QqbotSendService {
constructor(
@InjectRepository(QqbotSendLog)
private readonly sendLogRepository: Repository<QqbotSendLog>,
private readonly accountService: QqbotAccountService,
private readonly busService: QqbotBusService,
private readonly messageService: QqbotMessageService,
private readonly moduleRef: ModuleRef,
private readonly rateLimitService: QqbotRateLimitService,
) {}
async logPage(query: QqbotSendLogQueryDto) {
const { pageNo, pageSize, skip } = getPageParams(query);
const builder = this.sendLogRepository.createQueryBuilder('log');
if (query.selfId) {
builder.andWhere('log.selfId = :selfId', { selfId: query.selfId });
}
if (query.targetType) {
builder.andWhere('log.targetType = :targetType', {
targetType: query.targetType,
});
}
if (query.targetId) {
builder.andWhere('log.targetId LIKE :targetId', {
targetId: `%${query.targetId}%`,
});
}
if (query.status) {
builder.andWhere('log.status = :status', { status: query.status });
}
const [list, total] = await builder
.orderBy('log.createTime', 'DESC')
.skip(skip)
.take(pageSize)
.getManyAndCount();
return { list, pageNo, pageSize, total };
}
async sendPrivate(body: QqbotSendPrivateDto) {
return this.sendText({
message: body.message,
selfId: body.selfId,
targetId: body.userId,
targetType: 'private',
});
}
async sendGroup(body: QqbotSendGroupDto) {
return this.sendText({
message: body.message,
selfId: body.selfId,
targetId: body.groupId,
targetType: 'group',
});
}
async sendText(params: {
message: string;
selfId?: string;
targetId: string;
targetType: QqbotMessageType;
}) {
const account = await this.accountService.getDefaultAccount(params.selfId);
if (!account) {
throwVbenError('没有可用 QQBot 账号');
}
this.rateLimitService.assertCanSend(account.selfId, params.targetId);
const action =
params.targetType === 'group' ? 'send_group_msg' : 'send_private_msg';
const actionParams =
params.targetType === 'group'
? { group_id: params.targetId, message: params.message }
: { message: params.message, user_id: params.targetId };
const log = await this.sendLogRepository.save(
this.sendLogRepository.create({
action,
messageText: params.message,
params: actionParams,
selfId: account.selfId,
status: 'pending',
targetId: params.targetId,
targetType: params.targetType,
}),
);
await this.busService.publish(
QQBOT_MQTT_TOPICS.commandSend(account.selfId),
{
action,
logId: log.id,
params: actionParams,
selfId: account.selfId,
},
);
try {
const reverseWsService = await this.getReverseWsService();
const response = await reverseWsService.sendAction(
account.selfId,
action,
actionParams,
);
const success = response.status === 'ok' || response.retcode === 0;
const messageId = response.data?.message_id
? `${response.data.message_id}`
: null;
await this.sendLogRepository.update(
{ id: log.id },
{
echo: response.echo || null,
errorMessage: success ? null : response.message || 'OneBot 发送失败',
messageId,
response: response as any,
status: success ? 'success' : 'failed',
},
);
if (success) {
await this.messageService.saveOutgoing({
messageId,
messageText: params.message,
messageType: params.targetType,
selfId: account.selfId,
targetId: params.targetId,
userId:
params.targetType === 'private' ? params.targetId : account.selfId,
});
}
if (!success) throwVbenError(response.message || 'OneBot 发送失败');
return { ...response, logId: log.id };
} catch (err) {
const message = err instanceof Error ? err.message : 'OneBot 发送失败';
await this.sendLogRepository.update(
{ id: log.id },
{
errorMessage: message,
status: 'failed',
},
);
throwVbenError(message);
}
}
private async getReverseWsService() {
const { QqbotReverseWsService } = await import(
'../connection/qqbot-reverse-ws.service'
);
return this.moduleRef.get<QqbotReverseWsService>(QqbotReverseWsService, {
strict: false,
});
}
}