mirror of https://github.com/usbharu/Hideout.git
feat: Nodeinfoのデシリアライズ用クラスを別に準備
This commit is contained in:
parent
4837192139
commit
ee56adcf27
|
@ -3,7 +3,10 @@ package dev.usbharu.hideout.activitypub.service.common
|
||||||
import dev.usbharu.hideout.activitypub.domain.model.objects.Object
|
import dev.usbharu.hideout.activitypub.domain.model.objects.Object
|
||||||
import dev.usbharu.hideout.core.domain.model.user.User
|
import dev.usbharu.hideout.core.domain.model.user.User
|
||||||
import dev.usbharu.hideout.core.domain.model.user.UserRepository
|
import dev.usbharu.hideout.core.domain.model.user.UserRepository
|
||||||
|
import dev.usbharu.hideout.core.service.resource.CacheManager
|
||||||
|
import dev.usbharu.hideout.core.service.resource.ResolveResponse
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
import java.io.InputStream
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class APResourceResolveServiceImpl(
|
class APResourceResolveServiceImpl(
|
||||||
|
@ -25,7 +28,7 @@ class APResourceResolveServiceImpl(
|
||||||
cacheManager.putCache(key) {
|
cacheManager.putCache(key) {
|
||||||
runResolve(url, singerId?.let { userRepository.findById(it) }, clazz)
|
runResolve(url, singerId?.let { userRepository.findById(it) }, clazz)
|
||||||
}
|
}
|
||||||
return cacheManager.getOrWait(key) as T
|
return (cacheManager.getOrWait(key) as APResolveResponse<T>).objects
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun <T : Object> internalResolve(url: String, singer: User?, clazz: Class<T>): T {
|
private suspend fun <T : Object> internalResolve(url: String, singer: User?, clazz: Class<T>): T {
|
||||||
|
@ -33,11 +36,12 @@ class APResourceResolveServiceImpl(
|
||||||
cacheManager.putCache(key) {
|
cacheManager.putCache(key) {
|
||||||
runResolve(url, singer, clazz)
|
runResolve(url, singer, clazz)
|
||||||
}
|
}
|
||||||
return cacheManager.getOrWait(key) as T
|
return (cacheManager.getOrWait(key) as APResolveResponse<T>).objects
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun <T : Object> runResolve(url: String, singer: User?, clazz: Class<T>): Object =
|
private suspend fun <T : Object> runResolve(url: String, singer: User?, clazz: Class<T>): ResolveResponse {
|
||||||
apRequestService.apGet(url, singer, clazz)
|
return APResolveResponse(apRequestService.apGet(url, singer, clazz))
|
||||||
|
}
|
||||||
|
|
||||||
private fun genCacheKey(url: String, singerId: Long?): String {
|
private fun genCacheKey(url: String, singerId: Long?): String {
|
||||||
if (singerId != null) {
|
if (singerId != null) {
|
||||||
|
@ -45,4 +49,30 @@ class APResourceResolveServiceImpl(
|
||||||
}
|
}
|
||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class APResolveResponse<T : Object>(val objects: T) : ResolveResponse {
|
||||||
|
override suspend fun body(): InputStream {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun bodyAsText(): String {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun bodyAsBytes(): ByteArray {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun header(): Map<String, List<String>> {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun status(): Int {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun statusMessage(): String {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
package dev.usbharu.hideout.activitypub.service.common
|
|
||||||
|
|
||||||
import dev.usbharu.hideout.activitypub.domain.model.objects.Object
|
|
||||||
|
|
||||||
interface CacheManager {
|
|
||||||
|
|
||||||
suspend fun putCache(key: String, block: suspend () -> Object)
|
|
||||||
suspend fun getOrWait(key: String): Object
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
package dev.usbharu.hideout.activitypub.service.common
|
|
||||||
|
|
||||||
import dev.usbharu.hideout.activitypub.domain.model.objects.Object
|
|
||||||
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, Object>()
|
|
||||||
private val keyMutex = Mutex()
|
|
||||||
|
|
||||||
override suspend fun putCache(key: String, block: suspend () -> Object) {
|
|
||||||
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): Object {
|
|
||||||
while (valueStore.contains(key).not()) {
|
|
||||||
if (cacheKey.containsKey(key).not()) {
|
|
||||||
throw IllegalStateException("Invalid cache key.")
|
|
||||||
}
|
|
||||||
delay(1)
|
|
||||||
}
|
|
||||||
return valueStore.getValue(key)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package dev.usbharu.hideout.core.domain.model.instance
|
||||||
|
|
||||||
|
class Nodeinfo {
|
||||||
|
|
||||||
|
var links: List<Links> = emptyList()
|
||||||
|
|
||||||
|
protected constructor()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Links {
|
||||||
|
var rel: String? = null
|
||||||
|
var href: String? = null
|
||||||
|
|
||||||
|
protected constructor()
|
||||||
|
}
|
|
@ -1,11 +1,12 @@
|
||||||
package dev.usbharu.hideout.core.service.instance
|
package dev.usbharu.hideout.core.service.instance
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import dev.usbharu.hideout.activitypub.domain.model.nodeinfo.Nodeinfo
|
|
||||||
import dev.usbharu.hideout.activitypub.domain.model.nodeinfo.Nodeinfo2_0
|
import dev.usbharu.hideout.activitypub.domain.model.nodeinfo.Nodeinfo2_0
|
||||||
import dev.usbharu.hideout.core.domain.model.instance.Instance
|
import dev.usbharu.hideout.core.domain.model.instance.Instance
|
||||||
import dev.usbharu.hideout.core.domain.model.instance.InstanceRepository
|
import dev.usbharu.hideout.core.domain.model.instance.InstanceRepository
|
||||||
|
import dev.usbharu.hideout.core.domain.model.instance.Nodeinfo
|
||||||
import dev.usbharu.hideout.core.service.resource.ResourceResolveService
|
import dev.usbharu.hideout.core.service.resource.ResourceResolveService
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
@ -20,21 +21,21 @@ interface InstanceService {
|
||||||
class InstanceServiceImpl(
|
class InstanceServiceImpl(
|
||||||
private val instanceRepository: InstanceRepository,
|
private val instanceRepository: InstanceRepository,
|
||||||
private val resourceResolveService: ResourceResolveService,
|
private val resourceResolveService: ResourceResolveService,
|
||||||
private val objectMapper: ObjectMapper
|
@Qualifier("activitypub") private val objectMapper: ObjectMapper
|
||||||
) : InstanceService {
|
) : InstanceService {
|
||||||
override suspend fun fetchInstance(url: String): Instance {
|
override suspend fun fetchInstance(url: String): Instance {
|
||||||
val u = URL(url)
|
val u = URL(url)
|
||||||
val resolveInstanceUrl = u.protocol + "://" + u.host
|
val resolveInstanceUrl = u.protocol + "://" + u.host
|
||||||
val nodeinfoJson = resourceResolveService.resolve("$resolveInstanceUrl/.well-known/nodeinfo").bodyAsText()
|
val nodeinfoJson = resourceResolveService.resolve("$resolveInstanceUrl/.well-known/nodeinfo").bodyAsText()
|
||||||
val nodeinfo = objectMapper.readValue(nodeinfoJson, Nodeinfo::class.java)
|
val nodeinfo = objectMapper.readValue(nodeinfoJson, Nodeinfo::class.java)
|
||||||
val nodeinfoPathMap = nodeinfo.links.map { it.rel to it.href }.toMap()
|
val nodeinfoPathMap = nodeinfo.links.associate { it.rel to it.href }
|
||||||
|
|
||||||
|
|
||||||
for ((key, value) in nodeinfoPathMap) {
|
for ((key, value) in nodeinfoPathMap) {
|
||||||
when (key) {
|
when (key) {
|
||||||
"http://nodeinfo.diaspora.software/ns/schema/2.0" -> {
|
"http://nodeinfo.diaspora.software/ns/schema/2.0" -> {
|
||||||
val nodeinfo20 = objectMapper.readValue(
|
val nodeinfo20 = objectMapper.readValue(
|
||||||
resourceResolveService.resolve(value).bodyAsText(),
|
resourceResolveService.resolve(value!!).bodyAsText(),
|
||||||
Nodeinfo2_0::class.java
|
Nodeinfo2_0::class.java
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue