Skip to content

Commit

Permalink
fix: channel gateway, game gateway 수정
Browse files Browse the repository at this point in the history
  • Loading branch information
tomatoziyun committed Dec 11, 2023
1 parent 4bce1f0 commit 57cc309
Show file tree
Hide file tree
Showing 12 changed files with 225 additions and 71 deletions.
2 changes: 1 addition & 1 deletion src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { Response } from 'express';
import { User } from 'src/users/entities/user.entity';
import { SignupRequestDto } from '../users/dto/signup-request.dto';
import { UsersService } from '../users/users.service';
import { AppService } from './../app.service';
import { AppService } from '../app.service';
import { AuthService } from './auth.service';
import { UserSigninResponseDto } from './dto/user-signin-response.dto';
import { FtAuthService } from './ft-auth.service';
Expand Down
1 change: 0 additions & 1 deletion src/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ import { JwtRefreshStrategy } from './jwt-refresh.strategy';
GameInvitationRepository,
FriendsRepository,
BlocksRepository,
ChannelsGateway,
ChannelUsersRepository,
FriendsRepository,
AppService,
Expand Down
38 changes: 37 additions & 1 deletion src/channels/channels.gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ import Redis from 'ioredis';
import { Server, Socket } from 'socket.io';
import { AuthService } from 'src/auth/auth.service';
import { UserStatus } from 'src/common/enum';
import { EVENT_USER_STATUS } from 'src/common/events';
import { EVENT_GAME_INVITATION, EVENT_USER_STATUS } from 'src/common/events';
import { WSBadRequestException } from 'src/common/exception/custom-exception';
import { WsExceptionFilter } from 'src/common/exception/custom-ws-exception.filter';
import { FriendsRepository } from 'src/users/friends.repository';
import { UsersRepository } from 'src/users/users.repository';
import { ChannelUsersRepository } from './channel-users.repository';
import { EventMessageOnDto } from './dto/event-message-on.dto';
import { GatewayCreateInvitationParamDto } from '../game/dto/gateway-create-invitation-param.dto';

@WebSocketGateway({ namespace: 'channels' })
@UseFilters(WsExceptionFilter)
Expand Down Expand Up @@ -194,4 +195,39 @@ export class ChannelsGateway
this.logger.log('ClientToServer: ', data);
this.server.emit('ServerToClient', 'Hello Client!');
}

async inviteGame(
gatewayInvitationParamDto: GatewayCreateInvitationParamDto,
) {
const invitationId = gatewayInvitationParamDto.invitationId;
const invitingUserNickname =
gatewayInvitationParamDto.invitingUserNickname;
const invitedUserId = gatewayInvitationParamDto.invitedUserId;

const invitedUser = await this.usersRepository.findOne({
where: {
id: invitedUserId,
},
});
if (!invitedUser) {
throw WSBadRequestException(`user ${invitedUserId} does not exist`);
}

// 상대가 접속 중인지 => 접속 중인 유저가 아니라면 없던 일이 됨
if (
invitedUser.status === UserStatus.OFFLINE ||
!invitedUser.channelSocketId
)
throw WSBadRequestException('invited user is now offline');

console.log(`inviting user nickname: ${invitingUserNickname}`);

this.server
.to(invitedUser.channelSocketId)
.emit(EVENT_GAME_INVITATION, {
invitationId: invitationId,
invitingUserNickname: invitingUserNickname,
gameType: gatewayInvitationParamDto.gameType,
});
}
}
1 change: 1 addition & 0 deletions src/channels/channels.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,6 @@ import { Channel } from './entities/channel.entity';
FriendsRepository,
BlocksRepository,
],
exports: [ChannelsGateway],
})
export class ChannelsModule {}
4 changes: 4 additions & 0 deletions src/game/dto/create-game-param.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export class CreateGameParamDto {
invitedUserId: number;
invitationId: number;
}
5 changes: 5 additions & 0 deletions src/game/dto/gateway-join-room-param.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export class GatewayJoinRoomParamDto {
invitingUserId: number;
invitedUserId: number;
roomName: string;
}
22 changes: 22 additions & 0 deletions src/game/game-invitation.repository.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,33 @@
import { DataSource, Repository } from 'typeorm';
import { GameInvitation } from './entities/game-invitation.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { CreateGameInvitationParamDto } from './dto/create-invitation-param.dto';
import { DBUpdateFailureException } from '../common/exception/custom-exception';

export class GameInvitationRepository extends Repository<GameInvitation> {
constructor(
@InjectRepository(GameInvitation) private dataSource: DataSource,
) {
super(GameInvitation, dataSource.manager);
}

async createGameInvitation(
gameInvitationDto: CreateGameInvitationParamDto,
) {
const gameInvitation = this.create({
invitingUserId: gameInvitationDto.invitingUser.id,
invitedUserId: gameInvitationDto.invitedUserId,
gameType: gameInvitationDto.gameType,
});
const result = await this.save(gameInvitation);
if (!result)
throw DBUpdateFailureException('create game invitation failed');
return result;
}

async deleteGameInvitaiton(invitationId: number) {
const result = await this.softDelete(invitationId);
if (result.affected !== 1)
throw DBUpdateFailureException('delete user from channel failed');
}
}
51 changes: 45 additions & 6 deletions src/game/game.controller.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import { Body, Controller, Post, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ApiTags } from '@nestjs/swagger';
import {
Body,
Controller,
Delete,
ParseIntPipe,
Post,
UseGuards,
} from '@nestjs/common';
import { GameService } from './game.service';
import { CreateInvitationRequestDto } from './dto/create-invitation-request.dto';
import { GetUser } from '../auth/get-user.decorator';
import { User } from '../users/entities/user.entity';
import { ApiTags } from '@nestjs/swagger';
import { CreateGameInvitationParamDto } from './dto/create-invitation-param.dto';
import { CreateInvitationRequestDto } from './dto/create-invitation-request.dto';
import { GameService } from './game.service';
import { PositiveIntPipe } from '../common/pipes/positiveInt.pipe';
import { CreateGameParamDto } from './dto/create-game-param.dto';
import { AuthGuard } from '@nestjs/passport';

@Controller('game')
@ApiTags('game')
Expand All @@ -27,5 +36,35 @@ export class GameController {
await this.gameService.createInvitation(invitationParamDto);
}

// @Post('/accept')
/**
* 초대 수락
* @param user
* @param invitationId 초대 테이블의 id
* (초대시 프론트가 이벤트를 수신하며 받은 data 입니다)
*/
@Post('/accept')
async createGame(
@GetUser() user: User,
@Body('invitationId', ParseIntPipe, PositiveIntPipe)
invitationId: number,
) {
const createGameParamDto: CreateGameParamDto = {
invitedUserId: user.id,
invitationId: invitationId,
};
await this.gameService.createGame(createGameParamDto);
}

@Delete('/reject')
async deleteInvitation(
@GetUser() user: User,
@Body('invitationId', ParseIntPipe, PositiveIntPipe)
invitationId: number,
) {
const deleteInvitationParamDto: CreateGameParamDto = {
invitedUserId: user.id,
invitationId: invitationId,
};
await this.gameService.deleteInvitation(deleteInvitationParamDto);
}
}
72 changes: 39 additions & 33 deletions src/game/game.gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@ import {
import { UsersRepository } from '../users/users.repository';
import { Server, Socket } from 'socket.io';
import { AuthService } from '../auth/auth.service';
import { GatewayCreateInvitationParamDto } from './dto/gateway-create-invitation-param.dto';
import { UserStatus } from '../common/enum';
import { WSBadRequestException } from '../common/exception/custom-exception';
import { EVENT_GAME_INVITATION } from '../common/events';
import { UseFilters } from '@nestjs/common';
import { UseFilters, UsePipes, ValidationPipe } from '@nestjs/common';
import { WsExceptionFilter } from '../common/exception/custom-ws-exception.filter';
import { GatewayJoinRoomParamDto } from './dto/gateway-join-room-param.dto';
import { GameInvitation } from './entities/game-invitation.entity';

@UseFilters(WsExceptionFilter)
@WebSocketGateway({ namespace: 'game' })
@UseFilters(WsExceptionFilter)
export class GameGateway implements OnGatewayConnection, OnGatewayDisconnect {
constructor(
private readonly authService: AuthService,
Expand All @@ -25,6 +24,7 @@ export class GameGateway implements OnGatewayConnection, OnGatewayDisconnect {

@WebSocketServer()
server: Server;
private connectedClients: Map<number, Socket> = new Map();

async handleConnection(@ConnectedSocket() client: Socket) {
const user = await this.authService.getUserFromSocket(client);
Expand All @@ -37,47 +37,53 @@ export class GameGateway implements OnGatewayConnection, OnGatewayDisconnect {
await this.usersRepository.update(user.id, {
gameSocketId: client.id,
});
this.connectedClients.set(user.id, client);
}

async handleDisconnect(@ConnectedSocket() client: Socket) {
const user = await this.authService.getUserFromSocket(client);
if (!user || !client.id || user.gameSocketId) return;
if (!user || client.id !== user.gameSocketId) return;

await this.usersRepository.update(user.id, {
gameSocketId: null,
});
this.connectedClients.delete(user.id);
client.rooms.clear();
}

async inviteGame(
gatewayInvitationParamDto: GatewayCreateInvitationParamDto,
) {
const invitationId = gatewayInvitationParamDto.invitationId;
const invitingUserNickname =
gatewayInvitationParamDto.invitingUserNickname;
const invitedUserId = gatewayInvitationParamDto.invitedUserId;
gameSetting(invitation: GameInvitation) {
// 1. Game DB 생성하기

const invitedUser = await this.usersRepository.findOne({
where: {
id: invitedUserId,
},
});
if (!invitedUser) {
throw WSBadRequestException(`user ${invitedUserId} does not exist`);
}
// 2. 초대 해 준 사람이랑 같이 room에 들어가기
const invitingUserId = invitation.invitingUserId;
const invitedUserId = invitation.invitedUserId;
const gatewayJoinRoomParamDto: GatewayJoinRoomParamDto = {
invitingUserId: invitingUserId,
invitedUserId: invitedUserId,
roomName: `${invitingUserId}:${invitedUserId}`,
};
this.joinGameRoom(gatewayJoinRoomParamDto);

// 상대가 접속 중인지 => 접속 중인 유저가 아니라면 없던 일이 됨
if (
invitedUser.status === UserStatus.OFFLINE ||
!invitedUser.gameSocketId
)
throw WSBadRequestException('invited user is now offline');
// game start emit ?
}

console.log(`invitation id: ${invitationId}`);
console.log(`invited user gameSocketId: ${invitedUser.gameSocketId}`);
this.server.to(invitedUser.gameSocketId).emit(EVENT_GAME_INVITATION, {
invitationId: invitationId,
invitingUserNickname: invitingUserNickname,
});
joinGameRoom(gatewayJoinRoomParamDto: GatewayJoinRoomParamDto) {
const invitingUserId = gatewayJoinRoomParamDto.invitingUserId;
const invitedUserId = gatewayJoinRoomParamDto.invitedUserId;
const room = gatewayJoinRoomParamDto.roomName;

const invitingUserSocket = this.connectedClients.get(invitingUserId);
if (!invitingUserSocket)
throw WSBadRequestException(
`${invitingUserId} 는 연결되지 않은 클라이언트입니다`,
);
const invitedUserSocket = this.connectedClients.get(invitedUserId);
if (!invitedUserSocket)
throw WSBadRequestException(
`${invitedUserId} 는 연결되지 않은 클라이언트입니다`,
);

invitingUserSocket.join(room);
invitedUserSocket.join(room);
}
}
18 changes: 17 additions & 1 deletion src/game/game.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,31 @@ import { GameInvitation } from './entities/game-invitation.entity';
import { GameGateway } from './game.gateway';
import { AuthService } from '../auth/auth.service';
import { JwtService } from '@nestjs/jwt';
import { ChannelUsersRepository } from '../channels/channel-users.repository';
import { FriendsRepository } from '../users/friends.repository';
import { ChannelUser } from '../channels/entities/channel-user.entity';
import { Friend } from '../users/entities/friend.entity';
import { ChannelsModule } from '../channels/channels.module';

@Module({
imports: [TypeOrmModule.forFeature([Game, GameInvitation, User])],
imports: [
TypeOrmModule.forFeature([
Game,
GameInvitation,
User,
ChannelUser,
Friend,
]),
ChannelsModule,
],
controllers: [GameController],
providers: [
GameGateway,
GameService,
AuthService,
JwtService,
ChannelUsersRepository,
FriendsRepository,
GameRepository,
GameInvitationRepository,
UsersRepository,
Expand Down
22 changes: 1 addition & 21 deletions src/game/game.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,8 @@ import { InjectRepository } from '@nestjs/typeorm';
import { GAME_DEFAULT_PAGE_SIZE } from 'src/common/constants';
import { DataSource, Repository } from 'typeorm';
import { Game } from './entities/game.entity';
import { CreateGameInvitationParamDto } from './dto/create-invitation-param.dto';
import { DBUpdateFailureException } from '../common/exception/custom-exception';
import { GameInvitationRepository } from './game-invitation.repository';
export class GameRepository extends Repository<Game> {
constructor(
@InjectRepository(Game) private dataSource: DataSource,
private readonly gameInvitationRepository: GameInvitationRepository,
) {
constructor(@InjectRepository(Game) private dataSource: DataSource) {
super(Game, dataSource.manager);
}

Expand Down Expand Up @@ -44,18 +38,4 @@ export class GameRepository extends Repository<Game> {
);
return gameHistories;
}

async createGameInvitation(
gameInvitationDto: CreateGameInvitationParamDto,
) {
const gameInvitation = this.gameInvitationRepository.create({
invitingUserId: gameInvitationDto.invitingUser.id,
invitedUserId: gameInvitationDto.invitedUserId,
gameType: gameInvitationDto.gameType,
});
const result = await this.gameInvitationRepository.save(gameInvitation);
if (!result)
throw DBUpdateFailureException('create game invitation failed');
return result;
}
}
Loading

0 comments on commit 57cc309

Please sign in to comment.