From bb87cab45fbb0579372f502f35599c479d353481 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Sat, 18 Nov 2023 11:05:02 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B1=8E=E7=94=A8ResourceResolver?= =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/service/resource/CacheManager.kt | 6 +++ .../service/resource/InMemoryCacheManager.kt | 49 +++++++++++++++++++ .../service/resource/KtorResolveResponse.kt | 14 ++++++ .../resource/KtorResourceResolveService.kt | 24 +++++++++ .../core/service/resource/ResolveResponse.kt | 10 ++++ .../resource/ResourceResolveService.kt | 5 ++ 6 files changed, 108 insertions(+) create mode 100644 src/main/kotlin/dev/usbharu/hideout/core/service/resource/CacheManager.kt create mode 100644 src/main/kotlin/dev/usbharu/hideout/core/service/resource/InMemoryCacheManager.kt create mode 100644 src/main/kotlin/dev/usbharu/hideout/core/service/resource/KtorResolveResponse.kt create mode 100644 src/main/kotlin/dev/usbharu/hideout/core/service/resource/KtorResourceResolveService.kt create mode 100644 src/main/kotlin/dev/usbharu/hideout/core/service/resource/ResolveResponse.kt create mode 100644 src/main/kotlin/dev/usbharu/hideout/core/service/resource/ResourceResolveService.kt diff --git a/src/main/kotlin/dev/usbharu/hideout/core/service/resource/CacheManager.kt b/src/main/kotlin/dev/usbharu/hideout/core/service/resource/CacheManager.kt new file mode 100644 index 00000000..44dfd2a6 --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/core/service/resource/CacheManager.kt @@ -0,0 +1,6 @@ +package dev.usbharu.hideout.core.service.resource + +interface CacheManager { + suspend fun putCache(key: String, block: suspend () -> ResolveResponse) + suspend fun getOrWait(key: String): ResolveResponse +} diff --git a/src/main/kotlin/dev/usbharu/hideout/core/service/resource/InMemoryCacheManager.kt b/src/main/kotlin/dev/usbharu/hideout/core/service/resource/InMemoryCacheManager.kt new file mode 100644 index 00000000..b48fadd7 --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/core/service/resource/InMemoryCacheManager.kt @@ -0,0 +1,49 @@ +package dev.usbharu.hideout.core.service.resource + +import dev.usbharu.hideout.util.LruCache +import kotlinx.coroutines.delay +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import org.springframework.stereotype.Service +import java.time.Instant + +@Service +class InMemoryCacheManager : CacheManager { + private val cacheKey = LruCache(15) + private val valueStore = mutableMapOf() + private val keyMutex = Mutex() + + override suspend fun putCache(key: String, block: suspend () -> ResolveResponse) { + val needRunBlock: Boolean + keyMutex.withLock { + cacheKey.filter { Instant.ofEpochMilli(it.value).plusSeconds(300) <= Instant.now() } + + val cached = cacheKey.get(key) + if (cached == null) { + needRunBlock = true + cacheKey[key] = Instant.now().toEpochMilli() + + valueStore.remove(key) + } else { + needRunBlock = false + } + } + if (needRunBlock) { + val processed = block() + + if (cacheKey.containsKey(key)) { + valueStore[key] = processed + } + } + } + + override suspend fun getOrWait(key: String): ResolveResponse { + while (valueStore.contains(key).not()) { + if (cacheKey.containsKey(key).not()) { + throw IllegalStateException("Invalid cache key.") + } + delay(1) + } + return valueStore.getValue(key) + } +} diff --git a/src/main/kotlin/dev/usbharu/hideout/core/service/resource/KtorResolveResponse.kt b/src/main/kotlin/dev/usbharu/hideout/core/service/resource/KtorResolveResponse.kt new file mode 100644 index 00000000..8261d8dc --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/core/service/resource/KtorResolveResponse.kt @@ -0,0 +1,14 @@ +package dev.usbharu.hideout.core.service.resource + +import io.ktor.client.statement.* +import io.ktor.util.* +import io.ktor.utils.io.jvm.javaio.* +import java.io.InputStream + +class KtorResolveResponse(val ktorHttpResponse: HttpResponse) : ResolveResponse { + + override suspend fun body(): InputStream = ktorHttpResponse.bodyAsChannel().toInputStream() + override suspend fun header(): Map> = ktorHttpResponse.headers.toMap() + override suspend fun status(): Int = ktorHttpResponse.status.value + override suspend fun statusMessage(): String = ktorHttpResponse.status.description +} diff --git a/src/main/kotlin/dev/usbharu/hideout/core/service/resource/KtorResourceResolveService.kt b/src/main/kotlin/dev/usbharu/hideout/core/service/resource/KtorResourceResolveService.kt new file mode 100644 index 00000000..4cd99bc8 --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/core/service/resource/KtorResourceResolveService.kt @@ -0,0 +1,24 @@ +package dev.usbharu.hideout.core.service.resource + +import io.ktor.client.* +import io.ktor.client.request.* +import org.springframework.stereotype.Service + +@Service +open class KtorResourceResolveService(private val httpClient: HttpClient, private val cacheManager: CacheManager) : + ResourceResolveService { + override suspend fun resolve(url: String): ResolveResponse { + cacheManager.putCache(getCacheKey(url)) { + runResolve(url) + } + return cacheManager.getOrWait(getCacheKey(url)) + } + + protected suspend fun runResolve(url: String): ResolveResponse { + val httpResponse = httpClient.get(url) + + return KtorResolveResponse(httpResponse) + } + + protected suspend fun getCacheKey(url: String) = url +} diff --git a/src/main/kotlin/dev/usbharu/hideout/core/service/resource/ResolveResponse.kt b/src/main/kotlin/dev/usbharu/hideout/core/service/resource/ResolveResponse.kt new file mode 100644 index 00000000..bcfb0bcb --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/core/service/resource/ResolveResponse.kt @@ -0,0 +1,10 @@ +package dev.usbharu.hideout.core.service.resource + +import java.io.InputStream + +interface ResolveResponse { + suspend fun body(): InputStream + suspend fun header(): Map> + suspend fun status(): Int + suspend fun statusMessage(): String +} diff --git a/src/main/kotlin/dev/usbharu/hideout/core/service/resource/ResourceResolveService.kt b/src/main/kotlin/dev/usbharu/hideout/core/service/resource/ResourceResolveService.kt new file mode 100644 index 00000000..b2229b30 --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/core/service/resource/ResourceResolveService.kt @@ -0,0 +1,5 @@ +package dev.usbharu.hideout.core.service.resource + +interface ResourceResolveService { + suspend fun resolve(url: String): ResolveResponse +}