Skip to content

Commit ef667dc

Browse files
authored
Merge pull request #227 from prgrms-web-devcourse-final-project/Refactor/223
Refactor: webRTC 도메인 리팩토링 (#223)
2 parents 5a6f6ae + 575ac32 commit ef667dc

20 files changed

+337
-477
lines changed

build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ dependencies {
5050
// Development Tools
5151
compileOnly("org.projectlombok:lombok")
5252
annotationProcessor("org.projectlombok:lombok")
53+
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
5354
developmentOnly("org.springframework.boot:spring-boot-devtools")
5455

5556
// Swagger

src/main/java/com/back/Application.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22

33
import org.springframework.boot.SpringApplication;
44
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
56
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
67

7-
@SpringBootApplication
88
@EnableJpaAuditing
9+
@SpringBootApplication
10+
@ConfigurationPropertiesScan
911
public class Application {
1012

1113
public static void main(String[] args) {

src/main/java/com/back/domain/studyroom/entity/Room.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,6 @@ public String getRawThumbnailUrl() {
5454
private boolean allowAudio;
5555
private boolean allowScreenShare;
5656

57-
@Builder.Default
58-
@Column(nullable = false)
59-
private Integer currentParticipants = 0;
60-
6157
// 방 상태
6258
@Builder.Default
6359
@Enumerated(EnumType.STRING)
@@ -191,7 +187,6 @@ public static Room create(String title, String description, boolean isPrivate,
191187
room.allowAudio = useWebRTC; // WebRTC 사용 여부에 따라 설정
192188
room.allowScreenShare = useWebRTC; // WebRTC 사용 여부에 따라 설정
193189
room.status = RoomStatus.WAITING; // 생성 시 대기 상태
194-
room.currentParticipants = 0;
195190
room.createdBy = creator;
196191
room.theme = theme;
197192

src/main/java/com/back/global/exception/ErrorCode.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public enum ErrorCode {
6161
// ======================== 학습 기록 관련 ========================
6262
DURATION_MISMATCH(HttpStatus.BAD_REQUEST, "RECORD_001", "받은 duration과 계산된 duration이 5초 이상 차이납니다."),
6363

64-
// ======================== 알림 관련 ========================
64+
// ======================== 메모 관련 ========================
6565
MEMO_NOT_FOUND(HttpStatus.NOT_FOUND, "MEMO_001", "존재하지 않는 메모입니다."),
6666

6767
// ======================== 알림 관련 ========================
@@ -99,6 +99,7 @@ public enum ErrorCode {
9999
WS_INVALID_REQUEST(HttpStatus.BAD_REQUEST, "WS_014", "잘못된 WebSocket 요청입니다."),
100100
WS_INTERNAL_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "WS_015", "WebSocket 내부 오류가 발생했습니다."),
101101
WS_CHAT_DELETE_FORBIDDEN(HttpStatus.FORBIDDEN, "WS_016", "채팅 삭제 권한이 없습니다. 방장 또는 부방장만 가능합니다."),
102+
WS_TARGET_OFFLINE(HttpStatus.NOT_FOUND, "WS_017", "상대방이 오프라인 상태이거나 연결할 수 없습니다."),
102103

103104
// ======================== 커뮤니티 관련 ========================
104105
POST_NOT_FOUND(HttpStatus.NOT_FOUND, "POST_001", "존재하지 않는 게시글입니다."),

src/main/java/com/back/global/websocket/dto/WebSocketSessionInfo.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,19 @@
44

55
public record WebSocketSessionInfo(
66
Long userId,
7+
String username,
78
String sessionId,
89
LocalDateTime connectedAt,
910
LocalDateTime lastActiveAt,
1011
Long currentRoomId
1112
) {
1213

1314
// 새로운 세션 생성
14-
public static WebSocketSessionInfo createNewSession(Long userId, String sessionId) {
15+
public static WebSocketSessionInfo createNewSession(Long userId, String username, String sessionId) {
1516
LocalDateTime now = LocalDateTime.now();
1617
return new WebSocketSessionInfo(
1718
userId,
19+
username,
1820
sessionId,
1921
now, // connectedAt
2022
now, // lastActiveAt
@@ -26,6 +28,7 @@ public static WebSocketSessionInfo createNewSession(Long userId, String sessionI
2628
public WebSocketSessionInfo withUpdatedActivity() {
2729
return new WebSocketSessionInfo(
2830
userId,
31+
username,
2932
sessionId,
3033
connectedAt,
3134
LocalDateTime.now(),
@@ -37,6 +40,7 @@ public WebSocketSessionInfo withUpdatedActivity() {
3740
public WebSocketSessionInfo withRoomId(Long newRoomId) {
3841
return new WebSocketSessionInfo(
3942
userId,
43+
username,
4044
sessionId,
4145
connectedAt,
4246
LocalDateTime.now(),
@@ -48,6 +52,7 @@ public WebSocketSessionInfo withRoomId(Long newRoomId) {
4852
public WebSocketSessionInfo withoutRoom() {
4953
return new WebSocketSessionInfo(
5054
userId,
55+
username,
5156
sessionId,
5257
connectedAt,
5358
LocalDateTime.now(),

src/main/java/com/back/global/websocket/event/WebSocketEventListener.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ public void handleWebSocketConnectListener(SessionConnectEvent event) {
3131

3232
String sessionId = headerAccessor.getSessionId();
3333
Long userId = userDetails.getUserId();
34+
String username = userDetails.getUsername();
3435

3536
// 세션 매니저에 등록 (TTL 10분 자동 설정)
36-
sessionManager.addSession(userId, sessionId);
37+
sessionManager.addSession(userId, username, sessionId);
3738

3839
log.info("WebSocket 연결 완료 - 사용자: {} ({}), 세션: {}",
3940
userDetails.getUsername(), userId, sessionId);

src/main/java/com/back/global/websocket/service/UserSessionService.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@ public class UserSessionService {
2323
private final RedisSessionStore redisSessionStore;
2424

2525
// 세션 등록
26-
public void registerSession(Long userId, String sessionId) {
26+
public void registerSession(Long userId, String username, String sessionId) {
2727
WebSocketSessionInfo existingSession = redisSessionStore.getUserSession(userId);
2828
if (existingSession != null) {
2929
terminateSession(existingSession.sessionId());
3030
log.info("기존 세션 제거 후 새 세션 등록 - 사용자: {}", userId);
3131
}
3232

33-
WebSocketSessionInfo newSession = WebSocketSessionInfo.createNewSession(userId, sessionId);
33+
WebSocketSessionInfo newSession = WebSocketSessionInfo.createNewSession(userId, username, sessionId);
3434
redisSessionStore.saveUserSession(userId, newSession);
3535
redisSessionStore.saveSessionUserMapping(sessionId, userId);
3636

src/main/java/com/back/global/websocket/service/WebSocketSessionManager.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ public class WebSocketSessionManager {
1616
private final RoomParticipantService roomParticipantService;
1717

1818
// 사용자 세션 추가 (WebSocket 연결 시 호출)
19-
public void addSession(Long userId, String sessionId) {
20-
userSessionService.registerSession(userId, sessionId);
19+
public void addSession(Long userId, String username, String sessionId) {
20+
userSessionService.registerSession(userId, username, sessionId);
2121
}
2222

2323
// 세션 제거 (WebSocket 연결 종료 시 호출)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.back.global.websocket.webrtc.config;
2+
3+
import org.springframework.boot.context.properties.ConfigurationProperties;
4+
import java.util.List;
5+
6+
@ConfigurationProperties(prefix = "webrtc")
7+
public record WebRTCProperties(
8+
List<IceServer> iceServers
9+
) {
10+
// yml의 각 항목과 매핑될 내부 record
11+
public record IceServer(String urls, String username, String credential) {}
12+
}

src/main/java/com/back/global/websocket/webrtc/controller/WebRTCApiController.java

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,55 @@
11
package com.back.global.websocket.webrtc.controller;
22

33
import com.back.global.common.dto.RsData;
4+
import com.back.global.websocket.webrtc.config.WebRTCProperties;
5+
import com.back.global.websocket.webrtc.dto.ice.IceServer;
46
import com.back.global.websocket.webrtc.dto.ice.IceServerConfig;
57
import io.swagger.v3.oas.annotations.Operation;
68
import io.swagger.v3.oas.annotations.Parameter;
7-
import io.swagger.v3.oas.annotations.responses.ApiResponse;
8-
import io.swagger.v3.oas.annotations.responses.ApiResponses;
99
import io.swagger.v3.oas.annotations.tags.Tag;
1010
import lombok.RequiredArgsConstructor;
1111
import lombok.extern.slf4j.Slf4j;
12+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
1213
import org.springframework.http.HttpStatus;
1314
import org.springframework.http.ResponseEntity;
1415
import org.springframework.web.bind.annotation.*;
1516

17+
import java.util.List;
18+
1619
@Slf4j
1720
@RestController
1821
@RequiredArgsConstructor
1922
@RequestMapping("/api/webrtc")
23+
@EnableConfigurationProperties(WebRTCProperties.class)
2024
@Tag(name = "WebRTC API", description = "WebRTC 시그널링 및 ICE 서버 관련 REST API")
2125
public class WebRTCApiController {
2226

23-
// ICE 서버 설정 조회
27+
private final WebRTCProperties webRTCProperties;
28+
2429
@GetMapping("/ice-servers")
25-
@Operation(
26-
summary = "ICE 서버 설정 조회",
27-
description = "WebRTC 연결에 필요한 STUN/TURN 서버 정보를 조회합니다."
28-
)
29-
@ApiResponses({
30-
@ApiResponse(responseCode = "200", description = "조회 성공"),
31-
@ApiResponse(responseCode = "500", description = "서버 오류")
32-
})
30+
@Operation(summary = "ICE 서버 설정 조회")
3331
public ResponseEntity<RsData<IceServerConfig>> getIceServers(
3432
@Parameter(description = "사용자 ID (선택)") @RequestParam(required = false) Long userId,
3533
@Parameter(description = "방 ID (선택)") @RequestParam(required = false) Long roomId) {
3634

3735
log.info("ICE 서버 설정 요청 - userId: {}, roomId: {}", userId, roomId);
3836

39-
// 기본 Google STUN 서버 사용
40-
IceServerConfig config = IceServerConfig.withDefaultStunServers();
37+
List<IceServer> iceServers =
38+
webRTCProperties.iceServers().stream()
39+
.map(s -> new IceServer(s.urls(), s.username(), s.credential()))
40+
.toList();
41+
42+
IceServerConfig config = new IceServerConfig(iceServers);
4143

42-
log.info("ICE 서버 설정 제공 완료 - STUN 서버 {}개", config.iceServers().size());
44+
log.info("ICE 서버 설정 제공 완료 - STUN/TURN 서버 {}개", config.iceServers().size());
4345

4446
return ResponseEntity
4547
.status(HttpStatus.OK)
4648
.body(RsData.success("ICE 서버 설정 조회 성공", config));
4749
}
4850

49-
// WebRTC 서비스 상태 확인
5051
@GetMapping("/health")
51-
@Operation(
52-
summary = "WebRTC 서비스 상태 확인",
53-
description = "WebRTC 시그널링 서버의 상태를 확인합니다."
54-
)
55-
@ApiResponse(responseCode = "200", description = "정상 작동 중")
52+
@Operation(summary = "WebRTC 서비스 상태 확인")
5653
public ResponseEntity<RsData<String>> healthCheck() {
5754
return ResponseEntity
5855
.status(HttpStatus.OK)

0 commit comments

Comments
 (0)