refactor: 收敛QQBot核心模块边界
This commit is contained in:
parent
8ada857f57
commit
379e5fb608
@ -4,7 +4,7 @@ import * as path from 'path';
|
|||||||
import {
|
import {
|
||||||
parseQqbotPluginManifest,
|
parseQqbotPluginManifest,
|
||||||
type QqbotPluginManifest,
|
type QqbotPluginManifest,
|
||||||
} from '../../src/modules/qqbot/plugin-platform/manifest';
|
} from '../../src/modules/qqbot/plugin-platform/domain/manifest';
|
||||||
|
|
||||||
export type QqbotPluginCliCommand =
|
export type QqbotPluginCliCommand =
|
||||||
| 'create'
|
| 'create'
|
||||||
@ -284,8 +284,8 @@ export const runQqbotPluginCli = async (
|
|||||||
const command = argv[0] as QqbotPluginCliCommand | undefined;
|
const command = argv[0] as QqbotPluginCliCommand | undefined;
|
||||||
const resolvedOptions: Required<QqbotPluginCliOptions> = {
|
const resolvedOptions: Required<QqbotPluginCliOptions> = {
|
||||||
cwd: options.cwd || process.cwd(),
|
cwd: options.cwd || process.cwd(),
|
||||||
stderr: options.stderr || ((message) => console.error(message)),
|
stderr: options.stderr || ((message) => process.stderr.write(`${message}\n`)),
|
||||||
stdout: options.stdout || ((message) => console.log(message)),
|
stdout: options.stdout || ((message) => process.stdout.write(`${message}\n`)),
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (command) {
|
switch (command) {
|
||||||
|
|||||||
@ -9,26 +9,26 @@ import {
|
|||||||
ToolsService,
|
ToolsService,
|
||||||
} from '@/common';
|
} from '@/common';
|
||||||
import { AdminPasswordCryptoService } from '@/modules/admin/identity/auth/admin-password-crypto.service';
|
import { AdminPasswordCryptoService } from '@/modules/admin/identity/auth/admin-password-crypto.service';
|
||||||
import { QqbotAccountAbility } from './qqbot-account-ability.entity';
|
import { QqbotAccountAbility } from '../../infrastructure/persistence/account/qqbot-account-ability.entity';
|
||||||
import { QqbotAccount } from './qqbot-account.entity';
|
import { QqbotAccount } from '../../infrastructure/persistence/account/qqbot-account.entity';
|
||||||
import type {
|
import type {
|
||||||
QqbotAccountBodyDto,
|
QqbotAccountBodyDto,
|
||||||
QqbotAccountQueryDto,
|
QqbotAccountQueryDto,
|
||||||
QqbotAccountUpdateDto,
|
QqbotAccountUpdateDto,
|
||||||
} from './qqbot-account.dto';
|
} from '../../contract/account/qqbot-account.dto';
|
||||||
import { QqbotAccountNapcat } from '../../napcat/infrastructure/persistence/qqbot-account-napcat.entity';
|
import { QqbotAccountNapcat } from '@/modules/qqbot/napcat/infrastructure/persistence/qqbot-account-napcat.entity';
|
||||||
import { QqbotNapcatContainer } from '../../napcat/infrastructure/persistence/qqbot-napcat-container.entity';
|
import { QqbotNapcatContainer } from '@/modules/qqbot/napcat/infrastructure/persistence/qqbot-napcat-container.entity';
|
||||||
import { QqbotNapcatContainerService } from '../../napcat/qqbot-napcat-container.service';
|
import { QqbotNapcatContainerService } from '@/modules/qqbot/napcat/infrastructure/integration/container/qqbot-napcat-container.service';
|
||||||
import {
|
import {
|
||||||
QQBOT_DEFAULT_PAGE_NO,
|
QQBOT_DEFAULT_PAGE_NO,
|
||||||
QQBOT_DEFAULT_PAGE_SIZE,
|
QQBOT_DEFAULT_PAGE_SIZE,
|
||||||
} from '../contract/qqbot.constants';
|
} from '../../contract/qqbot.constants';
|
||||||
import type {
|
import type {
|
||||||
QqbotAccountAbilityType,
|
QqbotAccountAbilityType,
|
||||||
QqbotAccountListItem,
|
QqbotAccountListItem,
|
||||||
QqbotConnectionRole,
|
QqbotConnectionRole,
|
||||||
QqbotNapcatRuntimeStatusSnapshot,
|
QqbotNapcatRuntimeStatusSnapshot,
|
||||||
} from '../contract/qqbot.types';
|
} from '../../contract/qqbot.types';
|
||||||
|
|
||||||
const NAPCAT_RUNTIME_CHECK_TTL_MS = 30_000;
|
const NAPCAT_RUNTIME_CHECK_TTL_MS = 30_000;
|
||||||
const NAPCAT_AUTO_LOGIN_CLEANUP_FAILED_MESSAGE =
|
const NAPCAT_AUTO_LOGIN_CLEANUP_FAILED_MESSAGE =
|
||||||
@ -1,10 +1,13 @@
|
|||||||
import { Injectable, Logger } from '@nestjs/common';
|
import { Inject, Injectable, Logger } from '@nestjs/common';
|
||||||
import { ToolsService } from '@/common';
|
import { ToolsService } from '@/common';
|
||||||
import { QqbotPluginRegistryService } from '@/modules/qqbot/plugin-platform/registry/qqbot-plugin-registry.service';
|
import {
|
||||||
import type { QqbotNormalizedMessage } from '../contract/qqbot.types';
|
QQBOT_PLUGIN_EXECUTION_PORT,
|
||||||
|
type QqbotPluginExecutionPort,
|
||||||
|
} from '../../domain/plugin-execution.port';
|
||||||
|
import type { QqbotNormalizedMessage } from '../../contract/qqbot.types';
|
||||||
import { QqbotSendService } from '../send/qqbot-send.service';
|
import { QqbotSendService } from '../send/qqbot-send.service';
|
||||||
import type { QqbotCommandTestDto } from './qqbot-command.dto';
|
import type { QqbotCommandTestDto } from '../../contract/command/qqbot-command.dto';
|
||||||
import type { QqbotCommand } from './qqbot-command.entity';
|
import type { QqbotCommand } from '../../infrastructure/persistence/command/qqbot-command.entity';
|
||||||
import { QqbotCommandParserService } from './qqbot-command-parser.service';
|
import { QqbotCommandParserService } from './qqbot-command-parser.service';
|
||||||
import { QqbotCommandService } from './qqbot-command.service';
|
import { QqbotCommandService } from './qqbot-command.service';
|
||||||
import { QqbotReplyTemplateService } from './qqbot-reply-template.service';
|
import { QqbotReplyTemplateService } from './qqbot-reply-template.service';
|
||||||
@ -16,7 +19,8 @@ export class QqbotCommandEngineService {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly commandParser: QqbotCommandParserService,
|
private readonly commandParser: QqbotCommandParserService,
|
||||||
private readonly commandService: QqbotCommandService,
|
private readonly commandService: QqbotCommandService,
|
||||||
private readonly pluginRegistry: QqbotPluginRegistryService,
|
@Inject(QQBOT_PLUGIN_EXECUTION_PORT)
|
||||||
|
private readonly pluginExecution: QqbotPluginExecutionPort,
|
||||||
private readonly replyTemplate: QqbotReplyTemplateService,
|
private readonly replyTemplate: QqbotReplyTemplateService,
|
||||||
private readonly sendService: QqbotSendService,
|
private readonly sendService: QqbotSendService,
|
||||||
private readonly toolsService: ToolsService,
|
private readonly toolsService: ToolsService,
|
||||||
@ -32,16 +36,16 @@ export class QqbotCommandEngineService {
|
|||||||
await this.commandService.markHit(command);
|
await this.commandService.markHit(command);
|
||||||
const input = this.mergeInput(command, matched.input);
|
const input = this.mergeInput(command, matched.input);
|
||||||
try {
|
try {
|
||||||
const output = await this.pluginRegistry.execute(
|
const output = await this.pluginExecution.executeOperation({
|
||||||
command.pluginKey,
|
context: {
|
||||||
command.operationKey,
|
|
||||||
input,
|
|
||||||
{
|
|
||||||
args: matched.input,
|
args: matched.input,
|
||||||
command,
|
command,
|
||||||
message,
|
message,
|
||||||
},
|
},
|
||||||
);
|
input,
|
||||||
|
operationKey: command.operationKey,
|
||||||
|
pluginKey: command.pluginKey,
|
||||||
|
});
|
||||||
const replyText = this.buildReplyText(command, input, output);
|
const replyText = this.buildReplyText(command, input, output);
|
||||||
if (replyText) {
|
if (replyText) {
|
||||||
await this.sendService.sendText({
|
await this.sendService.sendText({
|
||||||
@ -97,16 +101,16 @@ export class QqbotCommandEngineService {
|
|||||||
|
|
||||||
const input = this.mergeInput(command, matched.input);
|
const input = this.mergeInput(command, matched.input);
|
||||||
try {
|
try {
|
||||||
const output = await this.pluginRegistry.execute(
|
const output = await this.pluginExecution.executeOperation({
|
||||||
command.pluginKey,
|
context: {
|
||||||
command.operationKey,
|
|
||||||
input,
|
|
||||||
{
|
|
||||||
args: matched.input,
|
args: matched.input,
|
||||||
command,
|
command,
|
||||||
message,
|
message,
|
||||||
},
|
},
|
||||||
);
|
input,
|
||||||
|
operationKey: command.operationKey,
|
||||||
|
pluginKey: command.pluginKey,
|
||||||
|
});
|
||||||
const replyText = this.buildReplyText(command, input, output);
|
const replyText = this.buildReplyText(command, input, output);
|
||||||
return {
|
return {
|
||||||
command: this.commandService.toResponse(command),
|
command: this.commandService.toResponse(command),
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import type { QqbotCommandMatchResult } from '../../contract/qqbot.types';
|
||||||
|
import type { QqbotNormalizedMessage } from '../../contract/qqbot.types';
|
||||||
|
import type { QqbotCommand } from '../../infrastructure/persistence/command/qqbot-command.entity';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class QqbotCommandParserService {
|
||||||
|
async match(command: QqbotCommand, message: QqbotNormalizedMessage) {
|
||||||
|
const source = `${message.messageText || ''}`.trim();
|
||||||
|
if (!source) return null;
|
||||||
|
|
||||||
|
const aliases = this.getAliases(command);
|
||||||
|
const prefixes = this.getPrefixes(command);
|
||||||
|
for (const alias of aliases) {
|
||||||
|
for (const prefix of prefixes) {
|
||||||
|
const commandText = `${prefix}${alias}`.trim();
|
||||||
|
const rawArgs = this.pickArgs(source, commandText);
|
||||||
|
if (rawArgs === null) continue;
|
||||||
|
return {
|
||||||
|
alias,
|
||||||
|
input: this.parseRawInput(rawArgs),
|
||||||
|
matched: true,
|
||||||
|
rawArgs,
|
||||||
|
} satisfies QqbotCommandMatchResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
getAliases(command: QqbotCommand) {
|
||||||
|
return this.normalizeList(command.aliases, [command.code, command.name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
getPrefixes(command: QqbotCommand) {
|
||||||
|
return this.normalizeList(command.prefixes, ['/', '!', '!']);
|
||||||
|
}
|
||||||
|
|
||||||
|
private pickArgs(source: string, commandText: string) {
|
||||||
|
if (!commandText) return null;
|
||||||
|
if (source === commandText) return '';
|
||||||
|
if (source.startsWith(`${commandText} `)) {
|
||||||
|
return source.slice(commandText.length).trim();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseRawInput(rawArgs: string) {
|
||||||
|
const args = rawArgs ? rawArgs.split(/\s+/).filter(Boolean) : [];
|
||||||
|
return {
|
||||||
|
args,
|
||||||
|
raw: rawArgs,
|
||||||
|
text: rawArgs,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private normalizeList(value: string | undefined, fallback: string[]) {
|
||||||
|
const raw = `${value || ''}`.trim();
|
||||||
|
const parsed = this.tryParseJsonArray(raw);
|
||||||
|
const source = parsed.length > 0 ? parsed : raw.split(',');
|
||||||
|
const list = [...source, ...fallback]
|
||||||
|
.map((item) => `${item || ''}`.trim())
|
||||||
|
.filter(Boolean);
|
||||||
|
return [...new Set(list)];
|
||||||
|
}
|
||||||
|
|
||||||
|
private tryParseJsonArray(value: string) {
|
||||||
|
if (!value.startsWith('[')) return [];
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(value);
|
||||||
|
return Array.isArray(parsed) ? parsed : [];
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,27 +1,30 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Not, Repository } from 'typeorm';
|
import { Not, Repository } from 'typeorm';
|
||||||
import { throwVbenError, ToolsService } from '@/common';
|
import { throwVbenError, ToolsService } from '@/common';
|
||||||
import { QqbotAccountService } from '../account/qqbot-account.service';
|
import { QqbotAccountService } from '../account/qqbot-account.service';
|
||||||
import { QqbotPluginRegistryService } from '@/modules/qqbot/plugin-platform/registry/qqbot-plugin-registry.service';
|
import {
|
||||||
|
QQBOT_PLUGIN_EXECUTION_PORT,
|
||||||
|
type QqbotPluginExecutionPort,
|
||||||
|
} from '../../domain/plugin-execution.port';
|
||||||
import {
|
import {
|
||||||
QQBOT_DEFAULT_PAGE_NO,
|
QQBOT_DEFAULT_PAGE_NO,
|
||||||
QQBOT_DEFAULT_PAGE_SIZE,
|
QQBOT_DEFAULT_PAGE_SIZE,
|
||||||
} from '../contract/qqbot.constants';
|
} from '../../contract/qqbot.constants';
|
||||||
import type {
|
import type {
|
||||||
QqbotCommandParserType,
|
QqbotCommandParserType,
|
||||||
QqbotNormalizedMessage,
|
QqbotNormalizedMessage,
|
||||||
QqbotRuleTargetType,
|
QqbotRuleTargetType,
|
||||||
} from '../contract/qqbot.types';
|
} from '../../contract/qqbot.types';
|
||||||
import type {
|
import type {
|
||||||
QqbotCommandBodyDto,
|
QqbotCommandBodyDto,
|
||||||
QqbotCommandQueryDto,
|
QqbotCommandQueryDto,
|
||||||
QqbotCommandUpdateDto,
|
QqbotCommandUpdateDto,
|
||||||
} from './qqbot-command.dto';
|
} from '../../contract/command/qqbot-command.dto';
|
||||||
import { isWithinCooldown } from '../domain/qqbot-cooldown.policy';
|
import { isWithinCooldown } from '../../domain/qqbot-cooldown.policy';
|
||||||
import { QqbotCommandLog } from './qqbot-command-log.entity';
|
import { QqbotCommandLog } from '../../infrastructure/persistence/command/qqbot-command-log.entity';
|
||||||
import { QqbotCommand } from './qqbot-command.entity';
|
import { QqbotCommand } from '../../infrastructure/persistence/command/qqbot-command.entity';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class QqbotCommandService {
|
export class QqbotCommandService {
|
||||||
@ -31,7 +34,8 @@ export class QqbotCommandService {
|
|||||||
@InjectRepository(QqbotCommandLog)
|
@InjectRepository(QqbotCommandLog)
|
||||||
private readonly commandLogRepository: Repository<QqbotCommandLog>,
|
private readonly commandLogRepository: Repository<QqbotCommandLog>,
|
||||||
private readonly accountService: QqbotAccountService,
|
private readonly accountService: QqbotAccountService,
|
||||||
private readonly pluginRegistry: QqbotPluginRegistryService,
|
@Inject(QQBOT_PLUGIN_EXECUTION_PORT)
|
||||||
|
private readonly pluginExecution: QqbotPluginExecutionPort,
|
||||||
private readonly toolsService: ToolsService,
|
private readonly toolsService: ToolsService,
|
||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService,
|
||||||
) {}
|
) {}
|
||||||
@ -216,7 +220,7 @@ export class QqbotCommandService {
|
|||||||
const operationKey = `${body.operationKey || ''}`.trim();
|
const operationKey = `${body.operationKey || ''}`.trim();
|
||||||
if (!code) throwVbenError('命令编码不能为空');
|
if (!code) throwVbenError('命令编码不能为空');
|
||||||
if (!body.name?.trim()) throwVbenError('命令名称不能为空');
|
if (!body.name?.trim()) throwVbenError('命令名称不能为空');
|
||||||
this.pluginRegistry.assertOperation(pluginKey, operationKey);
|
await this.assertPluginOperation(pluginKey, operationKey);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
aliases: this.stringifyList(body.aliases),
|
aliases: this.stringifyList(body.aliases),
|
||||||
@ -248,6 +252,22 @@ export class QqbotCommandService {
|
|||||||
if (existed) throwVbenError(`命令编码已存在:${code}`);
|
if (existed) throwVbenError(`命令编码已存在:${code}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async assertPluginOperation(
|
||||||
|
pluginKey?: string,
|
||||||
|
operationKey?: string,
|
||||||
|
) {
|
||||||
|
if (!pluginKey || !operationKey) {
|
||||||
|
throwVbenError('请选择插件和插件能力');
|
||||||
|
}
|
||||||
|
const operation = await this.pluginExecution.getOperationByCommand({
|
||||||
|
operationKey,
|
||||||
|
pluginKey,
|
||||||
|
});
|
||||||
|
if (!operation) {
|
||||||
|
throwVbenError(`QQBot 插件能力不存在:${pluginKey}.${operationKey}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private stringifyList(value: string[] | string | undefined, fallback = []) {
|
private stringifyList(value: string[] | string | undefined, fallback = []) {
|
||||||
const list = Array.isArray(value)
|
const list = Array.isArray(value)
|
||||||
? value
|
? value
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
import { QqbotConfig } from './qqbot-config.entity';
|
import { QqbotConfig } from '../../infrastructure/persistence/config/qqbot-config.entity';
|
||||||
import type { QqbotPermissionConfig } from '../contract/qqbot.types';
|
import type { QqbotPermissionConfig } from '../../contract/qqbot.types';
|
||||||
|
|
||||||
const QQBOT_PERMISSION_CONFIG_KEYS = {
|
const QQBOT_PERMISSION_CONFIG_KEYS = {
|
||||||
allowlistEnabled: 'permission.allowlistEnabled',
|
allowlistEnabled: 'permission.allowlistEnabled',
|
||||||
@ -1,13 +1,13 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
import { QqbotAccount } from '../account/qqbot-account.entity';
|
import { QqbotBusService } from '../../infrastructure/integration/bus/qqbot-bus.service';
|
||||||
import { QqbotConversation } from '../message/qqbot-conversation.entity';
|
import { QqbotReverseWsService } from '../../infrastructure/integration/connection/qqbot-reverse-ws.service';
|
||||||
import { QqbotMessage } from '../message/qqbot-message.entity';
|
import { QqbotAccount } from '../../infrastructure/persistence/account/qqbot-account.entity';
|
||||||
import { QqbotBusService } from '../mqtt/qqbot-bus.service';
|
import { QqbotConversation } from '../../infrastructure/persistence/message/qqbot-conversation.entity';
|
||||||
import { QqbotReverseWsService } from '../connection/qqbot-reverse-ws.service';
|
import { QqbotMessage } from '../../infrastructure/persistence/message/qqbot-message.entity';
|
||||||
import { QqbotRule } from '../rule/qqbot-rule.entity';
|
import { QqbotRule } from '../../infrastructure/persistence/rule/qqbot-rule.entity';
|
||||||
import { QqbotSendLog } from '../send/qqbot-send-log.entity';
|
import { QqbotSendLog } from '../../infrastructure/persistence/send/qqbot-send-log.entity';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class QqbotDashboardService {
|
export class QqbotDashboardService {
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
import { QqbotDedupe } from './qqbot-dedupe.entity';
|
import { QqbotDedupe } from '../../infrastructure/persistence/dedupe/qqbot-dedupe.entity';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class QqbotDedupeService {
|
export class QqbotDedupeService {
|
||||||
@ -4,17 +4,17 @@ import {
|
|||||||
SystemNoticePublisher,
|
SystemNoticePublisher,
|
||||||
ToolsService,
|
ToolsService,
|
||||||
} from '@/common';
|
} from '@/common';
|
||||||
import { QQBOT_MQTT_TOPICS } from '../contract/qqbot.constants';
|
import { QQBOT_MQTT_TOPICS } from '../../contract/qqbot.constants';
|
||||||
import { QqbotDedupeService } from '../dedupe/qqbot-dedupe.service';
|
import { QqbotDedupeService } from '../dedupe/qqbot-dedupe.service';
|
||||||
import { QqbotMessageService } from '../message/qqbot-message.service';
|
import { QqbotMessageService } from '../message/qqbot-message.service';
|
||||||
import { QqbotBusService } from '../mqtt/qqbot-bus.service';
|
import { QqbotBusService } from '../../infrastructure/integration/bus/qqbot-bus.service';
|
||||||
import type { QqbotOneBotEvent } from '../contract/qqbot.types';
|
import type { QqbotOneBotEvent } from '../../contract/qqbot.types';
|
||||||
import {
|
import {
|
||||||
buildDedupeKey,
|
buildDedupeKey,
|
||||||
getOneBotOfflineReason,
|
getOneBotOfflineReason,
|
||||||
isOneBotMessageEvent,
|
isOneBotMessageEvent,
|
||||||
normalizeOneBotMessage,
|
normalizeOneBotMessage,
|
||||||
} from './qqbot-event-normalizer';
|
} from '../../domain/event/qqbot-event-normalizer';
|
||||||
import { QqbotRuleEngineService } from '../rule/qqbot-rule-engine.service';
|
import { QqbotRuleEngineService } from '../rule/qqbot-rule-engine.service';
|
||||||
import { QqbotAccountService } from '../account/qqbot-account.service';
|
import { QqbotAccountService } from '../account/qqbot-account.service';
|
||||||
|
|
||||||
@ -2,17 +2,20 @@ import { Injectable } from '@nestjs/common';
|
|||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
import { ToolsService } from '@/common';
|
import { ToolsService } from '@/common';
|
||||||
import { QqbotConversation } from './qqbot-conversation.entity';
|
import { QqbotConversation } from '../../infrastructure/persistence/message/qqbot-conversation.entity';
|
||||||
import { QqbotMessage } from './qqbot-message.entity';
|
import { QqbotMessage } from '../../infrastructure/persistence/message/qqbot-message.entity';
|
||||||
import type {
|
import type {
|
||||||
QqbotConversationQueryDto,
|
QqbotConversationQueryDto,
|
||||||
QqbotMessageQueryDto,
|
QqbotMessageQueryDto,
|
||||||
} from './qqbot-message.dto';
|
} from '../../contract/message/qqbot-message.dto';
|
||||||
import type { QqbotMessageType, QqbotNormalizedMessage } from '../contract/qqbot.types';
|
import type {
|
||||||
|
QqbotMessageType,
|
||||||
|
QqbotNormalizedMessage,
|
||||||
|
} from '../../contract/qqbot.types';
|
||||||
import {
|
import {
|
||||||
QQBOT_DEFAULT_PAGE_NO,
|
QQBOT_DEFAULT_PAGE_NO,
|
||||||
QQBOT_DEFAULT_PAGE_SIZE,
|
QQBOT_DEFAULT_PAGE_SIZE,
|
||||||
} from '../contract/qqbot.constants';
|
} from '../../contract/qqbot.constants';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class QqbotMessageService {
|
export class QqbotMessageService {
|
||||||
@ -2,24 +2,24 @@ import { Injectable } from '@nestjs/common';
|
|||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Brackets, Repository } from 'typeorm';
|
import { Brackets, Repository } from 'typeorm';
|
||||||
import { throwVbenError, ToolsService } from '@/common';
|
import { throwVbenError, ToolsService } from '@/common';
|
||||||
import { QqbotAllowlist } from './qqbot-allowlist.entity';
|
import { QqbotAllowlist } from '../../infrastructure/persistence/permission/qqbot-allowlist.entity';
|
||||||
import { QqbotBlocklist } from './qqbot-blocklist.entity';
|
import { QqbotBlocklist } from '../../infrastructure/persistence/permission/qqbot-blocklist.entity';
|
||||||
import type {
|
import type {
|
||||||
QqbotPermissionBodyDto,
|
QqbotPermissionBodyDto,
|
||||||
QqbotPermissionConfigDto,
|
QqbotPermissionConfigDto,
|
||||||
QqbotPermissionQueryDto,
|
QqbotPermissionQueryDto,
|
||||||
QqbotPermissionUpdateDto,
|
QqbotPermissionUpdateDto,
|
||||||
} from './qqbot-permission.dto';
|
} from '../../contract/permission/qqbot-permission.dto';
|
||||||
import { QqbotConfigService } from '../config/qqbot-config.service';
|
import { QqbotConfigService } from '../config/qqbot-config.service';
|
||||||
import {
|
import {
|
||||||
QQBOT_DEFAULT_PAGE_NO,
|
QQBOT_DEFAULT_PAGE_NO,
|
||||||
QQBOT_DEFAULT_PAGE_SIZE,
|
QQBOT_DEFAULT_PAGE_SIZE,
|
||||||
} from '../contract/qqbot.constants';
|
} from '../../contract/qqbot.constants';
|
||||||
import type {
|
import type {
|
||||||
QqbotNormalizedMessage,
|
QqbotNormalizedMessage,
|
||||||
QqbotPermissionEntity,
|
QqbotPermissionEntity,
|
||||||
QqbotPermissionKind,
|
QqbotPermissionKind,
|
||||||
} from '../contract/qqbot.types';
|
} from '../../contract/qqbot.types';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class QqbotPermissionService {
|
export class QqbotPermissionService {
|
||||||
@ -1,9 +1,12 @@
|
|||||||
import { Injectable, Logger } from '@nestjs/common';
|
import { Inject, Injectable, Logger } from '@nestjs/common';
|
||||||
import { ToolsService } from '@/common';
|
import { ToolsService } from '@/common';
|
||||||
import type { QqbotNormalizedMessage } from '../contract/qqbot.types';
|
import {
|
||||||
|
QQBOT_PLUGIN_EXECUTION_PORT,
|
||||||
|
type QqbotPluginExecutionPort,
|
||||||
|
} from '../../domain/plugin-execution.port';
|
||||||
|
import type { QqbotNormalizedMessage } from '../../contract/qqbot.types';
|
||||||
import { QqbotCommandEngineService } from '../command/qqbot-command-engine.service';
|
import { QqbotCommandEngineService } from '../command/qqbot-command-engine.service';
|
||||||
import { QqbotPermissionService } from '../permission/qqbot-permission.service';
|
import { QqbotPermissionService } from '../permission/qqbot-permission.service';
|
||||||
import { QqbotRepeaterPluginService } from '@/modules/qqbot/plugins/repeater/qqbot-repeater.plugin';
|
|
||||||
import { QqbotSendService } from '../send/qqbot-send.service';
|
import { QqbotSendService } from '../send/qqbot-send.service';
|
||||||
import { QqbotRuleService } from './qqbot-rule.service';
|
import { QqbotRuleService } from './qqbot-rule.service';
|
||||||
|
|
||||||
@ -14,7 +17,8 @@ export class QqbotRuleEngineService {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly commandEngineService: QqbotCommandEngineService,
|
private readonly commandEngineService: QqbotCommandEngineService,
|
||||||
private readonly permissionService: QqbotPermissionService,
|
private readonly permissionService: QqbotPermissionService,
|
||||||
private readonly repeaterPluginService: QqbotRepeaterPluginService,
|
@Inject(QQBOT_PLUGIN_EXECUTION_PORT)
|
||||||
|
private readonly pluginExecution: QqbotPluginExecutionPort,
|
||||||
private readonly ruleService: QqbotRuleService,
|
private readonly ruleService: QqbotRuleService,
|
||||||
private readonly sendService: QqbotSendService,
|
private readonly sendService: QqbotSendService,
|
||||||
private readonly toolsService: ToolsService,
|
private readonly toolsService: ToolsService,
|
||||||
@ -49,6 +53,9 @@ export class QqbotRuleEngineService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.repeaterPluginService.handleMessage(message);
|
await this.pluginExecution.dispatchEvent({
|
||||||
|
eventKey: 'message',
|
||||||
|
message,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4,22 +4,22 @@ import { InjectRepository } from '@nestjs/typeorm';
|
|||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
import { throwVbenError, ToolsService } from '@/common';
|
import { throwVbenError, ToolsService } from '@/common';
|
||||||
import { QqbotAccountService } from '../account/qqbot-account.service';
|
import { QqbotAccountService } from '../account/qqbot-account.service';
|
||||||
import { QqbotRule } from './qqbot-rule.entity';
|
import { QqbotRule } from '../../infrastructure/persistence/rule/qqbot-rule.entity';
|
||||||
import type {
|
import type {
|
||||||
QqbotRuleBodyDto,
|
QqbotRuleBodyDto,
|
||||||
QqbotRuleQueryDto,
|
QqbotRuleQueryDto,
|
||||||
QqbotRuleUpdateDto,
|
QqbotRuleUpdateDto,
|
||||||
} from './qqbot-rule.dto';
|
} from '../../contract/rule/qqbot-rule.dto';
|
||||||
import type {
|
import type {
|
||||||
QqbotNormalizedMessage,
|
QqbotNormalizedMessage,
|
||||||
QqbotRuleMatchType,
|
QqbotRuleMatchType,
|
||||||
QqbotRuleTargetType,
|
QqbotRuleTargetType,
|
||||||
} from '../contract/qqbot.types';
|
} from '../../contract/qqbot.types';
|
||||||
import {
|
import {
|
||||||
QQBOT_DEFAULT_PAGE_NO,
|
QQBOT_DEFAULT_PAGE_NO,
|
||||||
QQBOT_DEFAULT_PAGE_SIZE,
|
QQBOT_DEFAULT_PAGE_SIZE,
|
||||||
} from '../contract/qqbot.constants';
|
} from '../../contract/qqbot.constants';
|
||||||
import { isWithinCooldown } from '../domain/qqbot-cooldown.policy';
|
import { isWithinCooldown } from '../../domain/qqbot-cooldown.policy';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class QqbotRuleService {
|
export class QqbotRuleService {
|
||||||
@ -4,24 +4,24 @@ import { InjectRepository } from '@nestjs/typeorm';
|
|||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
import { throwVbenError, ToolsService } from '@/common';
|
import { throwVbenError, ToolsService } from '@/common';
|
||||||
import { QqbotAccountService } from '../account/qqbot-account.service';
|
import { QqbotAccountService } from '../account/qqbot-account.service';
|
||||||
import { QQBOT_MQTT_TOPICS } from '../contract/qqbot.constants';
|
import { QQBOT_MQTT_TOPICS } from '../../contract/qqbot.constants';
|
||||||
import { QqbotBusService } from '../mqtt/qqbot-bus.service';
|
import { QqbotBusService } from '../../infrastructure/integration/bus/qqbot-bus.service';
|
||||||
import { QqbotMessageService } from '../message/qqbot-message.service';
|
import { QqbotMessageService } from '../message/qqbot-message.service';
|
||||||
import type {
|
import type {
|
||||||
QqbotMessageType,
|
QqbotMessageType,
|
||||||
QqbotReverseActionSender,
|
QqbotReverseActionSender,
|
||||||
} from '../contract/qqbot.types';
|
} from '../../contract/qqbot.types';
|
||||||
import {
|
import {
|
||||||
QQBOT_DEFAULT_PAGE_NO,
|
QQBOT_DEFAULT_PAGE_NO,
|
||||||
QQBOT_DEFAULT_PAGE_SIZE,
|
QQBOT_DEFAULT_PAGE_SIZE,
|
||||||
} from '../contract/qqbot.constants';
|
} from '../../contract/qqbot.constants';
|
||||||
import { QqbotRateLimitService } from './qqbot-rate-limit.service';
|
import { QqbotRateLimitService } from './qqbot-rate-limit.service';
|
||||||
import { QqbotSendLog } from './qqbot-send-log.entity';
|
import { QqbotSendLog } from '../../infrastructure/persistence/send/qqbot-send-log.entity';
|
||||||
import type {
|
import type {
|
||||||
QqbotSendGroupDto,
|
QqbotSendGroupDto,
|
||||||
QqbotSendLogQueryDto,
|
QqbotSendLogQueryDto,
|
||||||
QqbotSendPrivateDto,
|
QqbotSendPrivateDto,
|
||||||
} from './qqbot-send.dto';
|
} from '../../contract/send/qqbot-send.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class QqbotSendService {
|
export class QqbotSendService {
|
||||||
@ -186,7 +186,7 @@ export class QqbotSendService {
|
|||||||
|
|
||||||
private async getReverseWsService(): Promise<QqbotReverseActionSender> {
|
private async getReverseWsService(): Promise<QqbotReverseActionSender> {
|
||||||
const { QqbotReverseWsService } =
|
const { QqbotReverseWsService } =
|
||||||
await import('../connection/qqbot-reverse-ws.service');
|
await import('../../infrastructure/integration/connection/qqbot-reverse-ws.service');
|
||||||
return this.moduleRef.get<QqbotReverseActionSender>(QqbotReverseWsService, {
|
return this.moduleRef.get<QqbotReverseActionSender>(QqbotReverseWsService, {
|
||||||
strict: false,
|
strict: false,
|
||||||
});
|
});
|
||||||
@ -19,9 +19,9 @@ import {
|
|||||||
QqbotAccountScanStatusDto,
|
QqbotAccountScanStatusDto,
|
||||||
QqbotAccountUpdateDto,
|
QqbotAccountUpdateDto,
|
||||||
} from './qqbot-account.dto';
|
} from './qqbot-account.dto';
|
||||||
import { QqbotAccountService } from './qqbot-account.service';
|
import { QqbotAccountService } from '../../application/account/qqbot-account.service';
|
||||||
import { QqbotNapcatLoginService } from '../../napcat/login/qqbot-napcat-login.service';
|
import { QqbotNapcatLoginService } from '@/modules/qqbot/napcat/application/login/qqbot-napcat-login.service';
|
||||||
import { QqbotReverseWsService } from '../connection/qqbot-reverse-ws.service';
|
import { QqbotReverseWsService } from '../../infrastructure/integration/connection/qqbot-reverse-ws.service';
|
||||||
|
|
||||||
@ApiTags('QQBot - 账号连接')
|
@ApiTags('QQBot - 账号连接')
|
||||||
@Controller('qqbot/account')
|
@Controller('qqbot/account')
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { ApiProperty, ApiPropertyOptional, PartialType } from '@nestjs/swagger';
|
import { ApiProperty, ApiPropertyOptional, PartialType } from '@nestjs/swagger';
|
||||||
import type { QqbotConnectionMode } from '../contract/qqbot.types';
|
import type { QqbotConnectionMode } from '../qqbot.types';
|
||||||
|
|
||||||
export class QqbotAccountBodyDto {
|
export class QqbotAccountBodyDto {
|
||||||
@ApiPropertyOptional({ default: 'reverse-ws' })
|
@ApiPropertyOptional({ default: 'reverse-ws' })
|
||||||
@ -17,8 +17,8 @@ import {
|
|||||||
QqbotCommandTestDto,
|
QqbotCommandTestDto,
|
||||||
QqbotCommandUpdateDto,
|
QqbotCommandUpdateDto,
|
||||||
} from './qqbot-command.dto';
|
} from './qqbot-command.dto';
|
||||||
import { QqbotCommandEngineService } from './qqbot-command-engine.service';
|
import { QqbotCommandEngineService } from '../../application/command/qqbot-command-engine.service';
|
||||||
import { QqbotCommandService } from './qqbot-command.service';
|
import { QqbotCommandService } from '../../application/command/qqbot-command.service';
|
||||||
|
|
||||||
@ApiTags('QQBot - 在线命令')
|
@ApiTags('QQBot - 在线命令')
|
||||||
@Controller('qqbot/command')
|
@Controller('qqbot/command')
|
||||||
@ -5,7 +5,7 @@ import type {
|
|||||||
QqbotCommandParserType,
|
QqbotCommandParserType,
|
||||||
QqbotMessageType,
|
QqbotMessageType,
|
||||||
QqbotRuleTargetType,
|
QqbotRuleTargetType,
|
||||||
} from '../contract/qqbot.types';
|
} from '../qqbot.types';
|
||||||
|
|
||||||
export class QqbotCommandQueryDto implements KtPageQuery {
|
export class QqbotCommandQueryDto implements KtPageQuery {
|
||||||
@ApiPropertyOptional()
|
@ApiPropertyOptional()
|
||||||
@ -2,7 +2,7 @@ import { Controller, Get, UseGuards } from '@nestjs/common';
|
|||||||
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||||
import { JwtAuthGuard } from '@/modules/admin/identity/auth/jwt-auth.guard';
|
import { JwtAuthGuard } from '@/modules/admin/identity/auth/jwt-auth.guard';
|
||||||
import { vbenSuccess } from '@/common';
|
import { vbenSuccess } from '@/common';
|
||||||
import { QqbotDashboardService } from './qqbot-dashboard.service';
|
import { QqbotDashboardService } from '../../application/dashboard/qqbot-dashboard.service';
|
||||||
|
|
||||||
@ApiTags('QQBot - 工作台')
|
@ApiTags('QQBot - 工作台')
|
||||||
@Controller('qqbot/dashboard')
|
@Controller('qqbot/dashboard')
|
||||||
@ -6,7 +6,7 @@ import {
|
|||||||
QqbotConversationQueryDto,
|
QqbotConversationQueryDto,
|
||||||
QqbotMessageQueryDto,
|
QqbotMessageQueryDto,
|
||||||
} from './qqbot-message.dto';
|
} from './qqbot-message.dto';
|
||||||
import { QqbotMessageService } from './qqbot-message.service';
|
import { QqbotMessageService } from '../../application/message/qqbot-message.service';
|
||||||
|
|
||||||
@ApiTags('QQBot - 会话与消息')
|
@ApiTags('QQBot - 会话与消息')
|
||||||
@Controller('qqbot')
|
@Controller('qqbot')
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
import type { QqbotMessageType } from '../contract/qqbot.types';
|
import type { QqbotMessageType } from '../qqbot.types';
|
||||||
|
|
||||||
export class QqbotConversationQueryDto {
|
export class QqbotConversationQueryDto {
|
||||||
@ApiPropertyOptional({ default: 1 })
|
@ApiPropertyOptional({ default: 1 })
|
||||||
@ -17,7 +17,7 @@ import {
|
|||||||
QqbotPermissionQueryDto,
|
QqbotPermissionQueryDto,
|
||||||
QqbotPermissionUpdateDto,
|
QqbotPermissionUpdateDto,
|
||||||
} from './qqbot-permission.dto';
|
} from './qqbot-permission.dto';
|
||||||
import { QqbotPermissionService } from './qqbot-permission.service';
|
import { QqbotPermissionService } from '../../application/permission/qqbot-permission.service';
|
||||||
|
|
||||||
@ApiTags('QQBot - 权限名单')
|
@ApiTags('QQBot - 权限名单')
|
||||||
@Controller('qqbot/permission')
|
@Controller('qqbot/permission')
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { ApiProperty, ApiPropertyOptional, PartialType } from '@nestjs/swagger';
|
import { ApiProperty, ApiPropertyOptional, PartialType } from '@nestjs/swagger';
|
||||||
import type { QqbotPermissionTargetType } from '../contract/qqbot.types';
|
import type { QqbotPermissionTargetType } from '../qqbot.types';
|
||||||
|
|
||||||
export class QqbotPermissionConfigDto {
|
export class QqbotPermissionConfigDto {
|
||||||
@ApiPropertyOptional({ default: false })
|
@ApiPropertyOptional({ default: false })
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import type { QrcodeLookupOptions } from '@/common/types';
|
import type { QrcodeLookupOptions } from '@/common/types';
|
||||||
import type { QqbotAccount } from '../account/qqbot-account.entity';
|
import type { QqbotAccount } from '../infrastructure/persistence/account/qqbot-account.entity';
|
||||||
import type { QqbotCommand } from '../command/qqbot-command.entity';
|
import type { QqbotCommand } from '../infrastructure/persistence/command/qqbot-command.entity';
|
||||||
import type { QqbotAllowlist } from '../permission/qqbot-allowlist.entity';
|
import type { QqbotAllowlist } from '../infrastructure/persistence/permission/qqbot-allowlist.entity';
|
||||||
import type { QqbotBlocklist } from '../permission/qqbot-blocklist.entity';
|
import type { QqbotBlocklist } from '../infrastructure/persistence/permission/qqbot-blocklist.entity';
|
||||||
|
|
||||||
export type { QrcodeLookupOptions } from '@/common/types';
|
export type { QrcodeLookupOptions } from '@/common/types';
|
||||||
|
|
||||||
@ -354,14 +354,6 @@ export type QqbotReverseActionSender = {
|
|||||||
) => Promise<QqbotOneBotActionResponse>;
|
) => Promise<QqbotOneBotActionResponse>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type QqbotRepeaterConversationState = {
|
|
||||||
count: number;
|
|
||||||
lastRepeatedAt?: number;
|
|
||||||
lastText: string;
|
|
||||||
repeatedText: string;
|
|
||||||
updatedAt: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type QrcodeRefreshOptions = QrcodeLookupOptions & {
|
export type QrcodeRefreshOptions = QrcodeLookupOptions & {
|
||||||
fallbackStatus?: NapcatLoginStatus;
|
fallbackStatus?: NapcatLoginStatus;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -16,7 +16,7 @@ import {
|
|||||||
QqbotRuleQueryDto,
|
QqbotRuleQueryDto,
|
||||||
QqbotRuleUpdateDto,
|
QqbotRuleUpdateDto,
|
||||||
} from './qqbot-rule.dto';
|
} from './qqbot-rule.dto';
|
||||||
import { QqbotRuleService } from './qqbot-rule.service';
|
import { QqbotRuleService } from '../../application/rule/qqbot-rule.service';
|
||||||
|
|
||||||
@ApiTags('QQBot - 自动回复规则')
|
@ApiTags('QQBot - 自动回复规则')
|
||||||
@Controller('qqbot/rule')
|
@Controller('qqbot/rule')
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { ApiProperty, ApiPropertyOptional, PartialType } from '@nestjs/swagger';
|
import { ApiProperty, ApiPropertyOptional, PartialType } from '@nestjs/swagger';
|
||||||
import type { QqbotRuleMatchType, QqbotRuleTargetType } from '../contract/qqbot.types';
|
import type { QqbotRuleMatchType, QqbotRuleTargetType } from '../qqbot.types';
|
||||||
|
|
||||||
export class QqbotRuleBodyDto {
|
export class QqbotRuleBodyDto {
|
||||||
@ApiPropertyOptional()
|
@ApiPropertyOptional()
|
||||||
@ -16,7 +16,7 @@ import {
|
|||||||
QqbotSendLogQueryDto,
|
QqbotSendLogQueryDto,
|
||||||
QqbotSendPrivateDto,
|
QqbotSendPrivateDto,
|
||||||
} from './qqbot-send.dto';
|
} from './qqbot-send.dto';
|
||||||
import { QqbotSendService } from './qqbot-send.service';
|
import { QqbotSendService } from '../../application/send/qqbot-send.service';
|
||||||
|
|
||||||
@ApiTags('QQBot - 发送日志')
|
@ApiTags('QQBot - 发送日志')
|
||||||
@Controller('qqbot/send')
|
@Controller('qqbot/send')
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
import type { QqbotMessageType, QqbotSendStatus } from '../contract/qqbot.types';
|
import type { QqbotMessageType, QqbotSendStatus } from '../qqbot.types';
|
||||||
|
|
||||||
export class QqbotSendPrivateDto {
|
export class QqbotSendPrivateDto {
|
||||||
@ApiPropertyOptional()
|
@ApiPropertyOptional()
|
||||||
@ -3,7 +3,7 @@ import type {
|
|||||||
QqbotMessageType,
|
QqbotMessageType,
|
||||||
QqbotNormalizedMessage,
|
QqbotNormalizedMessage,
|
||||||
QqbotOneBotEvent,
|
QqbotOneBotEvent,
|
||||||
} from '../contract/qqbot.types';
|
} from '../../contract/qqbot.types';
|
||||||
|
|
||||||
export function isOneBotMessageEvent(
|
export function isOneBotMessageEvent(
|
||||||
payload: QqbotOneBotEvent,
|
payload: QqbotOneBotEvent,
|
||||||
40
src/modules/qqbot/core/domain/plugin-execution.port.ts
Normal file
40
src/modules/qqbot/core/domain/plugin-execution.port.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import type {
|
||||||
|
QqbotNormalizedMessage,
|
||||||
|
QqbotPluginOperationSummary,
|
||||||
|
} from '../contract/qqbot.types';
|
||||||
|
|
||||||
|
export const QQBOT_PLUGIN_EXECUTION_PORT = Symbol(
|
||||||
|
'QQBOT_PLUGIN_EXECUTION_PORT',
|
||||||
|
);
|
||||||
|
|
||||||
|
export type QqbotPluginOperationLookup = {
|
||||||
|
operationKey?: string;
|
||||||
|
pluginKey?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type QqbotPluginExecutionInput = {
|
||||||
|
context?: Record<string, any>;
|
||||||
|
input: Record<string, any>;
|
||||||
|
operationKey: string;
|
||||||
|
pluginKey: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type QqbotPluginEventDispatchInput = {
|
||||||
|
eventKey: 'message';
|
||||||
|
message: QqbotNormalizedMessage;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type QqbotPluginOperationListContext = {
|
||||||
|
selfId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface QqbotPluginExecutionPort {
|
||||||
|
dispatchEvent(input: QqbotPluginEventDispatchInput): Promise<boolean>;
|
||||||
|
executeOperation(input: QqbotPluginExecutionInput): Promise<any>;
|
||||||
|
getOperationByCommand(
|
||||||
|
command: QqbotPluginOperationLookup,
|
||||||
|
): Promise<null | QqbotPluginOperationSummary>;
|
||||||
|
listActiveOperations(
|
||||||
|
context?: QqbotPluginOperationListContext,
|
||||||
|
): Promise<QqbotPluginOperationSummary[]>;
|
||||||
|
}
|
||||||
@ -8,7 +8,7 @@ import {
|
|||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import * as mqtt from 'mqtt';
|
import * as mqtt from 'mqtt';
|
||||||
import type { MqttClient } from 'mqtt';
|
import type { MqttClient } from 'mqtt';
|
||||||
import type { QqbotBusHandler } from '../contract/qqbot.types';
|
import type { QqbotBusHandler } from '../../../contract/qqbot.types';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class QqbotBusService implements OnModuleInit, OnModuleDestroy {
|
export class QqbotBusService implements OnModuleInit, OnModuleDestroy {
|
||||||
@ -10,16 +10,19 @@ import { ConfigService } from '@nestjs/config';
|
|||||||
import { HttpAdapterHost, ModuleRef } from '@nestjs/core';
|
import { HttpAdapterHost, ModuleRef } from '@nestjs/core';
|
||||||
import { WebSocket, WebSocketServer } from 'ws';
|
import { WebSocket, WebSocketServer } from 'ws';
|
||||||
import { ToolsService } from '@/common';
|
import { ToolsService } from '@/common';
|
||||||
import { QQBOT_MQTT_TOPICS, QQBOT_REVERSE_WS_PATH } from '../contract/qqbot.constants';
|
import {
|
||||||
|
QQBOT_MQTT_TOPICS,
|
||||||
|
QQBOT_REVERSE_WS_PATH,
|
||||||
|
} from '../../../contract/qqbot.constants';
|
||||||
import type {
|
import type {
|
||||||
QqbotConnectionRole,
|
QqbotConnectionRole,
|
||||||
QqbotOneBotActionResponse,
|
QqbotOneBotActionResponse,
|
||||||
QqbotOneBotEvent,
|
QqbotOneBotEvent,
|
||||||
QqbotPendingAction,
|
QqbotPendingAction,
|
||||||
} from '../contract/qqbot.types';
|
} from '../../../contract/qqbot.types';
|
||||||
import { QqbotAccountService } from '../account/qqbot-account.service';
|
import { QqbotAccountService } from '../../../application/account/qqbot-account.service';
|
||||||
import { QqbotEventService } from '../event/qqbot-event.service';
|
import { QqbotEventService } from '../../../application/event/qqbot-event.service';
|
||||||
import { QqbotBusService } from '../mqtt/qqbot-bus.service';
|
import { QqbotBusService } from '../bus/qqbot-bus.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class QqbotReverseWsService
|
export class QqbotReverseWsService
|
||||||
@ -5,7 +5,7 @@ import {
|
|||||||
KtDateTime,
|
KtDateTime,
|
||||||
KtUpdateDateColumn,
|
KtUpdateDateColumn,
|
||||||
} from '@/common';
|
} from '@/common';
|
||||||
import type { QqbotAccountAbilityType } from '../contract/qqbot.types';
|
import type { QqbotAccountAbilityType } from '../../../contract/qqbot.types';
|
||||||
|
|
||||||
@Entity('qqbot_account_ability')
|
@Entity('qqbot_account_ability')
|
||||||
@Index('uk_qqbot_account_ability', ['accountId', 'abilityType', 'abilityKey'], {
|
@Index('uk_qqbot_account_ability', ['accountId', 'abilityType', 'abilityKey'], {
|
||||||
@ -10,7 +10,7 @@ import type {
|
|||||||
QqbotConnectionMode,
|
QqbotConnectionMode,
|
||||||
QqbotConnectionRole,
|
QqbotConnectionRole,
|
||||||
QqbotConnectionStatus,
|
QqbotConnectionStatus,
|
||||||
} from '../contract/qqbot.types';
|
} from '../../../contract/qqbot.types';
|
||||||
|
|
||||||
@Entity('qqbot_account')
|
@Entity('qqbot_account')
|
||||||
export class QqbotAccount {
|
export class QqbotAccount {
|
||||||
@ -5,8 +5,8 @@ import {
|
|||||||
KtDateTime,
|
KtDateTime,
|
||||||
KtUpdateDateColumn,
|
KtUpdateDateColumn,
|
||||||
} from '@/common';
|
} from '@/common';
|
||||||
import type { QqbotMessageType } from '../contract/qqbot.types';
|
import type { QqbotMessageType } from '../../../contract/qqbot.types';
|
||||||
import type { QqbotCommandLogStatus } from '../contract/qqbot.types';
|
import type { QqbotCommandLogStatus } from '../../../contract/qqbot.types';
|
||||||
|
|
||||||
@Entity('qqbot_command_log')
|
@Entity('qqbot_command_log')
|
||||||
export class QqbotCommandLog {
|
export class QqbotCommandLog {
|
||||||
@ -9,7 +9,7 @@ import {
|
|||||||
import type {
|
import type {
|
||||||
QqbotCommandParserType,
|
QqbotCommandParserType,
|
||||||
QqbotRuleTargetType,
|
QqbotRuleTargetType,
|
||||||
} from '../contract/qqbot.types';
|
} from '../../../contract/qqbot.types';
|
||||||
|
|
||||||
@Entity('qqbot_command')
|
@Entity('qqbot_command')
|
||||||
export class QqbotCommand {
|
export class QqbotCommand {
|
||||||
@ -6,7 +6,7 @@ import {
|
|||||||
KtDateTimeColumn,
|
KtDateTimeColumn,
|
||||||
KtUpdateDateColumn,
|
KtUpdateDateColumn,
|
||||||
} from '@/common';
|
} from '@/common';
|
||||||
import type { QqbotMessageType } from '../contract/qqbot.types';
|
import type { QqbotMessageType } from '../../../contract/qqbot.types';
|
||||||
|
|
||||||
@Entity('qqbot_conversation')
|
@Entity('qqbot_conversation')
|
||||||
@Index('idx_qqbot_conversation_target', ['selfId', 'targetType', 'targetId'])
|
@Index('idx_qqbot_conversation_target', ['selfId', 'targetType', 'targetId'])
|
||||||
@ -6,7 +6,7 @@ import {
|
|||||||
KtDateTimeColumn,
|
KtDateTimeColumn,
|
||||||
KtUpdateDateColumn,
|
KtUpdateDateColumn,
|
||||||
} from '@/common';
|
} from '@/common';
|
||||||
import type { QqbotMessageDirection, QqbotMessageType } from '../contract/qqbot.types';
|
import type { QqbotMessageDirection, QqbotMessageType } from '../../../contract/qqbot.types';
|
||||||
|
|
||||||
@Entity('qqbot_message')
|
@Entity('qqbot_message')
|
||||||
@Index('idx_qqbot_message_self_message', ['selfId', 'messageId'])
|
@Index('idx_qqbot_message_self_message', ['selfId', 'messageId'])
|
||||||
@ -5,7 +5,7 @@ import {
|
|||||||
KtDateTime,
|
KtDateTime,
|
||||||
KtUpdateDateColumn,
|
KtUpdateDateColumn,
|
||||||
} from '@/common';
|
} from '@/common';
|
||||||
import type { QqbotPermissionTargetType } from '../contract/qqbot.types';
|
import type { QqbotPermissionTargetType } from '../../../contract/qqbot.types';
|
||||||
|
|
||||||
@Entity('qqbot_allowlist')
|
@Entity('qqbot_allowlist')
|
||||||
export class QqbotAllowlist {
|
export class QqbotAllowlist {
|
||||||
@ -5,7 +5,7 @@ import {
|
|||||||
KtDateTime,
|
KtDateTime,
|
||||||
KtUpdateDateColumn,
|
KtUpdateDateColumn,
|
||||||
} from '@/common';
|
} from '@/common';
|
||||||
import type { QqbotPermissionTargetType } from '../contract/qqbot.types';
|
import type { QqbotPermissionTargetType } from '../../../contract/qqbot.types';
|
||||||
|
|
||||||
@Entity('qqbot_blocklist')
|
@Entity('qqbot_blocklist')
|
||||||
export class QqbotBlocklist {
|
export class QqbotBlocklist {
|
||||||
@ -6,7 +6,7 @@ import {
|
|||||||
KtDateTimeColumn,
|
KtDateTimeColumn,
|
||||||
KtUpdateDateColumn,
|
KtUpdateDateColumn,
|
||||||
} from '@/common';
|
} from '@/common';
|
||||||
import type { QqbotRuleMatchType, QqbotRuleTargetType } from '../contract/qqbot.types';
|
import type { QqbotRuleMatchType, QqbotRuleTargetType } from '../../../contract/qqbot.types';
|
||||||
|
|
||||||
@Entity('qqbot_rule')
|
@Entity('qqbot_rule')
|
||||||
export class QqbotRule {
|
export class QqbotRule {
|
||||||
@ -5,7 +5,7 @@ import {
|
|||||||
KtDateTime,
|
KtDateTime,
|
||||||
KtUpdateDateColumn,
|
KtUpdateDateColumn,
|
||||||
} from '@/common';
|
} from '@/common';
|
||||||
import type { QqbotMessageType, QqbotSendStatus } from '../contract/qqbot.types';
|
import type { QqbotMessageType, QqbotSendStatus } from '../../../contract/qqbot.types';
|
||||||
|
|
||||||
@Entity('qqbot_send_log')
|
@Entity('qqbot_send_log')
|
||||||
@Index('idx_qqbot_send_log_target', ['selfId', 'targetType', 'targetId'])
|
@Index('idx_qqbot_send_log_target', ['selfId', 'targetType', 'targetId'])
|
||||||
@ -1,66 +1,54 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { forwardRef, Module } from '@nestjs/common';
|
||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
import { AdminAuthGuardModule } from '@/modules/admin/identity/auth/admin-auth-guard.module';
|
import { AdminAuthGuardModule } from '@/modules/admin/identity/auth/admin-auth-guard.module';
|
||||||
import { DictModule } from '@/modules/admin/platform-config/dict/dict.module';
|
import { DictModule } from '@/modules/admin/platform-config/dict/dict.module';
|
||||||
import { QqbotAccountAbility } from '@/modules/qqbot/core/account/qqbot-account-ability.entity';
|
import { QqbotPluginPlatformModule } from '@/modules/qqbot/plugin-platform/plugin-platform.module';
|
||||||
import { QqbotAccountController } from '@/modules/qqbot/core/account/qqbot-account.controller';
|
import { QqbotAccountAbility } from '@/modules/qqbot/core/infrastructure/persistence/account/qqbot-account-ability.entity';
|
||||||
import { QqbotAccount } from '@/modules/qqbot/core/account/qqbot-account.entity';
|
import { QqbotAccountController } from '@/modules/qqbot/core/contract/account/qqbot-account.controller';
|
||||||
import { QqbotAccountService } from '@/modules/qqbot/core/account/qqbot-account.service';
|
import { QqbotAccount } from '@/modules/qqbot/core/infrastructure/persistence/account/qqbot-account.entity';
|
||||||
import { QqbotNapcatLoginService } from '@/modules/qqbot/napcat/login/qqbot-napcat-login.service';
|
import { QqbotAccountService } from '@/modules/qqbot/core/application/account/qqbot-account.service';
|
||||||
import { QqbotNapcatWatchdogService } from '@/modules/qqbot/napcat/login/qqbot-napcat-watchdog.service';
|
import { QqbotNapcatLoginService } from '@/modules/qqbot/napcat/application/login/qqbot-napcat-login.service';
|
||||||
import { QqbotCommandController } from '@/modules/qqbot/core/command/qqbot-command.controller';
|
import { QqbotNapcatWatchdogService } from '@/modules/qqbot/napcat/application/login/qqbot-napcat-watchdog.service';
|
||||||
import { QqbotCommand } from '@/modules/qqbot/core/command/qqbot-command.entity';
|
import { QqbotCommandController } from '@/modules/qqbot/core/contract/command/qqbot-command.controller';
|
||||||
import { QqbotCommandEngineService } from '@/modules/qqbot/core/command/qqbot-command-engine.service';
|
import { QqbotCommand } from '@/modules/qqbot/core/infrastructure/persistence/command/qqbot-command.entity';
|
||||||
import { QqbotCommandLog } from '@/modules/qqbot/core/command/qqbot-command-log.entity';
|
import { QqbotCommandEngineService } from '@/modules/qqbot/core/application/command/qqbot-command-engine.service';
|
||||||
import { QqbotCommandParserService } from '@/modules/qqbot/core/command/qqbot-command-parser.service';
|
import { QqbotCommandLog } from '@/modules/qqbot/core/infrastructure/persistence/command/qqbot-command-log.entity';
|
||||||
import { QqbotCommandService } from '@/modules/qqbot/core/command/qqbot-command.service';
|
import { QqbotCommandParserService } from '@/modules/qqbot/core/application/command/qqbot-command-parser.service';
|
||||||
import { QqbotReplyTemplateService } from '@/modules/qqbot/core/command/qqbot-reply-template.service';
|
import { QqbotCommandService } from '@/modules/qqbot/core/application/command/qqbot-command.service';
|
||||||
import { QqbotReverseWsService } from '@/modules/qqbot/core/connection/qqbot-reverse-ws.service';
|
import { QqbotReplyTemplateService } from '@/modules/qqbot/core/application/command/qqbot-reply-template.service';
|
||||||
import { QqbotConfig } from '@/modules/qqbot/core/config/qqbot-config.entity';
|
import { QqbotReverseWsService } from '@/modules/qqbot/core/infrastructure/integration/connection/qqbot-reverse-ws.service';
|
||||||
import { QqbotConfigService } from '@/modules/qqbot/core/config/qqbot-config.service';
|
import { QqbotConfig } from '@/modules/qqbot/core/infrastructure/persistence/config/qqbot-config.entity';
|
||||||
import { QqbotDashboardController } from '@/modules/qqbot/core/dashboard/qqbot-dashboard.controller';
|
import { QqbotConfigService } from '@/modules/qqbot/core/application/config/qqbot-config.service';
|
||||||
import { QqbotDashboardService } from '@/modules/qqbot/core/dashboard/qqbot-dashboard.service';
|
import { QqbotDashboardController } from '@/modules/qqbot/core/contract/dashboard/qqbot-dashboard.controller';
|
||||||
import { QqbotDedupe } from '@/modules/qqbot/core/dedupe/qqbot-dedupe.entity';
|
import { QqbotDashboardService } from '@/modules/qqbot/core/application/dashboard/qqbot-dashboard.service';
|
||||||
import { QqbotDedupeService } from '@/modules/qqbot/core/dedupe/qqbot-dedupe.service';
|
import { QqbotDedupe } from '@/modules/qqbot/core/infrastructure/persistence/dedupe/qqbot-dedupe.entity';
|
||||||
import { QqbotEventService } from '@/modules/qqbot/core/event/qqbot-event.service';
|
import { QqbotDedupeService } from '@/modules/qqbot/core/application/dedupe/qqbot-dedupe.service';
|
||||||
import { QqbotPluginHttpClientService } from '@/modules/qqbot/plugin-platform/sdk';
|
import { QqbotEventService } from '@/modules/qqbot/core/application/event/qqbot-event.service';
|
||||||
import { NapcatDeviceIdentity } from '@/modules/qqbot/napcat/device/napcat-device-identity.entity';
|
import { NapcatDeviceIdentity } from '@/modules/qqbot/napcat/infrastructure/persistence/napcat-device-identity.entity';
|
||||||
import { NapcatDeviceIdentityService } from '@/modules/qqbot/napcat/device/napcat-device-identity.service';
|
import { NapcatDeviceIdentityService } from '@/modules/qqbot/napcat/infrastructure/integration/device/napcat-device-identity.service';
|
||||||
import { QqbotConversation } from '@/modules/qqbot/core/message/qqbot-conversation.entity';
|
import { QqbotConversation } from '@/modules/qqbot/core/infrastructure/persistence/message/qqbot-conversation.entity';
|
||||||
import { QqbotMessageController } from '@/modules/qqbot/core/message/qqbot-message.controller';
|
import { QqbotMessageController } from '@/modules/qqbot/core/contract/message/qqbot-message.controller';
|
||||||
import { QqbotMessage } from '@/modules/qqbot/core/message/qqbot-message.entity';
|
import { QqbotMessage } from '@/modules/qqbot/core/infrastructure/persistence/message/qqbot-message.entity';
|
||||||
import { QqbotMessageService } from '@/modules/qqbot/core/message/qqbot-message.service';
|
import { QqbotMessageService } from '@/modules/qqbot/core/application/message/qqbot-message.service';
|
||||||
import { QqbotBusService } from '@/modules/qqbot/core/mqtt/qqbot-bus.service';
|
import { QqbotBusService } from '@/modules/qqbot/core/infrastructure/integration/bus/qqbot-bus.service';
|
||||||
import { QqbotAccountNapcat } from '@/modules/qqbot/napcat/infrastructure/persistence/qqbot-account-napcat.entity';
|
import { QqbotAccountNapcat } from '@/modules/qqbot/napcat/infrastructure/persistence/qqbot-account-napcat.entity';
|
||||||
import { QqbotNapcatContainer } from '@/modules/qqbot/napcat/infrastructure/persistence/qqbot-napcat-container.entity';
|
import { QqbotNapcatContainer } from '@/modules/qqbot/napcat/infrastructure/persistence/qqbot-napcat-container.entity';
|
||||||
import { QqbotNapcatContainerService } from '@/modules/qqbot/napcat/qqbot-napcat-container.service';
|
import { QqbotNapcatContainerService } from '@/modules/qqbot/napcat/infrastructure/integration/container/qqbot-napcat-container.service';
|
||||||
import { QqbotAllowlist } from '@/modules/qqbot/core/permission/qqbot-allowlist.entity';
|
import { QqbotAllowlist } from '@/modules/qqbot/core/infrastructure/persistence/permission/qqbot-allowlist.entity';
|
||||||
import { QqbotBlocklist } from '@/modules/qqbot/core/permission/qqbot-blocklist.entity';
|
import { QqbotBlocklist } from '@/modules/qqbot/core/infrastructure/persistence/permission/qqbot-blocklist.entity';
|
||||||
import { QqbotPermissionController } from '@/modules/qqbot/core/permission/qqbot-permission.controller';
|
import { QqbotPermissionController } from '@/modules/qqbot/core/contract/permission/qqbot-permission.controller';
|
||||||
import { QqbotPermissionService } from '@/modules/qqbot/core/permission/qqbot-permission.service';
|
import { QqbotPermissionService } from '@/modules/qqbot/core/application/permission/qqbot-permission.service';
|
||||||
import { QqbotPluginController } from '@/modules/qqbot/plugin-platform/qqbot-plugin.controller';
|
import { QqbotRuleController } from '@/modules/qqbot/core/contract/rule/qqbot-rule.controller';
|
||||||
import { QqbotEventPluginRegistryService } from '@/modules/qqbot/plugin-platform/registry/qqbot-event-plugin-registry.service';
|
import { QqbotRule } from '@/modules/qqbot/core/infrastructure/persistence/rule/qqbot-rule.entity';
|
||||||
import { QqbotPluginRegistryService } from '@/modules/qqbot/plugin-platform/registry/qqbot-plugin-registry.service';
|
import { QqbotRuleEngineService } from '@/modules/qqbot/core/application/rule/qqbot-rule-engine.service';
|
||||||
import { QqbotBangDreamClientService } from '@/modules/qqbot/plugins/bangDream/application/bangdream-client.service';
|
import { QqbotRuleService } from '@/modules/qqbot/core/application/rule/qqbot-rule.service';
|
||||||
import { TsuguApplicationService } from '@/modules/qqbot/plugins/bangDream/application/bangdream-application.service';
|
import { QqbotRateLimitService } from '@/modules/qqbot/core/application/send/qqbot-rate-limit.service';
|
||||||
import { QqbotBangDreamRendererService } from '@/modules/qqbot/plugins/bangDream/application/bangdream-renderer.facade';
|
import { QqbotSendController } from '@/modules/qqbot/core/contract/send/qqbot-send.controller';
|
||||||
import { QqbotBangDreamPluginService } from '@/modules/qqbot/plugins/bangDream/qqbot-bangdream.plugin';
|
import { QqbotSendLog } from '@/modules/qqbot/core/infrastructure/persistence/send/qqbot-send-log.entity';
|
||||||
import { QqbotFf14ClientService } from '@/modules/qqbot/plugins/ff14Market/qqbot-ff14-client.service';
|
import { QqbotSendService } from '@/modules/qqbot/core/application/send/qqbot-send.service';
|
||||||
import { QqbotFf14MarketPluginService } from '@/modules/qqbot/plugins/ff14Market/qqbot-ff14-market.plugin';
|
|
||||||
import { QqbotFflogsClientService } from '@/modules/qqbot/plugins/fflogs/qqbot-fflogs-client.service';
|
|
||||||
import { QqbotFflogsPluginService } from '@/modules/qqbot/plugins/fflogs/qqbot-fflogs.plugin';
|
|
||||||
import { QqbotRepeaterPluginService } from '@/modules/qqbot/plugins/repeater/qqbot-repeater.plugin';
|
|
||||||
import { QqbotRuleController } from '@/modules/qqbot/core/rule/qqbot-rule.controller';
|
|
||||||
import { QqbotRule } from '@/modules/qqbot/core/rule/qqbot-rule.entity';
|
|
||||||
import { QqbotRuleEngineService } from '@/modules/qqbot/core/rule/qqbot-rule-engine.service';
|
|
||||||
import { QqbotRuleService } from '@/modules/qqbot/core/rule/qqbot-rule.service';
|
|
||||||
import { QqbotRateLimitService } from '@/modules/qqbot/core/send/qqbot-rate-limit.service';
|
|
||||||
import { QqbotSendController } from '@/modules/qqbot/core/send/qqbot-send.controller';
|
|
||||||
import { QqbotSendLog } from '@/modules/qqbot/core/send/qqbot-send-log.entity';
|
|
||||||
import { QqbotSendService } from '@/modules/qqbot/core/send/qqbot-send.service';
|
|
||||||
|
|
||||||
export { QQBOT_CORE_DOMAIN_CONTRACT } from './qqbot-core.contract';
|
export { QQBOT_CORE_DOMAIN_CONTRACT } from './contract/qqbot-core.contract';
|
||||||
|
|
||||||
export const QQBOT_CORE_ENTITIES = [
|
export const QQBOT_CORE_ENTITIES = [
|
||||||
QqbotAccount,
|
QqbotAccount,
|
||||||
@ -86,7 +74,6 @@ export const QQBOT_CORE_CONTROLLERS = [
|
|||||||
QqbotDashboardController,
|
QqbotDashboardController,
|
||||||
QqbotMessageController,
|
QqbotMessageController,
|
||||||
QqbotPermissionController,
|
QqbotPermissionController,
|
||||||
QqbotPluginController,
|
|
||||||
QqbotRuleController,
|
QqbotRuleController,
|
||||||
QqbotSendController,
|
QqbotSendController,
|
||||||
];
|
];
|
||||||
@ -101,24 +88,12 @@ export const QQBOT_CORE_PROVIDERS = [
|
|||||||
QqbotDashboardService,
|
QqbotDashboardService,
|
||||||
QqbotDedupeService,
|
QqbotDedupeService,
|
||||||
QqbotEventService,
|
QqbotEventService,
|
||||||
QqbotPluginHttpClientService,
|
|
||||||
QqbotBangDreamClientService,
|
|
||||||
QqbotBangDreamPluginService,
|
|
||||||
QqbotBangDreamRendererService,
|
|
||||||
TsuguApplicationService,
|
|
||||||
QqbotFf14ClientService,
|
|
||||||
QqbotFf14MarketPluginService,
|
|
||||||
QqbotFflogsClientService,
|
|
||||||
QqbotFflogsPluginService,
|
|
||||||
QqbotMessageService,
|
QqbotMessageService,
|
||||||
NapcatDeviceIdentityService,
|
NapcatDeviceIdentityService,
|
||||||
QqbotNapcatLoginService,
|
QqbotNapcatLoginService,
|
||||||
QqbotNapcatWatchdogService,
|
QqbotNapcatWatchdogService,
|
||||||
QqbotNapcatContainerService,
|
QqbotNapcatContainerService,
|
||||||
QqbotPermissionService,
|
QqbotPermissionService,
|
||||||
QqbotEventPluginRegistryService,
|
|
||||||
QqbotPluginRegistryService,
|
|
||||||
QqbotRepeaterPluginService,
|
|
||||||
QqbotRateLimitService,
|
QqbotRateLimitService,
|
||||||
QqbotReplyTemplateService,
|
QqbotReplyTemplateService,
|
||||||
QqbotReverseWsService,
|
QqbotReverseWsService,
|
||||||
@ -129,6 +104,7 @@ export const QQBOT_CORE_PROVIDERS = [
|
|||||||
|
|
||||||
export const QQBOT_CORE_EXPORTS = [
|
export const QQBOT_CORE_EXPORTS = [
|
||||||
QqbotAccountService,
|
QqbotAccountService,
|
||||||
|
QqbotSendService,
|
||||||
NapcatDeviceIdentityService,
|
NapcatDeviceIdentityService,
|
||||||
QqbotNapcatLoginService,
|
QqbotNapcatLoginService,
|
||||||
QqbotNapcatContainerService,
|
QqbotNapcatContainerService,
|
||||||
@ -140,6 +116,7 @@ export const QQBOT_CORE_EXPORTS = [
|
|||||||
ConfigModule,
|
ConfigModule,
|
||||||
AdminAuthGuardModule,
|
AdminAuthGuardModule,
|
||||||
DictModule,
|
DictModule,
|
||||||
|
forwardRef(() => QqbotPluginPlatformModule),
|
||||||
TypeOrmModule.forFeature(QQBOT_CORE_ENTITIES),
|
TypeOrmModule.forFeature(QQBOT_CORE_ENTITIES),
|
||||||
],
|
],
|
||||||
controllers: QQBOT_CORE_CONTROLLERS,
|
controllers: QQBOT_CORE_CONTROLLERS,
|
||||||
|
|||||||
33
src/modules/qqbot/core/schema/README.md
Normal file
33
src/modules/qqbot/core/schema/README.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# QQBot Core Schema
|
||||||
|
|
||||||
|
Core owns account, command, rule, permission, message, conversation, config,
|
||||||
|
dedupe, and send-log persistence.
|
||||||
|
|
||||||
|
Primary tables:
|
||||||
|
|
||||||
|
- `qqbot_account`
|
||||||
|
- `qqbot_account_ability`
|
||||||
|
- `qqbot_command`
|
||||||
|
- `qqbot_command_log`
|
||||||
|
- `qqbot_config`
|
||||||
|
- `qqbot_conversation`
|
||||||
|
- `qqbot_dedupe`
|
||||||
|
- `qqbot_message`
|
||||||
|
- `qqbot_allowlist`
|
||||||
|
- `qqbot_blocklist`
|
||||||
|
- `qqbot_rule`
|
||||||
|
- `qqbot_send_log`
|
||||||
|
|
||||||
|
Seed linkage:
|
||||||
|
|
||||||
|
- Online command rows bind to accounts through `qqbot_account_ability`.
|
||||||
|
- Core command rows refer to plugin capabilities by `plugin_key` and
|
||||||
|
`operation_key`; execution is delegated through `QQBOT_PLUGIN_EXECUTION_PORT`.
|
||||||
|
|
||||||
|
Verification SQL:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT COUNT(*) FROM qqbot_account WHERE is_deleted = 0;
|
||||||
|
SELECT COUNT(*) FROM qqbot_command WHERE is_deleted = 0;
|
||||||
|
SELECT COUNT(*) FROM qqbot_account_ability WHERE is_deleted = 0;
|
||||||
|
```
|
||||||
@ -5,7 +5,7 @@ import { Injectable } from '@nestjs/common';
|
|||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { throwVbenError, ToolsService } from '@/common';
|
import { throwVbenError, ToolsService } from '@/common';
|
||||||
import { NapcatLoginApiClient } from '../integration/napcat-login-api.client';
|
import { NapcatLoginApiClient } from '../../infrastructure/integration/napcat-login-api.client';
|
||||||
import type {
|
import type {
|
||||||
NapcatApiResponse,
|
NapcatApiResponse,
|
||||||
NapcatCaptchaLoginResult,
|
NapcatCaptchaLoginResult,
|
||||||
@ -23,9 +23,9 @@ import type {
|
|||||||
QqbotNapcatRuntime,
|
QqbotNapcatRuntime,
|
||||||
QrcodeLookupOptions,
|
QrcodeLookupOptions,
|
||||||
QrcodeRefreshOptions,
|
QrcodeRefreshOptions,
|
||||||
} from '../../core/contract/qqbot.types';
|
} from '@/modules/qqbot/core/contract/qqbot.types';
|
||||||
import { QqbotAccountService } from '../../core/account/qqbot-account.service';
|
import { QqbotAccountService } from '@/modules/qqbot/core/application/account/qqbot-account.service';
|
||||||
import { QqbotNapcatContainerService } from '../qqbot-napcat-container.service';
|
import { QqbotNapcatContainerService } from '../../infrastructure/integration/container/qqbot-napcat-container.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class QqbotNapcatLoginService {
|
export class QqbotNapcatLoginService {
|
||||||
@ -5,7 +5,7 @@ import {
|
|||||||
OnModuleInit,
|
OnModuleInit,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { QqbotAccountService } from '../../core/account/qqbot-account.service';
|
import { QqbotAccountService } from '@/modules/qqbot/core/application/account/qqbot-account.service';
|
||||||
|
|
||||||
const DEFAULT_INTERVAL_MS = 120_000;
|
const DEFAULT_INTERVAL_MS = 120_000;
|
||||||
const MIN_INTERVAL_MS = 30_000;
|
const MIN_INTERVAL_MS = 30_000;
|
||||||
@ -13,7 +13,7 @@ const MIN_INTERVAL_MS = 30_000;
|
|||||||
/**
|
/**
|
||||||
* NapCat 离线看门狗:定时主动巡检在线账号,及时发现掉线/被踢并触发既有站内信告警。
|
* NapCat 离线看门狗:定时主动巡检在线账号,及时发现掉线/被踢并触发既有站内信告警。
|
||||||
* 不依赖 @nestjs/schedule,采用 OnModuleInit + setInterval(与代码库既有定时器一致)。
|
* 不依赖 @nestjs/schedule,采用 OnModuleInit + setInterval(与代码库既有定时器一致)。
|
||||||
* 仅检测 + 告警,自动重登由容器 ACCOUNT 快速登录(-q)+ docker restart 策略负责。
|
* 仅检测 + 告警,自动重登由容器运行时适配器负责。
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class QqbotNapcatWatchdogService
|
export class QqbotNapcatWatchdogService
|
||||||
@ -1,11 +1,10 @@
|
|||||||
export * from './container/napcat-docker-device-options';
|
export * from './infrastructure/persistence/napcat-device-identity.entity';
|
||||||
export * from './device/napcat-device-identity.entity';
|
export * from './infrastructure/integration/device/napcat-device-identity.service';
|
||||||
export * from './device/napcat-device-identity.service';
|
|
||||||
export * from './infrastructure/persistence/qqbot-account-napcat.entity';
|
export * from './infrastructure/persistence/qqbot-account-napcat.entity';
|
||||||
export * from './infrastructure/persistence/qqbot-napcat-container.entity';
|
export * from './infrastructure/persistence/qqbot-napcat-container.entity';
|
||||||
export * from './integration/napcat-login-api.client';
|
export * from './infrastructure/integration/napcat-login-api.client';
|
||||||
export * from './login/napcat-login-state-machine';
|
export * from './domain/login/napcat-login-state-machine';
|
||||||
export * from './login/qqbot-napcat-login.service';
|
export * from './application/login/qqbot-napcat-login.service';
|
||||||
export * from './login/qqbot-napcat-watchdog.service';
|
export * from './application/login/qqbot-napcat-watchdog.service';
|
||||||
export * from './persistence';
|
export * from './infrastructure/persistence';
|
||||||
export * from './qqbot-napcat-container.service';
|
export * from './infrastructure/integration/container/qqbot-napcat-container.service';
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { NapcatDeviceIdentity } from '../device/napcat-device-identity.entity';
|
import type { NapcatDeviceIdentity } from '../../persistence/napcat-device-identity.entity';
|
||||||
|
|
||||||
export type NapcatDockerDeviceOptions = {
|
export type NapcatDockerDeviceOptions = {
|
||||||
dataDir: string;
|
dataDir: string;
|
||||||
@ -10,11 +10,11 @@ import { throwVbenError, ToolsService } from '@/common';
|
|||||||
import {
|
import {
|
||||||
toNapcatDockerDeviceOptions,
|
toNapcatDockerDeviceOptions,
|
||||||
type NapcatDockerDeviceOptions,
|
type NapcatDockerDeviceOptions,
|
||||||
} from './container/napcat-docker-device-options';
|
} from './napcat-docker-device-options';
|
||||||
import { NapcatDeviceIdentityService } from './device/napcat-device-identity.service';
|
import { NapcatDeviceIdentityService } from '../device/napcat-device-identity.service';
|
||||||
import { QqbotAccount } from '../core/account/qqbot-account.entity';
|
import { QqbotAccount } from '@/modules/qqbot/core/infrastructure/persistence/account/qqbot-account.entity';
|
||||||
import { QqbotAccountNapcat } from './infrastructure/persistence/qqbot-account-napcat.entity';
|
import { QqbotAccountNapcat } from '../../persistence/qqbot-account-napcat.entity';
|
||||||
import { QqbotNapcatContainer } from './infrastructure/persistence/qqbot-napcat-container.entity';
|
import { QqbotNapcatContainer } from '../../persistence/qqbot-napcat-container.entity';
|
||||||
import type {
|
import type {
|
||||||
NapcatApiResponse,
|
NapcatApiResponse,
|
||||||
NapcatCredential,
|
NapcatCredential,
|
||||||
@ -22,7 +22,7 @@ import type {
|
|||||||
QqbotNapcatRuntime,
|
QqbotNapcatRuntime,
|
||||||
QqbotNapcatRuntimeLoginStatus,
|
QqbotNapcatRuntimeLoginStatus,
|
||||||
QqbotNapcatRuntimeStatusSnapshot,
|
QqbotNapcatRuntimeStatusSnapshot,
|
||||||
} from '../core/contract/qqbot.types';
|
} from '@/modules/qqbot/core/contract/qqbot.types';
|
||||||
|
|
||||||
type NapcatLoginLogState = 'offline' | 'online' | 'unknown';
|
type NapcatLoginLogState = 'offline' | 'online' | 'unknown';
|
||||||
|
|
||||||
@ -4,7 +4,7 @@ import { ConfigService } from '@nestjs/config';
|
|||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
import { ensureSnowflakeId } from '@/common';
|
import { ensureSnowflakeId } from '@/common';
|
||||||
import { NapcatDeviceIdentity } from './napcat-device-identity.entity';
|
import { NapcatDeviceIdentity } from '../../persistence/napcat-device-identity.entity';
|
||||||
|
|
||||||
type ResolveNapcatDeviceIdentityInput = {
|
type ResolveNapcatDeviceIdentityInput = {
|
||||||
accountId: string;
|
accountId: string;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { NapcatDeviceIdentity } from './device/napcat-device-identity.entity';
|
import { NapcatDeviceIdentity } from './napcat-device-identity.entity';
|
||||||
import { QqbotAccountNapcat } from './infrastructure/persistence/qqbot-account-napcat.entity';
|
import { QqbotAccountNapcat } from './qqbot-account-napcat.entity';
|
||||||
import { QqbotNapcatContainer } from './infrastructure/persistence/qqbot-napcat-container.entity';
|
import { QqbotNapcatContainer } from './qqbot-napcat-container.entity';
|
||||||
|
|
||||||
export const NAPCAT_RUNTIME_DOMAIN_CONTRACT = {
|
export const NAPCAT_RUNTIME_DOMAIN_CONTRACT = {
|
||||||
tables: [
|
tables: [
|
||||||
@ -6,7 +6,7 @@ import {
|
|||||||
KtDateTimeColumn,
|
KtDateTimeColumn,
|
||||||
KtUpdateDateColumn,
|
KtUpdateDateColumn,
|
||||||
} from '@/common';
|
} from '@/common';
|
||||||
import type { QqbotAccountNapcatBindStatus } from '../../../core/contract/qqbot.types';
|
import type { QqbotAccountNapcatBindStatus } from '@/modules/qqbot/core/contract/qqbot.types';
|
||||||
|
|
||||||
@Entity('qqbot_account_napcat')
|
@Entity('qqbot_account_napcat')
|
||||||
@Index('idx_qqbot_account_napcat_account', ['accountId', 'isDeleted'])
|
@Index('idx_qqbot_account_napcat_account', ['accountId', 'isDeleted'])
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import {
|
|||||||
KtDateTimeColumn,
|
KtDateTimeColumn,
|
||||||
KtUpdateDateColumn,
|
KtUpdateDateColumn,
|
||||||
} from '@/common';
|
} from '@/common';
|
||||||
import type { QqbotNapcatContainerStatus } from '../../../core/contract/qqbot.types';
|
import type { QqbotNapcatContainerStatus } from '@/modules/qqbot/core/contract/qqbot.types';
|
||||||
|
|
||||||
@Entity('qqbot_napcat_container')
|
@Entity('qqbot_napcat_container')
|
||||||
@Index('uk_qqbot_napcat_container_name', ['name'], { unique: true })
|
@Index('uk_qqbot_napcat_container_name', ['name'], { unique: true })
|
||||||
|
|||||||
27
src/modules/qqbot/napcat/schema/README.md
Normal file
27
src/modules/qqbot/napcat/schema/README.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# QQBot NapCat Schema
|
||||||
|
|
||||||
|
NapCat owns container runtime, account binding, device identity, login session,
|
||||||
|
challenge, and cleanup persistence.
|
||||||
|
|
||||||
|
Current compatibility tables:
|
||||||
|
|
||||||
|
- `qqbot_account_napcat`
|
||||||
|
- `qqbot_napcat_container`
|
||||||
|
- `napcat_device_identity`
|
||||||
|
|
||||||
|
Target v3 tables:
|
||||||
|
|
||||||
|
- `napcat_container`
|
||||||
|
- `napcat_device_identity`
|
||||||
|
- `napcat_account_binding`
|
||||||
|
- `napcat_login_session`
|
||||||
|
- `napcat_login_challenge`
|
||||||
|
- `napcat_runtime_cleanup`
|
||||||
|
|
||||||
|
Verification SQL:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT COUNT(*) FROM napcat_device_identity;
|
||||||
|
SELECT COUNT(*) FROM qqbot_account_napcat WHERE is_deleted = 0;
|
||||||
|
SELECT COUNT(*) FROM qqbot_napcat_container WHERE is_deleted = 0;
|
||||||
|
```
|
||||||
@ -1,77 +1,39 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { DictService } from '@/modules/admin/platform-config/dict/dict.service';
|
import { DictService } from '@/modules/admin/platform-config/dict/dict.service';
|
||||||
import type { QqbotCommand } from './qqbot-command.entity';
|
|
||||||
import type { QqbotNormalizedMessage } from '../contract/qqbot.types';
|
|
||||||
import {
|
import {
|
||||||
buildQqbotFf14MarketCatalog,
|
buildQqbotFf14MarketCatalog,
|
||||||
buildQqbotFf14MarketCatalogFromTree,
|
buildQqbotFf14MarketCatalogFromTree,
|
||||||
QQBOT_FF14_MARKET_DICT_CODES,
|
|
||||||
isQqbotFf14DataCenterName,
|
isQqbotFf14DataCenterName,
|
||||||
isQqbotFf14LocationName,
|
isQqbotFf14LocationName,
|
||||||
isQqbotFf14RegionName,
|
isQqbotFf14RegionName,
|
||||||
isQqbotFf14WorldName,
|
isQqbotFf14WorldName,
|
||||||
|
QQBOT_FF14_MARKET_DICT_CODES,
|
||||||
splitQqbotFf14WorldPath,
|
splitQqbotFf14WorldPath,
|
||||||
} from '@/modules/qqbot/plugins/ff14Market/qqbot-ff14-worlds';
|
} from '@/modules/qqbot/plugins/ff14Market/qqbot-ff14-worlds';
|
||||||
import type { QqbotFf14MarketCatalog } from '@/modules/qqbot/plugins/ff14Market/qqbot-ff14-market.types';
|
import type { QqbotFf14MarketCatalog } from '@/modules/qqbot/plugins/ff14Market/qqbot-ff14-market.types';
|
||||||
import type { QqbotCommandMatchResult } from '../contract/qqbot.types';
|
import type { QqbotPluginExecutionInput } from '@/modules/qqbot/core/domain/plugin-execution.port';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class QqbotCommandParserService {
|
export class QqbotPluginArgumentParserService {
|
||||||
constructor(private readonly dictService: DictService) {}
|
constructor(private readonly dictService: DictService) {}
|
||||||
|
|
||||||
async match(command: QqbotCommand, message: QqbotNormalizedMessage) {
|
async normalizeInput(input: QqbotPluginExecutionInput) {
|
||||||
const source = `${message.messageText || ''}`.trim();
|
const parserKey = `${input.context?.command?.parserKey || 'plain'}`.trim();
|
||||||
if (!source) return null;
|
const rawArgs = `${input.input?.raw ?? input.input?.text ?? ''}`.trim();
|
||||||
|
if (parserKey === 'ff14Price') {
|
||||||
const aliases = this.getAliases(command);
|
|
||||||
const prefixes = this.getPrefixes(command);
|
|
||||||
for (const alias of aliases) {
|
|
||||||
for (const prefix of prefixes) {
|
|
||||||
const commandText = `${prefix}${alias}`.trim();
|
|
||||||
const rawArgs = this.pickArgs(source, commandText);
|
|
||||||
if (rawArgs === null) continue;
|
|
||||||
return {
|
return {
|
||||||
alias,
|
...input.input,
|
||||||
input: await this.parseInput(command, rawArgs),
|
...this.removeEmpty(await this.parseFf14PriceInput(rawArgs)),
|
||||||
matched: true,
|
|
||||||
rawArgs,
|
|
||||||
} satisfies QqbotCommandMatchResult;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
getAliases(command: QqbotCommand) {
|
|
||||||
return this.normalizeList(command.aliases, [command.code, command.name]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getPrefixes(command: QqbotCommand) {
|
|
||||||
return this.normalizeList(command.prefixes, ['/', '!', '!']);
|
|
||||||
}
|
|
||||||
|
|
||||||
private pickArgs(source: string, commandText: string) {
|
|
||||||
if (!commandText) return null;
|
|
||||||
if (source === commandText) return '';
|
|
||||||
if (source.startsWith(`${commandText} `)) {
|
|
||||||
return source.slice(commandText.length).trim();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async parseInput(command: QqbotCommand, rawArgs: string) {
|
|
||||||
if (command.parserKey === 'ff14Price') {
|
|
||||||
return this.parseFf14PriceInput(rawArgs);
|
|
||||||
}
|
|
||||||
if (command.parserKey === 'fflogsCharacter') {
|
|
||||||
return this.parseFflogsCharacterInput(rawArgs);
|
|
||||||
}
|
|
||||||
const args = rawArgs ? rawArgs.split(/\s+/).filter(Boolean) : [];
|
|
||||||
return {
|
|
||||||
args,
|
|
||||||
raw: rawArgs,
|
|
||||||
text: rawArgs,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (parserKey === 'fflogsCharacter') {
|
||||||
|
return {
|
||||||
|
...input.input,
|
||||||
|
...this.removeEmpty(await this.parseFflogsCharacterInput(rawArgs)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return input.input;
|
||||||
|
}
|
||||||
|
|
||||||
private async parseFf14PriceInput(rawArgs: string) {
|
private async parseFf14PriceInput(rawArgs: string) {
|
||||||
const catalog = await this.getFf14MarketCatalog();
|
const catalog = await this.getFf14MarketCatalog();
|
||||||
@ -240,11 +202,11 @@ export class QqbotCommandParserService {
|
|||||||
),
|
),
|
||||||
encounter: encounterName,
|
encounter: encounterName,
|
||||||
encounterName,
|
encounterName,
|
||||||
|
limit: this.normalizeString(flags.get('limit') || flags.get('数量')),
|
||||||
metric: this.normalizeString(flags.get('metric') || flags.get('指标')),
|
metric: this.normalizeString(flags.get('metric') || flags.get('指标')),
|
||||||
partition: this.normalizeString(
|
partition: this.normalizeString(
|
||||||
flags.get('partition') || flags.get('分区'),
|
flags.get('partition') || flags.get('分区'),
|
||||||
),
|
),
|
||||||
limit: this.normalizeString(flags.get('limit') || flags.get('数量')),
|
|
||||||
raw: rawArgs,
|
raw: rawArgs,
|
||||||
role: this.normalizeString(flags.get('role') || flags.get('职责')),
|
role: this.normalizeString(flags.get('role') || flags.get('职责')),
|
||||||
serverRegion: this.normalizeString(
|
serverRegion: this.normalizeString(
|
||||||
@ -318,7 +280,7 @@ export class QqbotCommandParserService {
|
|||||||
|
|
||||||
private async pickFflogsPositionalsByKnownWorld(positional: string[]) {
|
private async pickFflogsPositionalsByKnownWorld(positional: string[]) {
|
||||||
const catalog = await this.getFf14MarketCatalog();
|
const catalog = await this.getFf14MarketCatalog();
|
||||||
for (let index = positional.length - 2; index > 0; index--) {
|
for (let index = positional.length - 2; index > 0; index -= 1) {
|
||||||
const candidate = positional[index];
|
const candidate = positional[index];
|
||||||
if (!isQqbotFf14LocationName(catalog, candidate)) continue;
|
if (!isQqbotFf14LocationName(catalog, candidate)) continue;
|
||||||
const characterName = positional.slice(0, index).join(' ').trim();
|
const characterName = positional.slice(0, index).join(' ').trim();
|
||||||
@ -366,28 +328,18 @@ export class QqbotCommandParserService {
|
|||||||
return ['1', 'true', 'yes', 'hq'].includes(`${value}`.toLowerCase());
|
return ['1', 'true', 'yes', 'hq'].includes(`${value}`.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
private normalizeList(value: string | undefined, fallback: string[]) {
|
|
||||||
const raw = `${value || ''}`.trim();
|
|
||||||
const parsed = this.tryParseJsonArray(raw);
|
|
||||||
const source = parsed.length > 0 ? parsed : raw.split(',');
|
|
||||||
const list = [...source, ...fallback]
|
|
||||||
.map((item) => `${item || ''}`.trim())
|
|
||||||
.filter(Boolean);
|
|
||||||
return [...new Set(list)];
|
|
||||||
}
|
|
||||||
|
|
||||||
private tryParseJsonArray(value: string) {
|
|
||||||
if (!value.startsWith('[')) return [];
|
|
||||||
try {
|
|
||||||
const parsed = JSON.parse(value);
|
|
||||||
return Array.isArray(parsed) ? parsed : [];
|
|
||||||
} catch {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private normalizeString(value?: string | true) {
|
private normalizeString(value?: string | true) {
|
||||||
if (value === true) return '';
|
if (value === true) return '';
|
||||||
return `${value || ''}`.trim();
|
return `${value || ''}`.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private removeEmpty(input: Record<string, any>) {
|
||||||
|
return Object.entries(input).reduce<Record<string, any>>(
|
||||||
|
(result, [key, value]) => {
|
||||||
|
if (value !== undefined && value !== '') result[key] = value;
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import type {
|
||||||
|
QqbotPluginEventDispatchInput,
|
||||||
|
QqbotPluginExecutionInput,
|
||||||
|
QqbotPluginExecutionPort,
|
||||||
|
QqbotPluginOperationLookup,
|
||||||
|
} from '@/modules/qqbot/core/domain/plugin-execution.port';
|
||||||
|
import { QqbotEventPluginRegistryService } from './registry/qqbot-event-plugin-registry.service';
|
||||||
|
import { QqbotPluginRegistryService } from './registry/qqbot-plugin-registry.service';
|
||||||
|
import { QqbotPluginArgumentParserService } from './argument/qqbot-plugin-argument-parser.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class QqbotPluginExecutionAdapter implements QqbotPluginExecutionPort {
|
||||||
|
constructor(
|
||||||
|
private readonly argumentParser: QqbotPluginArgumentParserService,
|
||||||
|
private readonly eventPluginRegistry: QqbotEventPluginRegistryService,
|
||||||
|
private readonly pluginRegistry: QqbotPluginRegistryService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async executeOperation(input: QqbotPluginExecutionInput) {
|
||||||
|
const normalizedInput = await this.argumentParser.normalizeInput(input);
|
||||||
|
return this.pluginRegistry.execute(
|
||||||
|
input.pluginKey,
|
||||||
|
input.operationKey,
|
||||||
|
normalizedInput,
|
||||||
|
{
|
||||||
|
...(input.context || {}),
|
||||||
|
args: normalizedInput,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async dispatchEvent(input: QqbotPluginEventDispatchInput) {
|
||||||
|
if (input.eventKey !== 'message') return false;
|
||||||
|
return this.eventPluginRegistry.dispatchMessage(input.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
async listActiveOperations() {
|
||||||
|
return [
|
||||||
|
...this.pluginRegistry.listOperations(),
|
||||||
|
...this.eventPluginRegistry.listOperations(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
async getOperationByCommand(command: QqbotPluginOperationLookup) {
|
||||||
|
if (!command.pluginKey || !command.operationKey) return null;
|
||||||
|
return (
|
||||||
|
this.pluginRegistry
|
||||||
|
.listOperations(command.pluginKey)
|
||||||
|
.find((operation) => operation.key === command.operationKey) || null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,7 +2,10 @@ import { Injectable } from '@nestjs/common';
|
|||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
import { throwVbenError } from '@/common';
|
import { throwVbenError } from '@/common';
|
||||||
import { parseQqbotPluginManifest, type QqbotPluginManifest } from './manifest';
|
import {
|
||||||
|
parseQqbotPluginManifest,
|
||||||
|
type QqbotPluginManifest,
|
||||||
|
} from '../domain/manifest';
|
||||||
import {
|
import {
|
||||||
QqbotPlugin,
|
QqbotPlugin,
|
||||||
QqbotPluginAccountBinding,
|
QqbotPluginAccountBinding,
|
||||||
@ -14,7 +17,7 @@ import {
|
|||||||
QqbotPluginRuntimeEvent,
|
QqbotPluginRuntimeEvent,
|
||||||
QqbotPluginVersion,
|
QqbotPluginVersion,
|
||||||
type QqbotPluginInstallStatus,
|
type QqbotPluginInstallStatus,
|
||||||
} from './persistence';
|
} from '../infrastructure/persistence';
|
||||||
|
|
||||||
type ValidateManifestBody = {
|
type ValidateManifestBody = {
|
||||||
manifest?: unknown;
|
manifest?: unknown;
|
||||||
@ -1,9 +1,10 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { formatKtDateTime, throwVbenError } from '@/common';
|
import { formatKtDateTime, throwVbenError } from '@/common';
|
||||||
import { QqbotAccountService } from '@/modules/qqbot/core/account/qqbot-account.service';
|
import { QqbotAccountService } from '@/modules/qqbot/core/application/account/qqbot-account.service';
|
||||||
import { QqbotRepeaterPluginService } from '@/modules/qqbot/plugins/repeater/qqbot-repeater.plugin';
|
import { QqbotRepeaterPluginService } from '@/modules/qqbot/plugins/repeater/qqbot-repeater.plugin';
|
||||||
import type {
|
import type {
|
||||||
QqbotEventPluginDefinition,
|
QqbotEventPluginDefinition,
|
||||||
|
QqbotNormalizedMessage,
|
||||||
QqbotPluginHealth,
|
QqbotPluginHealth,
|
||||||
QqbotPluginOperationSummary,
|
QqbotPluginOperationSummary,
|
||||||
} from '@/modules/qqbot/core/contract/qqbot.types';
|
} from '@/modules/qqbot/core/contract/qqbot.types';
|
||||||
@ -61,6 +62,10 @@ export class QqbotEventPluginRegistryService {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async dispatchMessage(message: QqbotNormalizedMessage) {
|
||||||
|
return this.repeaterPlugin.handleMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
async bind(pluginKey: string, selfId: string) {
|
async bind(pluginKey: string, selfId: string) {
|
||||||
this.assertPlugin(pluginKey);
|
this.assertPlugin(pluginKey);
|
||||||
if (pluginKey === 'repeater') {
|
if (pluginKey === 'repeater') {
|
||||||
@ -11,7 +11,7 @@ import {
|
|||||||
import { ApiOperation, ApiQuery, ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiQuery, ApiTags } from '@nestjs/swagger';
|
||||||
import { JwtAuthGuard } from '@/modules/admin/identity/auth/jwt-auth.guard';
|
import { JwtAuthGuard } from '@/modules/admin/identity/auth/jwt-auth.guard';
|
||||||
import { vbenSuccess } from '@/common';
|
import { vbenSuccess } from '@/common';
|
||||||
import { QqbotPluginPlatformService } from './plugin-platform.service';
|
import { QqbotPluginPlatformService } from '../application/plugin-platform.service';
|
||||||
|
|
||||||
@ApiTags('QQBot - 插件平台')
|
@ApiTags('QQBot - 插件平台')
|
||||||
@Controller('qqbot/plugin-platform')
|
@Controller('qqbot/plugin-platform')
|
||||||
@ -10,8 +10,8 @@ import {
|
|||||||
import { ApiOperation, ApiQuery, ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiQuery, ApiTags } from '@nestjs/swagger';
|
||||||
import { JwtAuthGuard } from '@/modules/admin/identity/auth/jwt-auth.guard';
|
import { JwtAuthGuard } from '@/modules/admin/identity/auth/jwt-auth.guard';
|
||||||
import { ToolsService, vbenSuccess } from '@/common';
|
import { ToolsService, vbenSuccess } from '@/common';
|
||||||
import { QqbotEventPluginRegistryService } from './registry/qqbot-event-plugin-registry.service';
|
import { QqbotEventPluginRegistryService } from '../application/registry/qqbot-event-plugin-registry.service';
|
||||||
import { QqbotPluginRegistryService } from './registry/qqbot-plugin-registry.service';
|
import { QqbotPluginRegistryService } from '../application/registry/qqbot-plugin-registry.service';
|
||||||
import type {
|
import type {
|
||||||
QqbotPluginOperationSummary,
|
QqbotPluginOperationSummary,
|
||||||
QqbotPluginTriggerMode,
|
QqbotPluginTriggerMode,
|
||||||
@ -1,18 +1,63 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { forwardRef, Module } from '@nestjs/common';
|
||||||
|
import { ConfigModule } from '@nestjs/config';
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
import { AdminAuthGuardModule } from '@/modules/admin/identity/auth/admin-auth-guard.module';
|
import { AdminAuthGuardModule } from '@/modules/admin/identity/auth/admin-auth-guard.module';
|
||||||
import { QqbotPluginPlatformController } from './plugin-platform.controller';
|
import { DictModule } from '@/modules/admin/platform-config/dict/dict.module';
|
||||||
import { QqbotPluginPlatformService } from './plugin-platform.service';
|
import { QQBOT_PLUGIN_EXECUTION_PORT } from '@/modules/qqbot/core/domain/plugin-execution.port';
|
||||||
import { QQBOT_PLUGIN_PLATFORM_ENTITIES } from './persistence';
|
import { QqbotCoreModule } from '@/modules/qqbot/core/qqbot-core.module';
|
||||||
import { QqbotPluginHttpClientService } from './sdk';
|
import { QqbotBangDreamClientService } from '@/modules/qqbot/plugins/bangDream/application/bangdream-client.service';
|
||||||
|
import { TsuguApplicationService } from '@/modules/qqbot/plugins/bangDream/application/bangdream-application.service';
|
||||||
|
import { QqbotBangDreamRendererService } from '@/modules/qqbot/plugins/bangDream/application/bangdream-renderer.facade';
|
||||||
|
import { QqbotBangDreamPluginService } from '@/modules/qqbot/plugins/bangDream/qqbot-bangdream.plugin';
|
||||||
|
import { QqbotFf14ClientService } from '@/modules/qqbot/plugins/ff14Market/qqbot-ff14-client.service';
|
||||||
|
import { QqbotFf14MarketPluginService } from '@/modules/qqbot/plugins/ff14Market/qqbot-ff14-market.plugin';
|
||||||
|
import { QqbotFflogsClientService } from '@/modules/qqbot/plugins/fflogs/qqbot-fflogs-client.service';
|
||||||
|
import { QqbotFflogsPluginService } from '@/modules/qqbot/plugins/fflogs/qqbot-fflogs.plugin';
|
||||||
|
import { QqbotRepeaterPluginService } from '@/modules/qqbot/plugins/repeater/qqbot-repeater.plugin';
|
||||||
|
import { QqbotPluginArgumentParserService } from './application/argument/qqbot-plugin-argument-parser.service';
|
||||||
|
import { QqbotEventPluginRegistryService } from './application/registry/qqbot-event-plugin-registry.service';
|
||||||
|
import { QqbotPluginRegistryService } from './application/registry/qqbot-plugin-registry.service';
|
||||||
|
import { QqbotPluginExecutionAdapter } from './application/plugin-execution.adapter';
|
||||||
|
import { QqbotPluginPlatformService } from './application/plugin-platform.service';
|
||||||
|
import { QqbotPluginPlatformController } from './contract/plugin-platform.controller';
|
||||||
|
import { QqbotPluginController } from './contract/qqbot-plugin.controller';
|
||||||
|
import { QQBOT_PLUGIN_PLATFORM_ENTITIES } from './infrastructure/persistence';
|
||||||
|
import { QqbotPluginHttpClientService } from './infrastructure/integration/sdk';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [QqbotPluginPlatformController],
|
controllers: [QqbotPluginController, QqbotPluginPlatformController],
|
||||||
exports: [QqbotPluginHttpClientService, QqbotPluginPlatformService],
|
exports: [
|
||||||
|
QQBOT_PLUGIN_EXECUTION_PORT,
|
||||||
|
QqbotPluginHttpClientService,
|
||||||
|
QqbotPluginPlatformService,
|
||||||
|
],
|
||||||
imports: [
|
imports: [
|
||||||
|
ConfigModule,
|
||||||
AdminAuthGuardModule,
|
AdminAuthGuardModule,
|
||||||
|
DictModule,
|
||||||
|
forwardRef(() => QqbotCoreModule),
|
||||||
TypeOrmModule.forFeature([...QQBOT_PLUGIN_PLATFORM_ENTITIES]),
|
TypeOrmModule.forFeature([...QQBOT_PLUGIN_PLATFORM_ENTITIES]),
|
||||||
],
|
],
|
||||||
providers: [QqbotPluginHttpClientService, QqbotPluginPlatformService],
|
providers: [
|
||||||
|
QqbotBangDreamClientService,
|
||||||
|
QqbotBangDreamPluginService,
|
||||||
|
QqbotBangDreamRendererService,
|
||||||
|
QqbotEventPluginRegistryService,
|
||||||
|
QqbotFf14ClientService,
|
||||||
|
QqbotFf14MarketPluginService,
|
||||||
|
QqbotFflogsClientService,
|
||||||
|
QqbotFflogsPluginService,
|
||||||
|
QqbotPluginArgumentParserService,
|
||||||
|
QqbotPluginExecutionAdapter,
|
||||||
|
{
|
||||||
|
provide: QQBOT_PLUGIN_EXECUTION_PORT,
|
||||||
|
useExisting: QqbotPluginExecutionAdapter,
|
||||||
|
},
|
||||||
|
QqbotPluginHttpClientService,
|
||||||
|
QqbotPluginPlatformService,
|
||||||
|
QqbotPluginRegistryService,
|
||||||
|
QqbotRepeaterPluginService,
|
||||||
|
TsuguApplicationService,
|
||||||
|
],
|
||||||
})
|
})
|
||||||
export class QqbotPluginPlatformModule {}
|
export class QqbotPluginPlatformModule {}
|
||||||
|
|||||||
27
src/modules/qqbot/plugin-platform/schema/README.md
Normal file
27
src/modules/qqbot/plugin-platform/schema/README.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# QQBot Plugin Platform Schema
|
||||||
|
|
||||||
|
Plugin Platform owns plugin package, installation, lifecycle, runtime event,
|
||||||
|
operation registry, event dispatch, SDK host adapter, and account binding
|
||||||
|
persistence.
|
||||||
|
|
||||||
|
Current compatibility tables:
|
||||||
|
|
||||||
|
- `qqbot_plugin_package`
|
||||||
|
- `qqbot_plugin_installation`
|
||||||
|
- `qqbot_plugin_runtime_event`
|
||||||
|
- `qqbot_plugin_account_binding`
|
||||||
|
- `qqbot_plugin_config`
|
||||||
|
|
||||||
|
Seed linkage:
|
||||||
|
|
||||||
|
- Built-in command capabilities are exposed through the platform registry.
|
||||||
|
- Legacy `/qqbot/plugin/*` routes are contract compatibility endpoints owned by
|
||||||
|
Plugin Platform.
|
||||||
|
|
||||||
|
Verification SQL:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT COUNT(*) FROM qqbot_plugin_package WHERE is_deleted = 0;
|
||||||
|
SELECT COUNT(*) FROM qqbot_plugin_installation WHERE is_deleted = 0;
|
||||||
|
SELECT COUNT(*) FROM qqbot_plugin_runtime_event;
|
||||||
|
```
|
||||||
@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
|
|||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { formatKtDateTime } from '@/common';
|
import { formatKtDateTime } from '@/common';
|
||||||
import { DictService } from '@/modules/admin/platform-config/dict/dict.service';
|
import { DictService } from '@/modules/admin/platform-config/dict/dict.service';
|
||||||
import { QqbotPluginHttpClientService } from '@/modules/qqbot/plugin-platform/sdk';
|
import { QqbotPluginHttpClientService } from '@/modules/qqbot/plugin-platform/infrastructure/integration/sdk';
|
||||||
import {
|
import {
|
||||||
buildQqbotFf14MarketCatalog,
|
buildQqbotFf14MarketCatalog,
|
||||||
buildQqbotFf14MarketCatalogFromTree,
|
buildQqbotFf14MarketCatalogFromTree,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { DictService } from '@/modules/admin/platform-config/dict/dict.service';
|
import { DictService } from '@/modules/admin/platform-config/dict/dict.service';
|
||||||
import { QqbotPluginHttpClientService } from '@/modules/qqbot/plugin-platform/sdk';
|
import { QqbotPluginHttpClientService } from '@/modules/qqbot/plugin-platform/infrastructure/integration/sdk';
|
||||||
import type {
|
import type {
|
||||||
FflogsCharacterEncounterRankingsResponse,
|
FflogsCharacterEncounterRankingsResponse,
|
||||||
FflogsCharacterSummaryResponse,
|
FflogsCharacterSummaryResponse,
|
||||||
|
|||||||
@ -1,18 +1,25 @@
|
|||||||
import { Injectable, Logger } from '@nestjs/common';
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { ToolsService } from '@/common';
|
import { ToolsService } from '@/common';
|
||||||
import { QqbotAccountService } from '@/modules/qqbot/core/account/qqbot-account.service';
|
import { QqbotAccountService } from '@/modules/qqbot/core/application/account/qqbot-account.service';
|
||||||
import type {
|
import type {
|
||||||
QqbotEventPluginDefinition,
|
QqbotEventPluginDefinition,
|
||||||
QqbotEventPluginSummary,
|
QqbotEventPluginSummary,
|
||||||
QqbotNormalizedMessage,
|
QqbotNormalizedMessage,
|
||||||
QqbotRepeaterConversationState,
|
|
||||||
} from '@/modules/qqbot/core/contract/qqbot.types';
|
} from '@/modules/qqbot/core/contract/qqbot.types';
|
||||||
import { QqbotSendService } from '@/modules/qqbot/core/send/qqbot-send.service';
|
import { QqbotSendService } from '@/modules/qqbot/core/application/send/qqbot-send.service';
|
||||||
|
|
||||||
const QQBOT_REPEATER_VERSION = '1.0.0';
|
const QQBOT_REPEATER_VERSION = '1.0.0';
|
||||||
const QQBOT_REPEATER_PLUGIN_KEY = 'repeater';
|
const QQBOT_REPEATER_PLUGIN_KEY = 'repeater';
|
||||||
|
|
||||||
|
type QqbotRepeaterConversationState = {
|
||||||
|
count: number;
|
||||||
|
lastRepeatedAt?: number;
|
||||||
|
lastText: string;
|
||||||
|
repeatedText: string;
|
||||||
|
updatedAt: number;
|
||||||
|
};
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class QqbotRepeaterPluginService {
|
export class QqbotRepeaterPluginService {
|
||||||
private readonly logger = new Logger(QqbotRepeaterPluginService.name);
|
private readonly logger = new Logger(QqbotRepeaterPluginService.name);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
|
||||||
import { parseQqbotPluginManifest } from '../../../../src/modules/qqbot/plugin-platform/manifest';
|
import { parseQqbotPluginManifest } from '../../../../src/modules/qqbot/plugin-platform/domain/manifest';
|
||||||
import { BANGDREAM_OPERATION_REGISTRY } from '../../../../src/modules/qqbot/plugins/bangDream/registry/operation-registry';
|
import { BANGDREAM_OPERATION_REGISTRY } from '../../../../src/modules/qqbot/plugins/bangDream/registry/operation-registry';
|
||||||
|
|
||||||
const repoRoot = join(__dirname, '../../../..');
|
const repoRoot = join(__dirname, '../../../..');
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { QQBOT_CORE_DOMAIN_CONTRACT } from '../../../../src/modules/qqbot/core/qqbot-core.contract';
|
import { QQBOT_CORE_DOMAIN_CONTRACT } from '../../../../src/modules/qqbot/core/contract/qqbot-core.contract';
|
||||||
import { readRefactorV3SqlSchema } from '../../../helpers/sql-schema.helper';
|
import { readRefactorV3SqlSchema } from '../../../helpers/sql-schema.helper';
|
||||||
|
|
||||||
describe('QQBot core command contract', () => {
|
describe('QQBot core command contract', () => {
|
||||||
|
|||||||
@ -13,24 +13,19 @@ import { Test } from '@nestjs/testing';
|
|||||||
import * as request from 'supertest';
|
import * as request from 'supertest';
|
||||||
import { DictService } from '../../../../src/modules/admin/platform-config/dict/dict.service';
|
import { DictService } from '../../../../src/modules/admin/platform-config/dict/dict.service';
|
||||||
import { ToolsService } from '../../../../src/common';
|
import { ToolsService } from '../../../../src/common';
|
||||||
import { QqbotAccountService } from '../../../../src/modules/qqbot/core/account/qqbot-account.service';
|
import { QqbotAccountService } from '../../../../src/modules/qqbot/core/application/account/qqbot-account.service';
|
||||||
import { QqbotCommandController } from '../../../../src/modules/qqbot/core/command/qqbot-command.controller';
|
import { QqbotCommandController } from '../../../../src/modules/qqbot/core/contract/command/qqbot-command.controller';
|
||||||
import { QqbotCommand } from '../../../../src/modules/qqbot/core/command/qqbot-command.entity';
|
import { QqbotCommand } from '../../../../src/modules/qqbot/core/infrastructure/persistence/command/qqbot-command.entity';
|
||||||
import { QqbotCommandEngineService } from '../../../../src/modules/qqbot/core/command/qqbot-command-engine.service';
|
import { QqbotCommandEngineService } from '../../../../src/modules/qqbot/core/application/command/qqbot-command-engine.service';
|
||||||
import { QqbotCommandLog } from '../../../../src/modules/qqbot/core/command/qqbot-command-log.entity';
|
import { QqbotCommandLog } from '../../../../src/modules/qqbot/core/infrastructure/persistence/command/qqbot-command-log.entity';
|
||||||
import { QqbotCommandParserService } from '../../../../src/modules/qqbot/core/command/qqbot-command-parser.service';
|
import { QqbotCommandParserService } from '../../../../src/modules/qqbot/core/application/command/qqbot-command-parser.service';
|
||||||
import { QqbotCommandService } from '../../../../src/modules/qqbot/core/command/qqbot-command.service';
|
import { QqbotCommandService } from '../../../../src/modules/qqbot/core/application/command/qqbot-command.service';
|
||||||
import { QqbotReplyTemplateService } from '../../../../src/modules/qqbot/core/command/qqbot-reply-template.service';
|
import { QqbotReplyTemplateService } from '../../../../src/modules/qqbot/core/application/command/qqbot-reply-template.service';
|
||||||
import { QQBOT_CORE_PROVIDERS } from '../../../../src/modules/qqbot/core/qqbot-core.module';
|
import { QQBOT_PLUGIN_EXECUTION_PORT } from '../../../../src/modules/qqbot/core/domain/plugin-execution.port';
|
||||||
import { QqbotSendService } from '../../../../src/modules/qqbot/core/send/qqbot-send.service';
|
import { QqbotSendService } from '../../../../src/modules/qqbot/core/application/send/qqbot-send.service';
|
||||||
|
|
||||||
describe('QQBot core command local smoke', () => {
|
describe('QQBot core command local smoke', () => {
|
||||||
let app: INestApplication;
|
let app: INestApplication;
|
||||||
type ProviderClass = new (...args: never[]) => unknown;
|
|
||||||
const qqbotPluginRegistryProvider = QQBOT_CORE_PROVIDERS.find(
|
|
||||||
(provider) =>
|
|
||||||
(provider as { name?: string }).name === 'QqbotPluginRegistryService',
|
|
||||||
) as ProviderClass;
|
|
||||||
|
|
||||||
const command = {
|
const command = {
|
||||||
aliases: '["查歌"]',
|
aliases: '["查歌"]',
|
||||||
@ -72,11 +67,15 @@ describe('QQBot core command local smoke', () => {
|
|||||||
save: jest.fn(),
|
save: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const pluginRegistry = {
|
const pluginExecution = {
|
||||||
execute: jest.fn().mockResolvedValue({
|
executeOperation: jest.fn().mockResolvedValue({
|
||||||
title: 'FIRE BIRD',
|
title: 'FIRE BIRD',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
}),
|
}),
|
||||||
|
getOperationByCommand: jest.fn().mockResolvedValue({
|
||||||
|
key: command.operationKey,
|
||||||
|
pluginKey: command.pluginKey,
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
@ -103,8 +102,8 @@ describe('QQBot core command local smoke', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: qqbotPluginRegistryProvider,
|
provide: QQBOT_PLUGIN_EXECUTION_PORT,
|
||||||
useValue: pluginRegistry,
|
useValue: pluginExecution,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: QqbotSendService,
|
provide: QqbotSendService,
|
||||||
@ -190,14 +189,16 @@ describe('QQBot core command local smoke', () => {
|
|||||||
expect(commandRepository.findOne).toHaveBeenCalledWith({
|
expect(commandRepository.findOne).toHaveBeenCalledWith({
|
||||||
where: { id: command.id, isDeleted: false },
|
where: { id: command.id, isDeleted: false },
|
||||||
});
|
});
|
||||||
expect(pluginRegistry.execute).toHaveBeenCalledWith(
|
expect(pluginExecution.executeOperation).toHaveBeenCalledWith(
|
||||||
command.pluginKey,
|
|
||||||
command.operationKey,
|
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
|
context: expect.objectContaining({
|
||||||
|
command,
|
||||||
|
}),
|
||||||
|
input: expect.objectContaining({
|
||||||
text: 'FIRE BIRD',
|
text: 'FIRE BIRD',
|
||||||
}),
|
}),
|
||||||
expect.objectContaining({
|
operationKey: command.operationKey,
|
||||||
command,
|
pluginKey: command.pluginKey,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -50,13 +50,13 @@ import { getMetadataArgsStorage } from 'typeorm';
|
|||||||
import { AdminAuthGuardModule } from '../../../../src/modules/admin/identity/auth/admin-auth-guard.module';
|
import { AdminAuthGuardModule } from '../../../../src/modules/admin/identity/auth/admin-auth-guard.module';
|
||||||
import { DictModule } from '../../../../src/modules/admin/platform-config/dict/dict.module';
|
import { DictModule } from '../../../../src/modules/admin/platform-config/dict/dict.module';
|
||||||
import { AppModule } from '../../../../src/app.module';
|
import { AppModule } from '../../../../src/app.module';
|
||||||
import { QqbotAccountController } from '../../../../src/modules/qqbot/core/account/qqbot-account.controller';
|
import { QqbotAccountController } from '../../../../src/modules/qqbot/core/contract/account/qqbot-account.controller';
|
||||||
import { QqbotCommandController } from '../../../../src/modules/qqbot/core/command/qqbot-command.controller';
|
import { QqbotCommandController } from '../../../../src/modules/qqbot/core/contract/command/qqbot-command.controller';
|
||||||
import { QqbotDashboardController } from '../../../../src/modules/qqbot/core/dashboard/qqbot-dashboard.controller';
|
import { QqbotDashboardController } from '../../../../src/modules/qqbot/core/contract/dashboard/qqbot-dashboard.controller';
|
||||||
import { QqbotMessageController } from '../../../../src/modules/qqbot/core/message/qqbot-message.controller';
|
import { QqbotMessageController } from '../../../../src/modules/qqbot/core/contract/message/qqbot-message.controller';
|
||||||
import { QqbotPermissionController } from '../../../../src/modules/qqbot/core/permission/qqbot-permission.controller';
|
import { QqbotPermissionController } from '../../../../src/modules/qqbot/core/contract/permission/qqbot-permission.controller';
|
||||||
import { QqbotRuleController } from '../../../../src/modules/qqbot/core/rule/qqbot-rule.controller';
|
import { QqbotRuleController } from '../../../../src/modules/qqbot/core/contract/rule/qqbot-rule.controller';
|
||||||
import { QqbotSendController } from '../../../../src/modules/qqbot/core/send/qqbot-send.controller';
|
import { QqbotSendController } from '../../../../src/modules/qqbot/core/contract/send/qqbot-send.controller';
|
||||||
import {
|
import {
|
||||||
QQBOT_CORE_CONTROLLERS,
|
QQBOT_CORE_CONTROLLERS,
|
||||||
QQBOT_CORE_ENTITIES,
|
QQBOT_CORE_ENTITIES,
|
||||||
@ -128,7 +128,6 @@ describe('QQBot core module contract', () => {
|
|||||||
'GET /qqbot/permission/config',
|
'GET /qqbot/permission/config',
|
||||||
'GET /qqbot/permission/allowlist',
|
'GET /qqbot/permission/allowlist',
|
||||||
'GET /qqbot/permission/blocklist',
|
'GET /qqbot/permission/blocklist',
|
||||||
'GET /qqbot/plugin/list',
|
|
||||||
'GET /qqbot/rule/list',
|
'GET /qqbot/rule/list',
|
||||||
'GET /qqbot/send/log/list',
|
'GET /qqbot/send/log/list',
|
||||||
'POST /qqbot/send/private',
|
'POST /qqbot/send/private',
|
||||||
@ -191,9 +190,6 @@ describe('QQBot core module contract', () => {
|
|||||||
QqbotSendController,
|
QqbotSendController,
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
expect(getNames(QQBOT_CORE_CONTROLLERS)).toEqual(
|
|
||||||
expect.arrayContaining(['QqbotPluginController']),
|
|
||||||
);
|
|
||||||
expect(getNames(QQBOT_CORE_PROVIDERS)).toEqual(
|
expect(getNames(QQBOT_CORE_PROVIDERS)).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
'QqbotAccountService',
|
'QqbotAccountService',
|
||||||
@ -204,7 +200,6 @@ describe('QQBot core module contract', () => {
|
|||||||
'QqbotConfigService',
|
'QqbotConfigService',
|
||||||
'QqbotDashboardService',
|
'QqbotDashboardService',
|
||||||
'QqbotDedupeService',
|
'QqbotDedupeService',
|
||||||
'QqbotEventPluginRegistryService',
|
|
||||||
'QqbotEventService',
|
'QqbotEventService',
|
||||||
'QqbotMessageService',
|
'QqbotMessageService',
|
||||||
'NapcatDeviceIdentityService',
|
'NapcatDeviceIdentityService',
|
||||||
@ -212,8 +207,6 @@ describe('QQBot core module contract', () => {
|
|||||||
'QqbotNapcatLoginService',
|
'QqbotNapcatLoginService',
|
||||||
'QqbotNapcatWatchdogService',
|
'QqbotNapcatWatchdogService',
|
||||||
'QqbotPermissionService',
|
'QqbotPermissionService',
|
||||||
'QqbotPluginHttpClientService',
|
|
||||||
'QqbotPluginRegistryService',
|
|
||||||
'QqbotRateLimitService',
|
'QqbotRateLimitService',
|
||||||
'QqbotReplyTemplateService',
|
'QqbotReplyTemplateService',
|
||||||
'QqbotReverseWsService',
|
'QqbotReverseWsService',
|
||||||
|
|||||||
@ -25,7 +25,7 @@ describe('QQBot core plugin execution ports', () => {
|
|||||||
|
|
||||||
it('keeps command parser generic and leaves plugin-specific parsing to plugins', () => {
|
it('keeps command parser generic and leaves plugin-specific parsing to plugins', () => {
|
||||||
const source = readSource(
|
const source = readSource(
|
||||||
'src/modules/qqbot/core/command/qqbot-command-parser.service.ts',
|
'src/modules/qqbot/core/application/command/qqbot-command-parser.service.ts',
|
||||||
);
|
);
|
||||||
|
|
||||||
const bannedParserSignals = [
|
const bannedParserSignals = [
|
||||||
@ -41,7 +41,7 @@ describe('QQBot core plugin execution ports', () => {
|
|||||||
|
|
||||||
it('dispatches unconsumed events through Plugin Platform instead of directly invoking Repeater', () => {
|
it('dispatches unconsumed events through Plugin Platform instead of directly invoking Repeater', () => {
|
||||||
const source = readSource(
|
const source = readSource(
|
||||||
'src/modules/qqbot/core/rule/qqbot-rule-engine.service.ts',
|
'src/modules/qqbot/core/application/rule/qqbot-rule-engine.service.ts',
|
||||||
);
|
);
|
||||||
|
|
||||||
const bannedRepeaterSignals = [
|
const bannedRepeaterSignals = [
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { QQBOT_CORE_DOMAIN_CONTRACT } from '../../../../src/modules/qqbot/core/qqbot-core.contract';
|
import { QQBOT_CORE_DOMAIN_CONTRACT } from '../../../../src/modules/qqbot/core/contract/qqbot-core.contract';
|
||||||
import { readRefactorV3SqlSchema } from '../../../helpers/sql-schema.helper';
|
import { readRefactorV3SqlSchema } from '../../../helpers/sql-schema.helper';
|
||||||
|
|
||||||
describe('QQBot core send contract', () => {
|
describe('QQBot core send contract', () => {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { QQBOT_CORE_DOMAIN_CONTRACT } from '../../../../src/modules/qqbot/core/qqbot-core.contract';
|
import { QQBOT_CORE_DOMAIN_CONTRACT } from '../../../../src/modules/qqbot/core/contract/qqbot-core.contract';
|
||||||
import { readRefactorV3SqlSchema } from '../../../helpers/sql-schema.helper';
|
import { readRefactorV3SqlSchema } from '../../../helpers/sql-schema.helper';
|
||||||
|
|
||||||
describe('QQBot core status contract', () => {
|
describe('QQBot core status contract', () => {
|
||||||
|
|||||||
@ -5,9 +5,9 @@ import {
|
|||||||
NapcatDeviceIdentityService,
|
NapcatDeviceIdentityService,
|
||||||
NAPCAT_RUNTIME_DOMAIN_CONTRACT,
|
NAPCAT_RUNTIME_DOMAIN_CONTRACT,
|
||||||
NAPCAT_RUNTIME_ENTITIES,
|
NAPCAT_RUNTIME_ENTITIES,
|
||||||
toNapcatDockerDeviceOptions,
|
|
||||||
} from '../../../../src/modules/qqbot/napcat';
|
} from '../../../../src/modules/qqbot/napcat';
|
||||||
import { QqbotNapcatContainerService } from '../../../../src/modules/qqbot/napcat/qqbot-napcat-container.service';
|
import { toNapcatDockerDeviceOptions } from '../../../../src/modules/qqbot/napcat/infrastructure/integration/container/napcat-docker-device-options';
|
||||||
|
import { QqbotNapcatContainerService } from '../../../../src/modules/qqbot/napcat/infrastructure/integration/container/qqbot-napcat-container.service';
|
||||||
import { readRefactorV3SqlSchema } from '../../../helpers/sql-schema.helper';
|
import { readRefactorV3SqlSchema } from '../../../helpers/sql-schema.helper';
|
||||||
|
|
||||||
type EntityClass = new (...args: never[]) => unknown;
|
type EntityClass = new (...args: never[]) => unknown;
|
||||||
|
|||||||
@ -38,7 +38,7 @@ describe('NapCat persistent login state contract', () => {
|
|||||||
|
|
||||||
it('keeps login truth in persistence rather than in-memory scan sessions', () => {
|
it('keeps login truth in persistence rather than in-memory scan sessions', () => {
|
||||||
const loginSource = readSource(
|
const loginSource = readSource(
|
||||||
'src/modules/qqbot/napcat/login/qqbot-napcat-login.service.ts',
|
'src/modules/qqbot/napcat/application/login/qqbot-napcat-login.service.ts',
|
||||||
);
|
);
|
||||||
|
|
||||||
const bannedMemorySignals = ['new Map', 'scanSessions'].filter((signal) =>
|
const bannedMemorySignals = ['new Map', 'scanSessions'].filter((signal) =>
|
||||||
@ -56,7 +56,7 @@ describe('NapCat persistent login state contract', () => {
|
|||||||
|
|
||||||
it('keeps captcha and new-device challenges recoverable and separate', () => {
|
it('keeps captcha and new-device challenges recoverable and separate', () => {
|
||||||
const stateMachine = readSource(
|
const stateMachine = readSource(
|
||||||
'src/modules/qqbot/napcat/login/napcat-login-state-machine.ts',
|
'src/modules/qqbot/napcat/domain/login/napcat-login-state-machine.ts',
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(stateMachine).toEqual(expect.stringContaining("type: 'captcha'"));
|
expect(stateMachine).toEqual(expect.stringContaining("type: 'captcha'"));
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { runQqbotPluginCli } from '../../../../scripts/qqbot-plugin/cli';
|
import { runQqbotPluginCli } from '../../../../scripts/qqbot-plugin/cli';
|
||||||
import { parseQqbotPluginManifest } from '../../../../src/modules/qqbot/plugin-platform/manifest';
|
import { parseQqbotPluginManifest } from '../../../../src/modules/qqbot/plugin-platform/domain/manifest';
|
||||||
|
|
||||||
const projectRoot = path.resolve(__dirname, '..', '..', '..', '..');
|
const projectRoot = path.resolve(__dirname, '..', '..', '..', '..');
|
||||||
const workspaceTmpRoot = path.resolve(
|
const workspaceTmpRoot = path.resolve(
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import {
|
|||||||
QQBOT_PLUGIN_ALLOWED_PERMISSIONS,
|
QQBOT_PLUGIN_ALLOWED_PERMISSIONS,
|
||||||
parseQqbotPluginManifest,
|
parseQqbotPluginManifest,
|
||||||
QqbotPluginManifestValidationError,
|
QqbotPluginManifestValidationError,
|
||||||
} from '../../../../src/modules/qqbot/plugin-platform/manifest';
|
} from '../../../../src/modules/qqbot/plugin-platform/domain/manifest';
|
||||||
|
|
||||||
const createValidManifest = () => ({
|
const createValidManifest = () => ({
|
||||||
assets: [
|
assets: [
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { getMetadataArgsStorage } from 'typeorm';
|
|||||||
import {
|
import {
|
||||||
QQBOT_PLUGIN_PLATFORM_DOMAIN_CONTRACT,
|
QQBOT_PLUGIN_PLATFORM_DOMAIN_CONTRACT,
|
||||||
QQBOT_PLUGIN_PLATFORM_ENTITIES,
|
QQBOT_PLUGIN_PLATFORM_ENTITIES,
|
||||||
} from '../../../../src/modules/qqbot/plugin-platform/persistence';
|
} from '../../../../src/modules/qqbot/plugin-platform/infrastructure/persistence';
|
||||||
import { readRefactorV3SqlSchema } from '../../../helpers/sql-schema.helper';
|
import { readRefactorV3SqlSchema } from '../../../helpers/sql-schema.helper';
|
||||||
|
|
||||||
type EntityClass = new (...args: never[]) => unknown;
|
type EntityClass = new (...args: never[]) => unknown;
|
||||||
|
|||||||
@ -9,10 +9,10 @@ const readSource = (relativePath: string) =>
|
|||||||
describe('QQBot plugin platform lifecycle runtime contract', () => {
|
describe('QQBot plugin platform lifecycle runtime contract', () => {
|
||||||
it('uses dedicated lifecycle use cases instead of direct status flips', () => {
|
it('uses dedicated lifecycle use cases instead of direct status flips', () => {
|
||||||
const controller = readSource(
|
const controller = readSource(
|
||||||
'src/modules/qqbot/plugin-platform/plugin-platform.controller.ts',
|
'src/modules/qqbot/plugin-platform/contract/plugin-platform.controller.ts',
|
||||||
);
|
);
|
||||||
const service = readSource(
|
const service = readSource(
|
||||||
'src/modules/qqbot/plugin-platform/plugin-platform.service.ts',
|
'src/modules/qqbot/plugin-platform/application/plugin-platform.service.ts',
|
||||||
);
|
);
|
||||||
|
|
||||||
const bannedDirectStatusFlips = [
|
const bannedDirectStatusFlips = [
|
||||||
@ -36,8 +36,8 @@ describe('QQBot plugin platform lifecycle runtime contract', () => {
|
|||||||
|
|
||||||
it('activates workers and refreshes active registries during lifecycle transitions', () => {
|
it('activates workers and refreshes active registries during lifecycle transitions', () => {
|
||||||
const source = [
|
const source = [
|
||||||
readSource('src/modules/qqbot/plugin-platform/plugin-platform.service.ts'),
|
readSource('src/modules/qqbot/plugin-platform/application/plugin-platform.service.ts'),
|
||||||
readSource('src/modules/qqbot/plugin-platform/runtime/worker-runtime.ts'),
|
readSource('src/modules/qqbot/plugin-platform/infrastructure/integration/runtime/worker-runtime.ts'),
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
const missingRuntimeSignals = [
|
const missingRuntimeSignals = [
|
||||||
@ -55,7 +55,7 @@ describe('QQBot plugin platform lifecycle runtime contract', () => {
|
|||||||
|
|
||||||
it('exposes operation executor and event dispatcher through the platform', () => {
|
it('exposes operation executor and event dispatcher through the platform', () => {
|
||||||
const source = readSource(
|
const source = readSource(
|
||||||
'src/modules/qqbot/plugin-platform/plugin-platform.service.ts',
|
'src/modules/qqbot/plugin-platform/application/plugin-platform.service.ts',
|
||||||
);
|
);
|
||||||
|
|
||||||
const missingExecutorSignals = [
|
const missingExecutorSignals = [
|
||||||
|
|||||||
@ -5,9 +5,9 @@ import { Test } from '@nestjs/testing';
|
|||||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||||
import * as request from 'supertest';
|
import * as request from 'supertest';
|
||||||
import { JwtAuthGuard } from '../../../../src/modules/admin/identity/auth/jwt-auth.guard';
|
import { JwtAuthGuard } from '../../../../src/modules/admin/identity/auth/jwt-auth.guard';
|
||||||
import { QqbotPluginPlatformController } from '../../../../src/modules/qqbot/plugin-platform/plugin-platform.controller';
|
import { QqbotPluginPlatformController } from '../../../../src/modules/qqbot/plugin-platform/contract/plugin-platform.controller';
|
||||||
import { QqbotPluginPlatformModule } from '../../../../src/modules/qqbot/plugin-platform/plugin-platform.module';
|
import { QqbotPluginPlatformModule } from '../../../../src/modules/qqbot/plugin-platform/plugin-platform.module';
|
||||||
import { QqbotPluginPlatformService } from '../../../../src/modules/qqbot/plugin-platform/plugin-platform.service';
|
import { QqbotPluginPlatformService } from '../../../../src/modules/qqbot/plugin-platform/application/plugin-platform.service';
|
||||||
import {
|
import {
|
||||||
QQBOT_PLUGIN_PLATFORM_ENTITIES,
|
QQBOT_PLUGIN_PLATFORM_ENTITIES,
|
||||||
QqbotPlugin,
|
QqbotPlugin,
|
||||||
@ -19,7 +19,7 @@ import {
|
|||||||
QqbotPluginOperation,
|
QqbotPluginOperation,
|
||||||
QqbotPluginRuntimeEvent,
|
QqbotPluginRuntimeEvent,
|
||||||
QqbotPluginVersion,
|
QqbotPluginVersion,
|
||||||
} from '../../../../src/modules/qqbot/plugin-platform/persistence';
|
} from '../../../../src/modules/qqbot/plugin-platform/infrastructure/persistence';
|
||||||
import {
|
import {
|
||||||
collectControllerRoutes,
|
collectControllerRoutes,
|
||||||
routeKey,
|
routeKey,
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user