-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ping 통신을 위한 데이터 타입 변경 #773
Changes from all commits
96ec557
3011336
d890c10
36d279c
4fee0b6
2400802
eca1bc9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,14 +2,20 @@ | |
|
||
import com.ddang.ddang.chat.application.MessageService; | ||
import com.ddang.ddang.chat.application.dto.CreateMessageDto; | ||
import com.ddang.ddang.chat.application.dto.ReadMessageDto; | ||
import com.ddang.ddang.chat.application.event.MessageNotificationEvent; | ||
import com.ddang.ddang.chat.application.event.UpdateReadMessageLogEvent; | ||
import com.ddang.ddang.chat.domain.Message; | ||
import com.ddang.ddang.chat.domain.WebSocketChatSessions; | ||
import com.ddang.ddang.chat.handler.dto.ChatMessageDataDto; | ||
import com.ddang.ddang.chat.handler.dto.ChatPingDataDto; | ||
import com.ddang.ddang.chat.handler.dto.HandleMessageResponse; | ||
import com.ddang.ddang.chat.handler.dto.MessageDto; | ||
import com.ddang.ddang.chat.handler.dto.SendMessageStatus; | ||
import com.ddang.ddang.chat.presentation.dto.request.CreateMessageRequest; | ||
import com.ddang.ddang.chat.presentation.dto.request.ReadMessageRequest; | ||
import com.ddang.ddang.websocket.handler.WebSocketHandleTextMessageProvider; | ||
import com.ddang.ddang.websocket.handler.dto.ChattingType; | ||
import com.ddang.ddang.websocket.handler.dto.SendMessageDto; | ||
import com.ddang.ddang.websocket.handler.dto.SessionAttributeDto; | ||
import com.ddang.ddang.websocket.handler.dto.TextMessageType; | ||
|
@@ -30,6 +36,9 @@ | |
@RequiredArgsConstructor | ||
public class ChatWebSocketHandleTextMessageProvider implements WebSocketHandleTextMessageProvider { | ||
|
||
private static final String CHATROOM_ID_KEY = "chatRoomId"; | ||
private static final String CHATTTING_TYPE_KEY = "type"; | ||
|
||
private final WebSocketChatSessions sessions; | ||
private final ObjectMapper objectMapper; | ||
private final MessageService messageService; | ||
|
@@ -47,15 +56,18 @@ public List<SendMessageDto> handleCreateSendMessage( | |
final Map<String, String> data | ||
) throws JsonProcessingException { | ||
final SessionAttributeDto sessionAttribute = getSessionAttributes(session); | ||
final ChatMessageDataDto messageData = objectMapper.convertValue(data, ChatMessageDataDto.class); | ||
sessions.add(session, messageData.chatRoomId()); | ||
final long chatRoomId = getChatRoomId(data); | ||
sessions.add(session, chatRoomId); | ||
|
||
final Long writerId = sessionAttribute.userId(); | ||
final CreateMessageDto createMessageDto = createMessageDto(messageData, writerId); | ||
final Message message = messageService.create(createMessageDto); | ||
sendNotificationIfReceiverNotInSession(message, sessionAttribute); | ||
final ChattingType type = ChattingType.findValue(data.get(CHATTTING_TYPE_KEY)); | ||
if (ChattingType.PING == type) { | ||
return createPingResponse(sessionAttribute, data, session); | ||
} | ||
return createSendMessageResponse(data, sessionAttribute); | ||
} | ||
|
||
return createSendMessages(message, writerId, createMessageDto.chatRoomId()); | ||
private long getChatRoomId(final Map<String, String> data) { | ||
return Long.parseLong(data.get(CHATROOM_ID_KEY)); | ||
} | ||
|
||
private SessionAttributeDto getSessionAttributes(final WebSocketSession session) { | ||
|
@@ -64,6 +76,32 @@ private SessionAttributeDto getSessionAttributes(final WebSocketSession session) | |
return objectMapper.convertValue(attributes, SessionAttributeDto.class); | ||
} | ||
|
||
private List<SendMessageDto> createPingResponse(final SessionAttributeDto sessionAttribute, final Map<String, String> data, final WebSocketSession userSession) throws JsonProcessingException { | ||
final ChatPingDataDto pingData = objectMapper.convertValue(data, ChatPingDataDto.class); | ||
final ReadMessageRequest readMessageRequest = new ReadMessageRequest(sessionAttribute.userId(), pingData.chatRoomId(), pingData.lastMessageId()); | ||
final List<ReadMessageDto> readMessageDtos = messageService.readAllByLastMessageId(readMessageRequest); | ||
Comment on lines
+79
to
+82
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 필수해당 클래스에 기존 컨벤션이었던 120자를 초과하는 라인들이 많이 보이네요!! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 인텔리제이 설정이 초기화되어서 정렬이 잘 안 되고 있었네요...ㅠㅠ |
||
|
||
final List<MessageDto> messageDtos = convertToMessageDto(readMessageDtos, userSession); | ||
final HandleMessageResponse handleMessageResponse = new HandleMessageResponse(SendMessageStatus.SUCCESS, messageDtos); | ||
return List.of(new SendMessageDto(userSession, new TextMessage(objectMapper.writeValueAsString(handleMessageResponse)))); | ||
} | ||
|
||
private List<MessageDto> convertToMessageDto(final List<ReadMessageDto> readMessageDtos, final WebSocketSession session) { | ||
return readMessageDtos.stream() | ||
.map(readMessageDto -> MessageDto.of(readMessageDto, isMyMessage(session, readMessageDto.writerId()))) | ||
.toList(); | ||
} | ||
|
||
private List<SendMessageDto> createSendMessageResponse(final Map<String, String> data, final SessionAttributeDto sessionAttribute) throws JsonProcessingException { | ||
final Long writerId = sessionAttribute.userId(); | ||
final ChatMessageDataDto messageData = objectMapper.convertValue(data, ChatMessageDataDto.class); | ||
final CreateMessageDto createMessageDto = createMessageDto(messageData, writerId); | ||
final Message message = messageService.create(createMessageDto); | ||
sendNotificationIfReceiverNotInSession(message, sessionAttribute); | ||
|
||
return createSendMessages(message, writerId, createMessageDto.chatRoomId()); | ||
} | ||
|
||
private CreateMessageDto createMessageDto(final ChatMessageDataDto messageData, final Long userId) { | ||
final CreateMessageRequest request = new CreateMessageRequest( | ||
messageData.receiverId(), | ||
|
@@ -95,7 +133,8 @@ private List<SendMessageDto> createSendMessages( | |
|
||
final List<SendMessageDto> sendMessageDtos = new ArrayList<>(); | ||
for (final WebSocketSession currentSession : groupSessions) { | ||
final TextMessage textMessage = createTextMessage(message, writerId, currentSession); | ||
final MessageDto messageDto = MessageDto.of(message, isMyMessage(currentSession, writerId)); | ||
final TextMessage textMessage = createTextMessage(messageDto); | ||
sendMessageDtos.add(new SendMessageDto(currentSession, textMessage)); | ||
updateReadMessageLog(currentSession, chatRoomId, message); | ||
} | ||
|
@@ -104,14 +143,11 @@ private List<SendMessageDto> createSendMessages( | |
} | ||
|
||
private TextMessage createTextMessage( | ||
final Message message, | ||
final Long writerId, | ||
final WebSocketSession session | ||
final MessageDto messageDto | ||
) throws JsonProcessingException { | ||
final boolean isMyMessage = isMyMessage(session, writerId); | ||
final MessageDto messageDto = MessageDto.of(message, isMyMessage); | ||
final HandleMessageResponse handleMessageResponse = new HandleMessageResponse(SendMessageStatus.SUCCESS, List.of(messageDto)); | ||
|
||
return new TextMessage(objectMapper.writeValueAsString(messageDto)); | ||
return new TextMessage(objectMapper.writeValueAsString(handleMessageResponse)); | ||
} | ||
|
||
private boolean isMyMessage(final WebSocketSession session, final Long writerId) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package com.ddang.ddang.chat.handler.dto; | ||
|
||
public record ChatPingDataDto(Long chatRoomId, Long lastMessageId) { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.ddang.ddang.chat.handler.dto; | ||
|
||
import java.util.List; | ||
|
||
public record HandleMessageResponse(SendMessageStatus sendMessageStatus, List<MessageDto> messages) { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.ddang.ddang.chat.handler.dto; | ||
|
||
public enum SendMessageStatus { | ||
|
||
SUCCESS, | ||
DISCONNECTED, | ||
FORBIDDEN, | ||
; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package com.ddang.ddang.websocket.handler.dto; | ||
|
||
import java.util.Arrays; | ||
|
||
public enum ChattingType { | ||
|
||
MESSAGE("message"), | ||
PING("ping"), | ||
; | ||
Comment on lines
+7
to
+9
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 질문대소문자를 무관하게 하는 로직으로 수정하는 과정에서 value는 매핑을 위해 있는 것으로 보여 해당 값들을 없애고 name과 비교하는 로직으로 수정하려고 합니다. 괜찮을까요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저는 좋습니다 👍🏻 |
||
|
||
private String value; | ||
|
||
ChattingType(final String value) { | ||
this.value = value; | ||
} | ||
|
||
public static ChattingType findValue(final String value) { | ||
return Arrays.stream(ChattingType.values()) | ||
.filter(chattingType -> chattingType.value.equals(value)) | ||
.findFirst() | ||
.orElseThrow(() -> new IllegalArgumentException("잘못된 채팅 타입입니다.")); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,7 @@ | |
import java.util.Set; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | ||
import static org.mockito.ArgumentMatchers.any; | ||
import static org.mockito.BDDMockito.given; | ||
import static org.mockito.BDDMockito.willDoNothing; | ||
|
@@ -173,6 +174,19 @@ class ChatWebSocketHandleTextMessageProviderTest extends ChatWebSocketHandleText | |
assertThat(actual).hasSize(1); | ||
} | ||
|
||
@Test | ||
void 잘못된_데이터_타입_전달시_예외가_발생한다() throws JsonProcessingException { | ||
// given | ||
given(writerSession.getAttributes()).willReturn(발신자_세션_attribute_정보); | ||
willDoNothing().given(sessions).add(writerSession, 채팅방.getId()); | ||
willReturn(false).given(sessions).containsByUserId(채팅방.getId(), 수신자.getId()); | ||
willReturn(Set.of(writerSession)).given(sessions).getSessionsByChatRoomId(채팅방.getId()); | ||
|
||
// when | ||
assertThatThrownBy(() -> provider.handleCreateSendMessage(writerSession, 잘못된_메시지_전송_데이터)) | ||
.isInstanceOf(IllegalArgumentException.class); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 선택메시지는 비교하지 않아도 괜찮을까요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 메시지 내부 필드를 비교해야 하는지에 대한 질문이 맞나요?! |
||
} | ||
|
||
@Test | ||
void 세션을_삭제한다() { | ||
// given | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 선택해당 클래스를 한 번 정렬해 주면 좋을 것 같아요! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 정렬 완료 했습니다! |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package com.ddang.ddang.websocket.handler.dto; | ||
|
||
import org.junit.jupiter.api.Test; | ||
|
||
import java.util.Map; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | ||
|
||
class ChattingTypeTest { | ||
|
||
@Test | ||
void 타입에_해당하는_enum을_반환한다() { | ||
// given | ||
final Map<String, String> data = Map.of("type", "message"); | ||
|
||
// when | ||
final ChattingType actual = ChattingType.findValue(data.get("type")); | ||
|
||
// then | ||
assertThat(actual).isEqualTo(ChattingType.MESSAGE); | ||
} | ||
|
||
|
||
@Test | ||
void 해당하는_타입이_없는_경우_예외를_던진다() { | ||
// given | ||
final Map<String, String> data = Map.of("type", "wrong type"); | ||
|
||
// when & then | ||
assertThatThrownBy(() -> ChattingType.findValue(data.get("type"))).isInstanceOf(IllegalArgumentException.class); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
선택
당장 진행하지 않아도 괜찮긴 한데,
WebSocketHandler
에서 provider를 통해 chat 혹은 bid로 이동하는 것과 같이, chat type에 따라 클래스를 분리해 핸들링하는 것에 대해 어떻게 생각하시나요?현재 해당 클래스에서 많은 역할이 있는 것 같아 의견 여쭤봅니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
좋은 의견 감사합니다!
말씀해주신 것처럼
WebSocketHandler
에서 너무 많은 역할을 하고 있어서 chat type에 따라 클래스를 분리해 핸들링하도록 수정했습니다.추가로
WebSocketHandler
에서 PingHandler와 MessageHandler를 호출하여 데이터를 넘겨줄 때WebSocketSession
이나Map<String, String>
과 같은 원시 타입이 아닌 dto로 포장한 값을 전달하도록 수정했습니다.원시 타입을 넘겨주니 원시 타입 내부에 어떤 데이터를 포함하고 있는지 모르겠더라구요!
이 부분이 괜찮은지 제이미의 의견이 있다면 궁금합니다!