From aac918a75dac12a15f828a2516f281fb34b5f37d Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 11 Oct 2023 14:58:46 +0900 Subject: [PATCH 1/8] =?UTF-8?q?fix=20=E8=89=B2=E3=80=85=E7=9B=B4=E3=81=97?= =?UTF-8?q?=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 4 --- .../dev/usbharu/hideout/SpringApplication.kt | 2 ++ .../hideout/config/HttpClientConfig.kt | 3 ++- .../hideout/controller/InboxControllerImpl.kt | 6 +++++ .../mastodon/MastodonAppsApiController.kt | 1 - .../hideout/domain/model/UserDetailsImpl.kt | 1 - .../usbharu/hideout/domain/model/ap/Object.kt | 1 - .../domain/model/ap/ObjectDeserializer.kt | 1 - .../domain/model/hideout/entity/Timeline.kt | 2 ++ .../usbharu/hideout/plugins/ActivityPub.kt | 6 ++--- .../hideout/query/PostQueryServiceImpl.kt | 7 +++-- .../hideout/repository/PostRepositoryImpl.kt | 8 +++++- .../hideout/repository/UserRepositoryImpl.kt | 4 +-- .../hideout/service/ap/APLikeService.kt | 2 +- .../usbharu/hideout/service/ap/APService.kt | 2 -- .../api/mastodon/StatusesApiService.kt | 1 - .../service/core/ExposedTransaction.kt | 2 +- .../service/core/MdcXrequestIdFilter.kt | 27 +++++++++++++++++++ .../hideout/service/post/PostServiceImpl.kt | 13 ++++++--- .../hideout/service/user/UserServiceImpl.kt | 6 ++++- .../dev/usbharu/hideout/util/HttpUtil.kt | 1 - src/main/resources/logback.xml | 9 +++---- 22 files changed, 74 insertions(+), 35 deletions(-) create mode 100644 src/main/kotlin/dev/usbharu/hideout/service/core/MdcXrequestIdFilter.kt diff --git a/build.gradle.kts b/build.gradle.kts index e324753a..83910384 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -113,10 +113,6 @@ dependencies { compileOnly("io.swagger.core.v3:swagger-annotations:2.2.6") implementation("io.swagger.core.v3:swagger-models:2.2.6") implementation("org.jetbrains.exposed:exposed-java-time:$exposed_version") - implementation("org.jetbrains.exposed:spring-transaction:$exposed_version") - implementation("org.springframework.data:spring-data-commons") - implementation("org.springframework.boot:spring-boot-starter-jdbc") - implementation("org.springframework.boot:spring-boot-starter-data-jdbc") testImplementation("org.springframework.boot:spring-boot-test-autoconfigure") testImplementation("org.springframework.boot:spring-boot-starter-test") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") diff --git a/src/main/kotlin/dev/usbharu/hideout/SpringApplication.kt b/src/main/kotlin/dev/usbharu/hideout/SpringApplication.kt index d050b856..bbc2e3bd 100644 --- a/src/main/kotlin/dev/usbharu/hideout/SpringApplication.kt +++ b/src/main/kotlin/dev/usbharu/hideout/SpringApplication.kt @@ -3,9 +3,11 @@ package dev.usbharu.hideout import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.context.properties.ConfigurationPropertiesScan import org.springframework.boot.runApplication +import org.springframework.cache.annotation.EnableCaching @SpringBootApplication @ConfigurationPropertiesScan +@EnableCaching class SpringApplication @Suppress("SpreadOperator") diff --git a/src/main/kotlin/dev/usbharu/hideout/config/HttpClientConfig.kt b/src/main/kotlin/dev/usbharu/hideout/config/HttpClientConfig.kt index 2110618d..454a4de6 100644 --- a/src/main/kotlin/dev/usbharu/hideout/config/HttpClientConfig.kt +++ b/src/main/kotlin/dev/usbharu/hideout/config/HttpClientConfig.kt @@ -20,7 +20,8 @@ class HttpClientConfig { } install(Logging) { logger = Logger.DEFAULT - level = LogLevel.ALL + level = LogLevel.INFO + } expectSuccess = true } diff --git a/src/main/kotlin/dev/usbharu/hideout/controller/InboxControllerImpl.kt b/src/main/kotlin/dev/usbharu/hideout/controller/InboxControllerImpl.kt index d65560d0..a79ce5b0 100644 --- a/src/main/kotlin/dev/usbharu/hideout/controller/InboxControllerImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/controller/InboxControllerImpl.kt @@ -2,6 +2,7 @@ package dev.usbharu.hideout.controller import dev.usbharu.hideout.service.ap.APService import kotlinx.coroutines.runBlocking +import org.slf4j.LoggerFactory import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.RequestBody @@ -11,7 +12,12 @@ import org.springframework.web.bind.annotation.RestController class InboxControllerImpl(private val apService: APService) : InboxController { override fun inbox(@RequestBody string: String): ResponseEntity = runBlocking { val parseActivity = apService.parseActivity(string) + LOGGER.info("INBOX Processing Activity Type: {}", parseActivity) apService.processActivity(string, parseActivity) ResponseEntity(HttpStatus.ACCEPTED) } + + companion object { + val LOGGER = LoggerFactory.getLogger(InboxControllerImpl::class.java) + } } diff --git a/src/main/kotlin/dev/usbharu/hideout/controller/mastodon/MastodonAppsApiController.kt b/src/main/kotlin/dev/usbharu/hideout/controller/mastodon/MastodonAppsApiController.kt index 44d9582a..2b37eb9a 100644 --- a/src/main/kotlin/dev/usbharu/hideout/controller/mastodon/MastodonAppsApiController.kt +++ b/src/main/kotlin/dev/usbharu/hideout/controller/mastodon/MastodonAppsApiController.kt @@ -15,7 +15,6 @@ import org.springframework.web.bind.annotation.RequestParam @Controller class MastodonAppsApiController(private val appApiService: AppApiService) : AppApi { override fun apiV1AppsPost(appsRequest: AppsRequest): ResponseEntity = runBlocking { - println(appsRequest) ResponseEntity( appApiService.createApp(appsRequest), HttpStatus.OK diff --git a/src/main/kotlin/dev/usbharu/hideout/domain/model/UserDetailsImpl.kt b/src/main/kotlin/dev/usbharu/hideout/domain/model/UserDetailsImpl.kt index 2a3c808c..6eb655bc 100644 --- a/src/main/kotlin/dev/usbharu/hideout/domain/model/UserDetailsImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/domain/model/UserDetailsImpl.kt @@ -51,7 +51,6 @@ class UserDetailsDeserializer : JsonDeserializer() { override fun deserialize(p: JsonParser, ctxt: DeserializationContext): UserDetailsImpl { val mapper = p.codec as ObjectMapper val jsonNode: JsonNode = mapper.readTree(p) - println(jsonNode) val authorities: Set = mapper.convertValue( jsonNode["authorities"], SIMPLE_GRANTED_AUTHORITY_SET diff --git a/src/main/kotlin/dev/usbharu/hideout/domain/model/ap/Object.kt b/src/main/kotlin/dev/usbharu/hideout/domain/model/ap/Object.kt index 80a282aa..482ef329 100644 --- a/src/main/kotlin/dev/usbharu/hideout/domain/model/ap/Object.kt +++ b/src/main/kotlin/dev/usbharu/hideout/domain/model/ap/Object.kt @@ -54,7 +54,6 @@ open class Object : JsonLd { class TypeSerializer : JsonSerializer>() { override fun serialize(value: List?, gen: JsonGenerator?, serializers: SerializerProvider?) { - println(value) if (value?.size == 1) { gen?.writeString(value[0]) } else { diff --git a/src/main/kotlin/dev/usbharu/hideout/domain/model/ap/ObjectDeserializer.kt b/src/main/kotlin/dev/usbharu/hideout/domain/model/ap/ObjectDeserializer.kt index 72fabd37..c6a330c2 100644 --- a/src/main/kotlin/dev/usbharu/hideout/domain/model/ap/ObjectDeserializer.kt +++ b/src/main/kotlin/dev/usbharu/hideout/domain/model/ap/ObjectDeserializer.kt @@ -34,7 +34,6 @@ class ObjectDeserializer : JsonDeserializer() { return when (activityType) { ExtendedActivityVocabulary.Follow -> { val readValue = p.codec.treeToValue(treeNode, Follow::class.java) - println(readValue) readValue } diff --git a/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/entity/Timeline.kt b/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/entity/Timeline.kt index 64f450a8..e4aeabb6 100644 --- a/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/entity/Timeline.kt +++ b/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/entity/Timeline.kt @@ -1,7 +1,9 @@ package dev.usbharu.hideout.domain.model.hideout.entity import org.springframework.data.annotation.Id +import org.springframework.data.mongodb.core.mapping.Document +@Document data class Timeline( @Id val id: Long, diff --git a/src/main/kotlin/dev/usbharu/hideout/plugins/ActivityPub.kt b/src/main/kotlin/dev/usbharu/hideout/plugins/ActivityPub.kt index bed7c761..01ed970e 100644 --- a/src/main/kotlin/dev/usbharu/hideout/plugins/ActivityPub.kt +++ b/src/main/kotlin/dev/usbharu/hideout/plugins/ActivityPub.kt @@ -67,11 +67,9 @@ val httpSignaturePlugin: ClientPlugin = createClientP request.header("Date", format.format(Date())) request.header("Host", request.url.host) - println(request.bodyType) - println(request.bodyType?.type) if (request.bodyType?.type == String::class) { - println(body as String) - println("Digest !!") + body as String + // UserAuthService.sha256.reset() val digest = Base64.getEncoder().encodeToString(UserAuthServiceImpl.sha256.digest(body.toByteArray(Charsets.UTF_8))) diff --git a/src/main/kotlin/dev/usbharu/hideout/query/PostQueryServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/query/PostQueryServiceImpl.kt index 8e8ead0b..dc3d3d9a 100644 --- a/src/main/kotlin/dev/usbharu/hideout/query/PostQueryServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/query/PostQueryServiceImpl.kt @@ -6,25 +6,24 @@ import dev.usbharu.hideout.repository.Posts import dev.usbharu.hideout.repository.PostsMedia import dev.usbharu.hideout.repository.toPost import dev.usbharu.hideout.util.singleOr -import org.jetbrains.exposed.sql.innerJoin import org.jetbrains.exposed.sql.select import org.springframework.stereotype.Repository @Repository class PostQueryServiceImpl : PostQueryService { override suspend fun findById(id: Long): Post = - Posts.innerJoin(PostsMedia, onColumn = { Posts.id }, otherColumn = { PostsMedia.postId }) + Posts.leftJoin(PostsMedia) .select { Posts.id eq id } .singleOr { FailedToGetResourcesException("id: $id is duplicate or does not exist.", it) }.toPost() override suspend fun findByUrl(url: String): Post = - Posts.innerJoin(PostsMedia, onColumn = { Posts.id }, otherColumn = { PostsMedia.postId }) + Posts.leftJoin(PostsMedia) .select { Posts.url eq url } .toPost() .singleOr { FailedToGetResourcesException("url: $url is duplicate or does not exist.", it) } override suspend fun findByApId(string: String): Post = - Posts.innerJoin(PostsMedia, onColumn = { Posts.id }, otherColumn = { PostsMedia.postId }) + Posts.leftJoin(PostsMedia) .select { Posts.apId eq string } .toPost() .singleOr { FailedToGetResourcesException("apId: $string is duplicate or does not exist.", it) } diff --git a/src/main/kotlin/dev/usbharu/hideout/repository/PostRepositoryImpl.kt b/src/main/kotlin/dev/usbharu/hideout/repository/PostRepositoryImpl.kt index 400126ea..f179ce7f 100644 --- a/src/main/kotlin/dev/usbharu/hideout/repository/PostRepositoryImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/repository/PostRepositoryImpl.kt @@ -54,6 +54,12 @@ class PostRepositoryImpl(private val idGenerateService: IdGenerateService) : Pos it[apId] = post.apId } } + + + assert(Posts.select { Posts.id eq post.id }.singleOrNull() != null) { + "Faild to insert" + } + return post } @@ -109,5 +115,5 @@ fun ResultRow.toPost(): Post { fun Query.toPost(): List { return this.groupBy { it[Posts.id] } .map { it.value } - .map { it.first().toPost().copy(mediaIds = it.map { it[PostsMedia.mediaId] }) } + .map { it.first().toPost().copy(mediaIds = it.mapNotNull { it.getOrNull(PostsMedia.mediaId) }) } } diff --git a/src/main/kotlin/dev/usbharu/hideout/repository/UserRepositoryImpl.kt b/src/main/kotlin/dev/usbharu/hideout/repository/UserRepositoryImpl.kt index 5bfa479f..10fb3a2e 100644 --- a/src/main/kotlin/dev/usbharu/hideout/repository/UserRepositoryImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/repository/UserRepositoryImpl.kt @@ -14,8 +14,8 @@ class UserRepositoryImpl(private val idGenerateService: IdGenerateService) : UserRepository { override suspend fun save(user: User): User { - val singleOrNull = Users.select { Users.id eq user.id }.singleOrNull() - if (singleOrNull == null) { + val singleOrNull = Users.select { Users.id eq user.id or (Users.url eq user.url) }.empty() + if (singleOrNull) { Users.insert { it[id] = user.id it[name] = user.name diff --git a/src/main/kotlin/dev/usbharu/hideout/service/ap/APLikeService.kt b/src/main/kotlin/dev/usbharu/hideout/service/ap/APLikeService.kt index 089f8b50..c6173127 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/ap/APLikeService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/ap/APLikeService.kt @@ -26,7 +26,7 @@ class APLikeServiceImpl( val actor = like.actor ?: throw IllegalActivityPubObjectException("actor is null") val content = like.content ?: throw IllegalActivityPubObjectException("content is null") like.`object` ?: throw IllegalActivityPubObjectException("object is null") - transaction.transaction(java.sql.Connection.TRANSACTION_SERIALIZABLE) { + transaction.transaction { val person = apUserService.fetchPersonWithEntity(actor) apNoteService.fetchNote(like.`object` ?: return@transaction) diff --git a/src/main/kotlin/dev/usbharu/hideout/service/ap/APService.kt b/src/main/kotlin/dev/usbharu/hideout/service/ap/APService.kt index 146a70de..b52f8eb3 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/ap/APService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/ap/APService.kt @@ -226,8 +226,6 @@ class APServiceImpl( override suspend fun processActivity(job: JobContextWithProps, hideoutJob: HideoutJob) { logger.debug("processActivity: ${hideoutJob.name}") -// println(apReceiveFollowService::class.java) -// apReceiveFollowService.receiveFollowJob(job.props as JobProps) when (hideoutJob) { is ReceiveFollowJob -> { apReceiveFollowService.receiveFollowJob( diff --git a/src/main/kotlin/dev/usbharu/hideout/service/api/mastodon/StatusesApiService.kt b/src/main/kotlin/dev/usbharu/hideout/service/api/mastodon/StatusesApiService.kt index 039dfc2c..2baae425 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/api/mastodon/StatusesApiService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/api/mastodon/StatusesApiService.kt @@ -39,7 +39,6 @@ class StatsesApiServiceImpl( statusesRequest: dev.usbharu.hideout.domain.model.mastodon.StatusesRequest, userId: Long ): Status = transaction.transaction { - println("Post status media ids " + statusesRequest.media_ids) val visibility = when (statusesRequest.visibility) { StatusesRequest.Visibility.public -> Visibility.PUBLIC StatusesRequest.Visibility.unlisted -> Visibility.UNLISTED diff --git a/src/main/kotlin/dev/usbharu/hideout/service/core/ExposedTransaction.kt b/src/main/kotlin/dev/usbharu/hideout/service/core/ExposedTransaction.kt index 54252131..bcd95261 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/core/ExposedTransaction.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/core/ExposedTransaction.kt @@ -6,7 +6,7 @@ import org.springframework.stereotype.Service @Service class ExposedTransaction : Transaction { override suspend fun transaction(block: suspend () -> T): T { - return newSuspendedTransaction(transactionIsolation = java.sql.Connection.TRANSACTION_SERIALIZABLE) { + return newSuspendedTransaction { block() } } diff --git a/src/main/kotlin/dev/usbharu/hideout/service/core/MdcXrequestIdFilter.kt b/src/main/kotlin/dev/usbharu/hideout/service/core/MdcXrequestIdFilter.kt new file mode 100644 index 00000000..f3ecdcf6 --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/service/core/MdcXrequestIdFilter.kt @@ -0,0 +1,27 @@ +package dev.usbharu.hideout.service.core + +import jakarta.servlet.Filter +import jakarta.servlet.FilterChain +import jakarta.servlet.ServletRequest +import jakarta.servlet.ServletResponse +import org.slf4j.MDC +import org.springframework.stereotype.Service +import java.util.* + +@Service +class MdcXrequestIdFilter : Filter { + override fun doFilter(request: ServletRequest?, response: ServletResponse?, chain: FilterChain) { + val uuid = UUID.randomUUID() + try { + MDC.put(KEY, uuid.toString()) + chain.doFilter(request, response) + } finally { + MDC.remove(KEY) + } + + } + + companion object { + val KEY = "x-request-id" + } +} diff --git a/src/main/kotlin/dev/usbharu/hideout/service/post/PostServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/service/post/PostServiceImpl.kt index dbf30d9c..5b376c68 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/post/PostServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/post/PostServiceImpl.kt @@ -3,6 +3,7 @@ package dev.usbharu.hideout.service.post import dev.usbharu.hideout.domain.model.hideout.dto.PostCreateDto import dev.usbharu.hideout.domain.model.hideout.entity.Post import dev.usbharu.hideout.exception.UserNotFoundException +import dev.usbharu.hideout.query.PostQueryService import dev.usbharu.hideout.repository.PostRepository import dev.usbharu.hideout.repository.UserRepository import org.springframework.stereotype.Service @@ -13,7 +14,8 @@ import java.util.* class PostServiceImpl( private val postRepository: PostRepository, private val userRepository: UserRepository, - private val timelineService: TimelineService + private val timelineService: TimelineService, + private val postQueryService: PostQueryService ) : PostService { private val interceptors = Collections.synchronizedList(mutableListOf()) @@ -30,8 +32,13 @@ class PostServiceImpl( } private suspend fun internalCreate(post: Post, isLocal: Boolean): Post { - timelineService.publishTimeline(post, isLocal) - return postRepository.save(post) + val save = try { + postRepository.save(post) + } catch (e: Exception) { + postQueryService.findByApId(post.apId) + } + timelineService.publishTimeline(save, isLocal) + return save } private suspend fun internalCreate(post: PostCreateDto, isLocal: Boolean): Post { diff --git a/src/main/kotlin/dev/usbharu/hideout/service/user/UserServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/service/user/UserServiceImpl.kt index 76fb4c1e..474fa736 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/user/UserServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/user/UserServiceImpl.kt @@ -64,7 +64,11 @@ class UserServiceImpl( publicKey = user.publicKey, createdAt = Instant.now() ) - return userRepository.save(userEntity) + return try { + userRepository.save(userEntity) + } catch (e: Exception) { + userQueryService.findByUrl(user.url) + } } // TODO APのフォロー処理を作る diff --git a/src/main/kotlin/dev/usbharu/hideout/util/HttpUtil.kt b/src/main/kotlin/dev/usbharu/hideout/util/HttpUtil.kt index 78d01376..c6c1bfe5 100644 --- a/src/main/kotlin/dev/usbharu/hideout/util/HttpUtil.kt +++ b/src/main/kotlin/dev/usbharu/hideout/util/HttpUtil.kt @@ -20,7 +20,6 @@ object HttpUtil { subType: String, parameter: String ): Boolean { - println("$contentType/$subType $parameter") if (contentType != "application") { return false } diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 1b8d5251..565f4968 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -1,17 +1,16 @@ - %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{x-request-id}] %logger{36} - %msg%n - + - + - - + From 36d9fb864a7b93a05c6e75dfefd1210b161416b6 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 11 Oct 2023 15:34:12 +0900 Subject: [PATCH 2/8] =?UTF-8?q?feat:=20=E3=82=AD=E3=83=A3=E3=83=83?= =?UTF-8?q?=E3=82=B7=E3=83=A5=E3=82=92=E5=B0=8E=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../usbharu/hideout/config/HttpClientConfig.kt | 4 ++++ .../usbharu/hideout/service/ap/APLikeService.kt | 2 +- .../usbharu/hideout/service/ap/APNoteService.kt | 15 +++++++++++++++ .../service/reaction/ReactionServiceImpl.kt | 16 +++++++++++++--- 4 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/dev/usbharu/hideout/config/HttpClientConfig.kt b/src/main/kotlin/dev/usbharu/hideout/config/HttpClientConfig.kt index 454a4de6..324f1e93 100644 --- a/src/main/kotlin/dev/usbharu/hideout/config/HttpClientConfig.kt +++ b/src/main/kotlin/dev/usbharu/hideout/config/HttpClientConfig.kt @@ -6,6 +6,7 @@ import dev.usbharu.hideout.query.UserQueryService import dev.usbharu.hideout.service.core.Transaction import io.ktor.client.* import io.ktor.client.engine.cio.* +import io.ktor.client.plugins.cache.* import io.ktor.client.plugins.logging.* import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @@ -22,6 +23,9 @@ class HttpClientConfig { logger = Logger.DEFAULT level = LogLevel.INFO + } + install(HttpCache) { + } expectSuccess = true } diff --git a/src/main/kotlin/dev/usbharu/hideout/service/ap/APLikeService.kt b/src/main/kotlin/dev/usbharu/hideout/service/ap/APLikeService.kt index c6173127..83849581 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/ap/APLikeService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/ap/APLikeService.kt @@ -28,7 +28,7 @@ class APLikeServiceImpl( like.`object` ?: throw IllegalActivityPubObjectException("object is null") transaction.transaction { val person = apUserService.fetchPersonWithEntity(actor) - apNoteService.fetchNote(like.`object` ?: return@transaction) + apNoteService.fetchNoteAsync(like.`object` ?: return@transaction).await() val post = postQueryService.findByUrl(like.`object` ?: return@transaction) diff --git a/src/main/kotlin/dev/usbharu/hideout/service/ap/APNoteService.kt b/src/main/kotlin/dev/usbharu/hideout/service/ap/APNoteService.kt index 663b2d57..b41282db 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/ap/APNoteService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/ap/APNoteService.kt @@ -24,8 +24,14 @@ import dev.usbharu.hideout.service.post.PostService import io.ktor.client.* import io.ktor.client.statement.* import kjob.core.job.JobProps +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Deferred +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.cache.annotation.Cacheable import org.springframework.stereotype.Service import java.time.Instant @@ -34,6 +40,15 @@ interface APNoteService { suspend fun createNote(post: Post) suspend fun createNoteJob(props: JobProps) + @Cacheable("fetchNote") + fun fetchNoteAsync(url: String, targetActor: String? = null): Deferred { + return CoroutineScope(Dispatchers.IO).async { + newSuspendedTransaction { + fetchNote(url, targetActor) + } + } + } + suspend fun fetchNote(url: String, targetActor: String? = null): Note suspend fun fetchNote(note: Note, targetActor: String? = null): Note } diff --git a/src/main/kotlin/dev/usbharu/hideout/service/reaction/ReactionServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/service/reaction/ReactionServiceImpl.kt index 312c182b..07519bcc 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/reaction/ReactionServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/reaction/ReactionServiceImpl.kt @@ -4,6 +4,7 @@ import dev.usbharu.hideout.domain.model.hideout.entity.Reaction import dev.usbharu.hideout.query.ReactionQueryService import dev.usbharu.hideout.repository.ReactionRepository import dev.usbharu.hideout.service.ap.APReactionService +import org.slf4j.LoggerFactory import org.springframework.stereotype.Service @Service @@ -14,9 +15,14 @@ class ReactionServiceImpl( ) : ReactionService { override suspend fun receiveReaction(name: String, domain: String, userId: Long, postId: Long) { if (reactionQueryService.reactionAlreadyExist(postId, userId, 0).not()) { - reactionRepository.save( - Reaction(reactionRepository.generateId(), 0, postId, userId) - ) + + try { + reactionRepository.save( + Reaction(reactionRepository.generateId(), 0, postId, userId) + ) + } catch (_: Exception) { + LOGGER.warn("FAILED Failure to persist reaction information.") + } } } @@ -34,4 +40,8 @@ class ReactionServiceImpl( override suspend fun removeReaction(userId: Long, postId: Long) { reactionQueryService.deleteByPostIdAndUserId(postId, userId) } + + companion object { + val LOGGER = LoggerFactory.getLogger(ReactionServiceImpl::class.java) + } } From e5c3a583e6b473183aa3f0978e587d4b8c2f7059 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 11 Oct 2023 15:44:43 +0900 Subject: [PATCH 3/8] =?UTF-8?q?feat:=20=E3=82=AD=E3=83=A3=E3=83=83?= =?UTF-8?q?=E3=83=81=E3=81=99=E3=82=8B=E4=BE=8B=E5=A4=96=E3=82=92=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dev/usbharu/hideout/service/post/PostServiceImpl.kt | 3 ++- .../usbharu/hideout/service/reaction/ReactionServiceImpl.kt | 4 +++- .../dev/usbharu/hideout/service/user/UserServiceImpl.kt | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/dev/usbharu/hideout/service/post/PostServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/service/post/PostServiceImpl.kt index 5b376c68..f4d36084 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/post/PostServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/post/PostServiceImpl.kt @@ -6,6 +6,7 @@ import dev.usbharu.hideout.exception.UserNotFoundException import dev.usbharu.hideout.query.PostQueryService import dev.usbharu.hideout.repository.PostRepository import dev.usbharu.hideout.repository.UserRepository +import org.jetbrains.exposed.exceptions.ExposedSQLException import org.springframework.stereotype.Service import java.time.Instant import java.util.* @@ -34,7 +35,7 @@ class PostServiceImpl( private suspend fun internalCreate(post: Post, isLocal: Boolean): Post { val save = try { postRepository.save(post) - } catch (e: Exception) { + } catch (e: ExposedSQLException) { postQueryService.findByApId(post.apId) } timelineService.publishTimeline(save, isLocal) diff --git a/src/main/kotlin/dev/usbharu/hideout/service/reaction/ReactionServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/service/reaction/ReactionServiceImpl.kt index 07519bcc..6e56143f 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/reaction/ReactionServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/reaction/ReactionServiceImpl.kt @@ -4,6 +4,7 @@ import dev.usbharu.hideout.domain.model.hideout.entity.Reaction import dev.usbharu.hideout.query.ReactionQueryService import dev.usbharu.hideout.repository.ReactionRepository import dev.usbharu.hideout.service.ap.APReactionService +import org.jetbrains.exposed.exceptions.ExposedSQLException import org.slf4j.LoggerFactory import org.springframework.stereotype.Service @@ -20,8 +21,9 @@ class ReactionServiceImpl( reactionRepository.save( Reaction(reactionRepository.generateId(), 0, postId, userId) ) - } catch (_: Exception) { + } catch (e: ExposedSQLException) { LOGGER.warn("FAILED Failure to persist reaction information.") + LOGGER.debug("FAILED", e) } } } diff --git a/src/main/kotlin/dev/usbharu/hideout/service/user/UserServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/service/user/UserServiceImpl.kt index 474fa736..2af93ed6 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/user/UserServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/user/UserServiceImpl.kt @@ -10,6 +10,7 @@ import dev.usbharu.hideout.query.FollowerQueryService import dev.usbharu.hideout.query.UserQueryService import dev.usbharu.hideout.repository.UserRepository import dev.usbharu.hideout.service.ap.APSendFollowService +import org.jetbrains.exposed.exceptions.ExposedSQLException import org.springframework.stereotype.Service import java.time.Instant @@ -66,7 +67,7 @@ class UserServiceImpl( ) return try { userRepository.save(userEntity) - } catch (e: Exception) { + } catch (e: ExposedSQLException) { userQueryService.findByUrl(user.url) } } From cfa7f4e16fc04f2d245e052b45d8cb8258b2ba8c Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 11 Oct 2023 16:30:32 +0900 Subject: [PATCH 4/8] =?UTF-8?q?feat:=20=E3=82=BF=E3=82=A4=E3=83=A0?= =?UTF-8?q?=E3=83=A9=E3=82=A4=E3=83=B3=E3=81=8C=E8=A1=A8=E7=A4=BA=E3=81=95?= =?UTF-8?q?=E3=82=8C=E3=81=AA=E3=81=84=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../usbharu/hideout/config/SecurityConfig.kt | 21 +++++++++++++++++++ .../query/mastodon/StatusQueryServiceImpl.kt | 12 +++++------ .../hideout/repository/MediaRepositoryImpl.kt | 12 +++++++++++ src/main/resources/application.yml | 1 + 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/dev/usbharu/hideout/config/SecurityConfig.kt b/src/main/kotlin/dev/usbharu/hideout/config/SecurityConfig.kt index e9ff022b..f87c4dfd 100644 --- a/src/main/kotlin/dev/usbharu/hideout/config/SecurityConfig.kt +++ b/src/main/kotlin/dev/usbharu/hideout/config/SecurityConfig.kt @@ -1,5 +1,6 @@ package dev.usbharu.hideout.config +import com.fasterxml.jackson.annotation.JsonInclude import com.nimbusds.jose.jwk.JWKSet import com.nimbusds.jose.jwk.RSAKey import com.nimbusds.jose.jwk.source.ImmutableJWKSet @@ -8,12 +9,16 @@ import com.nimbusds.jose.proc.SecurityContext import dev.usbharu.hideout.domain.model.UserDetailsImpl import dev.usbharu.hideout.util.RsaUtil import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer import org.springframework.boot.autoconfigure.security.servlet.PathRequest import org.springframework.boot.context.properties.ConfigurationProperties import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Primary import org.springframework.core.annotation.Order import org.springframework.http.HttpMethod +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter import org.springframework.security.config.Customizer import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity @@ -35,6 +40,7 @@ import java.security.interfaces.RSAPrivateKey import java.security.interfaces.RSAPublicKey import java.util.* + @EnableWebSecurity(debug = false) @Configuration class SecurityConfig { @@ -155,6 +161,21 @@ class SecurityConfig { } } } + + @Bean + @Primary + fun jackson2ObjectMapperBuilderCustomizer(): Jackson2ObjectMapperBuilderCustomizer { + return Jackson2ObjectMapperBuilderCustomizer { + it.serializationInclusion(JsonInclude.Include.ALWAYS).serializers() + } + } + + @Bean + fun mappingJackson2HttpMessageConverter(): MappingJackson2HttpMessageConverter { + val builder = Jackson2ObjectMapperBuilder() + .serializationInclusion(JsonInclude.Include.NON_NULL) + return MappingJackson2HttpMessageConverter(builder.build()) + } } @ConfigurationProperties("hideout.security.jwt") diff --git a/src/main/kotlin/dev/usbharu/hideout/query/mastodon/StatusQueryServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/query/mastodon/StatusQueryServiceImpl.kt index 5fba667c..d5a5b5c2 100644 --- a/src/main/kotlin/dev/usbharu/hideout/query/mastodon/StatusQueryServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/query/mastodon/StatusQueryServiceImpl.kt @@ -50,16 +50,16 @@ class StatusQueryServiceImpl : StatusQueryService { @Suppress("FunctionMaxLength") private suspend fun findByPostIdsWithMediaAttachments(ids: List): List { val pairs = Posts - .innerJoin(PostsMedia, onColumn = { Posts.id }, otherColumn = { PostsMedia.postId }) - .innerJoin(Users, onColumn = { Posts.userId }, otherColumn = { id }) - .innerJoin(Media, onColumn = { PostsMedia.mediaId }, otherColumn = { id }) + .leftJoin(PostsMedia) + .leftJoin(Users) + .leftJoin(Media) .select { Posts.id inList ids } .groupBy { it[Posts.id] } .map { it.value } .map { toStatus(it.first()).copy( - mediaAttachments = it.map { - it.toMedia().let { + mediaAttachments = it.mapNotNull { + it.toMediaOrNull()?.let { MediaAttachment( id = it.id.toString(), type = when (it.type) { @@ -132,7 +132,7 @@ private fun toStatus(it: ResultRow) = Status( favouritesCount = 0, repliesCount = 0, url = it[Posts.apId], - inReplyToId = it[Posts.replyId].toString(), + inReplyToId = it[Posts.replyId]?.toString(), inReplyToAccountId = null, language = null, text = it[Posts.text], diff --git a/src/main/kotlin/dev/usbharu/hideout/repository/MediaRepositoryImpl.kt b/src/main/kotlin/dev/usbharu/hideout/repository/MediaRepositoryImpl.kt index cfcae2c4..6bbacbd3 100644 --- a/src/main/kotlin/dev/usbharu/hideout/repository/MediaRepositoryImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/repository/MediaRepositoryImpl.kt @@ -69,6 +69,18 @@ fun ResultRow.toMedia(): EntityMedia { ) } +fun ResultRow.toMediaOrNull(): EntityMedia? { + return EntityMedia( + id = this.getOrNull(Media.id) ?: return null, + name = this.getOrNull(Media.name) ?: return null, + url = this.getOrNull(Media.url) ?: return null, + remoteUrl = this[Media.remoteUrl], + thumbnailUrl = this[Media.thumbnailUrl], + type = FileType.values().first { it.ordinal == this.getOrNull(Media.type) }, + blurHash = this[Media.blurhash], + ) +} + object Media : Table("media") { val id = long("id") val name = varchar("name", 255) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 143486fb..60814a17 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -16,6 +16,7 @@ spring: jackson: serialization: WRITE_DATES_AS_TIMESTAMPS: false + default-property-inclusion: always datasource: driver-class-name: org.h2.Driver url: "jdbc:h2:./test-dev2;MODE=POSTGRESQL" From c8412cacb98df3385bee83573962da73a48c9134 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Thu, 12 Oct 2023 01:48:05 +0900 Subject: [PATCH 5/8] =?UTF-8?q?feat:=20=E3=83=AD=E3=82=B0=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...FailedToGetActivityPubResourceException.kt | 10 +++++ .../hideout/service/ap/APAcceptService.kt | 12 ++++++ .../hideout/service/ap/APCreateService.kt | 10 +++++ .../hideout/service/ap/APLikeService.kt | 25 ++++++++++- .../hideout/service/ap/APNoteService.kt | 42 +++++++++++++++---- .../usbharu/hideout/service/ap/APService.kt | 11 ++--- src/main/resources/logback.xml | 2 +- 7 files changed, 92 insertions(+), 20 deletions(-) create mode 100644 src/main/kotlin/dev/usbharu/hideout/exception/ap/FailedToGetActivityPubResourceException.kt diff --git a/src/main/kotlin/dev/usbharu/hideout/exception/ap/FailedToGetActivityPubResourceException.kt b/src/main/kotlin/dev/usbharu/hideout/exception/ap/FailedToGetActivityPubResourceException.kt new file mode 100644 index 00000000..73670af5 --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/exception/ap/FailedToGetActivityPubResourceException.kt @@ -0,0 +1,10 @@ +package dev.usbharu.hideout.exception.ap + +import dev.usbharu.hideout.exception.FailedToGetResourcesException + +class FailedToGetActivityPubResourceException : FailedToGetResourcesException { + constructor() : super() + constructor(s: String?) : super(s) + constructor(message: String?, cause: Throwable?) : super(message, cause) + constructor(cause: Throwable?) : super(cause) +} diff --git a/src/main/kotlin/dev/usbharu/hideout/service/ap/APAcceptService.kt b/src/main/kotlin/dev/usbharu/hideout/service/ap/APAcceptService.kt index 00b6777c..8832d8ad 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/ap/APAcceptService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/ap/APAcceptService.kt @@ -10,6 +10,7 @@ import dev.usbharu.hideout.query.UserQueryService import dev.usbharu.hideout.service.core.Transaction import dev.usbharu.hideout.service.user.UserService import io.ktor.http.* +import org.slf4j.LoggerFactory import org.springframework.stereotype.Service interface APAcceptService { @@ -25,21 +26,32 @@ class APAcceptServiceImpl( ) : APAcceptService { override suspend fun receiveAccept(accept: Accept): ActivityPubResponse { return transaction.transaction { + LOGGER.debug("START Follow") + LOGGER.trace("{}", accept) val value = accept.`object` ?: throw IllegalActivityPubObjectException("object is null") if (value.type.contains("Follow").not()) { + LOGGER.warn("FAILED Activity type is not 'Follow'") throw IllegalActivityPubObjectException("Invalid type ${value.type}") } val follow = value as Follow val userUrl = follow.`object` ?: throw IllegalActivityPubObjectException("object is null") val followerUrl = follow.actor ?: throw IllegalActivityPubObjectException("actor is null") + val user = userQueryService.findByUrl(userUrl) val follower = userQueryService.findByUrl(followerUrl) + if (followerQueryService.alreadyFollow(user.id, follower.id)) { + LOGGER.debug("END User already follow from ${follower.url} to ${user.url}") return@transaction ActivityPubStringResponse(HttpStatusCode.OK, "accepted") } userService.follow(user.id, follower.id) + LOGGER.debug("SUCCESS Follow from ${follower.url} to ${user.url}.") ActivityPubStringResponse(HttpStatusCode.OK, "accepted") } } + + companion object { + private val LOGGER = LoggerFactory.getLogger(APAcceptServiceImpl::class.java) + } } diff --git a/src/main/kotlin/dev/usbharu/hideout/service/ap/APCreateService.kt b/src/main/kotlin/dev/usbharu/hideout/service/ap/APCreateService.kt index 82d6013a..c4171528 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/ap/APCreateService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/ap/APCreateService.kt @@ -7,6 +7,7 @@ import dev.usbharu.hideout.domain.model.ap.Note import dev.usbharu.hideout.exception.ap.IllegalActivityPubObjectException import dev.usbharu.hideout.service.core.Transaction import io.ktor.http.* +import org.slf4j.LoggerFactory import org.springframework.stereotype.Service interface APCreateService { @@ -19,15 +20,24 @@ class APCreateServiceImpl( private val transaction: Transaction ) : APCreateService { override suspend fun receiveCreate(create: Create): ActivityPubResponse { + LOGGER.debug("START Create new remote note.") + LOGGER.trace("{}", create) + val value = create.`object` ?: throw IllegalActivityPubObjectException("object is null") if (value.type.contains("Note").not()) { + LOGGER.warn("FAILED Object type is not 'Note'") throw IllegalActivityPubObjectException("object is not Note") } return transaction.transaction { val note = value as Note apNoteService.fetchNote(note) + LOGGER.debug("SUCCESS Create new remote note. ${note.id} by ${note.attributedTo}") ActivityPubStringResponse(HttpStatusCode.OK, "Created") } } + + companion object { + private val LOGGER = LoggerFactory.getLogger(APCreateServiceImpl::class.java) + } } diff --git a/src/main/kotlin/dev/usbharu/hideout/service/ap/APLikeService.kt b/src/main/kotlin/dev/usbharu/hideout/service/ap/APLikeService.kt index 83849581..3ddba560 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/ap/APLikeService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/ap/APLikeService.kt @@ -3,11 +3,13 @@ package dev.usbharu.hideout.service.ap import dev.usbharu.hideout.domain.model.ActivityPubResponse import dev.usbharu.hideout.domain.model.ActivityPubStringResponse import dev.usbharu.hideout.domain.model.ap.Like +import dev.usbharu.hideout.exception.ap.FailedToGetActivityPubResourceException import dev.usbharu.hideout.exception.ap.IllegalActivityPubObjectException import dev.usbharu.hideout.query.PostQueryService import dev.usbharu.hideout.service.core.Transaction import dev.usbharu.hideout.service.reaction.ReactionService import io.ktor.http.* +import org.slf4j.LoggerFactory import org.springframework.stereotype.Service interface APLikeService { @@ -23,14 +25,28 @@ class APLikeServiceImpl( private val transaction: Transaction ) : APLikeService { override suspend fun receiveLike(like: Like): ActivityPubResponse { + LOGGER.debug("START Add Like") + LOGGER.trace("{}", like) + val actor = like.actor ?: throw IllegalActivityPubObjectException("actor is null") val content = like.content ?: throw IllegalActivityPubObjectException("content is null") like.`object` ?: throw IllegalActivityPubObjectException("object is null") transaction.transaction { - val person = apUserService.fetchPersonWithEntity(actor) - apNoteService.fetchNoteAsync(like.`object` ?: return@transaction).await() + LOGGER.trace("FETCH Liked Person $actor") + val person = apUserService.fetchPersonWithEntity(actor) + LOGGER.trace("{}", person.second) + + LOGGER.trace("FETCH Liked Note ${like.`object`}") + try { + apNoteService.fetchNoteAsync(like.`object` ?: return@transaction).await() + } catch (e: FailedToGetActivityPubResourceException) { + LOGGER.debug("FAILED Failed to Get ${like.`object`}") + LOGGER.trace("", e) + return@transaction + } val post = postQueryService.findByUrl(like.`object` ?: return@transaction) + LOGGER.trace("{}", post) reactionService.receiveReaction( content, @@ -38,7 +54,12 @@ class APLikeServiceImpl( person.second.id, post.id ) + LOGGER.debug("SUCCESS Add Like($content) from ${person.second.url} to ${post.url}") } return ActivityPubStringResponse(HttpStatusCode.OK, "") } + + companion object { + private val LOGGER = LoggerFactory.getLogger(APLikeServiceImpl::class.java) + } } diff --git a/src/main/kotlin/dev/usbharu/hideout/service/ap/APNoteService.kt b/src/main/kotlin/dev/usbharu/hideout/service/ap/APNoteService.kt index b41282db..41303839 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/ap/APNoteService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/ap/APNoteService.kt @@ -10,6 +10,7 @@ import dev.usbharu.hideout.domain.model.hideout.entity.Post import dev.usbharu.hideout.domain.model.hideout.entity.Visibility import dev.usbharu.hideout.domain.model.job.DeliverPostJob import dev.usbharu.hideout.exception.FailedToGetResourcesException +import dev.usbharu.hideout.exception.ap.FailedToGetActivityPubResourceException import dev.usbharu.hideout.exception.ap.IllegalActivityPubObjectException import dev.usbharu.hideout.plugins.getAp import dev.usbharu.hideout.plugins.postAp @@ -22,6 +23,7 @@ import dev.usbharu.hideout.service.job.JobQueueParentService import dev.usbharu.hideout.service.post.PostCreateInterceptor import dev.usbharu.hideout.service.post.PostService import io.ktor.client.* +import io.ktor.client.plugins.* import io.ktor.client.statement.* import kjob.core.job.JobProps import kotlinx.coroutines.CoroutineScope @@ -77,7 +79,13 @@ class APNoteServiceImpl( private val logger = LoggerFactory.getLogger(APNoteServiceImpl::class.java) override suspend fun createNote(post: Post) { + logger.info("CREATE Create Local Note ${post.url}") + logger.debug("START Create Local Note ${post.url}") + logger.trace("{}", post) val followers = followerQueryService.findFollowersById(post.userId) + + logger.debug("DELIVER Deliver Note Create ${followers.size} accounts.") + val userEntity = userQueryService.findById(post.userId) val note = objectMapper.writeValueAsString(post) val mediaList = objectMapper.writeValueAsString(mediaQueryService.findByPostId(post.id)) @@ -89,6 +97,8 @@ class APNoteServiceImpl( props[DeliverPostJob.media] = mediaList } } + + logger.debug("SUCCESS Create Local Note ${post.url}") } override suspend fun createNoteJob(props: JobProps) { @@ -124,18 +134,32 @@ class APNoteServiceImpl( } override suspend fun fetchNote(url: String, targetActor: String?): Note { + logger.debug("START Fetch Note url: {}", url) try { val post = postQueryService.findByUrl(url) + logger.debug("SUCCESS Found in local url: {}", url) return postToNote(post) } catch (_: FailedToGetResourcesException) { } - val response = httpClient.getAp( - url, - targetActor?.let { "$targetActor#pubkey" } - ) + logger.info("AP GET url: {}", url) + val response = try { + httpClient.getAp( + url, + targetActor?.let { "$targetActor#pubkey" } + ) + } catch (e: ClientRequestException) { + logger.warn( + "FAILED Failed to retrieve ActivityPub resource. HTTP Status Code: {} url: {}", + e.response.status, + url + ) + throw FailedToGetActivityPubResourceException("Could not retrieve $url.", e) + } val note = objectMapper.readValue(response.bodyAsText()) - return note(note, targetActor, url) + val savedNote = saveIfMissing(note, targetActor, url) + logger.debug("SUCCESS Fetch Note url: {}", url) + return savedNote } private suspend fun postToNote(post: Post): Note { @@ -154,7 +178,7 @@ class APNoteServiceImpl( ) } - private suspend fun note( + private suspend fun saveIfMissing( note: Note, targetActor: String?, url: String @@ -167,12 +191,12 @@ class APNoteServiceImpl( val findByApId = try { postQueryService.findByApId(note.id!!) } catch (_: FailedToGetResourcesException) { - return internalNote(note, targetActor, url) + return saveNote(note, targetActor, url) } return postToNote(findByApId) } - private suspend fun internalNote(note: Note, targetActor: String?, url: String): Note { + private suspend fun saveNote(note: Note, targetActor: String?, url: String): Note { val person = apUserService.fetchPersonWithEntity( note.attributedTo ?: throw IllegalActivityPubObjectException("note.attributedTo is null"), targetActor @@ -212,7 +236,7 @@ class APNoteServiceImpl( } override suspend fun fetchNote(note: Note, targetActor: String?): Note = - note(note, targetActor, note.id ?: throw IllegalArgumentException("note.id is null")) + saveIfMissing(note, targetActor, note.id ?: throw IllegalArgumentException("note.id is null")) override suspend fun run(post: Post) { createNote(post) diff --git a/src/main/kotlin/dev/usbharu/hideout/service/ap/APService.kt b/src/main/kotlin/dev/usbharu/hideout/service/ap/APService.kt index b52f8eb3..00e7a822 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/ap/APService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/ap/APService.kt @@ -203,16 +203,11 @@ class APServiceImpl( @Suppress("CyclomaticComplexMethod", "NotImplementedDeclaration") override suspend fun processActivity(json: String, type: ActivityType): ActivityPubResponse { - logger.debug("proccess activity: {}", type) + logger.debug("process activity: {}", type) return when (type) { ActivityType.Accept -> apAcceptService.receiveAccept(objectMapper.readValue(json)) - ActivityType.Follow -> apReceiveFollowService.receiveFollow( - objectMapper.readValue( - json, - Follow::class.java - ) - ) - + ActivityType.Follow -> apReceiveFollowService + .receiveFollow(objectMapper.readValue(json, Follow::class.java)) ActivityType.Create -> apCreateService.receiveCreate(objectMapper.readValue(json)) ActivityType.Like -> apLikeService.receiveLike(objectMapper.readValue(json)) ActivityType.Undo -> apUndoService.receiveUndo(objectMapper.readValue(json)) diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 565f4968..5853405c 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -10,7 +10,7 @@ - + From d3a45cd3ba048d9c38d1d3c0dc00131a0ce1aaca Mon Sep 17 00:00:00 2001 From: usbharu Date: Thu, 12 Oct 2023 01:55:32 +0900 Subject: [PATCH 6/8] Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../kotlin/dev/usbharu/hideout/config/HttpClientConfig.kt | 2 -- src/main/kotlin/dev/usbharu/hideout/config/SecurityConfig.kt | 1 - .../dev/usbharu/hideout/repository/PostRepositoryImpl.kt | 1 - .../kotlin/dev/usbharu/hideout/service/ap/APLikeService.kt | 1 - src/main/kotlin/dev/usbharu/hideout/service/ap/APService.kt | 5 +++-- .../dev/usbharu/hideout/service/core/MdcXrequestIdFilter.kt | 1 - .../usbharu/hideout/service/reaction/ReactionServiceImpl.kt | 1 - 7 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/dev/usbharu/hideout/config/HttpClientConfig.kt b/src/main/kotlin/dev/usbharu/hideout/config/HttpClientConfig.kt index 324f1e93..f373805c 100644 --- a/src/main/kotlin/dev/usbharu/hideout/config/HttpClientConfig.kt +++ b/src/main/kotlin/dev/usbharu/hideout/config/HttpClientConfig.kt @@ -22,10 +22,8 @@ class HttpClientConfig { install(Logging) { logger = Logger.DEFAULT level = LogLevel.INFO - } install(HttpCache) { - } expectSuccess = true } diff --git a/src/main/kotlin/dev/usbharu/hideout/config/SecurityConfig.kt b/src/main/kotlin/dev/usbharu/hideout/config/SecurityConfig.kt index f87c4dfd..82f61ed9 100644 --- a/src/main/kotlin/dev/usbharu/hideout/config/SecurityConfig.kt +++ b/src/main/kotlin/dev/usbharu/hideout/config/SecurityConfig.kt @@ -40,7 +40,6 @@ import java.security.interfaces.RSAPrivateKey import java.security.interfaces.RSAPublicKey import java.util.* - @EnableWebSecurity(debug = false) @Configuration class SecurityConfig { diff --git a/src/main/kotlin/dev/usbharu/hideout/repository/PostRepositoryImpl.kt b/src/main/kotlin/dev/usbharu/hideout/repository/PostRepositoryImpl.kt index f179ce7f..9100422a 100644 --- a/src/main/kotlin/dev/usbharu/hideout/repository/PostRepositoryImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/repository/PostRepositoryImpl.kt @@ -55,7 +55,6 @@ class PostRepositoryImpl(private val idGenerateService: IdGenerateService) : Pos } } - assert(Posts.select { Posts.id eq post.id }.singleOrNull() != null) { "Faild to insert" } diff --git a/src/main/kotlin/dev/usbharu/hideout/service/ap/APLikeService.kt b/src/main/kotlin/dev/usbharu/hideout/service/ap/APLikeService.kt index 3ddba560..d7d62fc3 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/ap/APLikeService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/ap/APLikeService.kt @@ -32,7 +32,6 @@ class APLikeServiceImpl( val content = like.content ?: throw IllegalActivityPubObjectException("content is null") like.`object` ?: throw IllegalActivityPubObjectException("object is null") transaction.transaction { - LOGGER.trace("FETCH Liked Person $actor") val person = apUserService.fetchPersonWithEntity(actor) LOGGER.trace("{}", person.second) diff --git a/src/main/kotlin/dev/usbharu/hideout/service/ap/APService.kt b/src/main/kotlin/dev/usbharu/hideout/service/ap/APService.kt index 00e7a822..6e241375 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/ap/APService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/ap/APService.kt @@ -206,8 +206,9 @@ class APServiceImpl( logger.debug("process activity: {}", type) return when (type) { ActivityType.Accept -> apAcceptService.receiveAccept(objectMapper.readValue(json)) - ActivityType.Follow -> apReceiveFollowService - .receiveFollow(objectMapper.readValue(json, Follow::class.java)) + ActivityType.Follow -> + apReceiveFollowService + .receiveFollow(objectMapper.readValue(json, Follow::class.java)) ActivityType.Create -> apCreateService.receiveCreate(objectMapper.readValue(json)) ActivityType.Like -> apLikeService.receiveLike(objectMapper.readValue(json)) ActivityType.Undo -> apUndoService.receiveUndo(objectMapper.readValue(json)) diff --git a/src/main/kotlin/dev/usbharu/hideout/service/core/MdcXrequestIdFilter.kt b/src/main/kotlin/dev/usbharu/hideout/service/core/MdcXrequestIdFilter.kt index f3ecdcf6..d934449c 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/core/MdcXrequestIdFilter.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/core/MdcXrequestIdFilter.kt @@ -18,7 +18,6 @@ class MdcXrequestIdFilter : Filter { } finally { MDC.remove(KEY) } - } companion object { diff --git a/src/main/kotlin/dev/usbharu/hideout/service/reaction/ReactionServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/service/reaction/ReactionServiceImpl.kt index 6e56143f..4ccac212 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/reaction/ReactionServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/reaction/ReactionServiceImpl.kt @@ -16,7 +16,6 @@ class ReactionServiceImpl( ) : ReactionService { override suspend fun receiveReaction(name: String, domain: String, userId: Long, postId: Long) { if (reactionQueryService.reactionAlreadyExist(postId, userId, 0).not()) { - try { reactionRepository.save( Reaction(reactionRepository.generateId(), 0, postId, userId) From e019d293c25d1539886d43f1f2edea4b1aab1024 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Thu, 12 Oct 2023 02:04:08 +0900 Subject: [PATCH 7/8] =?UTF-8?q?style:=20=E3=82=B9=E3=82=BF=E3=82=A4?= =?UTF-8?q?=E3=83=AB=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dev/usbharu/hideout/service/core/MdcXrequestIdFilter.kt | 2 +- .../kotlin/dev/usbharu/hideout/service/post/PostServiceImpl.kt | 2 +- .../kotlin/dev/usbharu/hideout/service/user/UserServiceImpl.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/dev/usbharu/hideout/service/core/MdcXrequestIdFilter.kt b/src/main/kotlin/dev/usbharu/hideout/service/core/MdcXrequestIdFilter.kt index d934449c..2ad64bd9 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/core/MdcXrequestIdFilter.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/core/MdcXrequestIdFilter.kt @@ -21,6 +21,6 @@ class MdcXrequestIdFilter : Filter { } companion object { - val KEY = "x-request-id" + private const val KEY = "x-request-id" } } diff --git a/src/main/kotlin/dev/usbharu/hideout/service/post/PostServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/service/post/PostServiceImpl.kt index f4d36084..ac5e54c6 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/post/PostServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/post/PostServiceImpl.kt @@ -35,7 +35,7 @@ class PostServiceImpl( private suspend fun internalCreate(post: Post, isLocal: Boolean): Post { val save = try { postRepository.save(post) - } catch (e: ExposedSQLException) { + } catch (_: ExposedSQLException) { postQueryService.findByApId(post.apId) } timelineService.publishTimeline(save, isLocal) diff --git a/src/main/kotlin/dev/usbharu/hideout/service/user/UserServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/service/user/UserServiceImpl.kt index 2af93ed6..0f865526 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/user/UserServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/user/UserServiceImpl.kt @@ -67,7 +67,7 @@ class UserServiceImpl( ) return try { userRepository.save(userEntity) - } catch (e: ExposedSQLException) { + } catch (_: ExposedSQLException) { userQueryService.findByUrl(user.url) } } From eca18ee7fa85784cd566e3c7ab663d9df8507d7f Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Thu, 12 Oct 2023 02:12:45 +0900 Subject: [PATCH 8/8] =?UTF-8?q?chore:=20=E4=BE=9D=E5=AD=98=E9=96=A2?= =?UTF-8?q?=E4=BF=82=E3=82=92=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 2 +- .../controller/mastodon/MastodonStatusesApiContoller.kt | 4 +++- .../usbharu/hideout/domain/model/mastodon/StatusesRequest.kt | 2 +- .../kotlin/dev/usbharu/kjob/exposed/ExposedLockRepository.kt | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 83910384..af9d60f7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -145,7 +145,7 @@ dependencies { implementation("org.drewcarlson:kjob-mongo:0.6.0") testImplementation("org.slf4j:slf4j-simple:2.0.7") - detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.22.0") + detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.23.1") } detekt { diff --git a/src/main/kotlin/dev/usbharu/hideout/controller/mastodon/MastodonStatusesApiContoller.kt b/src/main/kotlin/dev/usbharu/hideout/controller/mastodon/MastodonStatusesApiContoller.kt index 7b537601..11a3c753 100644 --- a/src/main/kotlin/dev/usbharu/hideout/controller/mastodon/MastodonStatusesApiContoller.kt +++ b/src/main/kotlin/dev/usbharu/hideout/controller/mastodon/MastodonStatusesApiContoller.kt @@ -13,7 +13,9 @@ import org.springframework.stereotype.Controller @Controller class MastodonStatusesApiContoller(private val statusesApiService: StatusesApiService) : StatusApi { - override fun apiV1StatusesPost(devUsbharuHideoutDomainModelMastodonStatusesRequest: StatusesRequest): ResponseEntity { + override fun apiV1StatusesPost( + devUsbharuHideoutDomainModelMastodonStatusesRequest: StatusesRequest + ): ResponseEntity { return runBlocking { val jwt = SecurityContextHolder.getContext().authentication.principal as Jwt diff --git a/src/main/kotlin/dev/usbharu/hideout/domain/model/mastodon/StatusesRequest.kt b/src/main/kotlin/dev/usbharu/hideout/domain/model/mastodon/StatusesRequest.kt index a3a98ec4..aa91e738 100644 --- a/src/main/kotlin/dev/usbharu/hideout/domain/model/mastodon/StatusesRequest.kt +++ b/src/main/kotlin/dev/usbharu/hideout/domain/model/mastodon/StatusesRequest.kt @@ -72,6 +72,6 @@ class StatusesRequest { `public`, unlisted, private, - direct; + direct } } diff --git a/src/main/kotlin/dev/usbharu/kjob/exposed/ExposedLockRepository.kt b/src/main/kotlin/dev/usbharu/kjob/exposed/ExposedLockRepository.kt index e29341ba..fc990e92 100644 --- a/src/main/kotlin/dev/usbharu/kjob/exposed/ExposedLockRepository.kt +++ b/src/main/kotlin/dev/usbharu/kjob/exposed/ExposedLockRepository.kt @@ -49,7 +49,7 @@ class ExposedLockRepository( val lock = Lock(id, now) query { if (locks.select(locks.id eq id).limit(1) - .map { Lock(it[locks.id].value, Instant.ofEpochMilli(it[locks.expiresAt])) }.isEmpty() + .map { Lock(it[locks.id].value, Instant.ofEpochMilli(it[locks.expiresAt])) }.isEmpty() ) { locks.insert { it[locks.id] = id