merge: 자동 갱신 접속 벌점 제외를 반영
This commit is contained in:
@@ -6,7 +6,6 @@ import { asRecord } from '@sammo-ts/common';
|
|||||||
|
|
||||||
import type { GameApiContext } from '../../context.js';
|
import type { GameApiContext } from '../../context.js';
|
||||||
import {
|
import {
|
||||||
accessAuthedProcedure,
|
|
||||||
accessEngineAuthedProcedure,
|
accessEngineAuthedProcedure,
|
||||||
accessEngineAuthedInputProcedure,
|
accessEngineAuthedInputProcedure,
|
||||||
accessLimitAuthedProcedure,
|
accessLimitAuthedProcedure,
|
||||||
@@ -790,7 +789,10 @@ export const generalRouter = router({
|
|||||||
history: trimRecentRecords(history, input.lastWorldHistoryId),
|
history: trimRecentRecords(history, input.lastWorldHistoryId),
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
getFrontStatus: accessAuthedProcedure.query(async ({ ctx }) => {
|
// 메인 화면은 SSE invalidation, 탭 복귀와 직접 갱신이 같은 read model을
|
||||||
|
// 호출한다. 클라이언트가 주장하는 갱신 원인을 신뢰해 구분하지 않고 이
|
||||||
|
// projection 전체를 무가점으로 두되, 이미 제한된 사용자의 gate는 유지한다.
|
||||||
|
getFrontStatus: accessLimitAuthedProcedure.query(async ({ ctx }) => {
|
||||||
const me = await getMyGeneral(ctx);
|
const me = await getMyGeneral(ctx);
|
||||||
const worldState = await ctx.db.worldState.findFirst({
|
const worldState = await ctx.db.worldState.findFirst({
|
||||||
orderBy: { id: 'asc' },
|
orderBy: { id: 'asc' },
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ export const generalAccessEndpointWeights = {
|
|||||||
'diplomacy.getLetters': 2,
|
'diplomacy.getLetters': 2,
|
||||||
'battle.getGeneralDetail': 1,
|
'battle.getGeneralDetail': 1,
|
||||||
'betting.getList': 1,
|
'betting.getList': 1,
|
||||||
'general.getFrontStatus': 1,
|
|
||||||
'yearbook.getHistory': 1,
|
'yearbook.getHistory': 1,
|
||||||
'world.getGlobalInfo': 1,
|
'world.getGlobalInfo': 1,
|
||||||
'nation.getBattleCenter': 1,
|
'nation.getBattleCenter': 1,
|
||||||
@@ -85,14 +84,11 @@ export const generalAccessLimitEndpoints = new Set<GeneralAccessEndpoint>([
|
|||||||
'diplomacy.rollbackLetter',
|
'diplomacy.rollbackLetter',
|
||||||
'diplomacy.destroyLetter',
|
'diplomacy.destroyLetter',
|
||||||
'betting.getList',
|
'betting.getList',
|
||||||
'general.getFrontStatus',
|
|
||||||
'yearbook.getHistory',
|
'yearbook.getHistory',
|
||||||
'messages.send',
|
'messages.send',
|
||||||
'turns.getCommandTable',
|
'turns.getCommandTable',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const generalAccessLimitBeforeRecordEndpoints = new Set<GeneralAccessEndpoint>(['general.getFrontStatus']);
|
|
||||||
|
|
||||||
export type GeneralAccessState = {
|
export type GeneralAccessState = {
|
||||||
generalId: number;
|
generalId: number;
|
||||||
refreshScore: number;
|
refreshScore: number;
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import { IdempotentTurnDaemonTransport } from './daemon/idempotentTransport.js';
|
|||||||
import { DuplicateInputEventError, executeInputEvent } from './inputEventBoundary.js';
|
import { DuplicateInputEventError, executeInputEvent } from './inputEventBoundary.js';
|
||||||
import {
|
import {
|
||||||
formatGeneralAccessLimitMessage,
|
formatGeneralAccessLimitMessage,
|
||||||
generalAccessLimitBeforeRecordEndpoints,
|
|
||||||
generalAccessLimitEndpoints,
|
generalAccessLimitEndpoints,
|
||||||
getGeneralAccessState,
|
getGeneralAccessState,
|
||||||
recordGeneralAccessWeight,
|
recordGeneralAccessWeight,
|
||||||
@@ -103,17 +102,8 @@ const generalAccessEndpointMiddleware = t.middleware(async ({ ctx, path, input,
|
|||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
const endpoint = path as GeneralAccessEndpoint;
|
const endpoint = path as GeneralAccessEndpoint;
|
||||||
if (generalAccessLimitBeforeRecordEndpoints.has(endpoint)) {
|
|
||||||
const state = await getGeneralAccessState(ctx);
|
|
||||||
if (state?.level === 2) {
|
|
||||||
throw new TRPCError({
|
|
||||||
code: 'TOO_MANY_REQUESTS',
|
|
||||||
message: formatGeneralAccessLimitMessage(state),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await recordGeneralAccessWeight(ctx, weight);
|
await recordGeneralAccessWeight(ctx, weight);
|
||||||
if (generalAccessLimitEndpoints.has(endpoint) && !generalAccessLimitBeforeRecordEndpoints.has(endpoint)) {
|
if (generalAccessLimitEndpoints.has(endpoint)) {
|
||||||
const state = await getGeneralAccessState(ctx);
|
const state = await getGeneralAccessState(ctx);
|
||||||
if (state?.level === 2) {
|
if (state?.level === 2) {
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
|
|||||||
@@ -383,6 +383,10 @@ integration('general access tracking persistence', () => {
|
|||||||
} as unknown as GameApiContext;
|
} as unknown as GameApiContext;
|
||||||
const boundaryCaller = endpointBoundaryRouter.createCaller(context);
|
const boundaryCaller = endpointBoundaryRouter.createCaller(context);
|
||||||
|
|
||||||
|
const dashboardCaller = appRouter.createCaller(context);
|
||||||
|
await expect(dashboardCaller.general.getFrontStatus()).resolves.toBeDefined();
|
||||||
|
await expect(db.generalAccessLog.findUnique({ where: { generalId: endpointGeneralId } })).resolves.toBeNull();
|
||||||
|
|
||||||
await expect(boundaryCaller.world.getGeneralDirectory({ accepted: false as true })).rejects.toMatchObject({
|
await expect(boundaryCaller.world.getGeneralDirectory({ accepted: false as true })).rejects.toMatchObject({
|
||||||
code: 'BAD_REQUEST',
|
code: 'BAD_REQUEST',
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -101,7 +101,6 @@ describe('general access tracking', () => {
|
|||||||
'diplomacy.getLetters': 2,
|
'diplomacy.getLetters': 2,
|
||||||
'battle.getGeneralDetail': 1,
|
'battle.getGeneralDetail': 1,
|
||||||
'betting.getList': 1,
|
'betting.getList': 1,
|
||||||
'general.getFrontStatus': 1,
|
|
||||||
'yearbook.getHistory': 1,
|
'yearbook.getHistory': 1,
|
||||||
'world.getGlobalInfo': 1,
|
'world.getGlobalInfo': 1,
|
||||||
'nation.getBattleCenter': 1,
|
'nation.getBattleCenter': 1,
|
||||||
@@ -130,6 +129,7 @@ describe('general access tracking', () => {
|
|||||||
expect(resolveGeneralAccessEndpointWeight('yearbook.getHistory', {}, 'che')).toBe(1);
|
expect(resolveGeneralAccessEndpointWeight('yearbook.getHistory', {}, 'che')).toBe(1);
|
||||||
expect(resolveGeneralAccessEndpointWeight('yearbook.getHistory', { serverID: 'che' }, 'che')).toBe(1);
|
expect(resolveGeneralAccessEndpointWeight('yearbook.getHistory', { serverID: 'che' }, 'che')).toBe(1);
|
||||||
expect(resolveGeneralAccessEndpointWeight('yearbook.getHistory', { serverID: 'hwe' }, 'che')).toBeNull();
|
expect(resolveGeneralAccessEndpointWeight('yearbook.getHistory', { serverID: 'hwe' }, 'che')).toBeNull();
|
||||||
|
expect(resolveGeneralAccessEndpointWeight('general.getFrontStatus', {}, 'che')).toBeUndefined();
|
||||||
expect(resolveGeneralAccessEndpointWeight('unknown.path', {}, 'che')).toBeUndefined();
|
expect(resolveGeneralAccessEndpointWeight('unknown.path', {}, 'che')).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user