This commit is contained in:
syuilo
2024-01-18 20:59:21 +09:00
parent 58f4d5d790
commit 1259fabd7f
21 changed files with 1297 additions and 55 deletions

View File

@@ -162,7 +162,7 @@ export interface AdminEventTypes {
export interface ReversiEventTypes {
matched: {
game: Packed<'ReversiGame'>;
game: Packed<'ReversiGameDetailed'>;
};
invited: {
game: Packed<'ReversiMatching'>;
@@ -180,18 +180,21 @@ export interface ReversiGameEventTypes {
key: string;
value: any;
};
putStone: {
pos: number;
};
putStone: {
at: Date;
color: boolean;
pos: number;
next: boolean;
};
syncState: {
crc32: string;
};
started: {
game: Packed<'ReversiGame'>;
game: Packed<'ReversiGameDetailed'>;
};
ended: {
winnerId: MiUser['id'] | null;
game: Packed<'ReversiGame'>;
game: Packed<'ReversiGameDetailed'>;
};
}
//#endregion

View File

@@ -86,7 +86,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
isLlotheo: false,
}).then(x => this.reversiGamesRepository.findOneByOrFail(x.identifiers[0]));
const packed = await this.reversiGameEntityService.pack(game, { id: exist.parentId });
const packed = await this.reversiGameEntityService.packDetail(game, { id: exist.parentId });
this.globalEventService.publishReversiStream(exist.parentId, 'matched', { game: packed });
return game;
@@ -202,13 +202,13 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
this.globalEventService.publishReversiGameStream(game.id, 'ended', {
winnerId: winner,
game: await this.reversiGameEntityService.pack(game.id, user),
game: await this.reversiGameEntityService.packDetail(game.id, user),
});
}
//#endregion
this.globalEventService.publishReversiGameStream(game.id, 'started', {
game: await this.reversiGameEntityService.pack(game.id, user),
game: await this.reversiGameEntityService.packDetail(game.id, user),
});
}, 3000);
}
@@ -288,14 +288,14 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
logs: game.logs,
});
this.globalEventService.publishReversiGameStream(game.id, 'set', Object.assign(log, {
this.globalEventService.publishReversiGameStream(game.id, 'putStone', Object.assign(log, {
next: o.turn,
}));
if (o.isEnded) {
this.globalEventService.publishReversiGameStream(game.id, 'ended', {
winnerId: winner,
game: await this.reversiGameEntityService.pack(game.id, user),
game: await this.reversiGameEntityService.packDetail(game.id, user),
});
}
}
@@ -315,7 +315,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
this.globalEventService.publishReversiGameStream(game.id, 'ended', {
winnerId: winnerId,
game: await this.reversiGameEntityService.pack(game.id, user),
game: await this.reversiGameEntityService.packDetail(game.id, user),
});
}

View File

@@ -27,14 +27,10 @@ export class ReversiGameEntityService {
}
@bindThis
public async pack(
public async packDetail(
src: MiReversiGame['id'] | MiReversiGame,
me?: { id: MiUser['id'] } | null | undefined,
options?: {
detail?: boolean;
skipHide?: boolean;
},
): Promise<Packed<'ReversiGame'>> {
): Promise<Packed<'ReversiGameDetailed'>> {
const game = typeof src === 'object' ? src : await this.reversiGamesRepository.findOneByOrFail({ id: src });
return await awaitAll({
@@ -59,23 +55,61 @@ export class ReversiGameEntityService {
isLlotheo: game.isLlotheo,
canPutEverywhere: game.canPutEverywhere,
loopedBoard: game.loopedBoard,
...(options?.detail ? {
logs: game.logs.map(log => ({
at: log.at.toISOString(),
color: log.color,
pos: log.pos,
})),
map: game.map,
} : {}),
logs: game.logs.map(log => ({
at: log.at.toISOString(),
color: log.color,
pos: log.pos,
})),
map: game.map,
});
}
@bindThis
public packMany(
public packDetailMany(
xs: MiReversiGame[],
me?: { id: MiUser['id'] } | null | undefined,
) {
return Promise.all(xs.map(x => this.pack(x, me)));
return Promise.all(xs.map(x => this.packDetail(x, me)));
}
@bindThis
public async packLite(
src: MiReversiGame['id'] | MiReversiGame,
me?: { id: MiUser['id'] } | null | undefined,
): Promise<Packed<'ReversiGameLite'>> {
const game = typeof src === 'object' ? src : await this.reversiGamesRepository.findOneByOrFail({ id: src });
return await awaitAll({
id: game.id,
createdAt: this.idService.parse(game.id).date.toISOString(),
startedAt: game.startedAt && game.startedAt.toISOString(),
isStarted: game.isStarted,
isEnded: game.isEnded,
form1: game.form1,
form2: game.form2,
user1Accepted: game.user1Accepted,
user2Accepted: game.user2Accepted,
user1Id: game.user1Id,
user2Id: game.user2Id,
user1: this.userEntityService.pack(game.user1Id, me),
user2: this.userEntityService.pack(game.user2Id, me),
winnerId: game.winnerId,
winner: game.winnerId ? this.userEntityService.pack(game.winnerId, me) : null,
surrendered: game.surrendered,
black: game.black,
bw: game.bw,
isLlotheo: game.isLlotheo,
canPutEverywhere: game.canPutEverywhere,
loopedBoard: game.loopedBoard,
});
}
@bindThis
public packLiteMany(
xs: MiReversiGame[],
me?: { id: MiUser['id'] } | null | undefined,
) {
return Promise.all(xs.map(x => this.packLite(x, me)));
}
}

View File

@@ -39,7 +39,7 @@ import { packedAnnouncementSchema } from '@/models/json-schema/announcement.js';
import { packedSigninSchema } from '@/models/json-schema/signin.js';
import { packedRoleLiteSchema, packedRoleSchema } from '@/models/json-schema/role.js';
import { packedAdSchema } from '@/models/json-schema/ad.js';
import { packedReversiGameSchema } from '@/models/json-schema/reversi-game.js';
import { packedReversiGameLiteSchema, packedReversiGameDetailedSchema } from '@/models/json-schema/reversi-game.js';
import { packedReversiMatchingSchema } from '@/models/json-schema/reversi-matching.js';
export const refs = {
@@ -80,7 +80,8 @@ export const refs = {
Signin: packedSigninSchema,
RoleLite: packedRoleLiteSchema,
Role: packedRoleSchema,
ReversiGame: packedReversiGameSchema,
ReversiGameLite: packedReversiGameLiteSchema,
ReversiGameDetailed: packedReversiGameDetailedSchema,
ReversiMatching: packedReversiMatchingSchema,
};

View File

@@ -3,7 +3,107 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
export const packedReversiGameSchema = {
export const packedReversiGameLiteSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
startedAt: {
type: 'string',
optional: false, nullable: true,
format: 'date-time',
},
isStarted: {
type: 'boolean',
optional: false, nullable: false,
},
isEnded: {
type: 'boolean',
optional: false, nullable: false,
},
form1: {
type: 'any',
optional: false, nullable: true,
},
form2: {
type: 'any',
optional: false, nullable: true,
},
user1Accepted: {
type: 'boolean',
optional: false, nullable: false,
},
user2Accepted: {
type: 'boolean',
optional: false, nullable: false,
},
user1Id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
user2Id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
user1: {
type: 'object',
optional: false, nullable: false,
ref: 'User',
},
user2: {
type: 'object',
optional: false, nullable: false,
ref: 'User',
},
winnerId: {
type: 'string',
optional: false, nullable: true,
format: 'id',
},
winner: {
type: 'object',
optional: false, nullable: true,
ref: 'User',
},
surrendered: {
type: 'string',
optional: false, nullable: true,
format: 'id',
},
black: {
type: 'number',
optional: false, nullable: true,
},
bw: {
type: 'string',
optional: false, nullable: false,
},
isLlotheo: {
type: 'boolean',
optional: false, nullable: false,
},
canPutEverywhere: {
type: 'boolean',
optional: false, nullable: false,
},
loopedBoard: {
type: 'boolean',
optional: false, nullable: false,
},
},
} as const;
export const packedReversiGameDetailedSchema = {
type: 'object',
properties: {
id: {
@@ -102,10 +202,10 @@ export const packedReversiGameSchema = {
},
logs: {
type: 'array',
optional: true, nullable: false,
optional: false, nullable: false,
items: {
type: 'object',
optional: true, nullable: false,
optional: false, nullable: false,
properties: {
at: {
type: 'string',
@@ -125,7 +225,7 @@ export const packedReversiGameSchema = {
},
map: {
type: 'array',
optional: true, nullable: false,
optional: false, nullable: false,
items: {
type: 'string',
optional: false, nullable: false,

View File

@@ -17,7 +17,7 @@ export const meta = {
res: {
type: 'array',
optional: false, nullable: false,
items: { ref: 'ReversiGame' },
items: { ref: 'ReversiGameLite' },
},
} as const;
@@ -55,7 +55,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const games = await query.take(ps.limit).getMany();
return await this.reversiGameEntityService.packMany(games, me);
return await this.reversiGameEntityService.packLiteMany(games, me);
});
}
}

View File

@@ -60,7 +60,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
if (game == null) return;
return await this.reversiGameEntityService.pack(game, me);
return await this.reversiGameEntityService.packDetail(game, me);
});
}
}

View File

@@ -23,7 +23,7 @@ export const meta = {
res: {
type: 'object',
optional: false, nullable: false,
ref: 'ReversiGame',
ref: 'ReversiGameDetailed',
},
} as const;
@@ -48,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.noSuchGame);
}
return await this.reversiGameEntityService.pack(game, me);
return await this.reversiGameEntityService.packDetail(game, me);
});
}
}

View File

@@ -92,7 +92,7 @@ class ReversiGameChannel extends Channel {
if (!game.isStarted) return;
if (crc32.toString() !== game.crc32) {
this.send('rescue', await this.reversiGameEntityService.pack(game, this.user));
this.send('rescue', await this.reversiGameEntityService.packDetail(game, this.user));
}
}