From 161424a2a3ce00bfded4c07e643bd71f4d59054d Mon Sep 17 00:00:00 2001 From: DongGeon0908 Date: Wed, 24 Jul 2024 23:42:14 +0900 Subject: [PATCH] feat: connection closed dev resource --- .github/workflows/gradle.yml | 2 + .../config/dev/DevResourceCheckConfig.kt | 37 +++++++++++++++++++ .../jwt/{JwtProperties.kt => JwtConfig.kt} | 0 .../config/swagger/SpringDocConfig.kt | 1 + .../ReactiveConcurrentUserWebSocketHandler.kt | 10 +++++ .../resource/DevUserInfoResource.kt | 13 ++++--- .../dev/resource/DevWebsocketResource.kt | 27 ++++++++++++++ src/main/resources/config/application.yml | 5 +++ 8 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 src/main/kotlin/com/hero/alignlab/config/dev/DevResourceCheckConfig.kt rename src/main/kotlin/com/hero/alignlab/config/jwt/{JwtProperties.kt => JwtConfig.kt} (100%) rename src/main/kotlin/com/hero/alignlab/domain/{user => dev}/resource/DevUserInfoResource.kt (65%) create mode 100644 src/main/kotlin/com/hero/alignlab/domain/dev/resource/DevWebsocketResource.kt diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 4de20b3..6e94ae8 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -56,6 +56,8 @@ jobs: # Encrypt 환경 변수 주입 encrypt.key: ${{ secrets.ENCRYPT_KEY }} encrypt.algorithm: ${{ secrets.ENCRYPT_ALGORITHM }} + # dev resource 환경 변수 주입 + hero-alignlab.dev.resource.key: ${{ secrets.HERO_ALIGNLAB_DEV_RESOURCE_KEY }} # Secret Setup - application-prod.yml - name: Inject env-values to application-prod.yml diff --git a/src/main/kotlin/com/hero/alignlab/config/dev/DevResourceCheckConfig.kt b/src/main/kotlin/com/hero/alignlab/config/dev/DevResourceCheckConfig.kt new file mode 100644 index 0000000..673b2ac --- /dev/null +++ b/src/main/kotlin/com/hero/alignlab/config/dev/DevResourceCheckConfig.kt @@ -0,0 +1,37 @@ +package com.hero.alignlab.config.dev + +import com.hero.alignlab.exception.ErrorCode +import com.hero.alignlab.exception.NoAuthorityException +import jakarta.validation.constraints.NotBlank +import org.springframework.boot.context.properties.ConfigurationProperties +import org.springframework.boot.context.properties.EnableConfigurationProperties +import org.springframework.context.annotation.Configuration + +@Configuration +@EnableConfigurationProperties(DevResourceCheckConfig.DevResourceCheckProperties::class) +class DevResourceCheckConfig( + _devResourceCheckProperties: DevResourceCheckProperties +) { + @ConfigurationProperties(prefix = "hero-alignlab.dev.resource") + data class DevResourceCheckProperties( + @field:NotBlank + var key: String = "", + ) + + init { + devResourceCheckProperties = _devResourceCheckProperties + } + + companion object { + const val DEV_AUTH_TOKEN_KEY = "X-HERO-DEV-AUTH-TOKEN" + + private lateinit var devResourceCheckProperties: DevResourceCheckProperties + + suspend fun devResource(key: String, function: suspend () -> T): T { + if (devResourceCheckProperties.key == key) { + return function.invoke() + } + throw NoAuthorityException(ErrorCode.NO_AUTHORITY_ERROR) + } + } +} diff --git a/src/main/kotlin/com/hero/alignlab/config/jwt/JwtProperties.kt b/src/main/kotlin/com/hero/alignlab/config/jwt/JwtConfig.kt similarity index 100% rename from src/main/kotlin/com/hero/alignlab/config/jwt/JwtProperties.kt rename to src/main/kotlin/com/hero/alignlab/config/jwt/JwtConfig.kt diff --git a/src/main/kotlin/com/hero/alignlab/config/swagger/SpringDocConfig.kt b/src/main/kotlin/com/hero/alignlab/config/swagger/SpringDocConfig.kt index 157820c..d6ca141 100644 --- a/src/main/kotlin/com/hero/alignlab/config/swagger/SpringDocConfig.kt +++ b/src/main/kotlin/com/hero/alignlab/config/swagger/SpringDocConfig.kt @@ -1,5 +1,6 @@ package com.hero.alignlab.config.swagger +import com.hero.alignlab.config.dev.DevResourceCheckConfig.Companion.DEV_AUTH_TOKEN_KEY import com.hero.alignlab.domain.auth.model.AUTH_TOKEN_KEY import com.hero.alignlab.domain.auth.model.AuthUser import io.swagger.v3.oas.models.Components diff --git a/src/main/kotlin/com/hero/alignlab/config/web/ReactiveConcurrentUserWebSocketHandler.kt b/src/main/kotlin/com/hero/alignlab/config/web/ReactiveConcurrentUserWebSocketHandler.kt index 9fa9ef3..f81a136 100644 --- a/src/main/kotlin/com/hero/alignlab/config/web/ReactiveConcurrentUserWebSocketHandler.kt +++ b/src/main/kotlin/com/hero/alignlab/config/web/ReactiveConcurrentUserWebSocketHandler.kt @@ -181,6 +181,16 @@ class ReactiveConcurrentUserWebSocketHandler( } } + fun forceCloseAllSessions() { + concurrentUserMap.forEach { (_, sessions) -> + sessions.forEach { (_, session) -> + session.close().subscribe() + } + } + + // 모든 세션이 종료된 후, 맵을 비울 수 있습니다. + concurrentUserMap.clear() + } } data class ConcurrentMessage( diff --git a/src/main/kotlin/com/hero/alignlab/domain/user/resource/DevUserInfoResource.kt b/src/main/kotlin/com/hero/alignlab/domain/dev/resource/DevUserInfoResource.kt similarity index 65% rename from src/main/kotlin/com/hero/alignlab/domain/user/resource/DevUserInfoResource.kt rename to src/main/kotlin/com/hero/alignlab/domain/dev/resource/DevUserInfoResource.kt index 65c72d1..20a27cc 100644 --- a/src/main/kotlin/com/hero/alignlab/domain/user/resource/DevUserInfoResource.kt +++ b/src/main/kotlin/com/hero/alignlab/domain/dev/resource/DevUserInfoResource.kt @@ -1,15 +1,13 @@ -package com.hero.alignlab.domain.user.resource +package com.hero.alignlab.domain.dev.resource import com.hero.alignlab.common.extension.wrapOk +import com.hero.alignlab.config.dev.DevResourceCheckConfig.Companion.devResource import com.hero.alignlab.config.swagger.SwaggerTag.DEV_TAG import com.hero.alignlab.domain.user.application.UserInfoService import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.http.MediaType -import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.PathVariable -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RestController +import org.springframework.web.bind.annotation.* @Tag(name = DEV_TAG) @RestController @@ -21,5 +19,8 @@ class DevUserInfoResource( @GetMapping("/api/dev/v1/users/{id}") suspend fun getUserInfo( @PathVariable id: Long, - ) = userInfoService.getUserInfo(id).wrapOk() + @RequestHeader("X-HERO-DEV-TOKEN") token: String + ) = devResource(token) { + userInfoService.getUserInfo(id).wrapOk() + } } diff --git a/src/main/kotlin/com/hero/alignlab/domain/dev/resource/DevWebsocketResource.kt b/src/main/kotlin/com/hero/alignlab/domain/dev/resource/DevWebsocketResource.kt new file mode 100644 index 0000000..2f31040 --- /dev/null +++ b/src/main/kotlin/com/hero/alignlab/domain/dev/resource/DevWebsocketResource.kt @@ -0,0 +1,27 @@ +package com.hero.alignlab.domain.dev.resource + +import com.hero.alignlab.config.dev.DevResourceCheckConfig.Companion.devResource +import com.hero.alignlab.config.swagger.SwaggerTag.DEV_TAG +import com.hero.alignlab.config.web.ReactiveConcurrentUserWebSocketHandler +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.http.MediaType +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestHeader +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@Tag(name = DEV_TAG) +@RestController +@RequestMapping(produces = [MediaType.APPLICATION_JSON_VALUE]) +class DevWebsocketResource( + private val reactiveConcurrentUserWebSocketHandler: ReactiveConcurrentUserWebSocketHandler +) { + @Operation(summary = "websocket connection closed") + @PostMapping("/api/dev/v1/websocket/connection-closed") + suspend fun closedConnection( + @RequestHeader("X-HERO-DEV-TOKEN") token: String + ) = devResource(token) { + reactiveConcurrentUserWebSocketHandler.forceCloseAllSessions() + } +} diff --git a/src/main/resources/config/application.yml b/src/main/resources/config/application.yml index ee42882..807b12a 100644 --- a/src/main/resources/config/application.yml +++ b/src/main/resources/config/application.yml @@ -50,3 +50,8 @@ auth: encrypt: key: algorithm: + +hero-alignlab: + dev: + resource: + key: