From 1323815abd1cb8f5121c80d943a209358f7c5683 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Sat, 18 Nov 2023 12:20:29 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20Instance=E3=81=AE=E9=87=8D=E8=A4=87?= =?UTF-8?q?=E3=83=81=E3=82=A7=E3=83=83=E3=82=AF=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/objects/user/APUserService.kt | 3 +- .../core/domain/model/instance/Nodeinfo2_0.kt | 22 ++++++++ .../exposedquery/InstanceQueryServiceImpl.kt | 16 ++++++ .../core/query/InstanceQueryService.kt | 7 +++ .../core/service/instance/InstanceService.kt | 53 +++++++++++++++---- .../core/service/user/RemoteUserCreateDto.kt | 3 +- .../core/service/user/UserServiceImpl.kt | 2 +- 7 files changed, 94 insertions(+), 12 deletions(-) create mode 100644 src/main/kotlin/dev/usbharu/hideout/core/domain/model/instance/Nodeinfo2_0.kt create mode 100644 src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedquery/InstanceQueryServiceImpl.kt create mode 100644 src/main/kotlin/dev/usbharu/hideout/core/query/InstanceQueryService.kt diff --git a/src/main/kotlin/dev/usbharu/hideout/activitypub/service/objects/user/APUserService.kt b/src/main/kotlin/dev/usbharu/hideout/activitypub/service/objects/user/APUserService.kt index 8aee16a4..9c0777e9 100644 --- a/src/main/kotlin/dev/usbharu/hideout/activitypub/service/objects/user/APUserService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/activitypub/service/objects/user/APUserService.kt @@ -124,7 +124,8 @@ class APUserServiceImpl( ?: throw IllegalActivityPubObjectException("publicKey is null"), keyId = person.publicKey?.id ?: throw IllegalActivityPubObjectException("publicKey keyId is null"), following = person.following, - followers = person.followers + followers = person.followers, + sharedInbox = person.endpoints["sharedInbox"] ) ) } diff --git a/src/main/kotlin/dev/usbharu/hideout/core/domain/model/instance/Nodeinfo2_0.kt b/src/main/kotlin/dev/usbharu/hideout/core/domain/model/instance/Nodeinfo2_0.kt new file mode 100644 index 00000000..6ff35b1e --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/core/domain/model/instance/Nodeinfo2_0.kt @@ -0,0 +1,22 @@ +package dev.usbharu.hideout.core.domain.model.instance + +class Nodeinfo2_0 { + var metadata: Metadata? = null + var software: Software? = null + + protected constructor() +} + +class Metadata { + var nodeName: String? = null + var nodeDescription: String? = null + + protected constructor() +} + +class Software { + var name: String? = null + var version: String? = null + + protected constructor() +} diff --git a/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedquery/InstanceQueryServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedquery/InstanceQueryServiceImpl.kt new file mode 100644 index 00000000..587f57a1 --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedquery/InstanceQueryServiceImpl.kt @@ -0,0 +1,16 @@ +package dev.usbharu.hideout.core.infrastructure.exposedquery + +import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException +import dev.usbharu.hideout.core.infrastructure.exposedrepository.Instance +import dev.usbharu.hideout.core.infrastructure.exposedrepository.toInstance +import dev.usbharu.hideout.core.query.InstanceQueryService +import dev.usbharu.hideout.util.singleOr +import org.jetbrains.exposed.sql.select +import org.springframework.stereotype.Repository +import dev.usbharu.hideout.core.domain.model.instance.Instance as InstanceEntity + +@Repository +class InstanceQueryServiceImpl : InstanceQueryService { + override suspend fun findByUrl(url: String): InstanceEntity = Instance.select { Instance.url eq url } + .singleOr { FailedToGetResourcesException("url is doesn't exist") }.toInstance() +} diff --git a/src/main/kotlin/dev/usbharu/hideout/core/query/InstanceQueryService.kt b/src/main/kotlin/dev/usbharu/hideout/core/query/InstanceQueryService.kt new file mode 100644 index 00000000..79e6b213 --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/core/query/InstanceQueryService.kt @@ -0,0 +1,7 @@ +package dev.usbharu.hideout.core.query + +import dev.usbharu.hideout.core.domain.model.instance.Instance + +interface InstanceQueryService { + suspend fun findByUrl(url: String): Instance +} diff --git a/src/main/kotlin/dev/usbharu/hideout/core/service/instance/InstanceService.kt b/src/main/kotlin/dev/usbharu/hideout/core/service/instance/InstanceService.kt index 5b54054e..2f6d8ef9 100644 --- a/src/main/kotlin/dev/usbharu/hideout/core/service/instance/InstanceService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/core/service/instance/InstanceService.kt @@ -1,18 +1,21 @@ package dev.usbharu.hideout.core.service.instance import com.fasterxml.jackson.databind.ObjectMapper -import dev.usbharu.hideout.activitypub.domain.model.nodeinfo.Nodeinfo2_0 +import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException 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.Nodeinfo +import dev.usbharu.hideout.core.domain.model.instance.Nodeinfo2_0 +import dev.usbharu.hideout.core.query.InstanceQueryService import dev.usbharu.hideout.core.service.resource.ResourceResolveService +import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Qualifier import org.springframework.stereotype.Service import java.net.URL import java.time.Instant interface InstanceService { - suspend fun fetchInstance(url: String): Instance + suspend fun fetchInstance(url: String, sharedInbox: String? = null): Instance suspend fun createNewInstance(instanceCreateDto: InstanceCreateDto): Instance } @@ -21,11 +24,20 @@ interface InstanceService { class InstanceServiceImpl( private val instanceRepository: InstanceRepository, private val resourceResolveService: ResourceResolveService, - @Qualifier("activitypub") private val objectMapper: ObjectMapper + @Qualifier("activitypub") private val objectMapper: ObjectMapper, + private val instanceQueryService: InstanceQueryService ) : InstanceService { - override suspend fun fetchInstance(url: String): Instance { + override suspend fun fetchInstance(url: String, sharedInbox: String?): Instance { val u = URL(url) val resolveInstanceUrl = u.protocol + "://" + u.host + + try { + return instanceQueryService.findByUrl(url) + } catch (e: FailedToGetResourcesException) { + logger.info("Instance not found. try fetch instance info. url: {}", resolveInstanceUrl) + logger.debug("Failed to get resources. url: {}", resolveInstanceUrl, e) + } + val nodeinfoJson = resourceResolveService.resolve("$resolveInstanceUrl/.well-known/nodeinfo").bodyAsText() val nodeinfo = objectMapper.readValue(nodeinfoJson, Nodeinfo::class.java) val nodeinfoPathMap = nodeinfo.links.associate { it.rel to it.href } @@ -40,13 +52,32 @@ class InstanceServiceImpl( ) val instanceCreateDto = InstanceCreateDto( - nodeinfo20.metadata.nodeName, - nodeinfo20.metadata.nodeDescription, + nodeinfo20.metadata?.nodeName, + nodeinfo20.metadata?.nodeDescription, resolveInstanceUrl, resolveInstanceUrl + "/favicon.ico", - null, - nodeinfo20.software.name, - nodeinfo20.software.version + sharedInbox, + nodeinfo20.software?.name, + nodeinfo20.software?.version + ) + return createNewInstance(instanceCreateDto) + } + + // TODO: 多分2.0と2.1で互換性有るのでそのまま使うけどなおす + "http://nodeinfo.diaspora.software/ns/schema/2.1" -> { + val nodeinfo20 = objectMapper.readValue( + resourceResolveService.resolve(value!!).bodyAsText(), + Nodeinfo2_0::class.java + ) + + val instanceCreateDto = InstanceCreateDto( + nodeinfo20.metadata?.nodeName, + nodeinfo20.metadata?.nodeDescription, + resolveInstanceUrl, + resolveInstanceUrl + "/favicon.ico", + sharedInbox, + nodeinfo20.software?.name, + nodeinfo20.software?.version ) return createNewInstance(instanceCreateDto) } @@ -78,4 +109,8 @@ class InstanceServiceImpl( instanceRepository.save(instance) return instance } + + companion object { + private val logger = LoggerFactory.getLogger(InstanceServiceImpl::class.java) + } } diff --git a/src/main/kotlin/dev/usbharu/hideout/core/service/user/RemoteUserCreateDto.kt b/src/main/kotlin/dev/usbharu/hideout/core/service/user/RemoteUserCreateDto.kt index 992956e3..de85e74d 100644 --- a/src/main/kotlin/dev/usbharu/hideout/core/service/user/RemoteUserCreateDto.kt +++ b/src/main/kotlin/dev/usbharu/hideout/core/service/user/RemoteUserCreateDto.kt @@ -11,5 +11,6 @@ data class RemoteUserCreateDto( val publicKey: String, val keyId: String, val followers: String?, - val following: String? + val following: String?, + val sharedInbox: String? ) diff --git a/src/main/kotlin/dev/usbharu/hideout/core/service/user/UserServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/core/service/user/UserServiceImpl.kt index 20a49f4f..3d486f45 100644 --- a/src/main/kotlin/dev/usbharu/hideout/core/service/user/UserServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/core/service/user/UserServiceImpl.kt @@ -57,7 +57,7 @@ class UserServiceImpl( } override suspend fun createRemoteUser(user: RemoteUserCreateDto): User { - instanceService.fetchInstance(user.url) + instanceService.fetchInstance(user.url, user.sharedInbox) val nextId = userRepository.nextId() val userEntity = userBuilder.of(