mirror of https://github.com/usbharu/Hideout.git
feat: 汎用ResourceResolverを追加
This commit is contained in:
parent
1db8f31b5f
commit
bb87cab45f
|
@ -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
|
||||||
|
}
|
|
@ -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<String, Long>(15)
|
||||||
|
private val valueStore = mutableMapOf<String, ResolveResponse>()
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<String, List<String>> = ktorHttpResponse.headers.toMap()
|
||||||
|
override suspend fun status(): Int = ktorHttpResponse.status.value
|
||||||
|
override suspend fun statusMessage(): String = ktorHttpResponse.status.description
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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<String, List<String>>
|
||||||
|
suspend fun status(): Int
|
||||||
|
suspend fun statusMessage(): String
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package dev.usbharu.hideout.core.service.resource
|
||||||
|
|
||||||
|
interface ResourceResolveService {
|
||||||
|
suspend fun resolve(url: String): ResolveResponse
|
||||||
|
}
|
Loading…
Reference in New Issue