Skip to content

Commit

Permalink
Merge pull request #344 from wafflestudio/develop
Browse files Browse the repository at this point in the history
Release
  • Loading branch information
Hank-Choi authored Feb 13, 2025
2 parents 9300e57 + 5e421dd commit ee887c6
Show file tree
Hide file tree
Showing 9 changed files with 34 additions and 47 deletions.
11 changes: 5 additions & 6 deletions api/src/main/kotlin/handler/EvServiceHandler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ package com.wafflestudio.snutt.handler

import com.wafflestudio.snutt.evaluation.service.EvService
import com.wafflestudio.snutt.middleware.SnuttRestApiDefaultMiddleware
import kotlinx.coroutines.reactor.awaitSingleOrNull
import org.springframework.http.HttpMethod
import org.springframework.stereotype.Component
import org.springframework.web.reactive.function.server.ServerRequest
import org.springframework.web.reactive.function.server.bodyToMono
import org.springframework.web.reactive.function.server.awaitBodyOrNull

@Component
class EvServiceHandler(
Expand All @@ -15,25 +14,25 @@ class EvServiceHandler(
) : ServiceHandler(snuttRestApiDefaultMiddleware) {
suspend fun handleGet(req: ServerRequest) =
handle(req) {
val body = req.bodyToMono<String>().awaitSingleOrNull() ?: ""
val body = req.awaitBodyOrNull<String>() ?: ""
evService.handleRouting(req.userId, req.pathVariable("requestPath"), req.queryParams(), body, HttpMethod.GET)
}

suspend fun handlePost(req: ServerRequest) =
handle(req) {
val body = req.bodyToMono<String>().awaitSingleOrNull() ?: ""
val body = req.awaitBodyOrNull<String>() ?: ""
evService.handleRouting(req.userId, req.pathVariable("requestPath"), req.queryParams(), body, HttpMethod.POST)
}

suspend fun handleDelete(req: ServerRequest) =
handle(req) {
val body = req.bodyToMono<String>().awaitSingleOrNull() ?: ""
val body = req.awaitBodyOrNull<String>() ?: ""
evService.handleRouting(req.userId, req.pathVariable("requestPath"), req.queryParams(), body, HttpMethod.DELETE)
}

suspend fun handlePatch(req: ServerRequest) =
handle(req) {
val body = req.bodyToMono<String>().awaitSingleOrNull() ?: ""
val body = req.awaitBodyOrNull<String>() ?: ""
evService.handleRouting(req.userId, req.pathVariable("requestPath"), req.queryParams(), body, HttpMethod.PATCH)
}

Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ subprojects {

implementation("org.springframework.boot:spring-boot-starter-data-redis")

implementation("com.wafflestudio.truffle.sdk:truffle-spring-boot-starter:1.1.3")
implementation("com.wafflestudio.truffle.sdk:truffle-spring-boot-starter:1.1.5")
implementation("com.wafflestudio.truffle.sdk:truffle-logback:1.1.3")

implementation("org.springdoc:springdoc-openapi-starter-webflux-ui:2.0.2")
Expand Down
12 changes: 6 additions & 6 deletions core/src/main/kotlin/auth/AuthProvider.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.wafflestudio.snutt.auth

enum class AuthProvider(val value: String) {
LOCAL("local"),
FACEBOOK("facebook"),
APPLE("apple"),
GOOGLE("google"),
KAKAO("kakao"),
enum class AuthProvider(val value: String, val korName: String) {
LOCAL("local", "아이디/비밀번호"),
FACEBOOK("facebook", "페이스북"),
APPLE("apple", "애플"),
GOOGLE("google", "구글"),
KAKAO("kakao", "카카오"),
;

companion object {
Expand Down
7 changes: 2 additions & 5 deletions core/src/main/kotlin/common/exception/SnuttException.kt
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,8 @@ class DuplicateEmailException(authProviders: List<AuthProvider>) : SnuttExceptio
run {
val socialProviders = authProviders.filter { it != AuthProvider.LOCAL }
when {
authProviders.contains(AuthProvider.LOCAL) && socialProviders.isEmpty() -> "이미 가입된 이메일입니다. 아이디 찾기를 이용해주세요."
authProviders.contains(AuthProvider.LOCAL) && socialProviders.isNotEmpty() ->
"이미 가입된 이메일입니다. (${socialProviders.joinToString(", ") { it.value }}) 중 하나의 계정으로 로그인하거나 '아이디 찾기'를 이용해주세요."

socialProviders.isNotEmpty() -> "이미 가입된 이메일입니다. 이전에 가입한 ${socialProviders.joinToString(", ") { it.value }} 계정으로 로그인해주세요."
socialProviders.isNotEmpty() -> "이미 ${socialProviders.joinToString(", ") { it.korName }}과(와) 연동된 계정이 있습니다."
authProviders.contains(AuthProvider.LOCAL) -> "이미 가입된 이메일입니다. 아이디 찾기를 이용해주세요."
else -> throw IllegalStateException("로그인 방법이 없는 계정")
}
},
Expand Down
9 changes: 3 additions & 6 deletions core/src/main/kotlin/common/extension/WebClientExtensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ package com.wafflestudio.snutt.common.extension
import com.wafflestudio.snutt.common.util.WebClientUtils.logWebClientError
import com.wafflestudio.snutt.common.util.addHeaders
import com.wafflestudio.snutt.common.util.uriWithParams
import kotlinx.coroutines.reactor.awaitSingleOrNull
import org.springframework.core.ParameterizedTypeReference
import org.springframework.web.reactive.function.client.WebClient
import org.springframework.web.reactive.function.client.awaitBodyOrNull

suspend inline fun <reified T : Any> WebClient.get(
uri: String,
Expand All @@ -19,8 +18,7 @@ suspend inline fun <reified T : Any> WebClient.get(
uriWithParams(uri, params)
}
.retrieve()
.bodyToMono(object : ParameterizedTypeReference<T>() {})
.awaitSingleOrNull()
.awaitBodyOrNull<T>()
}.onFailure {
logWebClientError(uri, it)
}
Expand All @@ -39,8 +37,7 @@ suspend inline fun <reified ResponseT : Any> WebClient.post(
body?.let { bodyValue(it) }
}
.retrieve()
.bodyToMono(object : ParameterizedTypeReference<ResponseT>() {})
.awaitSingleOrNull()
.awaitBodyOrNull<ResponseT>()
}.onFailure {
logWebClientError(uri, it)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ import com.google.api.core.ApiFutureCallback
import com.google.api.core.ApiFutures
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.suspendCancellableCoroutine
import java.io.IOException
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine

suspend fun <F : Any> ApiFuture<F>.await(): F {
return this.await { it }
}

suspend fun <F : Any, R : Any?> ApiFuture<F>.await(successHandler: (F) -> R): R {
return suspendCoroutine { cont ->
return suspendCancellableCoroutine { cont ->
ApiFutures.addCallback(
this,
object : ApiFutureCallback<F> {
Expand All @@ -29,5 +29,8 @@ suspend fun <F : Any, R : Any?> ApiFuture<F>.await(successHandler: (F) -> R): R
},
Dispatchers.IO.asExecutor(),
)
cont.invokeOnCancellation {
this.cancel(true)
}
}
}
18 changes: 3 additions & 15 deletions core/src/main/kotlin/config/ApiWebClientConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import org.springframework.stereotype.Component
import org.springframework.web.reactive.function.client.WebClient
import reactor.netty.Connection
import reactor.netty.http.client.HttpClient
import reactor.netty.resources.ConnectionProvider
import java.time.Duration
import java.util.concurrent.TimeUnit

@Configuration
Expand All @@ -31,23 +29,13 @@ class ApiWebClientConfig(
private fun create(apiConfig: ApiConfig): WebClient {
val connector =
ReactorClientHttpConnector(
HttpClient.create(
ConnectionProvider.builder("snuttev-provider")
.maxConnections(100)
.pendingAcquireTimeout(Duration.ofMillis(300))
.maxLifeTime(Duration.ofSeconds(3600))
.maxIdleTime(Duration.ofSeconds(240))
.lifo()
.build(),
)
HttpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, apiConfig.connectTimeout)
.doOnConnected { conn: Connection ->
conn
.addHandlerLast(ReadTimeoutHandler(apiConfig.readTimeout, TimeUnit.MILLISECONDS))
.addHandlerLast(WriteTimeoutHandler(apiConfig.readTimeout, TimeUnit.MILLISECONDS))
conn.addHandlerLast(ReadTimeoutHandler(apiConfig.readTimeout, TimeUnit.MILLISECONDS))
conn.addHandlerLast(WriteTimeoutHandler(apiConfig.readTimeout, TimeUnit.MILLISECONDS))
},
)

return WebClient.builder().clientConnector(connector).baseUrl(apiConfig.baseUrl).build()
}
}
Expand Down
14 changes: 8 additions & 6 deletions core/src/main/kotlin/evaluation/service/EvService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,17 @@ import com.wafflestudio.snutt.evaluation.dto.EvLectureInfoDto
import com.wafflestudio.snutt.evaluation.dto.EvUserDto
import com.wafflestudio.snutt.timetables.service.TimetableService
import com.wafflestudio.snutt.users.service.UserService
import io.netty.util.ReferenceCounted
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.reactive.awaitFirstOrNull
import kotlinx.coroutines.reactor.awaitSingle
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpMethod
import org.springframework.http.HttpStatusCode
import org.springframework.http.MediaType
import org.springframework.stereotype.Service
import org.springframework.util.MultiValueMap
import org.springframework.web.reactive.function.BodyInserters
import org.springframework.web.reactive.function.client.awaitBody
import org.springframework.web.reactive.function.client.awaitBodyOrNull
import org.springframework.web.reactive.function.client.bodyToMono
import reactor.core.publisher.Mono

Expand All @@ -40,19 +41,20 @@ class EvService(
val result: MutableMap<String, Any?>? =
snuttEvWebClient.method(method)
.uri { builder -> builder.path(requestPath).queryParams(requestQueryParams).build() }
.contentType(MediaType.APPLICATION_JSON)
.header("Snutt-User-Id", userId)
.header(HttpHeaders.CONTENT_ENCODING, "UTF-8")
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.body(BodyInserters.fromValue(originalBody))
.retrieve()
.onStatus(HttpStatusCode::isError) { response ->
response.bodyToMono<Map<String, Any?>>()
.doOnDiscard(ReferenceCounted::class.java) { it.release() }
.flatMap { errorBody ->
Mono.error(EvServiceProxyException(response.statusCode(), errorBody))
}
}
.bodyToMono<MutableMap<String, Any?>>()
.awaitFirstOrNull()
.awaitBodyOrNull<MutableMap<String, Any?>>()
return updateUserInfo(result)
}

Expand Down Expand Up @@ -90,12 +92,12 @@ class EvService(
.retrieve()
.onStatus(HttpStatusCode::isError) { response ->
response.bodyToMono<Map<String, Any?>>()
.doOnDiscard(ReferenceCounted::class.java) { it.release() }
.flatMap { errorBody ->
Mono.error(EvServiceProxyException(response.statusCode(), errorBody))
}
}
.bodyToMono<MutableMap<String, Any?>>()
.awaitSingle()
.awaitBody<MutableMap<String, Any?>>()
}

@Suppress("UNCHECKED_CAST")
Expand Down
1 change: 1 addition & 0 deletions core/src/main/resources/application-common.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,5 +109,6 @@ api:
server:
snuttev:
base-url: http://snutt-ev.snutt-prod.svc.cluster.local
read-timeout: 5000

secret-names: prod/snutt-timetable

0 comments on commit ee887c6

Please sign in to comment.