Merge branch 'main' into feature/command-argument-ui
This commit is contained in:
@@ -15,6 +15,18 @@ const zGeneralSettings = z.object({
|
||||
});
|
||||
|
||||
const zGeneralLogType = z.enum(['generalHistory', 'battleDetail', 'battleResult', 'generalAction']);
|
||||
const MAIN_RECORD_LIMIT = 15;
|
||||
|
||||
const trimRecentRecords = <Entry extends { id: number }>(entries: Entry[], cursor: number): Entry[] => {
|
||||
if (entries.length === 0) {
|
||||
return entries;
|
||||
}
|
||||
const result = [...entries];
|
||||
if (result.at(-1)?.id === cursor || result.length > MAIN_RECORD_LIMIT) {
|
||||
result.pop();
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
const readNumber = (value: unknown, fallback: number): number => {
|
||||
if (typeof value === 'number' && Number.isFinite(value)) {
|
||||
@@ -319,4 +331,54 @@ export const generalRouter = router({
|
||||
})),
|
||||
};
|
||||
}),
|
||||
getRecentRecords: authedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
lastGeneralRecordId: z.number().int().nonnegative().default(0),
|
||||
lastWorldHistoryId: z.number().int().nonnegative().default(0),
|
||||
})
|
||||
)
|
||||
.query(async ({ ctx, input }) => {
|
||||
const me = await getMyGeneral(ctx);
|
||||
const take = MAIN_RECORD_LIMIT + 1;
|
||||
const [global, general, history] = await Promise.all([
|
||||
ctx.db.logEntry.findMany({
|
||||
where: {
|
||||
scope: LogScope.SYSTEM,
|
||||
category: LogCategory.SUMMARY,
|
||||
id: { gte: input.lastGeneralRecordId },
|
||||
},
|
||||
orderBy: { id: 'desc' },
|
||||
take,
|
||||
select: { id: true, text: true },
|
||||
}),
|
||||
ctx.db.logEntry.findMany({
|
||||
where: {
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.ACTION,
|
||||
generalId: me.id,
|
||||
id: { gte: input.lastGeneralRecordId },
|
||||
},
|
||||
orderBy: { id: 'desc' },
|
||||
take,
|
||||
select: { id: true, text: true },
|
||||
}),
|
||||
ctx.db.logEntry.findMany({
|
||||
where: {
|
||||
scope: LogScope.SYSTEM,
|
||||
category: LogCategory.HISTORY,
|
||||
id: { gte: input.lastWorldHistoryId },
|
||||
},
|
||||
orderBy: { id: 'desc' },
|
||||
take,
|
||||
select: { id: true, text: true },
|
||||
}),
|
||||
]);
|
||||
|
||||
return {
|
||||
global: trimRecentRecords(global, input.lastGeneralRecordId),
|
||||
general: trimRecentRecords(general, input.lastGeneralRecordId),
|
||||
history: trimRecentRecords(history, input.lastWorldHistoryId),
|
||||
};
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { TRPCError } from '@trpc/server';
|
||||
import { asRecord } from '@sammo-ts/common';
|
||||
import { LogCategory, LogScope } from '@sammo-ts/infra';
|
||||
import { z } from 'zod';
|
||||
|
||||
import type { GameApiContext } from '../../context.js';
|
||||
@@ -241,14 +242,45 @@ export const publicRouter = router({
|
||||
return loadMapLayout(ctx.profile.scenario);
|
||||
}),
|
||||
getCachedMap: procedure.query(async ({ ctx }) => {
|
||||
const map = await loadPublicMap(ctx, true);
|
||||
const cacheKey = buildPublicCacheKey(ctx, 'cachedMapWithHistory');
|
||||
const cached = await ctx.redis.get(cacheKey);
|
||||
if (cached) {
|
||||
try {
|
||||
return JSON.parse(cached) as NonNullable<Awaited<ReturnType<typeof loadPublicMap>>> & {
|
||||
history: { id: number; text: string }[];
|
||||
};
|
||||
} catch {
|
||||
// Ignore cache parse errors.
|
||||
}
|
||||
}
|
||||
|
||||
const [map, history] = await Promise.all([
|
||||
loadPublicMap(ctx, true),
|
||||
ctx.db.logEntry.findMany({
|
||||
where: {
|
||||
scope: LogScope.SYSTEM,
|
||||
category: LogCategory.HISTORY,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
text: true,
|
||||
},
|
||||
orderBy: { id: 'desc' },
|
||||
take: 10,
|
||||
}),
|
||||
]);
|
||||
if (!map) {
|
||||
throw new TRPCError({
|
||||
code: 'PRECONDITION_FAILED',
|
||||
message: 'World state is not initialized.',
|
||||
});
|
||||
}
|
||||
return map;
|
||||
const snapshot = {
|
||||
...map,
|
||||
history,
|
||||
};
|
||||
await ctx.redis.set(cacheKey, JSON.stringify(snapshot), { EX: PUBLIC_CACHE_TTL_SECONDS });
|
||||
return snapshot;
|
||||
}),
|
||||
getWorldTrend: procedure.query(async ({ ctx }) => {
|
||||
return loadCachedWorldTrend(ctx);
|
||||
|
||||
Reference in New Issue
Block a user