- Introduced InputEvent model with status tracking (PENDING, PROCESSING, SUCCEEDED, FAILED) and unique request IDs. - Added DatabaseTurnDaemonTransport for sending commands and handling idempotency. - Implemented executeInputEvent function to manage input event lifecycle and error handling. - Created DatabaseTurnDaemonCommandQueue for managing command processing and lease recovery. - Enhanced turn daemon lifecycle to support atomic command execution and error recovery. - Added tests for input event atomicity, command queuing, and error handling scenarios.
110 lines
3.8 KiB
TypeScript
110 lines
3.8 KiB
TypeScript
import { z } from 'zod';
|
|
import type { GameSessionTokenPayload } from '@sammo-ts/common/auth/gameToken';
|
|
import type { DatabaseClient as InfraDatabaseClient, RedisConnector, GamePrisma } from '@sammo-ts/infra';
|
|
|
|
import type { TurnDaemonTransport } from './daemon/transport.js';
|
|
import type { BattleSimTransport } from './battleSim/transport.js';
|
|
import type { FlushStore } from './auth/flushStore.js';
|
|
import type { RedisAccessTokenStore } from './auth/accessTokenStore.js';
|
|
|
|
export interface GameProfile {
|
|
id: string;
|
|
scenario: string;
|
|
name: string;
|
|
}
|
|
|
|
export const zWorldStateConfig = z.object({
|
|
maxUserCnt: z.number().optional(),
|
|
fictionMode: z.string().optional(),
|
|
fiction: z.number().optional(),
|
|
joinMode: z.string().optional(),
|
|
blockGeneralCreate: z.number().optional(),
|
|
npcMode: z.number().optional(),
|
|
showImgLevel: z.number().optional(),
|
|
tournamentTrig: z.boolean().optional(),
|
|
extendedGeneral: z.boolean().optional(),
|
|
turnTermMinutes: z.number().optional(),
|
|
syncTurnTime: z.boolean().optional(),
|
|
});
|
|
export type WorldStateConfig = z.infer<typeof zWorldStateConfig>;
|
|
|
|
export const zWorldStateMeta = z.object({
|
|
starttime: z.string().optional(),
|
|
opentime: z.string().optional(),
|
|
preopenAt: z.string().optional(),
|
|
turntime: z.string().optional(),
|
|
otherTextInfo: z.string().optional(),
|
|
isUnited: z.number().optional(),
|
|
autorun_user: z
|
|
.object({
|
|
limit_minutes: z.number().optional(),
|
|
options: z.record(z.string(), z.boolean()).optional(),
|
|
})
|
|
.nullable()
|
|
.optional(),
|
|
});
|
|
export type WorldStateMeta = z.infer<typeof zWorldStateMeta>;
|
|
|
|
export type WorldStateRow = GamePrisma.WorldStateGetPayload<Record<string, never>>;
|
|
export type GeneralRow = GamePrisma.GeneralGetPayload<Record<string, never>>;
|
|
export type GeneralTurnRow = GamePrisma.GeneralTurnGetPayload<Record<string, never>>;
|
|
export type NationTurnRow = GamePrisma.NationTurnGetPayload<Record<string, never>>;
|
|
export type CityRow = GamePrisma.CityGetPayload<Record<string, never>>;
|
|
export type NationRow = GamePrisma.NationGetPayload<Record<string, never>>;
|
|
export type TroopRow = GamePrisma.TroopGetPayload<Record<string, never>>;
|
|
|
|
export type JsonValue = GamePrisma.JsonValue;
|
|
export type JsonObject = GamePrisma.JsonObject;
|
|
export type JsonArray = GamePrisma.JsonArray;
|
|
export type InputJsonValue = GamePrisma.InputJsonValue;
|
|
|
|
export type DatabaseClient = InfraDatabaseClient;
|
|
|
|
export interface GameApiContext {
|
|
requestId?: string;
|
|
db: DatabaseClient;
|
|
redis: RedisConnector['client'];
|
|
turnDaemon: TurnDaemonTransport;
|
|
battleSim: BattleSimTransport;
|
|
profile: GameProfile;
|
|
uploadDir: string;
|
|
uploadPath: string;
|
|
uploadPublicUrl: string | null;
|
|
auth: GameSessionTokenPayload | null;
|
|
accessTokenStore: RedisAccessTokenStore;
|
|
flushStore: FlushStore;
|
|
gameTokenSecret: string;
|
|
}
|
|
|
|
export const createGameApiContext = (options: {
|
|
requestId?: string;
|
|
db: DatabaseClient;
|
|
redis: RedisConnector['client'];
|
|
turnDaemon: TurnDaemonTransport;
|
|
battleSim: BattleSimTransport;
|
|
profile: GameProfile;
|
|
uploadDir: string;
|
|
uploadPath: string;
|
|
uploadPublicUrl: string | null;
|
|
auth: GameSessionTokenPayload | null;
|
|
accessTokenStore: RedisAccessTokenStore;
|
|
flushStore: FlushStore;
|
|
gameTokenSecret: string;
|
|
}): GameApiContext => {
|
|
return {
|
|
requestId: options.requestId,
|
|
db: options.db,
|
|
redis: options.redis,
|
|
turnDaemon: options.turnDaemon,
|
|
battleSim: options.battleSim,
|
|
profile: options.profile,
|
|
uploadDir: options.uploadDir,
|
|
uploadPath: options.uploadPath,
|
|
uploadPublicUrl: options.uploadPublicUrl,
|
|
auth: options.auth,
|
|
accessTokenStore: options.accessTokenStore,
|
|
flushStore: options.flushStore,
|
|
gameTokenSecret: options.gameTokenSecret,
|
|
};
|
|
};
|