Skip to content

Commit

Permalink
Merge pull request #63 from modern-agile-team/feature/socket
Browse files Browse the repository at this point in the history
Refactor(hobiJeong/socket) : 채팅 생성 쪽 코드(소켓) 구조 변경 및 swagger 문서 추가
  • Loading branch information
hobiJeong authored Oct 23, 2023
2 parents 6916c22 + 27c29d0 commit 9bb3373
Show file tree
Hide file tree
Showing 25 changed files with 558 additions and 106 deletions.
4 changes: 0 additions & 4 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ import { S3Service } from './common/s3/s3.service';
import { BoardsModule } from './boards/boards.module';
import { FriendsModule } from './friends/friends.module';
import { NoticeModule } from './notice/notice.module';
import { EventsGateway } from './events/events.gateway';
import { EventsModule } from './events/events.module';
import * as mongoose from 'mongoose';
import { UserImageRepository } from './users/repositories/user-image.repository';
import { TokenRepository } from './auth/repositories/token.repository';
Expand All @@ -40,15 +38,13 @@ import { TokenRepository } from './auth/repositories/token.repository';
BoardsModule,
FriendsModule,
NoticeModule,
EventsModule,
], //
providers: [
TokenService,
TokenRepository,
UserImageService,
UserImageRepository,
S3Service,
EventsGateway,
],
})
export class AppModule implements NestModule {
Expand Down
6 changes: 3 additions & 3 deletions src/chat/chat.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import {
ChatNotification,
ChatNotificationSchema,
} from './schemas/chat-notifiation.schemas';
import { EventsModule } from 'src/events/events.module';
import { S3Module } from 'src/common/s3/s3.module';
import { ChatRepository } from './repositories/chat.repository';
import { NotificationService } from './services/notification.service';
import { EventsGateway } from './events/events.gateway';

@Module({
imports: [
Expand All @@ -21,10 +22,9 @@ import { ChatRepository } from './repositories/chat.repository';
{ name: ChatImage.name, schema: ChatImageSchema },
{ name: ChatNotification.name, schema: ChatNotificationSchema },
]),
EventsModule,
S3Module,
],
controllers: [ChatController],
providers: [ChatService, ChatRepository],
providers: [ChatService, ChatRepository, NotificationService, EventsGateway],
})
export class ChatModule {}
39 changes: 18 additions & 21 deletions src/chat/controllers/chat.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
Get,
Param,
Post,
Sse,
UploadedFile,
UseInterceptors,
UsePipes,
Expand All @@ -13,26 +14,37 @@ import {
import { ChatService } from '../services/chat.service';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { ReceivedUserDto } from '../dto/received-user.dto';
import { PostChatDto } from '../dto/post-chat.dto';
import mongoose from 'mongoose';
import { FileInterceptor } from '@nestjs/platform-express';
import { Users } from 'src/common/decorators/user.decorator';
import { User } from 'src/users/entities/user.entity';
import { ParseObjectIdPipe } from '../parse-object-id.pipe';
import { ApiCreateChatRoom } from '../swagger-decorators/create-chat-room.decorator';
import { ApiGetChatRooms } from '../swagger-decorators/get-chat-rooms.decorator';
import { ApiGetOneChatRoom } from '../swagger-decorators/get-one-chat-room.decorator';
import { ApiDeleteChatRoom } from '../swagger-decorators/delete-chat-room.decorator';
import { ApiGetChats } from '../swagger-decorators/get-chats.decorator';
import { ApiGetChatNotification } from '../swagger-decorators/get-chat-notification.decorator';

@ApiTags('CHAT')
@Controller('chat-room')
@UsePipes(ValidationPipe)
export class ChatController {
constructor(private chatService: ChatService) {}

@ApiOperation({ summary: '채팅방 전체 조회' })
@ApiGetChatNotification()
@Sse('listener')
notificationListener() {
return this.chatService.notificationListener();
}

@ApiGetChatRooms()
@Get()
async getChatRooms(@Users() user: User) {
return this.chatService.getChatRooms(user.id);
}

@ApiOperation({ summary: '채팅방 단일 조회' })
@ApiGetOneChatRoom()
@Get(':roomId')
async getOneChatRoom(
@Users() user: User,
Expand All @@ -41,13 +53,13 @@ export class ChatController {
return this.chatService.getOneChatRoom(user.id, roomId);
}

@ApiOperation({ summary: '채팅방 생성' })
@ApiCreateChatRoom()
@Post()
async createChatRoom(@Users() user: User, @Body() body: ReceivedUserDto) {
return this.chatService.createChatRoom(user.id, body.receiverId);
}

@ApiOperation({ summary: '해당 채팅방 삭제' })
@ApiDeleteChatRoom()
@Delete(':roomId')
async deleteChatRoom(
@Users() user: User,
Expand All @@ -56,29 +68,14 @@ export class ChatController {
return this.chatService.deleteChatRoom(user.id, roomId);
}

@ApiOperation({ summary: '특정 채팅방 채팅 전체 조회' })
@ApiGetChats()
@Get(':roomId/chat')
async getChats(
@Param('roomId', ParseObjectIdPipe) roomId: mongoose.Types.ObjectId,
) {
return this.chatService.getChats(roomId);
}

@ApiOperation({ summary: '특정 채팅방 채팅 생성' })
@Post(':roomId/chat')
async createChat(
@Users() user: User,
@Param('roomId', ParseObjectIdPipe) roomId: mongoose.Types.ObjectId,
@Body() body: PostChatDto,
) {
return this.chatService.createChat(
roomId,
body.content,
user.id,
body.receiverId,
);
}

@ApiOperation({ summary: '특정 채팅방 채팅 이미지 생성' })
@Post(':roomId/chat/image')
@UseInterceptors(FileInterceptor('file'))
Expand Down
41 changes: 38 additions & 3 deletions src/chat/dto/post-chat.dto.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,55 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty, IsNumber, IsString } from 'class-validator';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import {
IsMongoId,
IsNotEmpty,
IsNumber,
IsOptional,
IsString,
} from 'class-validator';
import mongoose from 'mongoose';

export class PostChatDto {
@IsMongoId()
@IsNotEmpty()
@ApiProperty({
example: '650bde3798dd4c34439c30dc',
description: '채팅을 전송하는 채팅방 id',
})
roomId: mongoose.Types.ObjectId;

@ApiProperty({
example: '안녕하세요',
description: '채팅 내용',
})
@IsString()
@ApiPropertyOptional({
example: '안녕하세요',
description: '채팅 내용',
})
@IsString()
@IsNotEmpty()
content: string;
@IsOptional()
content?: string;

@ApiProperty({
example: '1',
description: '채팅을 보내는 유저 아이디',
})
@IsNumber()
senderId: number;

@ApiProperty({
example: '2',
description: '채팅을 받는 유저 아이디',
})
@IsNumber()
@IsNotEmpty()
receiverId: number;

@ApiProperty({
example: 'Key: file, Value: asd.png',
description: 'FormData. 이미지 파일',
})
@IsOptional()
imageUrl?: FormData;
}
33 changes: 15 additions & 18 deletions src/events/events.gateway.ts → src/chat/events/events.gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import {
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
import mongoose from 'mongoose';
import { ChatService } from 'src/chat/services/chat.service';
import { PostChatDto } from '../dto/post-chat.dto';

@WebSocketGateway({ namespace: /\/ch-\d+/, cors: true })
// @WebSocketGateway({ namespace: '/ch123' })
@WebSocketGateway({ namespace: /\/ch-.+/, cors: true })
export class EventsGateway
implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect
{
constructor(private chatService: ChatService) {}
@WebSocketServer() public server: Server;

@SubscribeMessage('test')
Expand All @@ -25,37 +27,32 @@ export class EventsGateway

@SubscribeMessage('login')
handleLogin(
// @MessageBody() data: { id: number; roomId: number[] },
@MessageBody() data: { id: number; rooms: mongoose.Types.ObjectId[] },
@ConnectedSocket() socket: Socket,
) {
console.log('login', data.id);
data.rooms.forEach((room) => {
socket.join(`${room}`);
console.log('join', room);
console.log('join', socket.nsp.name, room);
socket.join(room.toString());
});
}

@SubscribeMessage('message')
async handleMessage(
@MessageBody() postChatDto: PostChatDto,
@ConnectedSocket() socket: Socket,
) {
const chat = await this.chatService.createChat(postChatDto);
socket.to(postChatDto.roomId.toString()).emit('message', chat);
}

afterInit(server: Server): any {
console.log('websocketserver init');
}

handleConnection(@ConnectedSocket() socket: Socket): any {
console.log('connected', socket.nsp.name);
socket.emit('hello', socket.nsp.name);
socket.on('hello', (data) => {
console.log(data);
});
socket.on('login', (data) => {
const userName = data.id;
socket.data.userName = userName;
});
socket.on('message', (data) => {
const userId = data.id;
const chat = data.message;
console.log('Received new chat message:', data.message);
socket.broadcast.emit('msgNoti', `${userId}의 message: ${chat}`);
});
}

handleDisconnect(@ConnectedSocket() socket: Socket): any {
Expand Down
1 change: 0 additions & 1 deletion src/chat/schemas/chat-image.schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export class ChatImage {
chat_id: mongoose.Types.ObjectId;

@IsString()
@IsNotEmpty()
@Prop({ required: true })
image_url: string;
}
Expand Down
8 changes: 2 additions & 6 deletions src/chat/schemas/chat-notifiation.schemas.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Prop, Schema, SchemaFactory, SchemaOptions } from '@nestjs/mongoose';
import * as mongoose from 'mongoose';
import { Chat } from './chat.schemas';
import { IsBoolean, IsMongoId, IsNotEmpty, IsNumber } from 'class-validator';
import { IsBoolean, IsMongoId, IsNumber } from 'class-validator';

const options: SchemaOptions = {
collection: 'ChatNotification',
Expand All @@ -11,25 +11,21 @@ const options: SchemaOptions = {
@Schema(options)
export class ChatNotification {
@IsMongoId()
@IsNotEmpty()
@Prop({ type: mongoose.Types.ObjectId, ref: Chat.name })
chat_id: mongoose.Types.ObjectId;

@IsNumber()
@IsNotEmpty()
@Prop({ required: true })
sender: number;

@IsNumber()
@IsNotEmpty()
@Prop({ required: true })
receiver: number;

@IsBoolean()
@IsNotEmpty()
@Prop({ required: true, default: false })
isSeen: boolean;
}

export const ChatNotificationSchema =
SchemaFactory.createForClass(ChatNotification);
SchemaFactory.createForClass(ChatNotification);
3 changes: 3 additions & 0 deletions src/chat/schemas/chat-room.schemas.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Prop, Schema, SchemaFactory, SchemaOptions } from '@nestjs/mongoose';
import { IsNumber } from 'class-validator';

const options: SchemaOptions = {
collection: 'ChatRoom',
Expand All @@ -7,9 +8,11 @@ const options: SchemaOptions = {

@Schema(options)
export class ChatRoom {
@IsNumber()
@Prop({ required: true })
host_id: number;

@IsNumber()
@Prop({ required: true })
guest_id: number;

Expand Down
6 changes: 1 addition & 5 deletions src/chat/schemas/chat.schemas.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Prop, Schema, SchemaFactory, SchemaOptions } from '@nestjs/mongoose';
import * as mongoose from 'mongoose';
import { ChatRoom } from './chat-room.schemas';
import { IsMongoId, IsNotEmpty, IsNumber, IsString } from 'class-validator';
import { IsMongoId, IsNumber, IsString } from 'class-validator';

const options: SchemaOptions = {
collection: 'Chat',
Expand All @@ -11,22 +11,18 @@ const options: SchemaOptions = {
@Schema(options)
export class Chat {
@IsMongoId()
@IsNotEmpty()
@Prop({ type: mongoose.Types.ObjectId, ref: ChatRoom.name })
chatroom_id: mongoose.Types.ObjectId;

@IsNumber()
@IsNotEmpty()
@Prop({ required: true })
sender: number;

@IsNumber()
@IsNotEmpty()
@Prop({ required: true })
receiver: number;

@IsString()
@IsNotEmpty()
@Prop({ required: true })
content: string;
}
Expand Down
Loading

0 comments on commit 9bb3373

Please sign in to comment.