fix: 按BangDream能力懒加载目录数据
This commit is contained in:
parent
4e5ed876c3
commit
0fe3f99c36
@ -58,9 +58,9 @@ export class BangDreamCommandContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async checkHealth() {
|
async checkHealth() {
|
||||||
await waitForBangDreamCatalogReady();
|
await waitForBangDreamCatalogReady(['songs']);
|
||||||
const data = bangdreamCatalogCache as { cards?: unknown; songs?: unknown };
|
const data = bangdreamCatalogCache as { songs?: unknown };
|
||||||
if (!data.songs || !data.cards) {
|
if (!data.songs) {
|
||||||
throw new Error('BangDream 数据配置未加载');
|
throw new Error('BangDream 数据配置未加载');
|
||||||
}
|
}
|
||||||
fuzzySearch('夏祭り');
|
fuzzySearch('夏祭り');
|
||||||
|
|||||||
@ -11,15 +11,16 @@ import {
|
|||||||
sleepBangDreamRuntime,
|
sleepBangDreamRuntime,
|
||||||
} from '@/modules/qqbot/plugins/bangdream/src/infrastructure/integration/runtime-io';
|
} from '@/modules/qqbot/plugins/bangdream/src/infrastructure/integration/runtime-io';
|
||||||
|
|
||||||
const bangdreamCatalogCache: Record<string, any> = {};
|
export type BangDreamCatalogKey = keyof typeof bestdoriApiPath;
|
||||||
|
|
||||||
|
const bangdreamCatalogCache: Record<string, any> = Object.fromEntries(
|
||||||
|
Object.keys(bestdoriApiPath).map((key) => [key, {}]),
|
||||||
|
);
|
||||||
const REQUIRED_CATALOG_KEYS = [
|
const REQUIRED_CATALOG_KEYS = [
|
||||||
'cards',
|
|
||||||
'characters',
|
|
||||||
'events',
|
|
||||||
'gacha',
|
|
||||||
'songs',
|
'songs',
|
||||||
];
|
] as const satisfies readonly BangDreamCatalogKey[];
|
||||||
const DEFAULT_CATALOG_READY_TIMEOUT_MS = 15000;
|
const DEFAULT_CATALOG_READY_TIMEOUT_MS = 15000;
|
||||||
|
const catalogLoadPromises = new Map<BangDreamCatalogKey, Promise<void>>();
|
||||||
|
|
||||||
function getCatalogReadyTimeoutMs(): number {
|
function getCatalogReadyTimeoutMs(): number {
|
||||||
return normalizeBangDreamPositiveInteger(
|
return normalizeBangDreamPositiveInteger(
|
||||||
@ -28,8 +29,22 @@ function getCatalogReadyTimeoutMs(): number {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isCatalogReady(): boolean {
|
function normalizeCatalogKeys(
|
||||||
return REQUIRED_CATALOG_KEYS.every((key) => {
|
keys: readonly BangDreamCatalogKey[] = REQUIRED_CATALOG_KEYS,
|
||||||
|
): BangDreamCatalogKey[] {
|
||||||
|
return [...new Set(keys)].filter((key) => key in bestdoriApiPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isCatalogKeyReady(key: BangDreamCatalogKey): boolean {
|
||||||
|
const collection = bangdreamCatalogCache[key];
|
||||||
|
if (!collection) return false;
|
||||||
|
return typeof collection === 'object'
|
||||||
|
? Object.keys(collection).length > 0
|
||||||
|
: true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isCatalogReady(keys?: readonly BangDreamCatalogKey[]): boolean {
|
||||||
|
return normalizeCatalogKeys(keys).every((key) => {
|
||||||
const collection = bangdreamCatalogCache[key];
|
const collection = bangdreamCatalogCache[key];
|
||||||
return collection && Object.keys(collection).length > 0;
|
return collection && Object.keys(collection).length > 0;
|
||||||
});
|
});
|
||||||
@ -45,26 +60,56 @@ async function rejectAfter(ms: number): Promise<never> {
|
|||||||
*
|
*
|
||||||
* @param useCache - use缓存参数,未传入时使用默认值。
|
* @param useCache - use缓存参数,未传入时使用默认值。
|
||||||
*/
|
*/
|
||||||
async function loadCatalogData(useCache: boolean = false) {
|
async function loadCatalogData(
|
||||||
|
keys?: readonly BangDreamCatalogKey[],
|
||||||
|
useCache: boolean = false,
|
||||||
|
) {
|
||||||
|
const catalogKeys = normalizeCatalogKeys(keys);
|
||||||
logger('catalog', 'loading catalog...');
|
logger('catalog', 'loading catalog...');
|
||||||
const promiseAll = Object.keys(bestdoriApiPath).map(async (key) => {
|
|
||||||
|
for (const key of catalogKeys) {
|
||||||
|
await loadCatalogKey(key, useCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
await applyStaticPatches(catalogKeys);
|
||||||
|
logger('catalog', 'catalog loaded');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadCatalogKey(key: BangDreamCatalogKey, useCache: boolean) {
|
||||||
|
if (isCatalogKeyReady(key)) return;
|
||||||
|
const pending = catalogLoadPromises.get(key);
|
||||||
|
if (pending) return await pending;
|
||||||
|
|
||||||
|
const promise = (async () => {
|
||||||
if (useCache) {
|
if (useCache) {
|
||||||
return (bangdreamCatalogCache[key] =
|
bangdreamCatalogCache[key] = await bangdreamBestdoriProvider.getJson(
|
||||||
await bangdreamBestdoriProvider.getJson(bestdoriApiPath[key], {
|
bestdoriApiPath[key],
|
||||||
|
{
|
||||||
cacheTime: 1 / 0,
|
cacheTime: 1 / 0,
|
||||||
}));
|
},
|
||||||
} else {
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return (bangdreamCatalogCache[key] =
|
bangdreamCatalogCache[key] = await bangdreamBestdoriProvider.getJson(
|
||||||
await bangdreamBestdoriProvider.getJson(bestdoriApiPath[key]));
|
bestdoriApiPath[key],
|
||||||
|
);
|
||||||
} catch {
|
} catch {
|
||||||
logger('catalog', `load ${key} failed`);
|
logger('catalog', `load ${key} failed`);
|
||||||
}
|
}
|
||||||
|
})();
|
||||||
|
catalogLoadPromises.set(key, promise);
|
||||||
|
try {
|
||||||
|
await promise;
|
||||||
|
} finally {
|
||||||
|
catalogLoadPromises.delete(key);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
await Promise.all(promiseAll);
|
|
||||||
|
|
||||||
|
async function applyStaticPatches(keys: readonly BangDreamCatalogKey[]) {
|
||||||
|
const keySet = new Set(keys);
|
||||||
|
if (keySet.has('cards')) {
|
||||||
const cardsCnFix =
|
const cardsCnFix =
|
||||||
await bangdreamStaticPatchProvider.readJson<Record<string, unknown>>(
|
await bangdreamStaticPatchProvider.readJson<Record<string, unknown>>(
|
||||||
'cards-cn-fix.json',
|
'cards-cn-fix.json',
|
||||||
@ -72,6 +117,8 @@ async function loadCatalogData(useCache: boolean = false) {
|
|||||||
for (const key in cardsCnFix) {
|
for (const key in cardsCnFix) {
|
||||||
bangdreamCatalogCache['cards'][key] = cardsCnFix[key];
|
bangdreamCatalogCache['cards'][key] = cardsCnFix[key];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (keySet.has('skills')) {
|
||||||
const skillsCnFix =
|
const skillsCnFix =
|
||||||
await bangdreamStaticPatchProvider.readJson<Record<string, unknown>>(
|
await bangdreamStaticPatchProvider.readJson<Record<string, unknown>>(
|
||||||
'skills-cn-fix.json',
|
'skills-cn-fix.json',
|
||||||
@ -79,6 +126,8 @@ async function loadCatalogData(useCache: boolean = false) {
|
|||||||
for (const key in skillsCnFix) {
|
for (const key in skillsCnFix) {
|
||||||
bangdreamCatalogCache['skills'][key] = skillsCnFix[key];
|
bangdreamCatalogCache['skills'][key] = skillsCnFix[key];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (keySet.has('areaItems')) {
|
||||||
const areaItemFix =
|
const areaItemFix =
|
||||||
await bangdreamStaticPatchProvider.readJson<Record<string, unknown>>(
|
await bangdreamStaticPatchProvider.readJson<Record<string, unknown>>(
|
||||||
'area-item-fix.json',
|
'area-item-fix.json',
|
||||||
@ -88,6 +137,8 @@ async function loadCatalogData(useCache: boolean = false) {
|
|||||||
bangdreamCatalogCache['areaItems'][key] = areaItemFix[key];
|
bangdreamCatalogCache['areaItems'][key] = areaItemFix[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (keySet.has('songs')) {
|
||||||
try {
|
try {
|
||||||
const songNickname = await bangdreamStaticPatchProvider.readExcelRows<{
|
const songNickname = await bangdreamStaticPatchProvider.readExcelRows<{
|
||||||
Id: number;
|
Id: number;
|
||||||
@ -103,33 +154,32 @@ async function loadCatalogData(useCache: boolean = false) {
|
|||||||
} catch {
|
} catch {
|
||||||
logger('catalog', '读取 nickname-song.xlsx 失败');
|
logger('catalog', '读取 nickname-song.xlsx 失败');
|
||||||
}
|
}
|
||||||
logger('catalog', 'catalog loaded');
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let initialLoadPromise: Promise<void> | undefined;
|
async function ensureCatalogInitialLoad(keys?: readonly BangDreamCatalogKey[]) {
|
||||||
|
const catalogKeys = normalizeCatalogKeys(keys);
|
||||||
function ensureCatalogInitialLoad() {
|
if (isCatalogReady(catalogKeys)) return;
|
||||||
if (!initialLoadPromise) {
|
|
||||||
logger('catalog', 'initializing...');
|
logger('catalog', 'initializing...');
|
||||||
initialLoadPromise = loadCatalogData(true).then(() => {
|
await loadCatalogData(catalogKeys, true);
|
||||||
logger('catalog', 'initializing done');
|
logger('catalog', 'initializing done');
|
||||||
});
|
|
||||||
}
|
|
||||||
return initialLoadPromise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 等待 BangDream 目录数据完成首次加载。
|
* 等待 BangDream 目录数据完成首次加载。
|
||||||
*/
|
*/
|
||||||
export async function waitForBangDreamCatalogReady(): Promise<void> {
|
export async function waitForBangDreamCatalogReady(
|
||||||
if (isCatalogReady()) {
|
keys?: readonly BangDreamCatalogKey[],
|
||||||
|
): Promise<void> {
|
||||||
|
const catalogKeys = normalizeCatalogKeys(keys);
|
||||||
|
if (isCatalogReady(catalogKeys)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await Promise.race([
|
await Promise.race([
|
||||||
ensureCatalogInitialLoad(),
|
ensureCatalogInitialLoad(catalogKeys),
|
||||||
rejectAfter(getCatalogReadyTimeoutMs()),
|
rejectAfter(getCatalogReadyTimeoutMs()),
|
||||||
]);
|
]);
|
||||||
if (!isCatalogReady()) {
|
if (!isCatalogReady(catalogKeys)) {
|
||||||
throw new Error('BangDream 主数据未完成关键集合加载');
|
throw new Error('BangDream 主数据未完成关键集合加载');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,6 +46,7 @@ type BangDreamManifestOperation = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type BangDreamResolvedOperation = BangDreamManifestOperation & {
|
type BangDreamResolvedOperation = BangDreamManifestOperation & {
|
||||||
|
catalogKeys?: BangDreamOperationModule['catalogKeys'];
|
||||||
execute: BangDreamOperationModule['execute'];
|
execute: BangDreamOperationModule['execute'];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -131,6 +132,7 @@ function resolveBangDreamOperations(operations: BangDreamManifestOperation[]) {
|
|||||||
operation.key,
|
operation.key,
|
||||||
{
|
{
|
||||||
...operation,
|
...operation,
|
||||||
|
catalogKeys: operationModule.catalogKeys,
|
||||||
execute: operationModule.execute,
|
execute: operationModule.execute,
|
||||||
},
|
},
|
||||||
] as const;
|
] as const;
|
||||||
@ -153,9 +155,6 @@ async function executeBangDreamOperation(options: {
|
|||||||
await options.lifecycle.beforeParse(operationContext);
|
await options.lifecycle.beforeParse(operationContext);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
operationContext.stage = 'catalog';
|
|
||||||
await waitForBangDreamCatalogReady();
|
|
||||||
|
|
||||||
operationContext.stage = 'operation';
|
operationContext.stage = 'operation';
|
||||||
const operation = options.operationsByKey.get(options.operationKey);
|
const operation = options.operationsByKey.get(options.operationKey);
|
||||||
if (!operation) {
|
if (!operation) {
|
||||||
@ -164,6 +163,9 @@ async function executeBangDreamOperation(options: {
|
|||||||
operationContext.handlerName = operation.handlerName;
|
operationContext.handlerName = operation.handlerName;
|
||||||
await options.lifecycle.afterResolve(operationContext);
|
await options.lifecycle.afterResolve(operationContext);
|
||||||
|
|
||||||
|
operationContext.stage = 'catalog';
|
||||||
|
await waitForBangDreamCatalogReady(operation.catalogKeys);
|
||||||
|
|
||||||
operationContext.stage = 'handler';
|
operationContext.stage = 'handler';
|
||||||
await options.lifecycle.beforeRender(operationContext);
|
await options.lifecycle.beforeRender(operationContext);
|
||||||
const output = await operation.execute(options.input, options.context);
|
const output = await operation.execute(options.input, options.context);
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
import { Card } from '@/modules/qqbot/plugins/bangdream/src/domain/card/card.model';
|
import { Card } from '@/modules/qqbot/plugins/bangdream/src/domain/card/card.model';
|
||||||
|
import { BANGDREAM_CARD_ILLUSTRATION_CATALOG_KEYS } from '@/modules/qqbot/plugins/bangdream/src/operations/catalog-keys';
|
||||||
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
||||||
|
|
||||||
export const cardIllustrationOperation: BangDreamOperationModule = {
|
export const cardIllustrationOperation: BangDreamOperationModule = {
|
||||||
|
catalogKeys: BANGDREAM_CARD_ILLUSTRATION_CATALOG_KEYS,
|
||||||
handlerName: 'getCardIllustration',
|
handlerName: 'getCardIllustration',
|
||||||
execute: async (input, context) => {
|
execute: async (input, context) => {
|
||||||
const cardId = context.requireNumber(
|
const cardId = context.requireNumber(
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import { drawCardDetail } from '@/modules/qqbot/plugins/bangdream/src/domain/card/card-detail.renderer';
|
import { drawCardDetail } from '@/modules/qqbot/plugins/bangdream/src/domain/card/card-detail.renderer';
|
||||||
import { drawCardList } from '@/modules/qqbot/plugins/bangdream/src/domain/card/card-search.renderer';
|
import { drawCardList } from '@/modules/qqbot/plugins/bangdream/src/domain/card/card-search.renderer';
|
||||||
|
import { BANGDREAM_CARD_CATALOG_KEYS } from '@/modules/qqbot/plugins/bangdream/src/operations/catalog-keys';
|
||||||
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
||||||
|
|
||||||
export const cardSearchOperation: BangDreamOperationModule = {
|
export const cardSearchOperation: BangDreamOperationModule = {
|
||||||
|
catalogKeys: BANGDREAM_CARD_CATALOG_KEYS,
|
||||||
handlerName: 'searchCard',
|
handlerName: 'searchCard',
|
||||||
execute: async (input, context) => {
|
execute: async (input, context) => {
|
||||||
const query = context.requireText(input, '请提供卡牌关键词或卡牌 ID');
|
const query = context.requireText(input, '请提供卡牌关键词或卡牌 ID');
|
||||||
|
|||||||
@ -0,0 +1,105 @@
|
|||||||
|
import type { BangDreamCatalogKey } from '@/modules/qqbot/plugins/bangdream/src/application/catalog/bangdream-catalog-cache';
|
||||||
|
|
||||||
|
export const BANGDREAM_BAND_CATALOG_KEYS = [
|
||||||
|
'singer',
|
||||||
|
'bands',
|
||||||
|
'characters',
|
||||||
|
] as const satisfies readonly BangDreamCatalogKey[];
|
||||||
|
|
||||||
|
export const BANGDREAM_SONG_CATALOG_KEYS = [
|
||||||
|
'songs',
|
||||||
|
'meta',
|
||||||
|
...BANGDREAM_BAND_CATALOG_KEYS,
|
||||||
|
] as const satisfies readonly BangDreamCatalogKey[];
|
||||||
|
|
||||||
|
export const BANGDREAM_SONG_SEARCH_CATALOG_KEYS = [
|
||||||
|
...BANGDREAM_SONG_CATALOG_KEYS,
|
||||||
|
'events',
|
||||||
|
] as const satisfies readonly BangDreamCatalogKey[];
|
||||||
|
|
||||||
|
export const BANGDREAM_CARD_ILLUSTRATION_CATALOG_KEYS = [
|
||||||
|
'cards',
|
||||||
|
'skills',
|
||||||
|
'characters',
|
||||||
|
] as const satisfies readonly BangDreamCatalogKey[];
|
||||||
|
|
||||||
|
export const BANGDREAM_CARD_CATALOG_KEYS = [
|
||||||
|
...BANGDREAM_CARD_ILLUSTRATION_CATALOG_KEYS,
|
||||||
|
'singer',
|
||||||
|
'bands',
|
||||||
|
'events',
|
||||||
|
'gacha',
|
||||||
|
'costumes',
|
||||||
|
] as const satisfies readonly BangDreamCatalogKey[];
|
||||||
|
|
||||||
|
export const BANGDREAM_CHARACTER_CATALOG_KEYS = [
|
||||||
|
'characters',
|
||||||
|
'singer',
|
||||||
|
'bands',
|
||||||
|
] as const satisfies readonly BangDreamCatalogKey[];
|
||||||
|
|
||||||
|
export const BANGDREAM_EVENT_CATALOG_KEYS = [
|
||||||
|
'events',
|
||||||
|
'characters',
|
||||||
|
'singer',
|
||||||
|
'bands',
|
||||||
|
'cards',
|
||||||
|
'skills',
|
||||||
|
'gacha',
|
||||||
|
'songs',
|
||||||
|
'meta',
|
||||||
|
'degrees',
|
||||||
|
'deco',
|
||||||
|
] as const satisfies readonly BangDreamCatalogKey[];
|
||||||
|
|
||||||
|
export const BANGDREAM_EVENT_STAGE_CATALOG_KEYS = [
|
||||||
|
'events',
|
||||||
|
'characters',
|
||||||
|
'songs',
|
||||||
|
'meta',
|
||||||
|
] as const satisfies readonly BangDreamCatalogKey[];
|
||||||
|
|
||||||
|
export const BANGDREAM_GACHA_CATALOG_KEYS = [
|
||||||
|
'gacha',
|
||||||
|
'cards',
|
||||||
|
'skills',
|
||||||
|
'characters',
|
||||||
|
'singer',
|
||||||
|
'bands',
|
||||||
|
'events',
|
||||||
|
'items',
|
||||||
|
] as const satisfies readonly BangDreamCatalogKey[];
|
||||||
|
|
||||||
|
export const BANGDREAM_GACHA_SIMULATE_CATALOG_KEYS = [
|
||||||
|
'gacha',
|
||||||
|
'cards',
|
||||||
|
'skills',
|
||||||
|
'characters',
|
||||||
|
'singer',
|
||||||
|
'bands',
|
||||||
|
] as const satisfies readonly BangDreamCatalogKey[];
|
||||||
|
|
||||||
|
export const BANGDREAM_CUTOFF_BASE_CATALOG_KEYS = [
|
||||||
|
'events',
|
||||||
|
'characters',
|
||||||
|
'rates',
|
||||||
|
] as const satisfies readonly BangDreamCatalogKey[];
|
||||||
|
|
||||||
|
export const BANGDREAM_CUTOFF_DETAIL_CATALOG_KEYS = [
|
||||||
|
...BANGDREAM_CUTOFF_BASE_CATALOG_KEYS,
|
||||||
|
'cards',
|
||||||
|
'skills',
|
||||||
|
'singer',
|
||||||
|
'bands',
|
||||||
|
'degrees',
|
||||||
|
] as const satisfies readonly BangDreamCatalogKey[];
|
||||||
|
|
||||||
|
export const BANGDREAM_PLAYER_CATALOG_KEYS = [
|
||||||
|
'cards',
|
||||||
|
'skills',
|
||||||
|
'characters',
|
||||||
|
'singer',
|
||||||
|
'bands',
|
||||||
|
'degrees',
|
||||||
|
'areaItems',
|
||||||
|
] as const satisfies readonly BangDreamCatalogKey[];
|
||||||
@ -1,8 +1,10 @@
|
|||||||
import { drawCharacterDetail } from '@/modules/qqbot/plugins/bangdream/src/domain/character/character-detail.renderer';
|
import { drawCharacterDetail } from '@/modules/qqbot/plugins/bangdream/src/domain/character/character-detail.renderer';
|
||||||
import { drawCharacterList } from '@/modules/qqbot/plugins/bangdream/src/domain/character/character-search.renderer';
|
import { drawCharacterList } from '@/modules/qqbot/plugins/bangdream/src/domain/character/character-search.renderer';
|
||||||
|
import { BANGDREAM_CHARACTER_CATALOG_KEYS } from '@/modules/qqbot/plugins/bangdream/src/operations/catalog-keys';
|
||||||
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
||||||
|
|
||||||
export const characterSearchOperation: BangDreamOperationModule = {
|
export const characterSearchOperation: BangDreamOperationModule = {
|
||||||
|
catalogKeys: BANGDREAM_CHARACTER_CATALOG_KEYS,
|
||||||
handlerName: 'searchCharacter',
|
handlerName: 'searchCharacter',
|
||||||
execute: async (input, context) => {
|
execute: async (input, context) => {
|
||||||
const query = context.requireText(input, '请提供角色关键词或角色 ID');
|
const query = context.requireText(input, '请提供角色关键词或角色 ID');
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import { drawCutoffAll } from '@/modules/qqbot/plugins/bangdream/src/domain/cutoff/cutoff-all.renderer';
|
import { drawCutoffAll } from '@/modules/qqbot/plugins/bangdream/src/domain/cutoff/cutoff-all.renderer';
|
||||||
import { getPresentEvent } from '@/modules/qqbot/plugins/bangdream/src/domain/event/event.model';
|
import { getPresentEvent } from '@/modules/qqbot/plugins/bangdream/src/domain/event/event.model';
|
||||||
|
import { BANGDREAM_CUTOFF_BASE_CATALOG_KEYS } from '@/modules/qqbot/plugins/bangdream/src/operations/catalog-keys';
|
||||||
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
||||||
|
|
||||||
export const cutoffAllOperation: BangDreamOperationModule = {
|
export const cutoffAllOperation: BangDreamOperationModule = {
|
||||||
|
catalogKeys: BANGDREAM_CUTOFF_BASE_CATALOG_KEYS,
|
||||||
handlerName: 'getCutoffAll',
|
handlerName: 'getCutoffAll',
|
||||||
execute: async (input, context) => {
|
execute: async (input, context) => {
|
||||||
const tokens = context.getTokens(input);
|
const tokens = context.getTokens(input);
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { drawCutoffDetail } from '@/modules/qqbot/plugins/bangdream/src/domain/cutoff/cutoff-detail.renderer';
|
import { drawCutoffDetail } from '@/modules/qqbot/plugins/bangdream/src/domain/cutoff/cutoff-detail.renderer';
|
||||||
import { drawCutoffEventTop } from '@/modules/qqbot/plugins/bangdream/src/domain/cutoff/cutoff-event-top.renderer';
|
import { drawCutoffEventTop } from '@/modules/qqbot/plugins/bangdream/src/domain/cutoff/cutoff-event-top.renderer';
|
||||||
import { getPresentEvent } from '@/modules/qqbot/plugins/bangdream/src/domain/event/event.model';
|
import { getPresentEvent } from '@/modules/qqbot/plugins/bangdream/src/domain/event/event.model';
|
||||||
|
import { BANGDREAM_CUTOFF_DETAIL_CATALOG_KEYS } from '@/modules/qqbot/plugins/bangdream/src/operations/catalog-keys';
|
||||||
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
||||||
|
|
||||||
const CUTOFF_DETAIL_COMMAND_ALIASES = new Set([
|
const CUTOFF_DETAIL_COMMAND_ALIASES = new Set([
|
||||||
@ -12,6 +13,7 @@ const CUTOFF_DETAIL_COMMAND_ALIASES = new Set([
|
|||||||
const DEFAULT_CUTOFF_DETAIL_TIER = 1000;
|
const DEFAULT_CUTOFF_DETAIL_TIER = 1000;
|
||||||
|
|
||||||
export const cutoffDetailOperation: BangDreamOperationModule = {
|
export const cutoffDetailOperation: BangDreamOperationModule = {
|
||||||
|
catalogKeys: BANGDREAM_CUTOFF_DETAIL_CATALOG_KEYS,
|
||||||
handlerName: 'getCutoffDetail',
|
handlerName: 'getCutoffDetail',
|
||||||
execute: async (input, context) => {
|
execute: async (input, context) => {
|
||||||
const tokens = context.getTokens(input);
|
const tokens = context.getTokens(input);
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import { drawCutoffListOfRecentEvent } from '@/modules/qqbot/plugins/bangdream/src/domain/cutoff/cutoff-recent.renderer';
|
import { drawCutoffListOfRecentEvent } from '@/modules/qqbot/plugins/bangdream/src/domain/cutoff/cutoff-recent.renderer';
|
||||||
import { getPresentEvent } from '@/modules/qqbot/plugins/bangdream/src/domain/event/event.model';
|
import { getPresentEvent } from '@/modules/qqbot/plugins/bangdream/src/domain/event/event.model';
|
||||||
|
import { BANGDREAM_CUTOFF_BASE_CATALOG_KEYS } from '@/modules/qqbot/plugins/bangdream/src/operations/catalog-keys';
|
||||||
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
||||||
|
|
||||||
export const cutoffRecentOperation: BangDreamOperationModule = {
|
export const cutoffRecentOperation: BangDreamOperationModule = {
|
||||||
|
catalogKeys: BANGDREAM_CUTOFF_BASE_CATALOG_KEYS,
|
||||||
handlerName: 'getCutoffRecent',
|
handlerName: 'getCutoffRecent',
|
||||||
execute: async (input, context) => {
|
execute: async (input, context) => {
|
||||||
const tokens = context.getTokens(input);
|
const tokens = context.getTokens(input);
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import { drawEventDetail } from '@/modules/qqbot/plugins/bangdream/src/domain/event/event-detail.renderer';
|
import { drawEventDetail } from '@/modules/qqbot/plugins/bangdream/src/domain/event/event-detail.renderer';
|
||||||
import { drawEventList } from '@/modules/qqbot/plugins/bangdream/src/domain/event/event-search.renderer';
|
import { drawEventList } from '@/modules/qqbot/plugins/bangdream/src/domain/event/event-search.renderer';
|
||||||
|
import { BANGDREAM_EVENT_CATALOG_KEYS } from '@/modules/qqbot/plugins/bangdream/src/operations/catalog-keys';
|
||||||
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
||||||
|
|
||||||
export const eventSearchOperation: BangDreamOperationModule = {
|
export const eventSearchOperation: BangDreamOperationModule = {
|
||||||
|
catalogKeys: BANGDREAM_EVENT_CATALOG_KEYS,
|
||||||
handlerName: 'searchEvent',
|
handlerName: 'searchEvent',
|
||||||
execute: async (input, context) => {
|
execute: async (input, context) => {
|
||||||
const query = context.requireText(input, '请提供活动关键词或活动 ID');
|
const query = context.requireText(input, '请提供活动关键词或活动 ID');
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import { getPresentEvent } from '@/modules/qqbot/plugins/bangdream/src/domain/event/event.model';
|
import { getPresentEvent } from '@/modules/qqbot/plugins/bangdream/src/domain/event/event.model';
|
||||||
import { drawEventStage } from '@/modules/qqbot/plugins/bangdream/src/domain/event/event-stage.renderer';
|
import { drawEventStage } from '@/modules/qqbot/plugins/bangdream/src/domain/event/event-stage.renderer';
|
||||||
|
import { BANGDREAM_EVENT_STAGE_CATALOG_KEYS } from '@/modules/qqbot/plugins/bangdream/src/operations/catalog-keys';
|
||||||
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
||||||
|
|
||||||
export const eventStageOperation: BangDreamOperationModule = {
|
export const eventStageOperation: BangDreamOperationModule = {
|
||||||
|
catalogKeys: BANGDREAM_EVENT_STAGE_CATALOG_KEYS,
|
||||||
expectedImageCount: 5,
|
expectedImageCount: 5,
|
||||||
handlerName: 'getEventStage',
|
handlerName: 'getEventStage',
|
||||||
execute: async (input, context) => {
|
execute: async (input, context) => {
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
import { drawGachaDetail } from '@/modules/qqbot/plugins/bangdream/src/domain/gacha/gacha-detail.renderer';
|
import { drawGachaDetail } from '@/modules/qqbot/plugins/bangdream/src/domain/gacha/gacha-detail.renderer';
|
||||||
|
import { BANGDREAM_GACHA_CATALOG_KEYS } from '@/modules/qqbot/plugins/bangdream/src/operations/catalog-keys';
|
||||||
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
||||||
|
|
||||||
export const gachaSearchOperation: BangDreamOperationModule = {
|
export const gachaSearchOperation: BangDreamOperationModule = {
|
||||||
|
catalogKeys: BANGDREAM_GACHA_CATALOG_KEYS,
|
||||||
handlerName: 'searchGacha',
|
handlerName: 'searchGacha',
|
||||||
execute: async (input, context) => {
|
execute: async (input, context) => {
|
||||||
const gachaId = context.requireNumber(
|
const gachaId = context.requireNumber(
|
||||||
|
|||||||
@ -7,9 +7,11 @@ import {
|
|||||||
BANGDREAM_GACHA_DEFAULT_SPIN_COUNT,
|
BANGDREAM_GACHA_DEFAULT_SPIN_COUNT,
|
||||||
isBirthdayGachaType,
|
isBirthdayGachaType,
|
||||||
} from '@/modules/qqbot/plugins/bangdream/src/domain/policy/gacha.policy';
|
} from '@/modules/qqbot/plugins/bangdream/src/domain/policy/gacha.policy';
|
||||||
|
import { BANGDREAM_GACHA_SIMULATE_CATALOG_KEYS } from '@/modules/qqbot/plugins/bangdream/src/operations/catalog-keys';
|
||||||
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
||||||
|
|
||||||
export const gachaSimulateOperation: BangDreamOperationModule = {
|
export const gachaSimulateOperation: BangDreamOperationModule = {
|
||||||
|
catalogKeys: BANGDREAM_GACHA_SIMULATE_CATALOG_KEYS,
|
||||||
handlerName: 'simulateGacha',
|
handlerName: 'simulateGacha',
|
||||||
execute: async (input, context) => {
|
execute: async (input, context) => {
|
||||||
const tokens = context.getTokens(input);
|
const tokens = context.getTokens(input);
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import type {
|
|||||||
BangDreamCommandOutput,
|
BangDreamCommandOutput,
|
||||||
BangDreamOperationHandlerName,
|
BangDreamOperationHandlerName,
|
||||||
} from '@/modules/qqbot/plugins/bangdream/src/domain/common/bangdream.types';
|
} from '@/modules/qqbot/plugins/bangdream/src/domain/common/bangdream.types';
|
||||||
|
import type { BangDreamCatalogKey } from '@/modules/qqbot/plugins/bangdream/src/application/catalog/bangdream-catalog-cache';
|
||||||
|
|
||||||
export type BangDreamOperationExecute = (
|
export type BangDreamOperationExecute = (
|
||||||
input: BangDreamCommandInput,
|
input: BangDreamCommandInput,
|
||||||
@ -11,6 +12,7 @@ export type BangDreamOperationExecute = (
|
|||||||
) => Promise<BangDreamCommandOutput>;
|
) => Promise<BangDreamCommandOutput>;
|
||||||
|
|
||||||
export type BangDreamOperationModule = {
|
export type BangDreamOperationModule = {
|
||||||
|
catalogKeys?: readonly BangDreamCatalogKey[];
|
||||||
execute: BangDreamOperationExecute;
|
execute: BangDreamOperationExecute;
|
||||||
expectedImageCount?: number;
|
expectedImageCount?: number;
|
||||||
handlerName: BangDreamOperationHandlerName;
|
handlerName: BangDreamOperationHandlerName;
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
import { drawPlayerDetail } from '@/modules/qqbot/plugins/bangdream/src/domain/player/player-detail.renderer';
|
import { drawPlayerDetail } from '@/modules/qqbot/plugins/bangdream/src/domain/player/player-detail.renderer';
|
||||||
|
import { BANGDREAM_PLAYER_CATALOG_KEYS } from '@/modules/qqbot/plugins/bangdream/src/operations/catalog-keys';
|
||||||
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
||||||
|
|
||||||
export const playerSearchOperation: BangDreamOperationModule = {
|
export const playerSearchOperation: BangDreamOperationModule = {
|
||||||
|
catalogKeys: BANGDREAM_PLAYER_CATALOG_KEYS,
|
||||||
handlerName: 'searchPlayer',
|
handlerName: 'searchPlayer',
|
||||||
execute: async (input, context) => {
|
execute: async (input, context) => {
|
||||||
const tokens = context.getTokens(input);
|
const tokens = context.getTokens(input);
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
import { drawSongChart } from '@/modules/qqbot/plugins/bangdream/src/domain/song/song-chart.renderer';
|
import { drawSongChart } from '@/modules/qqbot/plugins/bangdream/src/domain/song/song-chart.renderer';
|
||||||
|
import { BANGDREAM_SONG_CATALOG_KEYS } from '@/modules/qqbot/plugins/bangdream/src/operations/catalog-keys';
|
||||||
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
||||||
|
|
||||||
export const songChartOperation: BangDreamOperationModule = {
|
export const songChartOperation: BangDreamOperationModule = {
|
||||||
|
catalogKeys: BANGDREAM_SONG_CATALOG_KEYS,
|
||||||
handlerName: 'getSongChart',
|
handlerName: 'getSongChart',
|
||||||
execute: async (input, context) => {
|
execute: async (input, context) => {
|
||||||
const tokens = context.getTokens(input);
|
const tokens = context.getTokens(input);
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import { Server } from '@/modules/qqbot/plugins/bangdream/src/domain/catalog/server.model';
|
import { Server } from '@/modules/qqbot/plugins/bangdream/src/domain/catalog/server.model';
|
||||||
import { drawSongMetaList } from '@/modules/qqbot/plugins/bangdream/src/domain/song/song-meta.renderer';
|
import { drawSongMetaList } from '@/modules/qqbot/plugins/bangdream/src/domain/song/song-meta.renderer';
|
||||||
|
import { BANGDREAM_SONG_CATALOG_KEYS } from '@/modules/qqbot/plugins/bangdream/src/operations/catalog-keys';
|
||||||
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
||||||
|
|
||||||
export const songMetaOperation: BangDreamOperationModule = {
|
export const songMetaOperation: BangDreamOperationModule = {
|
||||||
|
catalogKeys: BANGDREAM_SONG_CATALOG_KEYS,
|
||||||
handlerName: 'getSongMeta',
|
handlerName: 'getSongMeta',
|
||||||
execute: async (input, context) => {
|
execute: async (input, context) => {
|
||||||
const mainServer = context.pickMainServer(input, context.getTokens(input));
|
const mainServer = context.pickMainServer(input, context.getTokens(input));
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
import { Server } from '@/modules/qqbot/plugins/bangdream/src/domain/catalog/server.model';
|
import { Server } from '@/modules/qqbot/plugins/bangdream/src/domain/catalog/server.model';
|
||||||
import { fuzzySearch } from '@/modules/qqbot/plugins/bangdream/src/domain/search/fuzzy-search';
|
import { fuzzySearch } from '@/modules/qqbot/plugins/bangdream/src/domain/search/fuzzy-search';
|
||||||
import { drawSongRandom } from '@/modules/qqbot/plugins/bangdream/src/domain/song/song-random.renderer';
|
import { drawSongRandom } from '@/modules/qqbot/plugins/bangdream/src/domain/song/song-random.renderer';
|
||||||
|
import { BANGDREAM_SONG_CATALOG_KEYS } from '@/modules/qqbot/plugins/bangdream/src/operations/catalog-keys';
|
||||||
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
||||||
|
|
||||||
export const songRandomOperation: BangDreamOperationModule = {
|
export const songRandomOperation: BangDreamOperationModule = {
|
||||||
|
catalogKeys: BANGDREAM_SONG_CATALOG_KEYS,
|
||||||
handlerName: 'randomSong',
|
handlerName: 'randomSong',
|
||||||
execute: async (input, context) => {
|
execute: async (input, context) => {
|
||||||
const query = context.pickText(input);
|
const query = context.pickText(input);
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
import { Song } from '@/modules/qqbot/plugins/bangdream/src/domain/song/song.model';
|
import { Song } from '@/modules/qqbot/plugins/bangdream/src/domain/song/song.model';
|
||||||
import { drawSongDetail } from '@/modules/qqbot/plugins/bangdream/src/domain/song/song-detail.renderer';
|
import { drawSongDetail } from '@/modules/qqbot/plugins/bangdream/src/domain/song/song-detail.renderer';
|
||||||
import { drawSongList } from '@/modules/qqbot/plugins/bangdream/src/domain/song/song-search.renderer';
|
import { drawSongList } from '@/modules/qqbot/plugins/bangdream/src/domain/song/song-search.renderer';
|
||||||
|
import { BANGDREAM_SONG_SEARCH_CATALOG_KEYS } from '@/modules/qqbot/plugins/bangdream/src/operations/catalog-keys';
|
||||||
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
import type { BangDreamOperationModule } from '@/modules/qqbot/plugins/bangdream/src/operations/operation';
|
||||||
|
|
||||||
export const songSearchOperation: BangDreamOperationModule = {
|
export const songSearchOperation: BangDreamOperationModule = {
|
||||||
|
catalogKeys: BANGDREAM_SONG_SEARCH_CATALOG_KEYS,
|
||||||
handlerName: 'searchSong',
|
handlerName: 'searchSong',
|
||||||
execute: async (input, context) => {
|
execute: async (input, context) => {
|
||||||
const query = context.requireText(input, '请提供歌曲名或歌曲 ID');
|
const query = context.requireText(input, '请提供歌曲名或歌曲 ID');
|
||||||
|
|||||||
@ -0,0 +1,129 @@
|
|||||||
|
import { getBangDreamOperationsByHandlerName } from '@/modules/qqbot/plugins/bangdream/src/operations';
|
||||||
|
|
||||||
|
describe('BangDream operation catalog keys', () => {
|
||||||
|
it('declares the catalog keys required by each operation', () => {
|
||||||
|
const operations = getBangDreamOperationsByHandlerName();
|
||||||
|
|
||||||
|
expectCatalogKeys(operations.get('searchSong')?.catalogKeys, [
|
||||||
|
'songs',
|
||||||
|
'meta',
|
||||||
|
'singer',
|
||||||
|
'bands',
|
||||||
|
'characters',
|
||||||
|
'events',
|
||||||
|
]);
|
||||||
|
expectCatalogKeys(operations.get('getSongChart')?.catalogKeys, [
|
||||||
|
'songs',
|
||||||
|
'meta',
|
||||||
|
'singer',
|
||||||
|
'bands',
|
||||||
|
'characters',
|
||||||
|
]);
|
||||||
|
expectCatalogKeys(operations.get('randomSong')?.catalogKeys, [
|
||||||
|
'songs',
|
||||||
|
'meta',
|
||||||
|
'singer',
|
||||||
|
'bands',
|
||||||
|
'characters',
|
||||||
|
]);
|
||||||
|
expectCatalogKeys(operations.get('getSongMeta')?.catalogKeys, [
|
||||||
|
'songs',
|
||||||
|
'meta',
|
||||||
|
'singer',
|
||||||
|
'bands',
|
||||||
|
'characters',
|
||||||
|
]);
|
||||||
|
expectCatalogKeys(operations.get('searchCard')?.catalogKeys, [
|
||||||
|
'cards',
|
||||||
|
'skills',
|
||||||
|
'characters',
|
||||||
|
'singer',
|
||||||
|
'bands',
|
||||||
|
'events',
|
||||||
|
'gacha',
|
||||||
|
'costumes',
|
||||||
|
]);
|
||||||
|
expectCatalogKeys(operations.get('getCardIllustration')?.catalogKeys, [
|
||||||
|
'cards',
|
||||||
|
'skills',
|
||||||
|
'characters',
|
||||||
|
]);
|
||||||
|
expectCatalogKeys(operations.get('searchCharacter')?.catalogKeys, [
|
||||||
|
'characters',
|
||||||
|
'singer',
|
||||||
|
'bands',
|
||||||
|
]);
|
||||||
|
expectCatalogKeys(operations.get('searchEvent')?.catalogKeys, [
|
||||||
|
'events',
|
||||||
|
'characters',
|
||||||
|
'singer',
|
||||||
|
'bands',
|
||||||
|
'cards',
|
||||||
|
'skills',
|
||||||
|
'gacha',
|
||||||
|
'songs',
|
||||||
|
'meta',
|
||||||
|
'degrees',
|
||||||
|
'deco',
|
||||||
|
]);
|
||||||
|
expectCatalogKeys(operations.get('getEventStage')?.catalogKeys, [
|
||||||
|
'events',
|
||||||
|
'characters',
|
||||||
|
'songs',
|
||||||
|
'meta',
|
||||||
|
]);
|
||||||
|
expectCatalogKeys(operations.get('searchPlayer')?.catalogKeys, [
|
||||||
|
'cards',
|
||||||
|
'skills',
|
||||||
|
'characters',
|
||||||
|
'singer',
|
||||||
|
'bands',
|
||||||
|
'degrees',
|
||||||
|
'areaItems',
|
||||||
|
]);
|
||||||
|
expectCatalogKeys(operations.get('searchGacha')?.catalogKeys, [
|
||||||
|
'gacha',
|
||||||
|
'cards',
|
||||||
|
'skills',
|
||||||
|
'characters',
|
||||||
|
'singer',
|
||||||
|
'bands',
|
||||||
|
'events',
|
||||||
|
'items',
|
||||||
|
]);
|
||||||
|
expectCatalogKeys(operations.get('simulateGacha')?.catalogKeys, [
|
||||||
|
'gacha',
|
||||||
|
'cards',
|
||||||
|
'skills',
|
||||||
|
'characters',
|
||||||
|
'singer',
|
||||||
|
'bands',
|
||||||
|
]);
|
||||||
|
expectCatalogKeys(operations.get('getCutoffDetail')?.catalogKeys, [
|
||||||
|
'events',
|
||||||
|
'characters',
|
||||||
|
'rates',
|
||||||
|
'cards',
|
||||||
|
'skills',
|
||||||
|
'singer',
|
||||||
|
'bands',
|
||||||
|
'degrees',
|
||||||
|
]);
|
||||||
|
expectCatalogKeys(operations.get('getCutoffAll')?.catalogKeys, [
|
||||||
|
'events',
|
||||||
|
'characters',
|
||||||
|
'rates',
|
||||||
|
]);
|
||||||
|
expectCatalogKeys(operations.get('getCutoffRecent')?.catalogKeys, [
|
||||||
|
'events',
|
||||||
|
'characters',
|
||||||
|
'rates',
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(operations.size).toBe(15);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function expectCatalogKeys(actual: readonly string[] | undefined, keys: string[]) {
|
||||||
|
expect(actual).toEqual(keys);
|
||||||
|
}
|
||||||
@ -51,6 +51,17 @@ jest.mock('@/modules/qqbot/plugins/bangdream/src/operations', () => ({
|
|||||||
return [
|
return [
|
||||||
handlerName,
|
handlerName,
|
||||||
{
|
{
|
||||||
|
catalogKeys:
|
||||||
|
key === 'bangdream.song.search'
|
||||||
|
? [
|
||||||
|
'songs',
|
||||||
|
'meta',
|
||||||
|
'singer',
|
||||||
|
'bands',
|
||||||
|
'characters',
|
||||||
|
'events',
|
||||||
|
]
|
||||||
|
: undefined,
|
||||||
execute,
|
execute,
|
||||||
handlerName,
|
handlerName,
|
||||||
},
|
},
|
||||||
@ -109,7 +120,14 @@ describe('BangDream package entry', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(mockContext.refreshDictionaryCache).toHaveBeenCalledTimes(1);
|
expect(mockContext.refreshDictionaryCache).toHaveBeenCalledTimes(1);
|
||||||
expect(waitForBangDreamCatalogReady).toHaveBeenCalledTimes(1);
|
expect(waitForBangDreamCatalogReady).toHaveBeenCalledWith([
|
||||||
|
'songs',
|
||||||
|
'meta',
|
||||||
|
'singer',
|
||||||
|
'bands',
|
||||||
|
'characters',
|
||||||
|
'events',
|
||||||
|
]);
|
||||||
expect(songSearch).toHaveBeenCalledWith(
|
expect(songSearch).toHaveBeenCalledWith(
|
||||||
{ text: '夏祭り' },
|
{ text: '夏祭り' },
|
||||||
mockContext,
|
mockContext,
|
||||||
|
|||||||
@ -0,0 +1,63 @@
|
|||||||
|
describe('BangDream catalog cache partial loading', () => {
|
||||||
|
it('loads only requested catalog keys and their matching static patches', async () => {
|
||||||
|
const getJson = jest.fn<
|
||||||
|
Promise<Record<string, { path: string }>>,
|
||||||
|
[string, { cacheTime?: number }?]
|
||||||
|
>(async (path) => ({
|
||||||
|
1: { path },
|
||||||
|
}));
|
||||||
|
const readJson = jest.fn(async () => ({}));
|
||||||
|
const readExcelRows = jest.fn(async () => []);
|
||||||
|
|
||||||
|
jest.resetModules();
|
||||||
|
jest.doMock(
|
||||||
|
'@/modules/qqbot/plugins/bangdream/src/infrastructure/integration/bestdori.provider',
|
||||||
|
() => ({
|
||||||
|
bangdreamBestdoriProvider: {
|
||||||
|
getJson,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
jest.doMock(
|
||||||
|
'@/modules/qqbot/plugins/bangdream/src/infrastructure/storage/static-patch.provider',
|
||||||
|
() => ({
|
||||||
|
bangdreamStaticPatchProvider: {
|
||||||
|
readExcelRows,
|
||||||
|
readJson,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
jest.doMock(
|
||||||
|
'@/modules/qqbot/plugins/bangdream/src/application/bangdream-logger',
|
||||||
|
() => ({
|
||||||
|
logger: jest.fn(),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
jest.doMock(
|
||||||
|
'@/modules/qqbot/plugins/bangdream/src/infrastructure/integration/runtime-io',
|
||||||
|
() => ({
|
||||||
|
readBangDreamRuntimeConfig: jest.fn(() => undefined),
|
||||||
|
sleepBangDreamRuntime: jest.fn(() => new Promise(() => undefined)),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const { BANGDREAM_BESTDORI_API_PATHS } = await import(
|
||||||
|
'@/modules/qqbot/plugins/bangdream/src/domain/common/bangdream-protocol'
|
||||||
|
);
|
||||||
|
const { waitForBangDreamCatalogReady } = await import(
|
||||||
|
'@/modules/qqbot/plugins/bangdream/src/application/catalog/bangdream-catalog-cache'
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitForBangDreamCatalogReady(['songs', 'meta']);
|
||||||
|
|
||||||
|
expect(getJson).toHaveBeenCalledTimes(2);
|
||||||
|
expect(getJson.mock.calls.map(([path]) => path).sort()).toEqual(
|
||||||
|
[
|
||||||
|
BANGDREAM_BESTDORI_API_PATHS.meta,
|
||||||
|
BANGDREAM_BESTDORI_API_PATHS.songs,
|
||||||
|
].sort(),
|
||||||
|
);
|
||||||
|
expect(readJson).not.toHaveBeenCalled();
|
||||||
|
expect(readExcelRows).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -51,9 +51,13 @@ describe('BangDream catalog cache', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('loads each Bestdori catalog path only once during the initial ready wait', async () => {
|
it('loads each Bestdori catalog path only once during the initial ready wait', async () => {
|
||||||
await waitForBangDreamCatalogReady!();
|
|
||||||
|
|
||||||
const catalogPaths = Object.values(BANGDREAM_BESTDORI_API_PATHS);
|
const catalogPaths = Object.values(BANGDREAM_BESTDORI_API_PATHS);
|
||||||
|
await waitForBangDreamCatalogReady(
|
||||||
|
Object.keys(BANGDREAM_BESTDORI_API_PATHS) as Array<
|
||||||
|
keyof typeof BANGDREAM_BESTDORI_API_PATHS
|
||||||
|
>,
|
||||||
|
);
|
||||||
|
|
||||||
expect(mockGetJson).toHaveBeenCalledTimes(catalogPaths.length);
|
expect(mockGetJson).toHaveBeenCalledTimes(catalogPaths.length);
|
||||||
expect(mockGetJson.mock.calls.map(([path]) => path).sort()).toEqual(
|
expect(mockGetJson.mock.calls.map(([path]) => path).sort()).toEqual(
|
||||||
[...catalogPaths].sort(),
|
[...catalogPaths].sort(),
|
||||||
@ -66,4 +70,5 @@ describe('BangDream catalog cache', () => {
|
|||||||
expect(mockReadJson).toHaveBeenCalledTimes(3);
|
expect(mockReadJson).toHaveBeenCalledTimes(3);
|
||||||
expect(mockReadExcelRows).toHaveBeenCalledTimes(1);
|
expect(mockReadExcelRows).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user