From 89fb0d50c881b0b14e6bd4d5ac498df9cb2b7362 Mon Sep 17 00:00:00 2001 From: EunJiJung Date: Wed, 26 Feb 2025 14:41:06 +0900 Subject: [PATCH 01/16] =?UTF-8?q?[BE]=20refactor:=20socket.io=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20(#30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: EunJiJung --- .../com/asyncgate/signaling_server/config/KurentoConfig.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/KurentoConfig.java b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/KurentoConfig.java index afb1ece3..591c6a4a 100644 --- a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/KurentoConfig.java +++ b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/KurentoConfig.java @@ -35,7 +35,9 @@ public KurentoHandler kurentoHandler(KurentoManager kurentoManager) { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { - registry.addHandler(kurentoHandler(kurentoManager(kurentoClient())), "/signal").setAllowedOrigins("*"); + registry.addHandler(kurentoHandler(kurentoManager(kurentoClient())), "/socket.io/") + .setAllowedOrigins("*") + .withSockJS(); } @Bean From 5e9a068e3e044100745aa48eb94e2a4502784d61 Mon Sep 17 00:00:00 2001 From: EunJiJung Date: Wed, 26 Feb 2025 14:51:24 +0900 Subject: [PATCH 02/16] =?UTF-8?q?[BE]=20refactor:=20socket=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=EB=A5=BC=20api=20gateway=EC=97=90=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=20(#30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: EunJiJung --- .../src/main/resources/application-local.yml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/backend/apigateway-server/src/main/resources/application-local.yml b/src/backend/apigateway-server/src/main/resources/application-local.yml index 8cca107c..a3a332aa 100644 --- a/src/backend/apigateway-server/src/main/resources/application-local.yml +++ b/src/backend/apigateway-server/src/main/resources/application-local.yml @@ -93,12 +93,20 @@ spring: - AuthorizationHeaderFilter - id: signaling-server - uri: lb://SIGNALING-SERVER + uri: ws://SIGNALING-SERVER predicates: - - Path=/signalings/signal + - Path=/signalings/** filters: - RemoveRequestHeader=Cookie - - RewritePath=/signalings/(?.*), /$\{segment} + - RewritePath=/signalings/(?.*), /$\{segment} + + - id: signaling-server + uri: wss://SIGNALING-SERVER + predicates: + - Path=/signalings/** + filters: + - RemoveRequestHeader=Cookie + - RewritePath=/signalings/(?.*), /$\{segment} default-filters: - DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-Allow-Credentials From 7133211552d5bf0b49f412622823876b3d7ad2c9 Mon Sep 17 00:00:00 2001 From: EunJiJung Date: Wed, 26 Feb 2025 15:37:22 +0900 Subject: [PATCH 03/16] =?UTF-8?q?[BE]=20refactor:=20socket.io=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0=20(#30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: EunJiJung --- .../com/asyncgate/signaling_server/config/KurentoConfig.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/KurentoConfig.java b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/KurentoConfig.java index 591c6a4a..afb1ece3 100644 --- a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/KurentoConfig.java +++ b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/KurentoConfig.java @@ -35,9 +35,7 @@ public KurentoHandler kurentoHandler(KurentoManager kurentoManager) { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { - registry.addHandler(kurentoHandler(kurentoManager(kurentoClient())), "/socket.io/") - .setAllowedOrigins("*") - .withSockJS(); + registry.addHandler(kurentoHandler(kurentoManager(kurentoClient())), "/signal").setAllowedOrigins("*"); } @Bean From d0b8c8eabe9e2c356025e1c2b43796d2b7d7e1eb Mon Sep 17 00:00:00 2001 From: EunJiJung Date: Wed, 26 Feb 2025 16:01:34 +0900 Subject: [PATCH 04/16] =?UTF-8?q?[BE]=20refactor:=20member=20profile=20get?= =?UTF-8?q?=EC=9D=84=20kurento=20manager=EC=97=90=20=EC=B6=94=EA=B0=80=20(?= =?UTF-8?q?#30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: EunJiJung --- .../config/KurentoConfig.java | 13 +++++-- .../signaling_server/domain/Member.java | 13 ++++--- .../signaling_server/entity/MemberEntity.java | 4 +- .../client/MemberServiceClient.java | 9 +++++ .../client/MemberServiceClientImpl.java | 38 +++++++++++++++++++ .../response/ReadUserRoomProfileResponse.java | 33 ++++++++++++++++ .../utility/HttpClientUtil.java | 33 ++++++++++++++++ .../signaling/KurentoManager.java | 29 +++++++------- .../service/ReadUserRoomProfileService.java | 2 - 9 files changed, 147 insertions(+), 27 deletions(-) create mode 100644 src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/client/MemberServiceClient.java create mode 100644 src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/client/MemberServiceClientImpl.java create mode 100644 src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/dto/response/ReadUserRoomProfileResponse.java create mode 100644 src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/utility/HttpClientUtil.java diff --git a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/KurentoConfig.java b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/KurentoConfig.java index afb1ece3..28a7de78 100644 --- a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/KurentoConfig.java +++ b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/KurentoConfig.java @@ -1,5 +1,7 @@ package com.asyncgate.signaling_server.config; +import com.asyncgate.signaling_server.infrastructure.client.MemberServiceClient; +import com.asyncgate.signaling_server.infrastructure.client.MemberServiceClientImpl; import com.asyncgate.signaling_server.signaling.KurentoManager; import com.asyncgate.signaling_server.support.handler.KurentoHandler; import org.kurento.client.KurentoClient; @@ -24,8 +26,13 @@ public KurentoClient kurentoClient() { } @Bean - public KurentoManager kurentoManager(KurentoClient kurentoClient) { - return new KurentoManager(kurentoClient); + public MemberServiceClient memberServiceClient() { + return new MemberServiceClientImpl(); + } + + @Bean + public KurentoManager kurentoManager(KurentoClient kurentoClient, MemberServiceClient memberServiceClient) { + return new KurentoManager(kurentoClient, memberServiceClient); } @Bean @@ -35,7 +42,7 @@ public KurentoHandler kurentoHandler(KurentoManager kurentoManager) { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { - registry.addHandler(kurentoHandler(kurentoManager(kurentoClient())), "/signal").setAllowedOrigins("*"); + registry.addHandler(kurentoHandler(kurentoManager(kurentoClient(), memberServiceClient())), "/signal").setAllowedOrigins("*"); } @Bean diff --git a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/domain/Member.java b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/domain/Member.java index 2e6b3b8d..d2d8e140 100644 --- a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/domain/Member.java +++ b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/domain/Member.java @@ -9,7 +9,8 @@ public class Member implements Identifiable { private final String id; // 고유한 식별자 - private final String userId; // 사용자의 ID + private final String progileImageUrl; + private final String nickname; private String roomId; // 사용자가 속한 방 ID // 미디어 상태 @@ -18,20 +19,22 @@ public class Member implements Identifiable { private boolean isScreenSharingEnabled; @Builder - public Member(final String id, final String userId, final String roomId, final boolean isMicEnabled, final boolean isCameraEnabled, final boolean isScreenSharingEnabled) { + public Member(final String id, final String roomId, final String progileImageUrl, final String nickname, final boolean isMicEnabled, final boolean isCameraEnabled, final boolean isScreenSharingEnabled) { this.id = id; - this.userId = userId; this.roomId = roomId; + this.progileImageUrl = progileImageUrl; + this.nickname = nickname; this.isMicEnabled = isMicEnabled; this.isCameraEnabled = isCameraEnabled; this.isScreenSharingEnabled = isScreenSharingEnabled; } - public static Member create(final String id, final String userId, final String roomId) { + public static Member create(final String id, final String roomId, final String progileImageUrl, final String nickname) { return Member.builder() .id(id) - .userId(userId) .roomId(roomId) + .progileImageUrl(progileImageUrl) + .nickname(nickname) .isMicEnabled(false) .isCameraEnabled(false) .isScreenSharingEnabled(false) diff --git a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/entity/MemberEntity.java b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/entity/MemberEntity.java index 0b13979d..54b18686 100644 --- a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/entity/MemberEntity.java +++ b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/entity/MemberEntity.java @@ -14,9 +14,11 @@ public class MemberEntity { @Id private String id; - private String userId; // 사용자 ID private String roomId; // 참가 중인 방 ID + private String profileImageUrl; + private String nickname; + private boolean isMicEnabled; private boolean isCameraEnabled; private boolean isScreenSharingEnabled; diff --git a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/client/MemberServiceClient.java b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/client/MemberServiceClient.java new file mode 100644 index 00000000..377542e4 --- /dev/null +++ b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/client/MemberServiceClient.java @@ -0,0 +1,9 @@ +package com.asyncgate.signaling_server.infrastructure.client; + +import com.asyncgate.signaling_server.domain.Member; +import com.asyncgate.signaling_server.support.annotation.UseCase; + +@UseCase +public interface MemberServiceClient { + Member fetchMemberById(String userId, String roomId); +} \ No newline at end of file diff --git a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/client/MemberServiceClientImpl.java b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/client/MemberServiceClientImpl.java new file mode 100644 index 00000000..b35ef192 --- /dev/null +++ b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/client/MemberServiceClientImpl.java @@ -0,0 +1,38 @@ +package com.asyncgate.signaling_server.infrastructure.client; + +import com.asyncgate.signaling_server.domain.Member; +import com.asyncgate.signaling_server.exception.FailType; +import com.asyncgate.signaling_server.exception.SignalingServerException; +import com.asyncgate.signaling_server.infrastructure.dto.response.ReadUserRoomProfileResponse; +import com.asyncgate.signaling_server.infrastructure.utility.HttpClientUtil; +import com.asyncgate.signaling_server.support.response.SuccessResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; + +@Service +@RequiredArgsConstructor +public class MemberServiceClientImpl implements MemberServiceClient { + + @Value("${service.member.url}") + private String memberServiceUrl; + + @Override + public Member fetchMemberById(String userId, String roomId) { + Map queryParams = new HashMap<>(); + queryParams.put("userId", userId); + + SuccessResponse response = HttpClientUtil.get( + memberServiceUrl, "/room/profile", queryParams, SuccessResponse.class); + + if (response == null || response.getResult() == null) { + throw new SignalingServerException(FailType._MEMBER_NOT_FOUND); + } + + ReadUserRoomProfileResponse userProfile = response.getResult(); + return Member.create(userId, roomId, userProfile.getProfileImageUrl(), userProfile.getNickname()); + } +} \ No newline at end of file diff --git a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/dto/response/ReadUserRoomProfileResponse.java b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/dto/response/ReadUserRoomProfileResponse.java new file mode 100644 index 00000000..0036a6cc --- /dev/null +++ b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/dto/response/ReadUserRoomProfileResponse.java @@ -0,0 +1,33 @@ +package com.asyncgate.signaling_server.infrastructure.dto.response; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotBlank; +import lombok.Builder; +import lombok.Getter; + +@Getter +public class ReadUserRoomProfileResponse { + // 유저의 id, 프로필 사진, 닉네임을 반환 + @JsonProperty("id") + @NotBlank + private String id; + + @JsonProperty("profile_image_url") + @NotBlank + private String profileImageUrl; + + @JsonProperty("nickname") + @NotBlank + private String nickname; + + @Builder + public ReadUserRoomProfileResponse( + String id, + String profileImageUrl, + String nickname + ) { + this.id = id; + this.profileImageUrl = profileImageUrl; + this.nickname = nickname; + } +} \ No newline at end of file diff --git a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/utility/HttpClientUtil.java b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/utility/HttpClientUtil.java new file mode 100644 index 00000000..67620ae6 --- /dev/null +++ b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/utility/HttpClientUtil.java @@ -0,0 +1,33 @@ +package com.asyncgate.signaling_server.infrastructure.utility; + +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.Map; + +public class HttpClientUtil { + private static final RestTemplate restTemplate = new RestTemplate(); + + // GET 요청 (쿼리 파라미터 지원) + public static T get(String baseUrl, String path, Map queryParams, Class responseType) { + String url = UriComponentsBuilder.fromUriString(baseUrl + path) + .queryParams(toMultiValueMap(queryParams)) + .toUriString(); + + return restTemplate.getForObject(url, responseType); + } + + // POST 요청 (Request Body 포함) + public static T post(String baseUrl, String path, R requestBody, Class responseType) { + String url = baseUrl + path; + return restTemplate.postForObject(url, requestBody, responseType); + } + + public static MultiValueMap toMultiValueMap(Map map) { + MultiValueMap multiValueMap = new LinkedMultiValueMap<>(); + map.forEach(multiValueMap::add); + return multiValueMap; + } +} diff --git a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/signaling/KurentoManager.java b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/signaling/KurentoManager.java index 0846c1ad..23740a7a 100644 --- a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/signaling/KurentoManager.java +++ b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/signaling/KurentoManager.java @@ -2,10 +2,10 @@ import com.asyncgate.signaling_server.domain.Member; import com.asyncgate.signaling_server.dto.response.GetUsersInChannelResponse; -import com.asyncgate.signaling_server.entity.MemberEntity; -import com.asyncgate.signaling_server.support.utility.DomainUtil; +import com.asyncgate.signaling_server.infrastructure.client.MemberServiceClient; import com.google.gson.Gson; import com.google.gson.JsonObject; +import lombok.RequiredArgsConstructor; import org.kurento.client.*; import org.springframework.stereotype.Service; @@ -20,18 +20,17 @@ @Slf4j @Service +@RequiredArgsConstructor public class KurentoManager { private final KurentoClient kurentoClient; + private final MemberServiceClient memberServiceClient; + // kurento media pipline (SFU) 방에 대한 데이터 (key, value) private final Map pipelines = new ConcurrentHashMap<>(); private final Map> roomEndpoints = new ConcurrentHashMap<>(); private final Map userStates = new ConcurrentHashMap<>(); - public KurentoManager(KurentoClient kurentoClient) { - this.kurentoClient = kurentoClient; - } - /** * 특정 방에 대한 MediaPipeline을 가져오거나 새로 생성 */ @@ -48,24 +47,22 @@ public synchronized WebRtcEndpoint createEndpoint(String roomId, String userId) MediaPipeline pipeline = getOrCreatePipeline(roomId); WebRtcEndpoint endpoint = new WebRtcEndpoint.Builder(pipeline).build(); + // 사용자 정보 조회 + Member member = memberServiceClient.fetchMemberById(userId, roomId); + // ICE Candidate 리스너 추가 endpoint.addIceCandidateFoundListener(event -> { JsonObject candidateMessage = new JsonObject(); candidateMessage.addProperty("id", "iceCandidate"); - candidateMessage.addProperty("userId", userId); + candidateMessage.addProperty("userId", member.getId()); candidateMessage.add("candidate", new Gson().toJsonTree(event.getCandidate())); - log.info("🧊 [Kurento] ICE Candidate 전송: roomId={}, userId={}, candidate={}", roomId, userId, event.getCandidate()); + log.info("🧊 [Kurento] ICE Candidate 전송: roomId={}, userId={}, candidate={}", roomId, member.getId(), event.getCandidate()); }); // 사용자 엔드포인트 저장 roomEndpoints.computeIfAbsent(roomId, k -> new ConcurrentHashMap<>()).put(userId, endpoint); - userStates.put(userId, DomainUtil.MemberMapper.toDomain( - MemberEntity.builder() - .userId(userId) - .roomId(roomId) - .build()) - ); + userStates.put(userId, member); log.info("[Kurento] WebRTC Endpoint 생성: roomId={}, userId={}", roomId, userId); return endpoint; @@ -154,7 +151,7 @@ public void updateUserMediaState(String roomId, String userId, String type, bool } switch (type) { - case "audio": + case "mic": if (enabled) { reconnectAudio(userId, endpoint); } else { @@ -164,7 +161,7 @@ public void updateUserMediaState(String roomId, String userId, String type, bool member.updateMediaState("mic", enabled); break; - case "video": + case "camera": if (enabled) { reconnectVideo(userId, endpoint); } else { diff --git a/src/backend/user-server/src/main/java/com/asyncgate/user_server/service/ReadUserRoomProfileService.java b/src/backend/user-server/src/main/java/com/asyncgate/user_server/service/ReadUserRoomProfileService.java index 09a3adb5..d74f53f1 100644 --- a/src/backend/user-server/src/main/java/com/asyncgate/user_server/service/ReadUserRoomProfileService.java +++ b/src/backend/user-server/src/main/java/com/asyncgate/user_server/service/ReadUserRoomProfileService.java @@ -10,8 +10,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import java.util.Optional; - @Slf4j @Service @RequiredArgsConstructor From fa050a484c6572fafce2ed648ece333f836cc9d6 Mon Sep 17 00:00:00 2001 From: EunJiJung Date: Wed, 26 Feb 2025 16:02:06 +0900 Subject: [PATCH 05/16] =?UTF-8?q?[BE]=20feat:=20member=20profile=20get?= =?UTF-8?q?=EC=9A=A9=20user=20service=20uri=20config=EC=97=90=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(#30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: EunJiJung --- config/signaling-server-prod.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/config/signaling-server-prod.yml b/config/signaling-server-prod.yml index 4aa1205b..8764452c 100644 --- a/config/signaling-server-prod.yml +++ b/config/signaling-server-prod.yml @@ -22,4 +22,8 @@ cloud: spring: kafka: - bootstrap-servers: '{cipher}276ada73fdb90a68125e2dcce993b77384c8c80d672a78b26eefda56bf60f808f77d486f86d9f1de94e6cb342711bb6211dd8f6cbf98b01e4ece80b938b40acf1cfef75ec74c910f32e68873b06dd3d5' \ No newline at end of file + bootstrap-servers: '{cipher}276ada73fdb90a68125e2dcce993b77384c8c80d672a78b26eefda56bf60f808f77d486f86d9f1de94e6cb342711bb6211dd8f6cbf98b01e4ece80b938b40acf1cfef75ec74c910f32e68873b06dd3d5' + +service: + member: + url: '{cipher}cfc51ed26a533a9c2dea91e247fab25cd2b6d7487d51884ef835d030b9b38373a30bf3596005dbaf2bd82921ee1f85f5614e0e3e4ed0c658b38950b544ceb5c5' \ No newline at end of file From 42c7dea345bc5ef07cc2f59a7e9f7bd7003682dc Mon Sep 17 00:00:00 2001 From: EunJiJung Date: Wed, 26 Feb 2025 18:12:19 +0900 Subject: [PATCH 06/16] =?UTF-8?q?[BE]=20feat:=20signaling=20server=20issue?= =?UTF-8?q?=20=ED=95=B4=EA=B2=B0=20(#30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: EunJiJung --- .../config/KurentoConfig.java | 3 +- .../client/MemberServiceClient.java | 36 ++++++++++++++++-- .../client/MemberServiceClientImpl.java | 38 ------------------- .../support/utility/DomainUtil.java | 2 - 4 files changed, 33 insertions(+), 46 deletions(-) delete mode 100644 src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/client/MemberServiceClientImpl.java diff --git a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/KurentoConfig.java b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/KurentoConfig.java index 28a7de78..9cd75d70 100644 --- a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/KurentoConfig.java +++ b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/KurentoConfig.java @@ -1,7 +1,6 @@ package com.asyncgate.signaling_server.config; import com.asyncgate.signaling_server.infrastructure.client.MemberServiceClient; -import com.asyncgate.signaling_server.infrastructure.client.MemberServiceClientImpl; import com.asyncgate.signaling_server.signaling.KurentoManager; import com.asyncgate.signaling_server.support.handler.KurentoHandler; import org.kurento.client.KurentoClient; @@ -27,7 +26,7 @@ public KurentoClient kurentoClient() { @Bean public MemberServiceClient memberServiceClient() { - return new MemberServiceClientImpl(); + return new MemberServiceClient(); } @Bean diff --git a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/client/MemberServiceClient.java b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/client/MemberServiceClient.java index 377542e4..19ed12d0 100644 --- a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/client/MemberServiceClient.java +++ b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/client/MemberServiceClient.java @@ -1,9 +1,37 @@ package com.asyncgate.signaling_server.infrastructure.client; import com.asyncgate.signaling_server.domain.Member; -import com.asyncgate.signaling_server.support.annotation.UseCase; +import com.asyncgate.signaling_server.exception.FailType; +import com.asyncgate.signaling_server.exception.SignalingServerException; +import com.asyncgate.signaling_server.infrastructure.dto.response.ReadUserRoomProfileResponse; +import com.asyncgate.signaling_server.infrastructure.utility.HttpClientUtil; +import com.asyncgate.signaling_server.support.response.SuccessResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; -@UseCase -public interface MemberServiceClient { - Member fetchMemberById(String userId, String roomId); +import java.util.HashMap; +import java.util.Map; + +@Service +@RequiredArgsConstructor +public class MemberServiceClient { + + // @Value("${service.member.url}") + private String memberServiceUrl = "http://43.201.101.122"; + + public Member fetchMemberById(String userId, String roomId) { + Map queryParams = new HashMap<>(); + queryParams.put("userId", userId); + + SuccessResponse response = HttpClientUtil.get( + memberServiceUrl, "/room/profile", queryParams, SuccessResponse.class); + + if (response == null || response.getResult() == null) { + throw new SignalingServerException(FailType._MEMBER_NOT_FOUND); + } + + ReadUserRoomProfileResponse userProfile = response.getResult(); + return Member.create(userId, roomId, userProfile.getProfileImageUrl(), userProfile.getNickname()); + } } \ No newline at end of file diff --git a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/client/MemberServiceClientImpl.java b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/client/MemberServiceClientImpl.java deleted file mode 100644 index b35ef192..00000000 --- a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/infrastructure/client/MemberServiceClientImpl.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.asyncgate.signaling_server.infrastructure.client; - -import com.asyncgate.signaling_server.domain.Member; -import com.asyncgate.signaling_server.exception.FailType; -import com.asyncgate.signaling_server.exception.SignalingServerException; -import com.asyncgate.signaling_server.infrastructure.dto.response.ReadUserRoomProfileResponse; -import com.asyncgate.signaling_server.infrastructure.utility.HttpClientUtil; -import com.asyncgate.signaling_server.support.response.SuccessResponse; -import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -import java.util.HashMap; -import java.util.Map; - -@Service -@RequiredArgsConstructor -public class MemberServiceClientImpl implements MemberServiceClient { - - @Value("${service.member.url}") - private String memberServiceUrl; - - @Override - public Member fetchMemberById(String userId, String roomId) { - Map queryParams = new HashMap<>(); - queryParams.put("userId", userId); - - SuccessResponse response = HttpClientUtil.get( - memberServiceUrl, "/room/profile", queryParams, SuccessResponse.class); - - if (response == null || response.getResult() == null) { - throw new SignalingServerException(FailType._MEMBER_NOT_FOUND); - } - - ReadUserRoomProfileResponse userProfile = response.getResult(); - return Member.create(userId, roomId, userProfile.getProfileImageUrl(), userProfile.getNickname()); - } -} \ No newline at end of file diff --git a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/support/utility/DomainUtil.java b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/support/utility/DomainUtil.java index 5d3e0d3d..e6386bcf 100644 --- a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/support/utility/DomainUtil.java +++ b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/support/utility/DomainUtil.java @@ -16,7 +16,6 @@ public static class MemberMapper { public static MemberEntity toEntity(final Member member) { return MemberEntity.builder() .id(member.getId()) - .userId(member.getUserId()) .roomId(member.getRoomId()) .isMicEnabled(member.isMicEnabled()) .isCameraEnabled(member.isCameraEnabled()) @@ -27,7 +26,6 @@ public static MemberEntity toEntity(final Member member) { public static Member toDomain(final MemberEntity entity) { return Member.builder() .id(entity.getId()) - .userId(entity.getUserId()) .roomId(entity.getRoomId()) .isMicEnabled(entity.isMicEnabled()) .isCameraEnabled(entity.isCameraEnabled()) From 038f5ccb6b9848e39908ea0315e3fabad1e8f8f9 Mon Sep 17 00:00:00 2001 From: EunJiJung Date: Wed, 26 Feb 2025 18:44:31 +0900 Subject: [PATCH 07/16] =?UTF-8?q?[BE]=20feat:=20websocket=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0=20=ED=99=95=EC=9D=B8=EC=9A=A9=20=EB=A1=9C=EA=B7=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(#30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: EunJiJung --- .../com/asyncgate/signaling_server/config/KurentoConfig.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/KurentoConfig.java b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/KurentoConfig.java index 9cd75d70..8227a9f3 100644 --- a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/KurentoConfig.java +++ b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/KurentoConfig.java @@ -41,6 +41,7 @@ public KurentoHandler kurentoHandler(KurentoManager kurentoManager) { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { + System.out.println("🚀 WebSocketHandlerRegistry 등록"); registry.addHandler(kurentoHandler(kurentoManager(kurentoClient(), memberServiceClient())), "/signal").setAllowedOrigins("*"); } From a69a4a9c0e1648c972b0b00d228b50865e684f58 Mon Sep 17 00:00:00 2001 From: EunJiJung Date: Wed, 26 Feb 2025 20:20:47 +0900 Subject: [PATCH 08/16] =?UTF-8?q?[BE]=20feat:=20user=20server=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20=EC=82=AC=ED=95=AD=20=EC=A0=9C=EA=B1=B0=20(#30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: EunJiJung --- .../user_server/service/ReadUserRoomProfileService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/backend/user-server/src/main/java/com/asyncgate/user_server/service/ReadUserRoomProfileService.java b/src/backend/user-server/src/main/java/com/asyncgate/user_server/service/ReadUserRoomProfileService.java index d74f53f1..09a3adb5 100644 --- a/src/backend/user-server/src/main/java/com/asyncgate/user_server/service/ReadUserRoomProfileService.java +++ b/src/backend/user-server/src/main/java/com/asyncgate/user_server/service/ReadUserRoomProfileService.java @@ -10,6 +10,8 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import java.util.Optional; + @Slf4j @Service @RequiredArgsConstructor From 70d9a0bb5fc78eb429c926beaf063e95061c6c3a Mon Sep 17 00:00:00 2001 From: EunJiJung Date: Wed, 26 Feb 2025 20:21:01 +0900 Subject: [PATCH 09/16] =?UTF-8?q?[BE]=20refactor:=20port=20=EA=B3=A0?= =?UTF-8?q?=EC=A0=95=EC=9C=BC=EB=A1=9C=20=EC=A7=80=EC=A0=95=20(#30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: EunJiJung --- .../signaling-server/src/main/resources/application-local.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/signaling-server/src/main/resources/application-local.yml b/src/backend/signaling-server/src/main/resources/application-local.yml index 3d163681..53d67df4 100644 --- a/src/backend/signaling-server/src/main/resources/application-local.yml +++ b/src/backend/signaling-server/src/main/resources/application-local.yml @@ -1,5 +1,5 @@ server: - port: 0 + port: 8600 eureka: instance: From 2ba0a4b9e104befdb59d27bc7b36c817786d13f6 Mon Sep 17 00:00:00 2001 From: EunJiJung Date: Wed, 26 Feb 2025 20:34:27 +0900 Subject: [PATCH 10/16] =?UTF-8?q?[BE]=20fix:=20cors=20allowedOrigins("*"),?= =?UTF-8?q?=20allowCredentials(true)=20=EC=A4=91=EB=B3=B5=20=EC=84=A0?= =?UTF-8?q?=EC=96=B8=20=EC=9D=B4=EC=8A=88=20=ED=95=B4=EA=B2=B0=20(#30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: EunJiJung --- .../java/com/asyncgate/signaling_server/config/CorsConfig.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/CorsConfig.java b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/CorsConfig.java index 7cee73b1..f7e42237 100644 --- a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/CorsConfig.java +++ b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/CorsConfig.java @@ -33,9 +33,6 @@ public static CorsConfigurationSource corsConfigurationSource() { configuration.setAllowedHeaders(Collections.singletonList("*")); // configuration.setAllowedHeaders(List.of(HttpHeaders.AUTHORIZATION, HttpHeaders.CONTENT_TYPE)); - //인증, 인가를 위한 credentials 를 TRUE로 설정 - configuration.setAllowCredentials(true); - UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); From 8969e77e6f677ddd9ca1582fd42cf123a4287861 Mon Sep 17 00:00:00 2001 From: EunJiJung Date: Wed, 26 Feb 2025 20:47:09 +0900 Subject: [PATCH 11/16] =?UTF-8?q?[BE]=20refactor:=20intellij=20http=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(#30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: EunJiJung --- .../http/SignalingControllerHttpRequest.http | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/backend/signaling-server/http/SignalingControllerHttpRequest.http diff --git a/src/backend/signaling-server/http/SignalingControllerHttpRequest.http b/src/backend/signaling-server/http/SignalingControllerHttpRequest.http new file mode 100644 index 00000000..d21a5e86 --- /dev/null +++ b/src/backend/signaling-server/http/SignalingControllerHttpRequest.http @@ -0,0 +1,65 @@ +### 0.0 health check +// @no-log +GET {{host_url}}/health +Authorization: Bearer {{access_token}} + +### 1.0 임시 회원가입 +// @no-log +POST {{host_url}}/sign-up +Content-Type: application/json + +{ + "email": "{{user.API_1_0_SIGNUP.email}}", + "password": "{{user.API_1_0_SIGNUP.password}}", + "name": "{{user.API_1_0_SIGNUP.name}}", + "nickname": "{{user.API_1_0_SIGNUP.nickname}}", + "birth": "{{user.API_1_0_SIGNUP.birth}}" +} + + +### 1.1 로그인 +// @no-log +POST {{host_url}}/sign-in +Content-Type: application/json + +{ + "email": "{{user.API_1_1_SIGNIN.email}}", + "password": "{{user.API_1_1_SIGNIN.password}}" +} + +> {% + client.global.set("access_token", response.body.result.access_token); +%} + + +### 1.2 인증코드 인증 +// @no-log +POST {{host_url}}/validation/authentication-code +Content-Type: application/json + +{ + "email": "{{user.API_1_2_AUTHENTICATION_CODE.email}}", + "authentication_code": "{{user.API_1_2_AUTHENTICATION_CODE.authentication_code}}" +} + +### 2,0 채널 생성 +// @no-log +POST {{host_url}}/room/create +Content-Type: application/json +Authorization: Bearer {{access_token}} + +{ + "room_id": "{{signaling.API_2_0_CREATE_CHAT_ROOM.chat_room_id}}" +} + +### 2.1 채널 참여 +// @no-log +POST {{host_url}}/room/{{signaling.API_2_0_CREATE_CHAT_ROOM.chat_room_id}}/join +Content-Type: application/json +Authorization: Bearer {{access_token}} + + +### 2.2 채널 참여 중인 유저 조회 +// @no-log +GET {{host_url}}/room/{{signaling.API_2_0_CREATE_CHAT_ROOM.chat_room_id}}/users +Authorization: Bearer {{access_token}} \ No newline at end of file From acc4e1713779f6a74053c6d8a176805879abd809 Mon Sep 17 00:00:00 2001 From: EunJiJung Date: Wed, 26 Feb 2025 20:52:02 +0900 Subject: [PATCH 12/16] =?UTF-8?q?[BE]=20refactor:=20user=20server=20https?= =?UTF-8?q?=EB=8F=84=20=ED=97=88=EC=9A=A9=20(#30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: EunJiJung --- .../com/asyncgate/user_server/security/config/CorsConfig.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/backend/user-server/src/main/java/com/asyncgate/user_server/security/config/CorsConfig.java b/src/backend/user-server/src/main/java/com/asyncgate/user_server/security/config/CorsConfig.java index 4dd48cba..f9f9c01c 100644 --- a/src/backend/user-server/src/main/java/com/asyncgate/user_server/security/config/CorsConfig.java +++ b/src/backend/user-server/src/main/java/com/asyncgate/user_server/security/config/CorsConfig.java @@ -6,6 +6,8 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; +import java.util.List; + @Configuration public class CorsConfig { @@ -15,7 +17,7 @@ public CorsFilter corsFilter() { CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); - config.addAllowedOrigin("http://localhost:5173"); + config.setAllowedOriginPatterns(List.of("http://localhost:5173", "https://localhost:5173")); config.addAllowedHeader("*"); config.addAllowedMethod("*"); config.addExposedHeader("Authorization"); From bf82ef6751ba446be175ee85a45f16413a490d2b Mon Sep 17 00:00:00 2001 From: EunJiJung Date: Wed, 26 Feb 2025 20:57:51 +0900 Subject: [PATCH 13/16] =?UTF-8?q?[BE]=20refactor:=20guild=20server=20https?= =?UTF-8?q?=EB=8F=84=20=ED=97=88=EC=9A=A9=20(#30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: EunJiJung --- .../java/com/asyncgate/guild_server/config/CorsConfig.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/backend/guild-server/src/main/java/com/asyncgate/guild_server/config/CorsConfig.java b/src/backend/guild-server/src/main/java/com/asyncgate/guild_server/config/CorsConfig.java index c7bc0d3b..31efd89b 100644 --- a/src/backend/guild-server/src/main/java/com/asyncgate/guild_server/config/CorsConfig.java +++ b/src/backend/guild-server/src/main/java/com/asyncgate/guild_server/config/CorsConfig.java @@ -1,5 +1,7 @@ package com.asyncgate.guild_server.config; +import java.util.List; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; @@ -15,7 +17,7 @@ public CorsFilter corsFilter() { CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); - config.addAllowedOrigin("http://localhost:5173"); + config.setAllowedOriginPatterns(List.of("http://localhost:5173", "https://localhost:5173")); config.addAllowedHeader("*"); config.addAllowedMethod("*"); config.addExposedHeader("Authorization"); From 146e7690ec3f9b8dba81105e24b357f10e8b5839 Mon Sep 17 00:00:00 2001 From: EunJiJung Date: Wed, 26 Feb 2025 21:05:39 +0900 Subject: [PATCH 14/16] =?UTF-8?q?[BE]=20refactor:=20channel=20=EC=B0=B8?= =?UTF-8?q?=EC=97=AC=20=EC=A4=91=EC=9D=B8=20member=20response=EC=97=90=20n?= =?UTF-8?q?ickname,=20profile=20image=20url=20=EB=93=B1=EB=A1=9D=20(#30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: EunJiJung --- .../signaling/KurentoManager.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/signaling/KurentoManager.java b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/signaling/KurentoManager.java index 23740a7a..809bd7fd 100644 --- a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/signaling/KurentoManager.java +++ b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/signaling/KurentoManager.java @@ -2,6 +2,8 @@ import com.asyncgate.signaling_server.domain.Member; import com.asyncgate.signaling_server.dto.response.GetUsersInChannelResponse; +import com.asyncgate.signaling_server.exception.FailType; +import com.asyncgate.signaling_server.exception.SignalingServerException; import com.asyncgate.signaling_server.infrastructure.client.MemberServiceClient; import com.google.gson.Gson; import com.google.gson.JsonObject; @@ -108,13 +110,21 @@ public List getUsersInChannel(String chann String userId = entry.getKey(); WebRtcEndpoint endpoint = entry.getValue(); + + Member member = userStates.get(userId); + + // member가 null이라면 exception + if (member == null) { + throw new SignalingServerException(FailType._MEMBER_NOT_FOUND); + } + boolean isMicEnabled = endpoint.isMediaFlowingIn(MediaType.AUDIO) && endpoint.isMediaFlowingOut(MediaType.AUDIO); boolean isCameraEnabled = endpoint.isMediaFlowingIn(MediaType.VIDEO) && endpoint.isMediaFlowingOut(MediaType.VIDEO); return GetUsersInChannelResponse.UserInRoom.builder() - .id(userId) - .nickname(userId) // 닉네임 정보가 없으면 기본 userId 사용 - .profileImage("") // 프로필 이미지 필드가 없으면 기본 값 설정 + .id(member.getId()) + .nickname(member.getNickname()) // 닉네임 정보가 없으면 기본 userId 사용 + .profileImage(member.getProgileImageUrl()) // 프로필 이미지 필드가 없으면 기본 값 설정 .isMicEnabled(isMicEnabled) .isCameraEnabled(isCameraEnabled) .isScreenSharingEnabled(false) From d0052d6eaaf582fccf1091d1e9447c66c2357e80 Mon Sep 17 00:00:00 2001 From: EunJiJung Date: Thu, 27 Feb 2025 18:25:30 +0900 Subject: [PATCH 15/16] =?UTF-8?q?[BE]=20refactor:=20channel=20=EC=B0=B8?= =?UTF-8?q?=EC=97=AC=20=EC=A4=91=EC=9D=B8=20member=20response=EC=97=90=20n?= =?UTF-8?q?ickname,=20profile=20image=20url=20=EB=93=B1=EB=A1=9D=20(#30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: EunJiJung --- .../signaling_server/config/CorsConfig.java | 2 +- .../signaling/KurentoManager.java | 64 +++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/CorsConfig.java b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/CorsConfig.java index f7e42237..a6b4b5f4 100644 --- a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/CorsConfig.java +++ b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/config/CorsConfig.java @@ -18,7 +18,7 @@ public static CorsConfigurationSource corsConfigurationSource() { //리소스를 허용 ArrayList allowedOriginPatterns = new ArrayList<>(); allowedOriginPatterns.add("*"); - configuration.setAllowedOrigins(allowedOriginPatterns); + configuration.setAllowedOriginPatterns(allowedOriginPatterns); //허용하는 HTTP METHOD ArrayList allowedHttpMethods = new ArrayList<>(); diff --git a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/signaling/KurentoManager.java b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/signaling/KurentoManager.java index 809bd7fd..6fc8dba7 100644 --- a/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/signaling/KurentoManager.java +++ b/src/backend/signaling-server/src/main/java/com/asyncgate/signaling_server/signaling/KurentoManager.java @@ -31,6 +31,10 @@ public class KurentoManager { // kurento media pipline (SFU) 방에 대한 데이터 (key, value) private final Map pipelines = new ConcurrentHashMap<>(); private final Map> roomEndpoints = new ConcurrentHashMap<>(); + + // 화면 공유용 WebRTC 엔드포인트 저장 (roomId -> userId -> WebRtcEndpoint) + private final Map> roomScreenEndpoints = new ConcurrentHashMap<>(); + private final Map userStates = new ConcurrentHashMap<>(); /** @@ -70,6 +74,33 @@ public synchronized WebRtcEndpoint createEndpoint(String roomId, String userId) return endpoint; } + /** + * 화면 공유용 WebRTC 엔드포인트 생성 + * + * @param roomId + * @param userId + * @return + */ + public synchronized WebRtcEndpoint createScreenShareEndpoint(String roomId, String userId) { + MediaPipeline pipeline = getOrCreatePipeline(roomId); + WebRtcEndpoint screenEndpoint = new WebRtcEndpoint.Builder(pipeline).build(); + + // ICE Candidate 리스너 추가 + screenEndpoint.addIceCandidateFoundListener(event -> { + JsonObject candidateMessage = new JsonObject(); + candidateMessage.addProperty("id", "iceCandidate"); + candidateMessage.addProperty("userId", userId); + candidateMessage.add("candidate", new Gson().toJsonTree(event.getCandidate())); + + log.info("🖥️ [Kurento] 화면 공유 ICE Candidate 전송: roomId={}, userId={}, candidate={}", roomId, userId, event.getCandidate()); + }); + + // 화면 공유 엔드포인트 저장 + roomScreenEndpoints.computeIfAbsent(roomId, k -> new ConcurrentHashMap<>()).put(userId, screenEndpoint); + log.info("🖥️ [Kurento] 화면 공유 WebRTC Endpoint 생성: roomId={}, userId={}", roomId, userId); + return screenEndpoint; + } + /** * SDP Offer를 처리하고 Answer를 반환 */ @@ -239,6 +270,32 @@ private void reconnectVideo(String userId, WebRtcEndpoint endpoint) { } } + /** + * 특정 사용자의 화면 공유 스트림 다시 연결 + */ + private void reconnectScreenShare(String userId, WebRtcEndpoint endpoint) { + endpoint.connect(endpoint, MediaType.VIDEO); + log.info("🖥️ [Kurento] 화면 공유 활성화: userId={}", userId); + + // ✅ userStates에서 해당 사용자의 상태 업데이트 + if (userStates.containsKey(userId)) { + userStates.get(userId).updateMediaState("screenShare", true); + } + } + + /** + * 특정 사용자의 화면 공유 스트림 연결 해제 + */ + private void disconnectScreenShare(String userId, WebRtcEndpoint endpoint) { + endpoint.disconnect(endpoint, MediaType.VIDEO); + log.info("🚫 [Kurento] 화면 공유 비활성화: userId={}", userId); + + // ✅ userStates에서 해당 사용자의 상태 업데이트 + if (userStates.containsKey(userId)) { + userStates.get(userId).updateMediaState("screenShare", false); + } + } + /** * 방을 제거함 */ @@ -248,9 +305,16 @@ public void removeRoom(String roomId) { roomEndpoints.remove(roomId); } + if (roomScreenEndpoints.containsKey(roomId)) { + roomScreenEndpoints.get(roomId).values().forEach(WebRtcEndpoint::release); + roomScreenEndpoints.remove(roomId); + } + if (pipelines.containsKey(roomId)) { pipelines.get(roomId).release(); pipelines.remove(roomId); } + + log.info("🛑 [Kurento] 방 제거 완료: roomId={}", roomId); } } \ No newline at end of file From 930b0a3236c074f31a546fd187647acfaeafcdd3 Mon Sep 17 00:00:00 2001 From: toychip Date: Thu, 27 Feb 2025 23:34:11 +0900 Subject: [PATCH 16/16] =?UTF-8?q?[BE]=20setting:=20rebase=20main=20applica?= =?UTF-8?q?tion.yml=20=EB=B6=84=EA=B8=B0=EC=B2=98=EB=A6=AC=20=EC=B6=A9?= =?UTF-8?q?=EB=8F=8C=20=ED=95=B4=EA=B2=B0=20(#85)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application-prod.yml | 16 ++++++++++++---- .../src/main/resources/application-prod.yml | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/backend/apigateway-server/src/main/resources/application-prod.yml b/src/backend/apigateway-server/src/main/resources/application-prod.yml index 8cca107c..d700e371 100644 --- a/src/backend/apigateway-server/src/main/resources/application-prod.yml +++ b/src/backend/apigateway-server/src/main/resources/application-prod.yml @@ -90,15 +90,23 @@ spring: filters: - RemoveRequestHeader=Cookie - RewritePath=/signalings/(?.*), /$\{segment} - - AuthorizationHeaderFilter + - AuthorizationHeaderFilter - id: signaling-server - uri: lb://SIGNALING-SERVER + uri: ws://SIGNALING-SERVER + predicates: + - Path=/signalings/** + filters: + - RemoveRequestHeader=Cookie + - RewritePath=/signalings/(?.*), /$\{segment} + + - id: signaling-server + uri: wss://SIGNALING-SERVER predicates: - - Path=/signalings/signal + - Path=/signalings/** filters: - RemoveRequestHeader=Cookie - - RewritePath=/signalings/(?.*), /$\{segment} + - RewritePath=/signalings/(?.*), /$\{segment} default-filters: - DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-Allow-Credentials diff --git a/src/backend/signaling-server/src/main/resources/application-prod.yml b/src/backend/signaling-server/src/main/resources/application-prod.yml index 3d163681..53d67df4 100644 --- a/src/backend/signaling-server/src/main/resources/application-prod.yml +++ b/src/backend/signaling-server/src/main/resources/application-prod.yml @@ -1,5 +1,5 @@ server: - port: 0 + port: 8600 eureka: instance: