-
Notifications
You must be signed in to change notification settings - Fork 3
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
[BE] SSE 기반 타이머 잔여 시간 조회 기능을 Web Socket 기반으로 변경 #966
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
40fa718
chore: #961 build.gradle Web Socket 의존성 추가
kelly6bf bd30648
chore: #961 SchedulerService WS 삽입 구간 마킹
kelly6bf 6afcc39
feat: #961 Web Socket 모듈 구현
kelly6bf 17a898f
refactor: 쿼리에서 액세스코드 파싱하는 역할 분리
yechop 2957562
refactor: 쿼리에서 액세스코드 파싱하는 역할 분리
yechop cce6861
refactor: #961 기존 SSE 기반 코드를 Web Socket 기반으로 변경
kelly6bf ada435c
Merge remote-tracking branch 'origin/BE/feature/#961' into BE/feature…
yechop 32f472f
chore: final 추가
yechop 676da02
chore: 테스트 임시 @Disabled
yechop File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
backend/src/main/java/site/coduo/pairroom/exception/NotFoundPairRoomSessionException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package site.coduo.pairroom.exception; | ||
|
||
public class NotFoundPairRoomSessionException extends PairRoomException { | ||
|
||
public NotFoundPairRoomSessionException(final String message) { | ||
super(message); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 25 additions & 0 deletions
25
backend/src/main/java/site/coduo/websocket/PairRoomWebSocketService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package site.coduo.websocket; | ||
|
||
import java.util.Set; | ||
|
||
import org.springframework.stereotype.Service; | ||
import org.springframework.web.socket.WebSocketSession; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
|
||
@RequiredArgsConstructor | ||
@Service | ||
public class PairRoomWebSocketService { | ||
|
||
private final PairRoomWebSocketSessionStore pairRoomWebSocketSessionStore; | ||
private final WebSocketSender prodWebSocketSender; | ||
|
||
public void sendAllPairRoomSessions(final String pairRoomAccessCode, final WebSocketMessage message) { | ||
final Set<WebSocketSession> sessions = pairRoomWebSocketSessionStore.getSessions(pairRoomAccessCode); | ||
prodWebSocketSender.sendMessage(sessions, message); | ||
} | ||
|
||
public boolean hasNoConnections(final String pairRoomAccessCode) { | ||
return !pairRoomWebSocketSessionStore.hasPairRoomSessions(pairRoomAccessCode); | ||
} | ||
} |
54 changes: 54 additions & 0 deletions
54
backend/src/main/java/site/coduo/websocket/PairRoomWebSocketSessionStore.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package site.coduo.websocket; | ||
|
||
import java.util.HashSet; | ||
import java.util.Map; | ||
import java.util.Set; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
|
||
import org.springframework.stereotype.Component; | ||
import org.springframework.web.socket.WebSocketSession; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import site.coduo.pairroom.exception.InvalidAccessCodeException; | ||
import site.coduo.pairroom.exception.NotFoundPairRoomSessionException; | ||
import site.coduo.pairroom.exception.PairRoomNotFoundException; | ||
import site.coduo.pairroom.repository.PairRoomRepository; | ||
|
||
@RequiredArgsConstructor | ||
@Component | ||
public class PairRoomWebSocketSessionStore { | ||
|
||
private final PairRoomRepository pairRoomRepository; | ||
private final Map<String, Set<WebSocketSession>> sessions = new ConcurrentHashMap<>(); | ||
|
||
public void addSession(final String pairRoomAccessCode, final WebSocketSession session) { | ||
validatePairRoomAccessCode(pairRoomAccessCode); | ||
if (!sessions.containsKey(pairRoomAccessCode)) { | ||
sessions.put(pairRoomAccessCode, new HashSet<>()); | ||
} | ||
sessions.get(pairRoomAccessCode).add(session); | ||
} | ||
|
||
private void validatePairRoomAccessCode(final String pairRoomAccessCode) { | ||
if (pairRoomAccessCode == null || pairRoomAccessCode.isBlank()) { | ||
throw new InvalidAccessCodeException("페어룸 접근 코드로 null이 입력될 수 없습니다."); | ||
} | ||
|
||
if (!pairRoomRepository.existsByAccessCode(pairRoomAccessCode)) { | ||
throw new PairRoomNotFoundException("존재하지 않는 페어룸 코드입니다. - " + pairRoomAccessCode); | ||
} | ||
} | ||
|
||
public Set<WebSocketSession> getSessions(final String pairRoomAccessCode) { | ||
validatePairRoomAccessCode(pairRoomAccessCode); | ||
if (!sessions.containsKey(pairRoomAccessCode)) { | ||
throw new NotFoundPairRoomSessionException("해당 페어룸의 세션이 존재하지 않습니다. - " + pairRoomAccessCode); | ||
} | ||
return sessions.get(pairRoomAccessCode); | ||
} | ||
|
||
public boolean hasPairRoomSessions(final String pairRoomAccessCode) { | ||
validatePairRoomAccessCode(pairRoomAccessCode); | ||
return sessions.containsKey(pairRoomAccessCode); | ||
} | ||
} |
35 changes: 35 additions & 0 deletions
35
backend/src/main/java/site/coduo/websocket/ProdWebSocketSender.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package site.coduo.websocket; | ||
|
||
import java.io.IOException; | ||
import java.util.Set; | ||
|
||
import org.springframework.stereotype.Component; | ||
import org.springframework.web.socket.TextMessage; | ||
import org.springframework.web.socket.WebSocketSession; | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
|
||
@Slf4j | ||
@RequiredArgsConstructor | ||
@Component | ||
public class ProdWebSocketSender implements WebSocketSender { | ||
|
||
private final ObjectMapper objectMapper; | ||
|
||
@Override | ||
public void sendMessage(final Set<WebSocketSession> sessions, final WebSocketMessage message) { | ||
sessions.parallelStream().forEach(session -> sendMessage(session, message)); | ||
} | ||
|
||
private void sendMessage(final WebSocketSession session, final WebSocketMessage message) { | ||
try { | ||
final TextMessage webSocketMessage = new TextMessage(objectMapper.writeValueAsString(message)); | ||
session.sendMessage(webSocketMessage); | ||
} catch (IOException e) { | ||
log.error(e.getMessage(), e); | ||
} | ||
} | ||
} |
38 changes: 38 additions & 0 deletions
38
backend/src/main/java/site/coduo/websocket/QueryAccessCodeParser.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package site.coduo.websocket; | ||
|
||
import java.net.URLDecoder; | ||
import java.nio.charset.StandardCharsets; | ||
import java.util.Arrays; | ||
|
||
import site.coduo.websocket.exception.EmptyQueryException; | ||
import site.coduo.websocket.exception.NotFoundAccessCodeInQueryException; | ||
|
||
public class QueryAccessCodeParser { | ||
|
||
private static final String QUERY_DELIMITER = "&"; | ||
private static final String KEY_VALUE_DELIMITER = "="; | ||
private static final int ACCESS_CODE_QUERY_SIZE = 2; | ||
private static final int KEY_INDEX = 0; | ||
private static final String ACCESS_CODE_KEY_NAME = "accesscode"; | ||
private static final int VALUE_INDEX = 1; | ||
|
||
public static String parse(final String query) { | ||
validateQuery(query); | ||
return Arrays.stream(query.split(QUERY_DELIMITER)) | ||
.map(keyValuePair -> keyValuePair.split(KEY_VALUE_DELIMITER)) | ||
.filter(QueryAccessCodeParser::isAccessCodeKeyValuePair) | ||
.findFirst() | ||
.map(accessCodeKeyValue -> URLDecoder.decode(accessCodeKeyValue[VALUE_INDEX], StandardCharsets.UTF_8)) | ||
.orElseThrow(() -> new NotFoundAccessCodeInQueryException("쿼리에 액세스코드가 존재하지 않습니다.")); | ||
} | ||
|
||
private static void validateQuery(final String query) { | ||
if (query == null || query.isEmpty()) { | ||
throw new EmptyQueryException("쿼리가 존재하지 않습니다."); | ||
} | ||
} | ||
|
||
private static boolean isAccessCodeKeyValuePair(final String[] keyValuePair) { | ||
return keyValuePair.length == ACCESS_CODE_QUERY_SIZE && keyValuePair[KEY_INDEX].equals(ACCESS_CODE_KEY_NAME); | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
backend/src/main/java/site/coduo/websocket/WebSocketConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package site.coduo.websocket; | ||
|
||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.web.socket.config.annotation.EnableWebSocket; | ||
import org.springframework.web.socket.config.annotation.WebSocketConfigurer; | ||
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
|
||
@RequiredArgsConstructor | ||
@EnableWebSocket | ||
@Configuration | ||
public class WebSocketConfig implements WebSocketConfigurer { | ||
|
||
private final WebSocketHandler webSocketHandler; | ||
|
||
@Override | ||
public void registerWebSocketHandlers(final WebSocketHandlerRegistry registry) { | ||
registry.addHandler(webSocketHandler, "/ws-connect") | ||
.setAllowedOrigins("*"); | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
backend/src/main/java/site/coduo/websocket/WebSocketHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package site.coduo.websocket; | ||
|
||
import org.springframework.stereotype.Component; | ||
import org.springframework.web.socket.CloseStatus; | ||
import org.springframework.web.socket.TextMessage; | ||
import org.springframework.web.socket.WebSocketSession; | ||
import org.springframework.web.socket.handler.TextWebSocketHandler; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
|
||
@Slf4j | ||
@RequiredArgsConstructor | ||
@Component | ||
public class WebSocketHandler extends TextWebSocketHandler { | ||
|
||
private final PairRoomWebSocketSessionStore pairRoomWebSocketSessionStore; | ||
|
||
@Override | ||
public void afterConnectionEstablished(final WebSocketSession session) { | ||
final String query = session.getUri().getQuery(); | ||
final String pairRoomAccessCode = QueryAccessCodeParser.parse(query); | ||
pairRoomWebSocketSessionStore.addSession(pairRoomAccessCode, session); | ||
log.info("연결 성공 : {}", session.getId()); | ||
} | ||
|
||
@Override | ||
protected void handleTextMessage(final WebSocketSession session, final TextMessage message) { | ||
// TODO : 클라이언트의 메시지를 파싱하는 메서드. 타이머 잔여 시간 조회에 필요가 없어 우선 보류 | ||
} | ||
|
||
@Override | ||
public void handleTransportError(final WebSocketSession session, final Throwable exception) { | ||
log.error("Web Socket 전송 중 에러 발생 : {}", exception.getMessage()); | ||
} | ||
|
||
@Override | ||
public void afterConnectionClosed(final WebSocketSession session, final CloseStatus status) { | ||
log.info("연결 종료 : {}, 상태 : {}", session.getId(), status); | ||
} | ||
} |
4 changes: 4 additions & 0 deletions
4
backend/src/main/java/site/coduo/websocket/WebSocketMessage.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package site.coduo.websocket; | ||
|
||
public interface WebSocketMessage { | ||
} |
10 changes: 10 additions & 0 deletions
10
backend/src/main/java/site/coduo/websocket/WebSocketSender.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package site.coduo.websocket; | ||
|
||
import java.util.Set; | ||
|
||
import org.springframework.web.socket.WebSocketSession; | ||
|
||
public interface WebSocketSender { | ||
|
||
void sendMessage(final Set<WebSocketSession> sessions, final WebSocketMessage message); | ||
} |
8 changes: 8 additions & 0 deletions
8
backend/src/main/java/site/coduo/websocket/exception/EmptyQueryException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package site.coduo.websocket.exception; | ||
|
||
public class EmptyQueryException extends WebSocketException { | ||
|
||
public EmptyQueryException(final String message) { | ||
super(message); | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
backend/src/main/java/site/coduo/websocket/exception/NotFoundAccessCodeInQueryException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package site.coduo.websocket.exception; | ||
|
||
public class NotFoundAccessCodeInQueryException extends WebSocketException { | ||
|
||
public NotFoundAccessCodeInQueryException(final String message) { | ||
super(message); | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
backend/src/main/java/site/coduo/websocket/exception/WebSocketException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package site.coduo.websocket.exception; | ||
|
||
public class WebSocketException extends RuntimeException { | ||
|
||
public WebSocketException(final String message) { | ||
super(message); | ||
} | ||
} |
6 changes: 6 additions & 0 deletions
6
backend/src/main/java/site/coduo/websocket/message/EventAndDataMessage.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package site.coduo.websocket.message; | ||
|
||
import site.coduo.websocket.WebSocketMessage; | ||
|
||
public record EventAndDataMessage(String event, String data) implements WebSocketMessage { | ||
} | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
WebSocketMessage 를 인터페이스로 두고 이 EventAndDataMessage를 레코드로 설계하신 이유가 궁금합니다!
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.
WebSocketMessage는 타이머, 레퍼런스 링크, 투두 에서 사용될 예정입니다.
현재 타이머엔 event와 data 만 필요하지만 도메인이나 상황에 따라 다양한 필드를 가진 WebSocketMessage들이 필요할 수 있어� 추상화 했습니다.
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.
아하 인터페이스를 레코드로 구현하는게 신기(?)해서 남긴 질문이였어요
지금 인터페이스는 뭔가 데이터 모음을 한번에 처리하기 위한 그런 역할이군요