summaryrefslogtreecommitdiff
path: root/packages/backend/src
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2024-01-22 15:41:29 +0900
committersyuilo <Syuilotan@yahoo.co.jp>2024-01-22 15:41:29 +0900
commit94e282b612ad3dc6fd336a82fff19b290e11d221 (patch)
tree2228600fea7aa80ad61cc03c762f17eb02fcd10a /packages/backend/src
parentenhance(reversi): some tweaks (diff)
downloadsharkey-94e282b612ad3dc6fd336a82fff19b290e11d221.tar.gz
sharkey-94e282b612ad3dc6fd336a82fff19b290e11d221.tar.bz2
sharkey-94e282b612ad3dc6fd336a82fff19b290e11d221.zip
perf(reversi): improve performance of reversi backend
Diffstat (limited to 'packages/backend/src')
-rw-r--r--packages/backend/src/core/ReversiService.ts37
-rw-r--r--packages/backend/src/core/entities/ReversiGameEntityService.ts35
-rw-r--r--packages/backend/src/models/json-schema/reversi-game.ts16
-rw-r--r--packages/backend/src/server/api/endpoints/reversi/games.ts6
-rw-r--r--packages/backend/src/server/api/endpoints/reversi/match.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/reversi/show-game.ts2
-rw-r--r--packages/backend/src/types.ts6
7 files changed, 63 insertions, 41 deletions
diff --git a/packages/backend/src/core/ReversiService.ts b/packages/backend/src/core/ReversiService.ts
index 0e59d0308d..0d5f989c11 100644
--- a/packages/backend/src/core/ReversiService.ts
+++ b/packages/backend/src/core/ReversiService.ts
@@ -234,10 +234,13 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
map: Reversi.maps.eighteight.data,
bw: 'random',
isLlotheo: false,
- }).then(x => this.reversiGamesRepository.findOneByOrFail(x.identifiers[0]));
+ }).then(x => this.reversiGamesRepository.findOneOrFail({
+ where: { id: x.identifiers[0].id },
+ relations: ['user1', 'user2'],
+ }));
this.cacheGame(game);
- const packed = await this.reversiGameEntityService.packDetail(game, { id: parentId });
+ const packed = await this.reversiGameEntityService.packDetail(game);
this.globalEventService.publishReversiStream(parentId, 'matched', { game: packed });
return game;
@@ -267,6 +270,9 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
.returning('*')
.execute()
.then((response) => response.raw[0]);
+ // キャッシュ効率化のためにユーザー情報は再利用
+ updatedGame.user1 = game.user1;
+ updatedGame.user2 = game.user2;
this.cacheGame(updatedGame);
//#region 盤面に最初から石がないなどして始まった瞬間に勝敗が決定する場合があるのでその処理
@@ -314,6 +320,9 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
.returning('*')
.execute()
.then((response) => response.raw[0]);
+ // キャッシュ効率化のためにユーザー情報は再利用
+ updatedGame.user1 = game.user1;
+ updatedGame.user2 = game.user2;
this.cacheGame(updatedGame);
this.globalEventService.publishReversiGameStream(game.id, 'ended', {
@@ -483,14 +492,36 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
public async get(id: MiReversiGame['id']): Promise<MiReversiGame | null> {
const cached = await this.redisClient.get(`reversi:game:cache:${id}`);
if (cached != null) {
+ // TODO: この辺りのデシリアライズ処理をどこか別のサービスに切り出したい
const parsed = JSON.parse(cached) as Serialized<MiReversiGame>;
return {
...parsed,
startedAt: parsed.startedAt != null ? new Date(parsed.startedAt) : null,
endedAt: parsed.endedAt != null ? new Date(parsed.endedAt) : null,
+ user1: parsed.user1 != null ? {
+ ...parsed.user1,
+ avatar: null,
+ banner: null,
+ updatedAt: parsed.user1.updatedAt != null ? new Date(parsed.user1.updatedAt) : null,
+ lastActiveDate: parsed.user1.lastActiveDate != null ? new Date(parsed.user1.lastActiveDate) : null,
+ lastFetchedAt: parsed.user1.lastFetchedAt != null ? new Date(parsed.user1.lastFetchedAt) : null,
+ movedAt: parsed.user1.movedAt != null ? new Date(parsed.user1.movedAt) : null,
+ } : null,
+ user2: parsed.user2 != null ? {
+ ...parsed.user2,
+ avatar: null,
+ banner: null,
+ updatedAt: parsed.user2.updatedAt != null ? new Date(parsed.user2.updatedAt) : null,
+ lastActiveDate: parsed.user2.lastActiveDate != null ? new Date(parsed.user2.lastActiveDate) : null,
+ lastFetchedAt: parsed.user2.lastFetchedAt != null ? new Date(parsed.user2.lastFetchedAt) : null,
+ movedAt: parsed.user2.movedAt != null ? new Date(parsed.user2.movedAt) : null,
+ } : null,
};
} else {
- const game = await this.reversiGamesRepository.findOneBy({ id });
+ const game = await this.reversiGamesRepository.findOne({
+ where: { id },
+ relations: ['user1', 'user2'],
+ });
if (game == null) return null;
this.cacheGame(game);
diff --git a/packages/backend/src/core/entities/ReversiGameEntityService.ts b/packages/backend/src/core/entities/ReversiGameEntityService.ts
index bcb0fd5a6f..6c89a70599 100644
--- a/packages/backend/src/core/entities/ReversiGameEntityService.ts
+++ b/packages/backend/src/core/entities/ReversiGameEntityService.ts
@@ -9,7 +9,6 @@ import type { ReversiGamesRepository } from '@/models/_.js';
import { awaitAll } from '@/misc/prelude/await-all.js';
import type { Packed } from '@/misc/json-schema.js';
import type { } from '@/models/Blocking.js';
-import type { MiUser } from '@/models/User.js';
import type { MiReversiGame } from '@/models/ReversiGame.js';
import { bindThis } from '@/decorators.js';
import { IdService } from '@/core/IdService.js';
@@ -29,10 +28,14 @@ export class ReversiGameEntityService {
@bindThis
public async packDetail(
src: MiReversiGame['id'] | MiReversiGame,
- me?: { id: MiUser['id'] } | null | undefined,
): Promise<Packed<'ReversiGameDetailed'>> {
const game = typeof src === 'object' ? src : await this.reversiGamesRepository.findOneByOrFail({ id: src });
+ const users = await Promise.all([
+ this.userEntityService.pack(game.user1 ?? game.user1Id),
+ this.userEntityService.pack(game.user2 ?? game.user2Id),
+ ]);
+
return await awaitAll({
id: game.id,
createdAt: this.idService.parse(game.id).date.toISOString(),
@@ -46,10 +49,10 @@ export class ReversiGameEntityService {
user2Ready: game.user2Ready,
user1Id: game.user1Id,
user2Id: game.user2Id,
- user1: this.userEntityService.pack(game.user1Id, me),
- user2: this.userEntityService.pack(game.user2Id, me),
+ user1: users[0],
+ user2: users[1],
winnerId: game.winnerId,
- winner: game.winnerId ? this.userEntityService.pack(game.winnerId, me) : null,
+ winner: game.winnerId ? users.find(u => u.id === game.winnerId)! : null,
surrenderedUserId: game.surrenderedUserId,
timeoutUserId: game.timeoutUserId,
black: game.black,
@@ -66,18 +69,21 @@ export class ReversiGameEntityService {
@bindThis
public packDetailMany(
xs: MiReversiGame[],
- me?: { id: MiUser['id'] } | null | undefined,
) {
- return Promise.all(xs.map(x => this.packDetail(x, me)));
+ return Promise.all(xs.map(x => this.packDetail(x)));
}
@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 });
+ const users = await Promise.all([
+ this.userEntityService.pack(game.user1 ?? game.user1Id),
+ this.userEntityService.pack(game.user2 ?? game.user2Id),
+ ]);
+
return await awaitAll({
id: game.id,
createdAt: this.idService.parse(game.id).date.toISOString(),
@@ -85,16 +91,12 @@ export class ReversiGameEntityService {
endedAt: game.endedAt && game.endedAt.toISOString(),
isStarted: game.isStarted,
isEnded: game.isEnded,
- form1: game.form1,
- form2: game.form2,
- user1Ready: game.user1Ready,
- user2Ready: game.user2Ready,
user1Id: game.user1Id,
user2Id: game.user2Id,
- user1: this.userEntityService.pack(game.user1Id, me),
- user2: this.userEntityService.pack(game.user2Id, me),
+ user1: users[0],
+ user2: users[1],
winnerId: game.winnerId,
- winner: game.winnerId ? this.userEntityService.pack(game.winnerId, me) : null,
+ winner: game.winnerId ? users.find(u => u.id === game.winnerId)! : null,
surrenderedUserId: game.surrenderedUserId,
timeoutUserId: game.timeoutUserId,
black: game.black,
@@ -109,9 +111,8 @@ export class ReversiGameEntityService {
@bindThis
public packLiteMany(
xs: MiReversiGame[],
- me?: { id: MiUser['id'] } | null | undefined,
) {
- return Promise.all(xs.map(x => this.packLite(x, me)));
+ return Promise.all(xs.map(x => this.packLite(x)));
}
}
diff --git a/packages/backend/src/models/json-schema/reversi-game.ts b/packages/backend/src/models/json-schema/reversi-game.ts
index 4ac4d165d8..8061d84ad6 100644
--- a/packages/backend/src/models/json-schema/reversi-game.ts
+++ b/packages/backend/src/models/json-schema/reversi-game.ts
@@ -34,22 +34,6 @@ export const packedReversiGameLiteSchema = {
type: 'boolean',
optional: false, nullable: false,
},
- form1: {
- type: 'any',
- optional: false, nullable: true,
- },
- form2: {
- type: 'any',
- optional: false, nullable: true,
- },
- user1Ready: {
- type: 'boolean',
- optional: false, nullable: false,
- },
- user2Ready: {
- type: 'boolean',
- optional: false, nullable: false,
- },
user1Id: {
type: 'string',
optional: false, nullable: false,
diff --git a/packages/backend/src/server/api/endpoints/reversi/games.ts b/packages/backend/src/server/api/endpoints/reversi/games.ts
index 5322cd0987..f28fe5d987 100644
--- a/packages/backend/src/server/api/endpoints/reversi/games.ts
+++ b/packages/backend/src/server/api/endpoints/reversi/games.ts
@@ -43,7 +43,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
) {
super(meta, paramDef, async (ps, me) => {
const query = this.queryService.makePaginationQuery(this.reversiGamesRepository.createQueryBuilder('game'), ps.sinceId, ps.untilId)
- .andWhere('game.isStarted = TRUE');
+ .andWhere('game.isStarted = TRUE')
+ .innerJoinAndSelect('game.user1', 'user1')
+ .innerJoinAndSelect('game.user2', 'user2');
if (ps.my && me) {
query.andWhere(new Brackets(qb => {
@@ -55,7 +57,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const games = await query.take(ps.limit).getMany();
- return await this.reversiGameEntityService.packLiteMany(games, me);
+ return await this.reversiGameEntityService.packLiteMany(games);
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/reversi/match.ts b/packages/backend/src/server/api/endpoints/reversi/match.ts
index da5a3409ef..1065ce5a89 100644
--- a/packages/backend/src/server/api/endpoints/reversi/match.ts
+++ b/packages/backend/src/server/api/endpoints/reversi/match.ts
@@ -60,7 +60,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
if (game == null) return;
- return await this.reversiGameEntityService.packDetail(game, me);
+ return await this.reversiGameEntityService.packDetail(game);
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/reversi/show-game.ts b/packages/backend/src/server/api/endpoints/reversi/show-game.ts
index de571053e1..86645ea4b4 100644
--- a/packages/backend/src/server/api/endpoints/reversi/show-game.ts
+++ b/packages/backend/src/server/api/endpoints/reversi/show-game.ts
@@ -48,7 +48,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.noSuchGame);
}
- return await this.reversiGameEntityService.packDetail(game, me);
+ return await this.reversiGameEntityService.packDetail(game);
});
}
}
diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts
index 361a4931eb..cfac5cd9d4 100644
--- a/packages/backend/src/types.ts
+++ b/packages/backend/src/types.ts
@@ -277,7 +277,11 @@ export type Serialized<T> = {
? (string | null)
: T[K] extends Record<string, any>
? Serialized<T[K]>
- : T[K];
+ : T[K] extends (Record<string, any> | null)
+ ? (Serialized<T[K]> | null)
+ : T[K] extends (Record<string, any> | undefined)
+ ? (Serialized<T[K]> | undefined)
+ : T[K];
};
export type FilterUnionByProperty<