Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/develop' into bsk-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
kanarikanaru committed Jan 22, 2024
2 parents 41518ae + 5e307e4 commit b605b26
Show file tree
Hide file tree
Showing 33 changed files with 480 additions and 378 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,6 @@ jobs:
- run: pnpm i --frozen-lockfile
- run: pnpm --filter misskey-js run build
if: ${{ matrix.workspace == 'backend' }}
- run: pnpm --filter misskey-reversi run build
if: ${{ matrix.workspace == 'backend' }}
- run: pnpm --filter ${{ matrix.workspace }} run typecheck
9 changes: 6 additions & 3 deletions cypress/e2e/basic.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,13 @@ describe('After user signed in', () => {
});

it('successfully loads', () => {
cy.get('[data-cy-user-setup-continue]').should('be.visible');
// 表示に時間がかかるのでデフォルト秒数だとタイムアウトする
cy.get('[data-cy-user-setup-continue]', { timeout: 12000 }).should('be.visible');
});

it('account setup wizard', () => {
cy.get('[data-cy-user-setup-continue]').click();
// 表示に時間がかかるのでデフォルト秒数だとタイムアウトする
cy.get('[data-cy-user-setup-continue]', { timeout: 12000 }).click();

cy.get('[data-cy-user-setup-user-name] input').type('ありす');
cy.get('[data-cy-user-setup-user-description] textarea').type('ほげ');
Expand Down Expand Up @@ -202,7 +204,8 @@ describe('After user setup', () => {
cy.login('alice', 'alice1234');

// アカウント初期設定ウィザード
cy.get('[data-cy-user-setup] [data-cy-modal-window-close]').click();
// 表示に時間がかかるのでデフォルト秒数だとタイムアウトする
cy.get('[data-cy-user-setup] [data-cy-modal-window-close]', { timeout: 12000 }).click();
cy.get('[data-cy-modal-dialog-ok]').click();
});

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@
"typescript": "5.3.3"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "6.19.0",
"@typescript-eslint/parser": "6.19.0",
"@typescript-eslint/eslint-plugin": "6.18.1",
"@typescript-eslint/parser": "6.18.1",
"cross-env": "7.0.3",
"cypress": "13.6.3",
"eslint": "8.56.0",
Expand Down
8 changes: 4 additions & 4 deletions packages/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
},
"scripts": {
"start": "node ./built/boot/entry.js",
"start:test": "NODE_ENV=test node ./built/boot/entry.js",
"start:test": "cross-env NODE_ENV=test node ./built/boot/entry.js",
"migrate": "pnpm typeorm migration:run -d ormconfig.js",
"revert": "pnpm typeorm migration:revert -d ormconfig.js",
"check:connect": "node ./check_connect.js",
Expand All @@ -31,7 +31,7 @@
"test:e2e": "pnpm build && pnpm build:test && pnpm jest:e2e",
"test-and-coverage": "pnpm jest-and-coverage",
"test-and-coverage:e2e": "pnpm build && pnpm build:test && pnpm jest-and-coverage:e2e",
"generate-api-json": "node ./generate_api_json.js"
"generate-api-json": "pnpm build && node ./generate_api_json.js"
},
"optionalDependencies": {
"@swc/core-android-arm64": "1.3.11",
Expand Down Expand Up @@ -227,8 +227,8 @@
"@types/vary": "1.1.3",
"@types/web-push": "3.6.3",
"@types/ws": "8.5.10",
"@typescript-eslint/eslint-plugin": "6.19.0",
"@typescript-eslint/parser": "6.19.0",
"@typescript-eslint/eslint-plugin": "6.18.1",
"@typescript-eslint/parser": "6.18.1",
"aws-sdk-client-mock": "3.0.1",
"cross-env": "7.0.3",
"eslint": "8.56.0",
Expand Down
12 changes: 9 additions & 3 deletions packages/backend/src/core/AntennaService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,23 +55,29 @@ export class AntennaService implements OnApplicationShutdown {
const { type, body } = obj.message as GlobalEvents['internal']['payload'];
switch (type) {
case 'antennaCreated':
this.antennas.push({
this.antennas.push({ // TODO: このあたりのデシリアライズ処理は各modelファイル内に関数としてexportしたい
...body,
lastUsedAt: new Date(body.lastUsedAt),
user: null, // joinなカラムは通常取ってこないので
userList: null, // joinなカラムは通常取ってこないので
});
break;
case 'antennaUpdated': {
const idx = this.antennas.findIndex(a => a.id === body.id);
if (idx >= 0) {
this.antennas[idx] = {
this.antennas[idx] = { // TODO: このあたりのデシリアライズ処理は各modelファイル内に関数としてexportしたい
...body,
lastUsedAt: new Date(body.lastUsedAt),
user: null, // joinなカラムは通常取ってこないので
userList: null, // joinなカラムは通常取ってこないので
};
} else {
// サーバ起動時にactiveじゃなかった場合、リストに持っていないので追加する必要あり
this.antennas.push({
this.antennas.push({ // TODO: このあたりのデシリアライズ処理は各modelファイル内に関数としてexportしたい
...body,
lastUsedAt: new Date(body.lastUsedAt),
user: null, // joinなカラムは通常取ってこないので
userList: null, // joinなカラムは通常取ってこないので
});
}
}
Expand Down
5 changes: 4 additions & 1 deletion packages/backend/src/core/MetaService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ export class MetaService implements OnApplicationShutdown {
const { type, body } = obj.message as GlobalEvents['internal']['payload'];
switch (type) {
case 'metaUpdated': {
this.cache = body;
this.cache = { // TODO: このあたりのデシリアライズ処理は各modelファイル内に関数としてexportしたい
...body,
proxyAccount: null, // joinなカラムは通常取ってこないので
};
break;
}
default:
Expand Down
37 changes: 34 additions & 3 deletions packages/backend/src/core/ReversiService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 盤面に最初から石がないなどして始まった瞬間に勝敗が決定する場合があるのでその処理
Expand Down Expand Up @@ -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', {
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 3 additions & 1 deletion packages/backend/src/core/RoleService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,11 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
case 'userRoleAssigned': {
const cached = this.roleAssignmentByUserIdCache.get(body.userId);
if (cached) {
cached.push({
cached.push({ // TODO: このあたりのデシリアライズ処理は各modelファイル内に関数としてexportしたい
...body,
expiresAt: body.expiresAt ? new Date(body.expiresAt) : null,
user: null, // joinなカラムは通常取ってこないので
role: null, // joinなカラムは通常取ってこないので
});
}
break;
Expand Down
9 changes: 6 additions & 3 deletions packages/backend/src/core/WebhookService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,24 +49,27 @@ export class WebhookService implements OnApplicationShutdown {
switch (type) {
case 'webhookCreated':
if (body.active) {
this.webhooks.push({
this.webhooks.push({ // TODO: このあたりのデシリアライズ処理は各modelファイル内に関数としてexportしたい
...body,
latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null,
user: null, // joinなカラムは通常取ってこないので
});
}
break;
case 'webhookUpdated':
if (body.active) {
const i = this.webhooks.findIndex(a => a.id === body.id);
if (i > -1) {
this.webhooks[i] = {
this.webhooks[i] = { // TODO: このあたりのデシリアライズ処理は各modelファイル内に関数としてexportしたい
...body,
latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null,
user: null, // joinなカラムは通常取ってこないので
};
} else {
this.webhooks.push({
this.webhooks.push({ // TODO: このあたりのデシリアライズ処理は各modelファイル内に関数としてexportしたい
...body,
latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null,
user: null, // joinなカラムは通常取ってこないので
});
}
} else {
Expand Down
35 changes: 18 additions & 17 deletions packages/backend/src/core/entities/ReversiGameEntityService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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(),
Expand All @@ -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,
Expand All @@ -66,35 +69,34 @@ 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(),
startedAt: game.startedAt && game.startedAt.toISOString(),
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,
Expand All @@ -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)));
}
}

20 changes: 2 additions & 18 deletions packages/backend/src/models/json-schema/reversi-game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -149,11 +133,11 @@ export const packedReversiGameDetailedSchema = {
optional: false, nullable: false,
},
form1: {
type: 'any',
type: 'object',
optional: false, nullable: true,
},
form2: {
type: 'any',
type: 'object',
optional: false, nullable: true,
},
user1Ready: {
Expand Down
6 changes: 4 additions & 2 deletions packages/backend/src/server/api/endpoints/reversi/games.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand All @@ -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);
});
}
}
2 changes: 1 addition & 1 deletion packages/backend/src/server/api/endpoints/reversi/match.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
}
}
Loading

0 comments on commit b605b26

Please sign in to comment.