Skip to content

Commit 45e4b8c

Browse files
authored
Merge pull request #71 from sgdevcamp2025/be/feat/30-media
[BE] feat: media 서버 구현
2 parents 4e2bd1e + 2c8741a commit 45e4b8c

File tree

57 files changed

+2074
-27
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+2074
-27
lines changed

.github/actions/ecr-push/action.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,23 @@ runs:
243243
echo " restart: unless-stopped" >> docker-compose.yml
244244
fi
245245
246+
if [ "${{ inputs.container_name }}" == "signaling-server" ]; then
247+
echo " mongodb:" >> docker-compose.yml
248+
echo " image: mongo:latest" >> docker-compose.yml
249+
echo " container_name: mongodb" >> docker-compose.yml
250+
echo " ports:" >> docker-compose.yml
251+
echo " - \"27017:27017\"" >> docker-compose.yml
252+
echo " restart: unless-stopped" >> docker-compose.yml
253+
echo " volumes:" >> docker-compose.yml
254+
echo " - mongo_data:/data/db" >> docker-compose.yml
255+
echo " redis:" >> docker-compose.yml
256+
echo " image: redis:latest" >> docker-compose.yml
257+
echo " container_name: redis" >> docker-compose.yml
258+
echo " ports:" >> docker-compose.yml
259+
echo " - \"6379:6379\"" >> docker-compose.yml
260+
echo " restart: unless-stopped" >> docker-compose.yml
261+
fi
262+
246263
echo "volumes:" >> docker-compose.yml
247264
echo " mongo_data:" >> docker-compose.yml
248265
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ eureka:
22
instance:
33
prefer-ip-address: true
44
hostname: signaling-server
5-
ip-address: '{cipher}52869f07a616cbb703d228900597bd2d08f7138667e0e839737cf0cad27e2913'
5+
ip-address: '{cipher}814f08466ab03c2cafb04104dc5c07690891d44daae88cb9caf1605849c201d2'
66
client:
77
service-url:
88
defaultZone: '{cipher}c10802fde605ba30df72871d3dfc9c765a71c43b3f6326fd0f9169b52210c582fe3aa81f882e05c08ffcfdb402f7949a'

src/backend/apigateway-server/src/main/resources/application.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,32 @@ spring:
8282
- RemoveRequestHeader=Cookie
8383
- RewritePath=/users/(?<segment>.*), /$\{segment}
8484
- AuthorizationHeaderFilter
85+
86+
- id: signaling-server
87+
uri: lb://SIGNALING-SERVER
88+
predicates:
89+
- Path=/signalings/**
90+
filters:
91+
- RemoveRequestHeader=Cookie
92+
- RewritePath=/signalings/(?<segment>.*), /$\{segment}
93+
- AuthorizationHeaderFilter
94+
95+
- id: signaling-server
96+
uri: lb://SIGNALING-SERVER
97+
predicates:
98+
- Path=/signalings/signal
99+
filters:
100+
- RemoveRequestHeader=Cookie
101+
- RewritePath=/signalings/(?<segment>.*), /$\{segment}
102+
85103
default-filters:
86104
- DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-Allow-Credentials
87105
globalcors:
88106
cors-configurations:
89107
'[/**]':
90108
allowed-origins:
91109
- 'http://localhost:5173'
110+
- 'https://localhost:5173'
92111
allow-credentials: true
93112
allowed-headers: '*'
94113
allowed-methods:

src/backend/config-server/src/main/java/com/asyncgate/configserver/config/ConfigPrinter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public ApplicationRunner printConfigs() {
2424
// config 폴더에 있는 모든 서비스 리스트
2525
String[] services = {
2626
"apigateway-server", "chat-server", "guild-server",
27-
"notification-server", "signaling_server", "state-server", "user-server"
27+
"notification-server", "signaling-server", "state-server", "user-server"
2828
};
2929

3030
for (String service : services) {

src/backend/signaling-server/build.gradle

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ ext {
2929

3030
dependencies {
3131
implementation 'org.springframework.boot:spring-boot-starter-web'
32+
// implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
3233
implementation 'org.springframework.boot:spring-boot-starter-actuator'
3334

35+
implementation 'org.springframework.cloud:spring-cloud-starter'
3436
implementation 'org.springframework.cloud:spring-cloud-starter-config'
3537
implementation 'org.springframework.cloud:spring-cloud-starter-bootstrap'
3638

@@ -39,11 +41,52 @@ dependencies {
3941

4042
compileOnly 'org.projectlombok:lombok'
4143
annotationProcessor 'org.projectlombok:lombok'
44+
4245
testImplementation 'org.springframework.boot:spring-boot-starter-test'
4346
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
4447

48+
// Security
49+
implementation 'org.springframework.boot:spring-boot-starter-security'
50+
implementation 'org.springframework.security:spring-security-oauth2-client'
51+
52+
// JWT
53+
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
54+
implementation 'jakarta.xml.bind:jakarta.xml.bind-api:4.0.0'
55+
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
56+
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'
57+
58+
// Validation
59+
implementation 'org.springframework.boot:spring-boot-starter-validation'
60+
4561
// AWS
4662
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
63+
64+
// mysql
65+
// runtimeOnly 'com.mysql:mysql-connector-j'
66+
67+
// mongo db
68+
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
69+
70+
// WebSocket
71+
implementation 'org.springframework.boot:spring-boot-starter-websocket'
72+
73+
// sockjs
74+
implementation 'org.webjars:sockjs-client:1.5.1'
75+
// stomp
76+
implementation 'org.webjars:stomp-websocket:2.3.4'
77+
// gson
78+
implementation 'com.google.code.gson:gson:2.9.0'
79+
80+
/* Kurento 미디어 서버 관련 2개 */
81+
// https://mvnrepository.com/artifact/org.kurento/kurento-client
82+
implementation group: 'org.kurento', name: 'kurento-client', version: '6.18.0'
83+
84+
// thymeleaf
85+
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
86+
87+
// aop
88+
implementation 'org.springframework.boot:spring-boot-starter-aop'
89+
4790
}
4891

4992
dependencyManagement {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.asyncgate.signaling_server.config;
2+
3+
import lombok.AccessLevel;
4+
import lombok.NoArgsConstructor;
5+
import org.springframework.web.cors.CorsConfiguration;
6+
import org.springframework.web.cors.CorsConfigurationSource;
7+
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
8+
9+
import java.util.ArrayList;
10+
import java.util.Collections;
11+
12+
@NoArgsConstructor(access = AccessLevel.PRIVATE)
13+
public class CorsConfig {
14+
15+
public static CorsConfigurationSource corsConfigurationSource() {
16+
CorsConfiguration configuration = new CorsConfiguration();
17+
18+
//리소스를 허용
19+
ArrayList<String> allowedOriginPatterns = new ArrayList<>();
20+
allowedOriginPatterns.add("*");
21+
configuration.setAllowedOrigins(allowedOriginPatterns);
22+
23+
//허용하는 HTTP METHOD
24+
ArrayList<String> allowedHttpMethods = new ArrayList<>();
25+
allowedHttpMethods.add("GET");
26+
allowedHttpMethods.add("POST");
27+
allowedHttpMethods.add("PUT");
28+
allowedHttpMethods.add("PATCH");
29+
allowedHttpMethods.add("DELETE");
30+
allowedHttpMethods.add("OPTIONS");
31+
configuration.setAllowedMethods(allowedHttpMethods);
32+
33+
configuration.setAllowedHeaders(Collections.singletonList("*"));
34+
// configuration.setAllowedHeaders(List.of(HttpHeaders.AUTHORIZATION, HttpHeaders.CONTENT_TYPE));
35+
36+
//인증, 인가를 위한 credentials 를 TRUE로 설정
37+
configuration.setAllowCredentials(true);
38+
39+
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
40+
source.registerCorsConfiguration("/**", configuration);
41+
42+
return source;
43+
}
44+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.asyncgate.signaling_server.config;
2+
3+
import com.asyncgate.signaling_server.signaling.KurentoManager;
4+
import com.asyncgate.signaling_server.support.handler.KurentoHandler;
5+
import org.kurento.client.KurentoClient;
6+
import org.springframework.beans.factory.annotation.Value;
7+
import org.springframework.context.annotation.Bean;
8+
import org.springframework.context.annotation.Configuration;
9+
import org.springframework.web.socket.config.annotation.EnableWebSocket;
10+
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
11+
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
12+
import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;
13+
14+
@Configuration
15+
@EnableWebSocket
16+
public class KurentoConfig implements WebSocketConfigurer {
17+
18+
@Value("${kms.url}")
19+
private String kmsUrl;
20+
21+
@Bean
22+
public KurentoClient kurentoClient() {
23+
return KurentoClient.create(kmsUrl);
24+
}
25+
26+
@Bean
27+
public KurentoManager kurentoManager(KurentoClient kurentoClient) {
28+
return new KurentoManager(kurentoClient);
29+
}
30+
31+
@Bean
32+
public KurentoHandler kurentoHandler(KurentoManager kurentoManager) {
33+
return new KurentoHandler(kurentoManager);
34+
}
35+
36+
@Override
37+
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
38+
registry.addHandler(kurentoHandler(kurentoManager(kurentoClient())), "/signal").setAllowedOrigins("*");
39+
}
40+
41+
@Bean
42+
public ServletServerContainerFactoryBean createWebSocketContainer() {
43+
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
44+
container.setMaxTextMessageBufferSize(32768);
45+
container.setMaxBinaryMessageBufferSize(32768);
46+
return container;
47+
}
48+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.asyncgate.signaling_server.config;
2+
3+
import lombok.Getter;
4+
import org.springframework.beans.factory.annotation.Value;
5+
import org.springframework.context.annotation.Configuration;
6+
7+
@Configuration
8+
@Getter
9+
public class WebRTCConfig {
10+
11+
@Value("${stun.server.urls}")
12+
private String stunServer;
13+
14+
@Value("${turn.server.urls}")
15+
private String turnServer;
16+
17+
@Value("${turn.server.username}")
18+
private String turnUsername;
19+
20+
@Value("${turn.server.credential}")
21+
private String turnPassword;
22+
23+
// TURN 서버 URL 반환
24+
public String getTurnUrl() {
25+
return String.format("turn:%s", turnServer);
26+
}
27+
28+
// TURN 서버 인증 정보 반환
29+
public String getTurnCredential() {
30+
return turnPassword;
31+
}
32+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.asyncgate.signaling_server.controller;
2+
3+
import com.asyncgate.signaling_server.dto.response.GetUsersInChannelResponse;
4+
import com.asyncgate.signaling_server.security.annotation.MemberID;
5+
import com.asyncgate.signaling_server.usecase.GetUsersInRoomUseCase;
6+
import com.asyncgate.signaling_server.usecase.JoinRoomUseCase;
7+
import lombok.RequiredArgsConstructor;
8+
import org.springframework.web.bind.annotation.*;
9+
import com.asyncgate.signaling_server.support.response.SuccessResponse;
10+
11+
@RestController
12+
@RequestMapping("/room")
13+
@RequiredArgsConstructor
14+
public class ChatRoomCommandController {
15+
16+
private final JoinRoomUseCase joinRoomUseCase;
17+
private final GetUsersInRoomUseCase getUsersInRoomUseCase;
18+
19+
/**
20+
* 채널 참여
21+
*/
22+
@PostMapping("/{room_id}/join")
23+
public SuccessResponse<String> joinRoom(@PathVariable("room_id") final String roomId, @MemberID final String memberId) {
24+
System.out.println("member id");
25+
System.out.println(memberId);
26+
joinRoomUseCase.execute(roomId, memberId);
27+
return SuccessResponse.ok("room: " + roomId + "에 user: " + memberId + "가 참여하였습니다.");
28+
}
29+
30+
/**
31+
* 채널에 참여 중인 유저 조회
32+
*/
33+
@GetMapping("/{room_id}/users")
34+
public SuccessResponse<GetUsersInChannelResponse> getUsersInRoom(@PathVariable("room_id") String roomId) {
35+
return SuccessResponse.ok(getUsersInRoomUseCase.execute(roomId));
36+
}
37+
38+
/**
39+
*
40+
* kurento room 제거 method
41+
*/
42+
@DeleteMapping("/{roomId}")
43+
public SuccessResponse<String> deleteRoom(@PathVariable("roomId") String roomId) {
44+
return SuccessResponse.ok("room: " + roomId + "가 삭제되었습니다.");
45+
}
46+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.asyncgate.signaling_server.controller;
2+
3+
import org.springframework.web.bind.annotation.GetMapping;
4+
import org.springframework.web.bind.annotation.RestController;
5+
6+
@RestController
7+
public class TestQueryController {
8+
9+
@GetMapping("/health")
10+
public String healthCheck() {
11+
return "OK";
12+
}
13+
}

0 commit comments

Comments
 (0)