fix: 갱신 비용에 따라 접속 점수를 기록
revision 확인과 서버 event 기반 선택 갱신은 무가점으로 두고 PostgreSQL projection을 다시 만드는 초기·수동·복구 갱신만 1점을 기록한다. 인증 범위에 묶인 1회용 realtime 증표와 회귀 검증을 추가한다.
This commit is contained in:
@@ -4,7 +4,7 @@ import fastifyStatic from '@fastify/static';
|
||||
import path from 'path';
|
||||
import fs from 'node:fs/promises';
|
||||
import { fastifyTRPCPlugin } from '@trpc/server/adapters/fastify';
|
||||
import { buildGameEventChannel, type RealtimeViewerIdentity } from '@sammo-ts/common';
|
||||
import { buildGameEventChannel, REALTIME_ACCESS_GRANT_HEADER, type RealtimeViewerIdentity } from '@sammo-ts/common';
|
||||
import type { GameSessionTokenPayload } from '@sammo-ts/common/auth/gameToken';
|
||||
import {
|
||||
createGamePostgresConnector,
|
||||
@@ -18,6 +18,11 @@ import { createGameApiContext, type DatabaseClient as _DatabaseClient } from './
|
||||
import { DatabaseTurnDaemonTransport } from './daemon/databaseTransport.js';
|
||||
import { InMemoryFlushStore, RedisGatewayFlushSubscriber, type FlushStore } from './auth/flushStore.js';
|
||||
import { RedisAccessTokenStore } from './auth/accessTokenStore.js';
|
||||
import {
|
||||
consumeRealtimeAccessGrantHeader,
|
||||
createRealtimeAccessGrant,
|
||||
registerRealtimeAccessGrant,
|
||||
} from './auth/realtimeAccessGrant.js';
|
||||
import { appRouter } from './router.js';
|
||||
import { buildBattleSimQueueKeys } from './battleSim/keys.js';
|
||||
import { RedisBattleSimTransport } from './battleSim/redisTransport.js';
|
||||
@@ -222,6 +227,13 @@ export const createGameApiServer = async () => {
|
||||
uploadPublicUrl: config.uploadPublicUrl,
|
||||
contentImageUpload,
|
||||
auth,
|
||||
realtimeAccessGranted: await consumeRealtimeAccessGrantHeader(
|
||||
redis.client,
|
||||
req.headers[REALTIME_ACCESS_GRANT_HEADER],
|
||||
auth,
|
||||
config.profileName,
|
||||
config.gameTokenSecret
|
||||
),
|
||||
...(auth && token ? { accessToken: token } : {}),
|
||||
accessTokenStore,
|
||||
flushStore,
|
||||
@@ -299,8 +311,20 @@ export const createGameApiServer = async () => {
|
||||
identities.push(nextIdentity);
|
||||
viewerIdentity = nextIdentity;
|
||||
}
|
||||
const publicEvent = toPublicRealtimeEvent(event, identities);
|
||||
let refreshGrant: string | undefined;
|
||||
const publicEvent = toPublicRealtimeEvent(event, identities, () => {
|
||||
refreshGrant ??= createRealtimeAccessGrant(auth, config.profileName, config.gameTokenSecret);
|
||||
return refreshGrant;
|
||||
});
|
||||
if (!publicEvent || closed) return;
|
||||
if (refreshGrant) {
|
||||
try {
|
||||
await registerRealtimeAccessGrant(redis.client, refreshGrant, config.profileName);
|
||||
} catch {
|
||||
// Preserve the invalidation. An unregistered grant safely falls back
|
||||
// to the normal scored refresh path.
|
||||
}
|
||||
}
|
||||
sendFrame(
|
||||
formatSseFrame({
|
||||
event: publicEvent.type,
|
||||
|
||||
Reference in New Issue
Block a user