diff --git a/push-message-provider-hpk/src/main/kotlin/ru/touchin/push/message/provider/hpk/services/HmsOauthAccessTokenCacheService.kt b/push-message-provider-hpk/src/main/kotlin/ru/touchin/push/message/provider/hpk/services/HmsOauthAccessTokenCacheService.kt new file mode 100644 index 0000000..4aab4c0 --- /dev/null +++ b/push-message-provider-hpk/src/main/kotlin/ru/touchin/push/message/provider/hpk/services/HmsOauthAccessTokenCacheService.kt @@ -0,0 +1,11 @@ +package ru.touchin.push.message.provider.hpk.services + +import ru.touchin.push.message.provider.hpk.services.dto.AccessToken + +interface HmsOauthAccessTokenCacheService { + + fun put(accessToken: AccessToken) + fun get(): AccessToken? + fun evict() + +} diff --git a/push-message-provider-hpk/src/main/kotlin/ru/touchin/push/message/provider/hpk/services/HmsOauthAccessTokenCacheServiceImpl.kt b/push-message-provider-hpk/src/main/kotlin/ru/touchin/push/message/provider/hpk/services/HmsOauthAccessTokenCacheServiceImpl.kt new file mode 100644 index 0000000..07fc5ab --- /dev/null +++ b/push-message-provider-hpk/src/main/kotlin/ru/touchin/push/message/provider/hpk/services/HmsOauthAccessTokenCacheServiceImpl.kt @@ -0,0 +1,73 @@ +package ru.touchin.push.message.provider.hpk.services + +import com.fasterxml.jackson.core.type.TypeReference +import com.fasterxml.jackson.databind.ObjectMapper +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.cache.Cache +import org.springframework.cache.CacheManager +import org.springframework.stereotype.Service +import ru.touchin.push.message.provider.hpk.properties.HpkProperties +import ru.touchin.push.message.provider.hpk.services.dto.AccessToken +import java.time.Instant + +@Service +class HmsOauthAccessTokenCacheServiceImpl( + @Qualifier("push-message-provider.hpk.webclient-cachemanager") + private val cacheManager: CacheManager, + @Qualifier("push-message-provider.hpk.client-objectmapper") + private val objectMapper: ObjectMapper, + private val hpkProperties: HpkProperties, +) : HmsOauthAccessTokenCacheService { + + override fun put(accessToken: AccessToken) { + getCache()?.put(hpkProperties.webServices.clientId, accessToken) + } + + override fun get(): AccessToken? { // TODO: implement synchronization for all threads + val cachedValue = getCache() + ?.get(hpkProperties.webServices.clientId) + ?.get() + ?: return null + + val accessToken = safeCast(cachedValue, object : TypeReference() {}) + ?: return null + + return if (accessToken.isValid()) { + accessToken + } else { + null + } + } + + override fun evict() { + getCache()?.evict(hpkProperties.webServices.clientId) + } + + private fun safeCast(item: Any, typeReference: TypeReference): T? { + return try { + objectMapper.convertValue(item, typeReference) + } catch (e: Exception) { + print(e.message) + null + } + } + + private fun AccessToken.isValid(): Boolean { + val expirationTime = with(hpkProperties.webServices.oauth) { + Instant.now().plus(http.connectionTimeout + http.readTimeout + http.writeTimeout) + } + + return expiresAt.isAfter(expirationTime) + } + + private fun getCache(): Cache? { + return cacheManager.getCache(HMS_CLIENT_SERVICE_CACHE_KEY) + } + + companion object { + + const val HMS_CLIENT_SERVICE_CACHE_KEY = "HMS_CLIENT_SERVICE" + + } + +} diff --git a/push-message-provider-hpk/src/main/kotlin/ru/touchin/push/message/provider/hpk/services/HmsOauthClientService.kt b/push-message-provider-hpk/src/main/kotlin/ru/touchin/push/message/provider/hpk/services/HmsOauthClientService.kt new file mode 100644 index 0000000..bc8ca65 --- /dev/null +++ b/push-message-provider-hpk/src/main/kotlin/ru/touchin/push/message/provider/hpk/services/HmsOauthClientService.kt @@ -0,0 +1,7 @@ +package ru.touchin.push.message.provider.hpk.services + +interface HmsOauthClientService { + + fun getAccessToken(): String + +} diff --git a/push-message-provider-hpk/src/main/kotlin/ru/touchin/push/message/provider/hpk/services/HmsOauthClientServiceImpl.kt b/push-message-provider-hpk/src/main/kotlin/ru/touchin/push/message/provider/hpk/services/HmsOauthClientServiceImpl.kt new file mode 100644 index 0000000..8b38b6c --- /dev/null +++ b/push-message-provider-hpk/src/main/kotlin/ru/touchin/push/message/provider/hpk/services/HmsOauthClientServiceImpl.kt @@ -0,0 +1,37 @@ +package ru.touchin.push.message.provider.hpk.services + +import org.springframework.stereotype.Service +import ru.touchin.push.message.provider.exceptions.PushMessageProviderException +import ru.touchin.push.message.provider.hpk.clients.hms_oauth.HmsOauthWebClient +import ru.touchin.push.message.provider.hpk.services.dto.AccessToken +import java.time.Instant + +@Service +class HmsOauthClientServiceImpl( + private val hmsOauthAccessTokenCacheService: HmsOauthAccessTokenCacheService, + private val hmsOauthWebClient: HmsOauthWebClient, +) : HmsOauthClientService { + + override fun getAccessToken(): String { + val accessToken = hmsOauthAccessTokenCacheService.get() + ?: retrieveAccessToken().also(hmsOauthAccessTokenCacheService::put) + + return accessToken.value + } + + private fun retrieveAccessToken(): AccessToken { + val result = hmsOauthWebClient.token() + + if (result.success == null) { + throw PushMessageProviderException(result.failure?.errorDescription.orEmpty(), null) + } + + return with(result.success) { + AccessToken( + value = accessToken, + expiresAt = Instant.now().plusSeconds(expiresIn) + ) + } + } + +} diff --git a/push-message-provider-hpk/src/main/kotlin/ru/touchin/push/message/provider/hpk/services/dto/AccessToken.kt b/push-message-provider-hpk/src/main/kotlin/ru/touchin/push/message/provider/hpk/services/dto/AccessToken.kt new file mode 100644 index 0000000..2966ad4 --- /dev/null +++ b/push-message-provider-hpk/src/main/kotlin/ru/touchin/push/message/provider/hpk/services/dto/AccessToken.kt @@ -0,0 +1,8 @@ +package ru.touchin.push.message.provider.hpk.services.dto + +import java.time.Instant + +data class AccessToken( + val value: String, + val expiresAt: Instant, +)