mirror of https://github.com/usbharu/Hideout.git
feat: Instanceの重複チェックを追加
This commit is contained in:
parent
ee56adcf27
commit
9cc8c77cbd
|
@ -124,7 +124,8 @@ class APUserServiceImpl(
|
||||||
?: throw IllegalActivityPubObjectException("publicKey is null"),
|
?: throw IllegalActivityPubObjectException("publicKey is null"),
|
||||||
keyId = person.publicKey?.id ?: throw IllegalActivityPubObjectException("publicKey keyId is null"),
|
keyId = person.publicKey?.id ?: throw IllegalActivityPubObjectException("publicKey keyId is null"),
|
||||||
following = person.following,
|
following = person.following,
|
||||||
followers = person.followers
|
followers = person.followers,
|
||||||
|
sharedInbox = person.endpoints["sharedInbox"]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
|
@ -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()
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -1,18 +1,21 @@
|
||||||
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.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.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.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 dev.usbharu.hideout.core.service.resource.ResourceResolveService
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.annotation.Qualifier
|
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
|
||||||
|
|
||||||
interface InstanceService {
|
interface InstanceService {
|
||||||
suspend fun fetchInstance(url: String): Instance
|
suspend fun fetchInstance(url: String, sharedInbox: String? = null): Instance
|
||||||
suspend fun createNewInstance(instanceCreateDto: InstanceCreateDto): Instance
|
suspend fun createNewInstance(instanceCreateDto: InstanceCreateDto): Instance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,11 +24,20 @@ interface InstanceService {
|
||||||
class InstanceServiceImpl(
|
class InstanceServiceImpl(
|
||||||
private val instanceRepository: InstanceRepository,
|
private val instanceRepository: InstanceRepository,
|
||||||
private val resourceResolveService: ResourceResolveService,
|
private val resourceResolveService: ResourceResolveService,
|
||||||
@Qualifier("activitypub") private val objectMapper: ObjectMapper
|
@Qualifier("activitypub") private val objectMapper: ObjectMapper,
|
||||||
|
private val instanceQueryService: InstanceQueryService
|
||||||
) : InstanceService {
|
) : InstanceService {
|
||||||
override suspend fun fetchInstance(url: String): Instance {
|
override suspend fun fetchInstance(url: String, sharedInbox: String?): Instance {
|
||||||
val u = URL(url)
|
val u = URL(url)
|
||||||
val resolveInstanceUrl = u.protocol + "://" + u.host
|
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 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.associate { it.rel to it.href }
|
val nodeinfoPathMap = nodeinfo.links.associate { it.rel to it.href }
|
||||||
|
@ -40,13 +52,32 @@ class InstanceServiceImpl(
|
||||||
)
|
)
|
||||||
|
|
||||||
val instanceCreateDto = InstanceCreateDto(
|
val instanceCreateDto = InstanceCreateDto(
|
||||||
nodeinfo20.metadata.nodeName,
|
nodeinfo20.metadata?.nodeName,
|
||||||
nodeinfo20.metadata.nodeDescription,
|
nodeinfo20.metadata?.nodeDescription,
|
||||||
resolveInstanceUrl,
|
resolveInstanceUrl,
|
||||||
resolveInstanceUrl + "/favicon.ico",
|
resolveInstanceUrl + "/favicon.ico",
|
||||||
null,
|
sharedInbox,
|
||||||
nodeinfo20.software.name,
|
nodeinfo20.software?.name,
|
||||||
nodeinfo20.software.version
|
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)
|
return createNewInstance(instanceCreateDto)
|
||||||
}
|
}
|
||||||
|
@ -78,4 +109,8 @@ class InstanceServiceImpl(
|
||||||
instanceRepository.save(instance)
|
instanceRepository.save(instance)
|
||||||
return instance
|
return instance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = LoggerFactory.getLogger(InstanceServiceImpl::class.java)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,5 +11,6 @@ data class RemoteUserCreateDto(
|
||||||
val publicKey: String,
|
val publicKey: String,
|
||||||
val keyId: String,
|
val keyId: String,
|
||||||
val followers: String?,
|
val followers: String?,
|
||||||
val following: String?
|
val following: String?,
|
||||||
|
val sharedInbox: String?
|
||||||
)
|
)
|
||||||
|
|
|
@ -57,7 +57,7 @@ class UserServiceImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun createRemoteUser(user: RemoteUserCreateDto): User {
|
override suspend fun createRemoteUser(user: RemoteUserCreateDto): User {
|
||||||
instanceService.fetchInstance(user.url)
|
instanceService.fetchInstance(user.url, user.sharedInbox)
|
||||||
|
|
||||||
val nextId = userRepository.nextId()
|
val nextId = userRepository.nextId()
|
||||||
val userEntity = userBuilder.of(
|
val userEntity = userBuilder.of(
|
||||||
|
|
Loading…
Reference in New Issue