diff --git a/packages/backend/src/core/CoreModule.ts b/packages/backend/src/core/CoreModule.ts index 0ad91ff308..c9e285346e 100644 --- a/packages/backend/src/core/CoreModule.ts +++ b/packages/backend/src/core/CoreModule.ts @@ -116,7 +116,6 @@ import { FlashEntityService } from './entities/FlashEntityService.js'; import { FlashLikeEntityService } from './entities/FlashLikeEntityService.js'; import { RoleEntityService } from './entities/RoleEntityService.js'; import { ReversiGameEntityService } from './entities/ReversiGameEntityService.js'; -import { ReversiMatchingEntityService } from './entities/ReversiMatchingEntityService.js'; import { ApAudienceService } from './activitypub/ApAudienceService.js'; import { ApDbResolverService } from './activitypub/ApDbResolverService.js'; @@ -255,7 +254,6 @@ const $FlashEntityService: Provider = { provide: 'FlashEntityService', useExisti const $FlashLikeEntityService: Provider = { provide: 'FlashLikeEntityService', useExisting: FlashLikeEntityService }; const $RoleEntityService: Provider = { provide: 'RoleEntityService', useExisting: RoleEntityService }; const $ReversiGameEntityService: Provider = { provide: 'ReversiGameEntityService', useExisting: ReversiGameEntityService }; -const $ReversiMatchingEntityService: Provider = { provide: 'ReversiMatchingEntityService', useExisting: ReversiMatchingEntityService }; const $ApAudienceService: Provider = { provide: 'ApAudienceService', useExisting: ApAudienceService }; const $ApDbResolverService: Provider = { provide: 'ApDbResolverService', useExisting: ApDbResolverService }; @@ -395,7 +393,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting FlashLikeEntityService, RoleEntityService, ReversiGameEntityService, - ReversiMatchingEntityService, ApAudienceService, ApDbResolverService, @@ -531,7 +528,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $FlashLikeEntityService, $RoleEntityService, $ReversiGameEntityService, - $ReversiMatchingEntityService, $ApAudienceService, $ApDbResolverService, @@ -667,7 +663,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting FlashLikeEntityService, RoleEntityService, ReversiGameEntityService, - ReversiMatchingEntityService, ApAudienceService, ApDbResolverService, @@ -802,7 +797,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $FlashLikeEntityService, $RoleEntityService, $ReversiGameEntityService, - $ReversiMatchingEntityService, $ApAudienceService, $ApDbResolverService, diff --git a/packages/backend/src/core/GlobalEventService.ts b/packages/backend/src/core/GlobalEventService.ts index 9eb5301d93..aa812c7a99 100644 --- a/packages/backend/src/core/GlobalEventService.ts +++ b/packages/backend/src/core/GlobalEventService.ts @@ -165,7 +165,7 @@ export interface ReversiEventTypes { game: Packed<'ReversiGameDetailed'>; }; invited: { - game: Packed<'ReversiMatching'>; + user: Packed<'User'>; }; } @@ -180,12 +180,12 @@ export interface ReversiGameEventTypes { key: string; value: any; }; -putStone: { -at: Date; -color: boolean; -pos: number; -next: boolean; -}; + putStone: { + at: Date; + color: boolean; + pos: number; + next: boolean; + }; syncState: { crc32: string; }; diff --git a/packages/backend/src/core/ReversiService.ts b/packages/backend/src/core/ReversiService.ts index 6e88270973..f5383af058 100644 --- a/packages/backend/src/core/ReversiService.ts +++ b/packages/backend/src/core/ReversiService.ts @@ -8,10 +8,10 @@ import * as Redis from 'ioredis'; import * as CRC32 from 'crc-32'; import { ModuleRef } from '@nestjs/core'; import * as Reversi from 'misskey-reversi'; +import { IsNull } from 'typeorm'; import type { MiReversiGame, ReversiGamesRepository, - ReversiMatchingsRepository, UsersRepository, } from '@/models/_.js'; import type { MiUser } from '@/models/User.js'; @@ -25,10 +25,11 @@ import { GlobalEventService } from '@/core/GlobalEventService.js'; import { IdService } from '@/core/IdService.js'; import type { Packed } from '@/misc/json-schema.js'; import { NotificationService } from '@/core/NotificationService.js'; -import { ReversiMatchingEntityService } from '@/core/entities/ReversiMatchingEntityService.js'; import { ReversiGameEntityService } from './entities/ReversiGameEntityService.js'; import type { OnApplicationShutdown, OnModuleInit } from '@nestjs/common'; +const MATCHING_TIMEOUT_MS = 15 * 1000; // 15sec + @Injectable() export class ReversiService implements OnApplicationShutdown, OnModuleInit { private notificationService: NotificationService; @@ -36,20 +37,16 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit { constructor( private moduleRef: ModuleRef, - @Inject(DI.usersRepository) - private usersRepository: UsersRepository, + @Inject(DI.redis) + private redisClient: Redis.Redis, @Inject(DI.reversiGamesRepository) private reversiGamesRepository: ReversiGamesRepository, - @Inject(DI.reversiMatchingsRepository) - private reversiMatchingsRepository: ReversiMatchingsRepository, - private cacheService: CacheService, private userEntityService: UserEntityService, private globalEventService: GlobalEventService, private reversiGameEntityService: ReversiGameEntityService, - private reversiMatchingsEntityService: ReversiMatchingEntityService, private idService: IdService, ) { } @@ -59,22 +56,19 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit { } @bindThis - public async match(me: MiUser, targetUser: MiUser): Promise { + public async matchSpecificUser(me: MiUser, targetUser: MiUser): Promise { if (targetUser.id === me.id) { throw new Error('You cannot match yourself.'); } - const exist = await this.reversiMatchingsRepository.findOneBy({ - parentId: targetUser.id, - childId: me.id, - }); + const invitations = await this.redisClient.zrange(`reversi:matchSpecific:${me.id}`, Date.now() - MATCHING_TIMEOUT_MS, '+inf'); - if (exist) { - this.reversiMatchingsRepository.delete(exist.id); + if (invitations.includes(targetUser.id)) { + await this.redisClient.zrem(`reversi:matchSpecific:${me.id}`, targetUser.id); const game = await this.reversiGamesRepository.insert({ id: this.idService.gen(), - user1Id: exist.parentId, + user1Id: targetUser.id, user2Id: me.id, user1Accepted: false, user2Accepted: false, @@ -86,35 +80,64 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit { isLlotheo: false, }).then(x => this.reversiGamesRepository.findOneByOrFail(x.identifiers[0])); - const packed = await this.reversiGameEntityService.packDetail(game, { id: exist.parentId }); - this.globalEventService.publishReversiStream(exist.parentId, 'matched', { game: packed }); + const packed = await this.reversiGameEntityService.packDetail(game, { id: targetUser.id }); + this.globalEventService.publishReversiStream(targetUser.id, 'matched', { game: packed }); return game; } else { - const child = targetUser; + this.redisClient.zadd(`reversi:matchSpecific:${targetUser.id}`, Date.now(), me.id); - await this.reversiMatchingsRepository.delete({ - parentId: me.id, + this.globalEventService.publishReversiStream(targetUser.id, 'invited', { + user: await this.userEntityService.pack(me, targetUser), }); - const matching = await this.reversiMatchingsRepository.insert({ - id: this.idService.gen(), - parentId: me.id, - childId: child.id, - }).then(x => this.reversiMatchingsRepository.findOneByOrFail(x.identifiers[0])); - - const packed = await this.reversiMatchingsEntityService.pack(matching, child); - this.globalEventService.publishReversiStream(child.id, 'invited', { game: packed }); - return null; } } @bindThis - public async matchCancel(user: MiUser) { - await this.reversiMatchingsRepository.delete({ - parentId: user.id, - }); + public async matchAnyUser(me: MiUser): Promise { + const scanRes = await this.redisClient.scan(0, 'MATCH', 'reversi:matchAny:*', 'COUNT', 10); + const userIds = scanRes[1].map(key => key.split(':')[2]).filter(id => id !== me.id); + + if (userIds.length > 0) { + // pick random + const matchedUserId = userIds[Math.floor(Math.random() * userIds.length)]; + + await this.redisClient.del(`reversi:matchAny:${matchedUserId}`); + + const game = await this.reversiGamesRepository.insert({ + id: this.idService.gen(), + user1Id: matchedUserId, + user2Id: me.id, + user1Accepted: false, + user2Accepted: false, + isStarted: false, + isEnded: false, + logs: [], + map: Reversi.maps.eighteight.data, + bw: 'random', + isLlotheo: false, + }).then(x => this.reversiGamesRepository.findOneByOrFail(x.identifiers[0])); + + const packed = await this.reversiGameEntityService.packDetail(game, { id: matchedUserId }); + this.globalEventService.publishReversiStream(matchedUserId, 'matched', { game: packed }); + + return game; + } else { + await this.redisClient.setex(`reversi:matchAny:${me.id}`, MATCHING_TIMEOUT_MS / 1000, ''); + return null; + } + } + + @bindThis + public async matchSpecificUserCancel(user: MiUser, targetUserId: MiUser['id']) { + await this.redisClient.zrem(`reversi:matchSpecific:${targetUserId}`, user.id); + } + + @bindThis + public async matchAnyUserCancel(user: MiUser) { + await this.redisClient.del(`reversi:matchAny:${user.id}`); } @bindThis @@ -214,6 +237,12 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit { } } + @bindThis + public async getInvitations(user: MiUser): Promise { + const invitations = await this.redisClient.zrange(`reversi:matchSpecific:${user.id}`, Date.now() - MATCHING_TIMEOUT_MS, '+inf'); + return invitations; + } + @bindThis public async updateSettings(game: MiReversiGame, user: MiUser, key: string, value: any) { if (game.isStarted) return; diff --git a/packages/backend/src/core/entities/ReversiMatchingEntityService.ts b/packages/backend/src/core/entities/ReversiMatchingEntityService.ts deleted file mode 100644 index 1b39679ec1..0000000000 --- a/packages/backend/src/core/entities/ReversiMatchingEntityService.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and other misskey contributors - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import { Inject, Injectable } from '@nestjs/common'; -import { DI } from '@/di-symbols.js'; -import type { MiReversiMatching, ReversiMatchingsRepository } 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 { bindThis } from '@/decorators.js'; -import { IdService } from '@/core/IdService.js'; -import { UserEntityService } from './UserEntityService.js'; - -@Injectable() -export class ReversiMatchingEntityService { - constructor( - @Inject(DI.reversiMatchingsRepository) - private reversiMatchingsRepository: ReversiMatchingsRepository, - - private userEntityService: UserEntityService, - private idService: IdService, - ) { - } - - @bindThis - public async pack( - src: MiReversiMatching['id'] | MiReversiMatching, - me?: { id: MiUser['id'] } | null | undefined, - ): Promise> { - const matching = typeof src === 'object' ? src : await this.reversiMatchingsRepository.findOneByOrFail({ id: src }); - - return await awaitAll({ - id: matching.id, - createdAt: this.idService.parse(matching.id).date.toISOString(), - parentId: matching.parentId, - parent: this.userEntityService.pack(matching.parentId, me, { - detail: true, - }), - childId: matching.childId, - child: this.userEntityService.pack(matching.childId, me, { - detail: true, - }), - }); - } - - @bindThis - public packMany( - xs: MiReversiMatching[], - me?: { id: MiUser['id'] } | null | undefined, - ) { - return Promise.all(xs.map(x => this.pack(x, me))); - } -} - diff --git a/packages/backend/src/di-symbols.ts b/packages/backend/src/di-symbols.ts index 841a9e9bb6..73de01f33a 100644 --- a/packages/backend/src/di-symbols.ts +++ b/packages/backend/src/di-symbols.ts @@ -80,6 +80,5 @@ export const DI = { userMemosRepository: Symbol('userMemosRepository'), bubbleGameRecordsRepository: Symbol('bubbleGameRecordsRepository'), reversiGamesRepository: Symbol('reversiGamesRepository'), - reversiMatchingsRepository: Symbol('reversiMatchingsRepository'), //#endregion }; diff --git a/packages/backend/src/misc/json-schema.ts b/packages/backend/src/misc/json-schema.ts index 3ee700fef7..b4f0541712 100644 --- a/packages/backend/src/misc/json-schema.ts +++ b/packages/backend/src/misc/json-schema.ts @@ -40,7 +40,6 @@ 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 { packedReversiGameLiteSchema, packedReversiGameDetailedSchema } from '@/models/json-schema/reversi-game.js'; -import { packedReversiMatchingSchema } from '@/models/json-schema/reversi-matching.js'; export const refs = { UserLite: packedUserLiteSchema, @@ -82,7 +81,6 @@ export const refs = { Role: packedRoleSchema, ReversiGameLite: packedReversiGameLiteSchema, ReversiGameDetailed: packedReversiGameDetailedSchema, - ReversiMatching: packedReversiMatchingSchema, }; export type Packed = SchemaType; diff --git a/packages/backend/src/models/RepositoryModule.ts b/packages/backend/src/models/RepositoryModule.ts index f2c4e29112..2b2aaeb91c 100644 --- a/packages/backend/src/models/RepositoryModule.ts +++ b/packages/backend/src/models/RepositoryModule.ts @@ -5,7 +5,7 @@ import { Module } from '@nestjs/common'; import { DI } from '@/di-symbols.js'; -import { MiAbuseUserReport, MiAccessToken, MiAd, MiAnnouncement, MiAnnouncementRead, MiAntenna, MiApp, MiAuthSession, MiAvatarDecoration, MiBlocking, MiChannel, MiChannelFavorite, MiChannelFollowing, MiClip, MiClipFavorite, MiClipNote, MiDriveFile, MiDriveFolder, MiEmoji, MiFlash, MiFlashLike, MiFollowRequest, MiFollowing, MiGalleryLike, MiGalleryPost, MiHashtag, MiInstance, MiMeta, MiModerationLog, MiMuting, MiNote, MiNoteFavorite, MiNoteReaction, MiNoteThreadMuting, MiNoteUnread, MiPage, MiPageLike, MiPasswordResetRequest, MiPoll, MiPollVote, MiPromoNote, MiPromoRead, MiRegistrationTicket, MiRegistryItem, MiRelay, MiRenoteMuting, MiRetentionAggregation, MiRole, MiRoleAssignment, MiSignin, MiSwSubscription, MiUsedUsername, MiUser, MiUserIp, MiUserKeypair, MiUserList, MiUserListFavorite, MiUserListMembership, MiUserMemo, MiUserNotePining, MiUserPending, MiUserProfile, MiUserPublickey, MiUserSecurityKey, MiWebhook, MiBubbleGameRecord, MiReversiGame, MiReversiMatching } from './_.js'; +import { MiAbuseUserReport, MiAccessToken, MiAd, MiAnnouncement, MiAnnouncementRead, MiAntenna, MiApp, MiAuthSession, MiAvatarDecoration, MiBlocking, MiChannel, MiChannelFavorite, MiChannelFollowing, MiClip, MiClipFavorite, MiClipNote, MiDriveFile, MiDriveFolder, MiEmoji, MiFlash, MiFlashLike, MiFollowRequest, MiFollowing, MiGalleryLike, MiGalleryPost, MiHashtag, MiInstance, MiMeta, MiModerationLog, MiMuting, MiNote, MiNoteFavorite, MiNoteReaction, MiNoteThreadMuting, MiNoteUnread, MiPage, MiPageLike, MiPasswordResetRequest, MiPoll, MiPollVote, MiPromoNote, MiPromoRead, MiRegistrationTicket, MiRegistryItem, MiRelay, MiRenoteMuting, MiRetentionAggregation, MiRole, MiRoleAssignment, MiSignin, MiSwSubscription, MiUsedUsername, MiUser, MiUserIp, MiUserKeypair, MiUserList, MiUserListFavorite, MiUserListMembership, MiUserMemo, MiUserNotePining, MiUserPending, MiUserProfile, MiUserPublickey, MiUserSecurityKey, MiWebhook, MiBubbleGameRecord, MiReversiGame } from './_.js'; import type { DataSource } from 'typeorm'; import type { Provider } from '@nestjs/common'; @@ -411,12 +411,6 @@ const $reversiGamesRepository: Provider = { inject: [DI.db], }; -const $reversiMatchingsRepository: Provider = { - provide: DI.reversiMatchingsRepository, - useFactory: (db: DataSource) => db.getRepository(MiReversiMatching), - inject: [DI.db], -}; - @Module({ imports: [ ], @@ -488,7 +482,6 @@ const $reversiMatchingsRepository: Provider = { $userMemosRepository, $bubbleGameRecordsRepository, $reversiGamesRepository, - $reversiMatchingsRepository, ], exports: [ $usersRepository, @@ -558,7 +551,6 @@ const $reversiMatchingsRepository: Provider = { $userMemosRepository, $bubbleGameRecordsRepository, $reversiGamesRepository, - $reversiMatchingsRepository, ], }) export class RepositoryModule {} diff --git a/packages/backend/src/models/ReversiMatching.ts b/packages/backend/src/models/ReversiMatching.ts deleted file mode 100644 index 1e31fca901..0000000000 --- a/packages/backend/src/models/ReversiMatching.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; -import { id } from './util/id.js'; -import { MiUser } from './User.js'; - -@Entity('reversi_matching') -export class MiReversiMatching { - @PrimaryColumn(id()) - public id: string; - - @Index() - @Column(id()) - public parentId: MiUser['id']; - - @ManyToOne(type => MiUser, { - onDelete: 'CASCADE', - }) - @JoinColumn() - public parent: MiUser | null; - - @Index() - @Column(id()) - public childId: MiUser['id']; - - @ManyToOne(type => MiUser, { - onDelete: 'CASCADE', - }) - @JoinColumn() - public child: MiUser | null; -} diff --git a/packages/backend/src/models/_.ts b/packages/backend/src/models/_.ts index 0b097caf95..a1a0d8823d 100644 --- a/packages/backend/src/models/_.ts +++ b/packages/backend/src/models/_.ts @@ -70,7 +70,6 @@ import { MiFlashLike } from '@/models/FlashLike.js'; import { MiUserListFavorite } from '@/models/UserListFavorite.js'; import { MiBubbleGameRecord } from '@/models/BubbleGameRecord.js'; import { MiReversiGame } from '@/models/ReversiGame.js'; -import { MiReversiMatching } from '@/models/ReversiMatching.js'; import type { Repository } from 'typeorm'; @@ -142,7 +141,6 @@ export { MiUserMemo, MiBubbleGameRecord, MiReversiGame, - MiReversiMatching, }; export type AbuseUserReportsRepository = Repository; @@ -212,4 +210,3 @@ export type FlashLikesRepository = Repository; export type UserMemoRepository = Repository; export type BubbleGameRecordsRepository = Repository; export type ReversiGamesRepository = Repository; -export type ReversiMatchingsRepository = Repository; diff --git a/packages/backend/src/models/json-schema/reversi-matching.ts b/packages/backend/src/models/json-schema/reversi-matching.ts deleted file mode 100644 index a98b0a1644..0000000000 --- a/packages/backend/src/models/json-schema/reversi-matching.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and other misskey contributors - * SPDX-License-Identifier: AGPL-3.0-only - */ - -export const packedReversiMatchingSchema = { - type: 'object', - properties: { - id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - }, - createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', - }, - parentId: { - type: 'string', - optional: false, nullable: false, - format: 'id', - }, - parent: { - type: 'object', - optional: false, nullable: true, - ref: 'User', - }, - childId: { - type: 'string', - optional: false, nullable: false, - format: 'id', - }, - child: { - type: 'object', - optional: false, nullable: false, - ref: 'User', - }, - }, -} as const; diff --git a/packages/backend/src/postgres.ts b/packages/backend/src/postgres.ts index 5435696b14..1e063c8673 100644 --- a/packages/backend/src/postgres.ts +++ b/packages/backend/src/postgres.ts @@ -78,7 +78,6 @@ import { MiFlashLike } from '@/models/FlashLike.js'; import { MiUserMemo } from '@/models/UserMemo.js'; import { MiBubbleGameRecord } from '@/models/BubbleGameRecord.js'; import { MiReversiGame } from '@/models/ReversiGame.js'; -import { MiReversiMatching } from '@/models/ReversiMatching.js'; import { Config } from '@/config.js'; import MisskeyLogger from '@/logger.js'; @@ -195,7 +194,6 @@ export const entities = [ MiUserMemo, MiBubbleGameRecord, MiReversiGame, - MiReversiMatching, ...charts, ]; diff --git a/packages/backend/src/server/api/endpoints/reversi/cancel-match.ts b/packages/backend/src/server/api/endpoints/reversi/cancel-match.ts index cacbc6d85e..8edc049500 100644 --- a/packages/backend/src/server/api/endpoints/reversi/cancel-match.ts +++ b/packages/backend/src/server/api/endpoints/reversi/cancel-match.ts @@ -22,6 +22,7 @@ export const meta = { export const paramDef = { type: 'object', properties: { + userId: { type: 'string', format: 'misskey:id', nullable: true }, }, required: [], } as const; @@ -32,7 +33,12 @@ export default class extends Endpoint { // eslint- private reversiService: ReversiService, ) { super(meta, paramDef, async (ps, me) => { - await this.reversiService.matchCancel(me); + if (ps.userId) { + await this.reversiService.matchSpecificUserCancel(me, ps.userId); + return; + } else { + await this.reversiService.matchAnyUserCancel(me); + } }); } } diff --git a/packages/backend/src/server/api/endpoints/reversi/invitations.ts b/packages/backend/src/server/api/endpoints/reversi/invitations.ts index da6cf66991..0b7107bb0d 100644 --- a/packages/backend/src/server/api/endpoints/reversi/invitations.ts +++ b/packages/backend/src/server/api/endpoints/reversi/invitations.ts @@ -6,8 +6,8 @@ import { Inject, Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { DI } from '@/di-symbols.js'; -import { ReversiMatchingEntityService } from '@/core/entities/ReversiMatchingEntityService.js'; -import type { ReversiMatchingsRepository } from '@/models/_.js'; +import { UserEntityService } from '@/core/entities/UserEntityService.js'; +import { ReversiService } from '@/core/ReversiService.js'; export const meta = { requireCredential: true, @@ -17,32 +17,23 @@ export const meta = { res: { type: 'array', optional: false, nullable: false, - items: { ref: 'ReversiMatching' }, + items: { ref: 'UserLite' }, }, } as const; export const paramDef = { - type: 'object', - properties: { - userId: { type: 'string', format: 'misskey:id' }, - }, - required: ['userId'], } as const; @Injectable() export default class extends Endpoint { // eslint-disable-line import/no-default-export constructor( - @Inject(DI.reversiMatchingsRepository) - private reversiMatchingsRepository: ReversiMatchingsRepository, - - private reversiMatchingEntityService: ReversiMatchingEntityService, + private userEntityService: UserEntityService, + private reversiService: ReversiService, ) { super(meta, paramDef, async (ps, me) => { - const invitations = await this.reversiMatchingsRepository.findBy({ - childId: me.id, - }); + const invitations = await this.reversiService.getInvitations(me); - return await this.reversiMatchingEntityService.packMany(invitations, me); + return await this.userEntityService.packMany(invitations, me); }); } } diff --git a/packages/backend/src/server/api/endpoints/reversi/match.ts b/packages/backend/src/server/api/endpoints/reversi/match.ts index 952d58ff6f..da5a3409ef 100644 --- a/packages/backend/src/server/api/endpoints/reversi/match.ts +++ b/packages/backend/src/server/api/endpoints/reversi/match.ts @@ -36,9 +36,9 @@ export const meta = { export const paramDef = { type: 'object', properties: { - userId: { type: 'string', format: 'misskey:id' }, + userId: { type: 'string', format: 'misskey:id', nullable: true }, }, - required: ['userId'], + required: [], } as const; @Injectable() @@ -51,12 +51,12 @@ export default class extends Endpoint { // eslint- super(meta, paramDef, async (ps, me) => { if (ps.userId === me.id) throw new ApiError(meta.errors.isYourself); - const child = await this.getterService.getUser(ps.userId).catch(err => { + const target = ps.userId ? await this.getterService.getUser(ps.userId).catch(err => { if (err.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); throw err; - }); + }) : null; - const game = await this.reversiService.match(me, child); + const game = target ? await this.reversiService.matchSpecificUser(me, target) : await this.reversiService.matchAnyUser(me); if (game == null) return; diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 9203474e7c..2b95e01533 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -1623,12 +1623,12 @@ declare namespace entities { BubbleGameRegisterResponse, BubbleGameRankingRequest, BubbleGameRankingResponse, + ReversiCancelMatchRequest, ReversiCancelMatchResponse, ReversiGamesRequest, ReversiGamesResponse, ReversiMatchRequest, ReversiMatchResponse, - ReversiInvitationsRequest, ReversiInvitationsResponse, ReversiShowGameRequest, ReversiShowGameResponse, @@ -1671,8 +1671,7 @@ declare namespace entities { RoleLite, Role, ReversiGameLite, - ReversiGameDetailed, - ReversiMatching + ReversiGameDetailed } } export { entities } @@ -2609,6 +2608,9 @@ type ResetPasswordRequest = operations['reset-password']['requestBody']['content // @public (undocumented) type RetentionResponse = operations['retention']['responses']['200']['content']['application/json']; +// @public (undocumented) +type ReversiCancelMatchRequest = operations['reversi/cancel-match']['requestBody']['content']['application/json']; + // @public (undocumented) type ReversiCancelMatchResponse = operations['reversi/cancel-match']['responses']['200']['content']['application/json']; @@ -2624,15 +2626,9 @@ type ReversiGamesRequest = operations['reversi/games']['requestBody']['content'] // @public (undocumented) type ReversiGamesResponse = operations['reversi/games']['responses']['200']['content']['application/json']; -// @public (undocumented) -type ReversiInvitationsRequest = operations['reversi/invitations']['requestBody']['content']['application/json']; - // @public (undocumented) type ReversiInvitationsResponse = operations['reversi/invitations']['responses']['200']['content']['application/json']; -// @public (undocumented) -type ReversiMatching = components['schemas']['ReversiMatching']; - // @public (undocumented) type ReversiMatchRequest = operations['reversi/match']['requestBody']['content']['application/json']; diff --git a/packages/misskey-js/src/autogen/apiClientJSDoc.ts b/packages/misskey-js/src/autogen/apiClientJSDoc.ts index cba6bdcfeb..7b71452292 100644 --- a/packages/misskey-js/src/autogen/apiClientJSDoc.ts +++ b/packages/misskey-js/src/autogen/apiClientJSDoc.ts @@ -1,6 +1,6 @@ /* * version: 2023.12.2 - * generatedAt: 2024-01-18T11:53:06.433Z + * generatedAt: 2024-01-19T01:59:26.059Z */ import type { SwitchCaseResponseType } from '../api.js'; diff --git a/packages/misskey-js/src/autogen/endpoint.ts b/packages/misskey-js/src/autogen/endpoint.ts index 354252a801..aa2acad2f2 100644 --- a/packages/misskey-js/src/autogen/endpoint.ts +++ b/packages/misskey-js/src/autogen/endpoint.ts @@ -1,6 +1,6 @@ /* * version: 2023.12.2 - * generatedAt: 2024-01-18T11:53:06.431Z + * generatedAt: 2024-01-19T01:59:26.057Z */ import type { @@ -544,12 +544,12 @@ import type { BubbleGameRegisterResponse, BubbleGameRankingRequest, BubbleGameRankingResponse, + ReversiCancelMatchRequest, ReversiCancelMatchResponse, ReversiGamesRequest, ReversiGamesResponse, ReversiMatchRequest, ReversiMatchResponse, - ReversiInvitationsRequest, ReversiInvitationsResponse, ReversiShowGameRequest, ReversiShowGameResponse, @@ -917,10 +917,10 @@ export type Endpoints = { 'retention': { req: EmptyRequest; res: RetentionResponse }; 'bubble-game/register': { req: BubbleGameRegisterRequest; res: BubbleGameRegisterResponse }; 'bubble-game/ranking': { req: BubbleGameRankingRequest; res: BubbleGameRankingResponse }; - 'reversi/cancel-match': { req: EmptyRequest; res: ReversiCancelMatchResponse }; + 'reversi/cancel-match': { req: ReversiCancelMatchRequest; res: ReversiCancelMatchResponse }; 'reversi/games': { req: ReversiGamesRequest; res: ReversiGamesResponse }; 'reversi/match': { req: ReversiMatchRequest; res: ReversiMatchResponse }; - 'reversi/invitations': { req: ReversiInvitationsRequest; res: ReversiInvitationsResponse }; + 'reversi/invitations': { req: EmptyRequest; res: ReversiInvitationsResponse }; 'reversi/show-game': { req: ReversiShowGameRequest; res: ReversiShowGameResponse }; 'reversi/surrender': { req: ReversiSurrenderRequest; res: EmptyResponse }; } diff --git a/packages/misskey-js/src/autogen/entities.ts b/packages/misskey-js/src/autogen/entities.ts index ed85c388c4..bae3fc9d04 100644 --- a/packages/misskey-js/src/autogen/entities.ts +++ b/packages/misskey-js/src/autogen/entities.ts @@ -1,6 +1,6 @@ /* * version: 2023.12.2 - * generatedAt: 2024-01-18T11:53:06.430Z + * generatedAt: 2024-01-19T01:59:26.055Z */ import { operations } from './types.js'; @@ -546,12 +546,12 @@ export type BubbleGameRegisterRequest = operations['bubble-game/register']['requ export type BubbleGameRegisterResponse = operations['bubble-game/register']['responses']['200']['content']['application/json']; export type BubbleGameRankingRequest = operations['bubble-game/ranking']['requestBody']['content']['application/json']; export type BubbleGameRankingResponse = operations['bubble-game/ranking']['responses']['200']['content']['application/json']; +export type ReversiCancelMatchRequest = operations['reversi/cancel-match']['requestBody']['content']['application/json']; export type ReversiCancelMatchResponse = operations['reversi/cancel-match']['responses']['200']['content']['application/json']; export type ReversiGamesRequest = operations['reversi/games']['requestBody']['content']['application/json']; export type ReversiGamesResponse = operations['reversi/games']['responses']['200']['content']['application/json']; export type ReversiMatchRequest = operations['reversi/match']['requestBody']['content']['application/json']; export type ReversiMatchResponse = operations['reversi/match']['responses']['200']['content']['application/json']; -export type ReversiInvitationsRequest = operations['reversi/invitations']['requestBody']['content']['application/json']; export type ReversiInvitationsResponse = operations['reversi/invitations']['responses']['200']['content']['application/json']; export type ReversiShowGameRequest = operations['reversi/show-game']['requestBody']['content']['application/json']; export type ReversiShowGameResponse = operations['reversi/show-game']['responses']['200']['content']['application/json']; diff --git a/packages/misskey-js/src/autogen/models.ts b/packages/misskey-js/src/autogen/models.ts index 40ecb6df21..81bfab2ece 100644 --- a/packages/misskey-js/src/autogen/models.ts +++ b/packages/misskey-js/src/autogen/models.ts @@ -1,6 +1,6 @@ /* * version: 2023.12.2 - * generatedAt: 2024-01-18T11:53:06.429Z + * generatedAt: 2024-01-19T01:59:26.054Z */ import { components } from './types.js'; @@ -43,4 +43,3 @@ export type RoleLite = components['schemas']['RoleLite']; export type Role = components['schemas']['Role']; export type ReversiGameLite = components['schemas']['ReversiGameLite']; export type ReversiGameDetailed = components['schemas']['ReversiGameDetailed']; -export type ReversiMatching = components['schemas']['ReversiMatching']; diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index db0d9885b2..fe583dc4b9 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -3,7 +3,7 @@ /* * version: 2023.12.2 - * generatedAt: 2024-01-18T11:53:06.350Z + * generatedAt: 2024-01-19T01:59:25.971Z */ /** @@ -4525,18 +4525,6 @@ export type components = { }[]; map: string[]; }; - ReversiMatching: { - /** Format: id */ - id: string; - /** Format: date-time */ - createdAt: string; - /** Format: id */ - parentId: string; - parent: components['schemas']['User'] | null; - /** Format: id */ - childId: string; - child: components['schemas']['User']; - }; }; responses: never; parameters: never; @@ -25682,6 +25670,14 @@ export type operations = { * **Credential required**: *Yes* / **Permission**: *write:account* */ 'reversi/cancel-match': { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + userId?: string | null; + }; + }; + }; responses: { /** @description OK (with results) */ 200: { @@ -25792,7 +25788,7 @@ export type operations = { content: { 'application/json': { /** Format: misskey:id */ - userId: string; + userId?: string | null; }; }; }; @@ -25842,19 +25838,11 @@ export type operations = { * **Credential required**: *Yes* / **Permission**: *read:account* */ 'reversi/invitations': { - requestBody: { - content: { - 'application/json': { - /** Format: misskey:id */ - userId: string; - }; - }; - }; responses: { /** @description OK (with results) */ 200: { content: { - 'application/json': components['schemas']['ReversiMatching'][]; + 'application/json': components['schemas']['UserLite'][]; }; }; /** @description Client error */