-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from prgrms-web-devcourse-final-project/QUZ-36-…
…Websocket-configuration [QUZ-36][FEATURE] WebSocket Configuration
- Loading branch information
Showing
12 changed files
with
333 additions
and
3 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
dependencies { | ||
api(project(":common")) | ||
|
||
implementation("org.springframework:spring-context") | ||
} |
7 changes: 7 additions & 0 deletions
7
game-service/game-domain/src/main/kotlin/com/grepp/quizy/domain/game/GameMessageSender.kt
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,7 @@ | ||
package com.grepp.quizy.domain.game | ||
|
||
import java.security.Principal | ||
|
||
interface GameMessageSender { | ||
fun send(principal: Principal, message: String) | ||
} |
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 |
---|---|---|
@@ -1,3 +1,27 @@ | ||
plugins { | ||
kotlin("plugin.jpa") version "1.8.22" | ||
} | ||
|
||
allOpen { | ||
annotation("jakarta.persistence.Entity") | ||
annotation("jakarta.persistence.MappedSuperclass") | ||
annotation("jakarta.persistence.Embeddable") | ||
} | ||
|
||
dependencies { | ||
implementation(project(":common")) | ||
} | ||
// Kafka Module | ||
api(project(":infrastructure:kafka")) | ||
// Game Domain Module | ||
implementation(project(":game-service:game-domain")) | ||
// H2 Database | ||
runtimeOnly("com.h2database:h2") | ||
// MySQL | ||
runtimeOnly("com.mysql:mysql-connector-j") | ||
// JPA | ||
implementation("org.springframework.boot:spring-boot-starter-data-jpa") | ||
// Redis | ||
implementation("com.github.codemonstur:embedded-redis:1.4.3") | ||
implementation("org.springframework.boot:spring-boot-starter-data-redis") | ||
// WebSocket | ||
implementation("org.springframework.boot:spring-boot-starter-websocket") | ||
} |
18 changes: 18 additions & 0 deletions
18
...game-infra/src/main/kotlin/com/grepp/quizy/infra/game/websocket/CustomHandshakeHandler.kt
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,18 @@ | ||
package com.grepp.quizy.infra.game.websocket | ||
|
||
import org.springframework.http.server.ServerHttpRequest | ||
import org.springframework.web.socket.WebSocketHandler | ||
import org.springframework.web.socket.server.support.DefaultHandshakeHandler | ||
import java.security.Principal | ||
import java.util.* | ||
|
||
class CustomHandshakeHandler : DefaultHandshakeHandler() { | ||
|
||
// TODO: 실제로 게이트웨이에서 사용자 정보를 받는 방식이 정해지면 구현 방식 변경 | ||
override fun determineUser( | ||
request: ServerHttpRequest, | ||
wsHandler: WebSocketHandler, | ||
attributes: MutableMap<String, Any> | ||
): Principal = WebSocketPrincipal(UUID.randomUUID().toString()) | ||
|
||
} |
22 changes: 22 additions & 0 deletions
22
...-infra/src/main/kotlin/com/grepp/quizy/infra/game/websocket/GameWebSocketMessageSender.kt
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 com.grepp.quizy.infra.game.websocket | ||
|
||
import com.grepp.quizy.domain.game.GameMessageSender | ||
import com.grepp.quizy.infra.game.websocket.WebSocketDestination.* | ||
import org.springframework.messaging.simp.SimpMessagingTemplate | ||
import org.springframework.stereotype.Component | ||
import java.security.Principal | ||
|
||
@Component | ||
class GameWebSocketMessageSender( | ||
private val messageTemplate: SimpMessagingTemplate | ||
) : GameMessageSender { | ||
|
||
override fun send(principal: Principal, message: String) { | ||
messageTemplate.convertAndSendToUser( | ||
principal.name, | ||
"${SINGLE_PREFIX.destination}${QUIZ_GRADE.destination}", | ||
message | ||
) | ||
} | ||
|
||
} |
26 changes: 26 additions & 0 deletions
26
.../game-infra/src/main/kotlin/com/grepp/quizy/infra/game/websocket/WebSocketBrokerConfig.kt
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,26 @@ | ||
package com.grepp.quizy.infra.game.websocket | ||
|
||
import com.grepp.quizy.infra.game.websocket.WebSocketDestination.* | ||
import org.springframework.context.annotation.Configuration | ||
import org.springframework.messaging.simp.config.MessageBrokerRegistry | ||
import org.springframework.web.socket.config.annotation.StompEndpointRegistry | ||
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer | ||
|
||
|
||
@Configuration | ||
class WebSocketBrokerConfig : WebSocketMessageBrokerConfigurer { | ||
|
||
override fun registerStompEndpoints(registry: StompEndpointRegistry) { | ||
registry.addEndpoint("/ws") | ||
.setAllowedOriginPatterns("*") | ||
.setHandshakeHandler(CustomHandshakeHandler()) | ||
.withSockJS() | ||
} | ||
|
||
override fun configureMessageBroker(registry: MessageBrokerRegistry) { | ||
registry.setApplicationDestinationPrefixes(APPLICATION_PREFIX.destination) | ||
registry.enableSimpleBroker(MULTIPLE_PREFIX.destination, SINGLE_PREFIX.destination) | ||
registry.setUserDestinationPrefix(USER_PREFIX.destination) | ||
} | ||
|
||
} |
15 changes: 15 additions & 0 deletions
15
...e/game-infra/src/main/kotlin/com/grepp/quizy/infra/game/websocket/WebSocketDestination.kt
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,15 @@ | ||
package com.grepp.quizy.infra.game.websocket | ||
|
||
enum class WebSocketDestination( | ||
val destination: String | ||
) { | ||
|
||
SINGLE_PREFIX("/queue"), | ||
MULTIPLE_PREFIX("/topic"), | ||
USER_PREFIX("/user"), | ||
APPLICATION_PREFIX("/app"), | ||
|
||
QUIZ_GRADE("/quiz-grade"), | ||
; | ||
|
||
} |
11 changes: 11 additions & 0 deletions
11
...ice/game-infra/src/main/kotlin/com/grepp/quizy/infra/game/websocket/WebSocketPrincipal.kt
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,11 @@ | ||
package com.grepp.quizy.infra.game.websocket | ||
|
||
import java.security.Principal | ||
|
||
class WebSocketPrincipal( | ||
private val name: String | ||
) : Principal { | ||
override fun getName(): String { | ||
return name | ||
} | ||
} |
105 changes: 105 additions & 0 deletions
105
game-service/game-infra/src/main/resources/application-infra.yml
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,105 @@ | ||
--- | ||
spring: | ||
config: | ||
activate: | ||
on-profile: local | ||
|
||
datasource: | ||
url: jdbc:h2:mem:~/webQuiz | ||
driver-class-name: org.h2.Driver | ||
username: sa | ||
password: | ||
jpa: | ||
hibernate: | ||
ddl-auto: create | ||
properties: | ||
hibernate: | ||
show-sql: true | ||
format_sql: true | ||
|
||
redis: | ||
host: localhost | ||
port: 6379 | ||
|
||
kafka: | ||
topic: | ||
quiz: quiz | ||
consumer-group: | ||
quiz: quiz | ||
|
||
kafka-config: | ||
bootstrap-servers: localhost:19092, localhost:29092, localhost:39092 | ||
num-of-partitions: 3 | ||
replication-factor: 3 | ||
|
||
kafka-producer-config: | ||
key-serializer-class: org.springframework.kafka.support.serializer.JsonSerializer | ||
value-serializer-class: org.springframework.kafka.support.serializer.JsonSerializer | ||
compression-type: none | ||
acks: all | ||
batch-size: 16384 | ||
batch-size-boost-factor: 100 | ||
linger-ms: 5 | ||
request-timeout-ms: 60000 | ||
retry-count: 5 | ||
|
||
kafka-consumer-config: | ||
key-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer | ||
value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer | ||
auto-offset-reset: earliest | ||
batch-listener: true | ||
auto-startup: true | ||
concurrency-level: 3 | ||
session-timeout-ms: 10000 | ||
heartbeat-interval-ms: 3000 | ||
max-poll-interval-ms: 300000 | ||
max-poll-records: 500 | ||
max-partition-fetch-bytes-default: 1048576 | ||
max-partition-fetch-bytes-boost-factor: 1 | ||
poll-timeout-ms: 150 | ||
|
||
--- | ||
spring: | ||
config: | ||
activate: | ||
on-profile: dev | ||
datasource: | ||
url: jdbc:mysql://${DATABASE_HOST}:${DATABASE_PORT}/${DATABASE_NAME}?useSSL=false&allowPublicKeyRetrieval=true | ||
username: ${DATABASE_USER} | ||
password: ${DATABASE_PASSWORD} | ||
driver-class-name: com.mysql.cj.jdbc.Driver | ||
jpa: | ||
hibernate: | ||
ddl-auto: ${JPA_DDL_AUTO} | ||
properties: | ||
hibernate: | ||
show-sql: false | ||
format_sql: false | ||
|
||
redis: | ||
host: ${REDIS_HOST} | ||
port: ${REDIS_PORT} | ||
|
||
--- | ||
spring: | ||
config: | ||
activate: | ||
on-profile: test | ||
|
||
datasource: | ||
url: jdbc:h2:mem:~/webQuiz | ||
driver-class-name: org.h2.Driver | ||
username: sa | ||
password: | ||
|
||
redis: | ||
host: localhost | ||
port: 6379 | ||
|
||
jpa: | ||
hibernate: | ||
ddl-auto: create-drop | ||
show-sql: true | ||
properties: | ||
hibernate: | ||
format_sql: true |
35 changes: 35 additions & 0 deletions
35
...ra/src/test/kotlin/com/grepp/quizy/infra/game/websocket/GameWebSocketMessageSenderTest.kt
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 com.grepp.quizy.infra.game.websocket | ||
|
||
import io.kotest.core.spec.style.DescribeSpec | ||
import io.mockk.every | ||
import io.mockk.justRun | ||
import io.mockk.mockk | ||
import io.mockk.verify | ||
import org.springframework.messaging.simp.SimpMessagingTemplate | ||
import java.security.Principal | ||
|
||
class GameWebSocketMessageSenderTest : DescribeSpec({ | ||
|
||
val messageTemplate: SimpMessagingTemplate = mockk() | ||
val messageSender = GameWebSocketMessageSender(messageTemplate) | ||
|
||
describe("GameWebSocketMessageSender") { | ||
context("메시지를 보내면") { | ||
val principal = mockk<Principal>() | ||
every { principal.name } returns "minhyeok" | ||
justRun { messageTemplate.convertAndSendToUser(any(), any(), any()) } | ||
val message = "테스트 메시지" | ||
messageSender.send(principal, message) | ||
it("메시지가 사용자에게 전달된다.") { | ||
verify { | ||
messageTemplate.convertAndSendToUser( | ||
"minhyeok", | ||
"/queue/quiz-grade", | ||
message | ||
) | ||
} | ||
} | ||
} | ||
} | ||
|
||
}) |
50 changes: 50 additions & 0 deletions
50
...e-infra/src/test/kotlin/com/grepp/quizy/infra/game/websocket/WebSocketBrokerConfigTest.kt
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,50 @@ | ||
package com.grepp.quizy.infra.game.websocket | ||
|
||
import io.kotest.core.spec.style.FunSpec | ||
import io.kotest.matchers.shouldBe | ||
import io.mockk.* | ||
import org.springframework.messaging.simp.stomp.StompSession | ||
import org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter | ||
import org.springframework.web.socket.messaging.WebSocketStompClient | ||
import java.util.concurrent.CompletableFuture | ||
import java.util.concurrent.TimeUnit | ||
|
||
class WebSocketBrokerConfigTest : FunSpec() { | ||
|
||
private val stompClient = mockk<WebSocketStompClient>() | ||
private val stompSession = mockk<StompSession>() | ||
|
||
init { | ||
beforeTest { | ||
every { | ||
stompClient.connectAsync(any(), any<StompSessionHandlerAdapter>()) | ||
} returns CompletableFuture.completedFuture(stompSession) | ||
|
||
every { stompSession.isConnected } returns true | ||
every { stompSession.disconnect() } just Runs | ||
every { stompClient.stop() } just Runs | ||
} | ||
|
||
afterTest { | ||
stompSession.disconnect() | ||
stompClient.stop() | ||
} | ||
|
||
test("웹소켓 연결") { | ||
// given | ||
val url = "ws://localhost:8080/ws" | ||
|
||
// when | ||
val session = stompClient | ||
.connectAsync(url, object : StompSessionHandlerAdapter() {}) | ||
.get(60, TimeUnit.SECONDS) | ||
|
||
// then | ||
session.isConnected shouldBe true | ||
verify { | ||
stompClient.connectAsync(url, any<StompSessionHandlerAdapter>()) | ||
session.isConnected | ||
} | ||
} | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
...game-infra/src/test/kotlin/com/grepp/quizy/infra/game/websocket/WebSocketPrincipalTest.kt
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,17 @@ | ||
package com.grepp.quizy.infra.game.websocket | ||
|
||
import io.kotest.core.spec.style.DescribeSpec | ||
import io.kotest.matchers.shouldBe | ||
|
||
class WebSocketPrincipalTest : DescribeSpec({ | ||
|
||
describe("웹소켓 사용자에서") { | ||
val principal = WebSocketPrincipal("minhyeok") | ||
context("이름을 가져오면") { | ||
val name = principal.name | ||
it("이름을 반환한다.") { | ||
name shouldBe "minhyeok" | ||
} | ||
} | ||
} | ||
}) |