feat: KJOBの使用箇所をなくした

This commit is contained in:
usbharu 2024-05-08 18:55:12 +09:00
parent 5ef130c94f
commit bb5cef6c22
61 changed files with 784 additions and 1837 deletions

1
.gitignore vendored
View File

@ -45,3 +45,4 @@ out/
/files/
*.log
/hideout-core/files/

View File

@ -19,7 +19,7 @@ package dev.usbharu.hideout.activitypub.service.activity.accept
import dev.usbharu.hideout.activitypub.domain.model.Accept
import dev.usbharu.hideout.activitypub.domain.model.Follow
import dev.usbharu.hideout.core.domain.model.actor.Actor
import dev.usbharu.hideout.core.external.job.DeliverAcceptJobParam
import dev.usbharu.hideout.core.external.job.DeliverAcceptTask
import dev.usbharu.owl.producer.api.OwlProducer
import org.springframework.stereotype.Service
@ -32,7 +32,7 @@ class ApSendAcceptServiceImpl(
private val owlProducer: OwlProducer,
) : ApSendAcceptService {
override suspend fun sendAcceptFollow(actor: Actor, target: Actor) {
val deliverAcceptJobParam = DeliverAcceptJobParam(
val deliverAcceptTask = DeliverAcceptTask(
Accept(
apObject = Follow(
apObject = actor.url,
@ -44,6 +44,6 @@ class ApSendAcceptServiceImpl(
actor.id
)
owlProducer.publishTask(deliverAcceptJobParam)
owlProducer.publishTask(deliverAcceptTask)
}
}

View File

@ -1,52 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.activitypub.service.activity.block
import dev.usbharu.hideout.activitypub.service.common.APRequestService
import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.external.job.DeliverBlockJob
import dev.usbharu.hideout.core.external.job.DeliverBlockJobParam
import dev.usbharu.hideout.core.service.job.JobProcessor
import org.springframework.stereotype.Service
/**
* ブロックアクティビティ配送を処理します
*/
@Service
class APDeliverBlockJobProcessor(
private val apRequestService: APRequestService,
private val actorRepository: ActorRepository,
private val transaction: Transaction,
private val deliverBlockJob: DeliverBlockJob
) : JobProcessor<DeliverBlockJobParam, DeliverBlockJob> {
override suspend fun process(param: DeliverBlockJobParam): Unit = transaction.transaction {
val signer = actorRepository.findById(param.signer)
apRequestService.apPost(
param.inbox,
param.reject,
signer
)
apRequestService.apPost(
param.inbox,
param.block,
signer
)
}
override fun job(): DeliverBlockJob = deliverBlockJob
}

View File

@ -16,12 +16,8 @@
package dev.usbharu.hideout.activitypub.service.activity.block
import dev.usbharu.hideout.activitypub.domain.model.Block
import dev.usbharu.hideout.activitypub.domain.model.Follow
import dev.usbharu.hideout.activitypub.domain.model.Reject
import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.core.domain.model.actor.Actor
import dev.usbharu.hideout.core.external.job.DeliverBlockJobParam
import dev.usbharu.owl.producer.api.OwlProducer
import org.springframework.stereotype.Service
@ -35,23 +31,23 @@ class ApSendBlockServiceImpl(
private val owlProducer: OwlProducer,
) : APSendBlockService {
override suspend fun sendBlock(actor: Actor, target: Actor) {
val blockJobParam = DeliverBlockJobParam(
actor.id,
Block(
actor.url,
"${applicationConfig.url}/block/${actor.id}/${target.id}",
target.url
),
Reject(
actor.url,
"${applicationConfig.url}/reject/${actor.id}/${target.id}",
Follow(
apObject = actor.url,
actor = target.url
)
),
target.inbox
)
owlProducer.publishTask(blockJobParam)
// val blockJobParam = DeliverBlockJobParam(
// actor.id,
// Block(
// actor.url,
// "${applicationConfig.url}/block/${actor.id}/${target.id}",
// target.url
// ),
// Reject(
// actor.url,
// "${applicationConfig.url}/reject/${actor.id}/${target.id}",
// Follow(
// apObject = actor.url,
// actor = target.url
// )
// ),
// target.inbox
// )
// owlProducer.publishTask(blockJobParam)
}
}

View File

@ -16,7 +16,6 @@
package dev.usbharu.hideout.activitypub.service.activity.create
import com.fasterxml.jackson.databind.ObjectMapper
import dev.usbharu.hideout.activitypub.domain.model.Create
import dev.usbharu.hideout.activitypub.query.NoteQueryService
import dev.usbharu.hideout.application.config.ApplicationConfig
@ -24,9 +23,8 @@ import dev.usbharu.hideout.core.domain.exception.resource.PostNotFoundException
import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.domain.model.post.Post
import dev.usbharu.hideout.core.external.job.DeliverPostTask
import dev.usbharu.hideout.core.external.job.DeliverCreateTask
import dev.usbharu.hideout.core.query.FollowerQueryService
import dev.usbharu.hideout.core.service.job.JobQueueParentService
import dev.usbharu.owl.producer.api.OwlProducer
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
@ -34,8 +32,6 @@ import org.springframework.stereotype.Service
@Service
class ApSendCreateServiceImpl(
private val followerQueryService: FollowerQueryService,
private val objectMapper: ObjectMapper,
private val jobQueueParentService: JobQueueParentService,
private val noteQueryService: NoteQueryService,
private val applicationConfig: ApplicationConfig,
private val actorRepository: ActorRepository,
@ -58,7 +54,7 @@ class ApSendCreateServiceImpl(
id = "${applicationConfig.url}/create/note/${post.id}"
)
followers.forEach { followerEntity ->
owlProducer.publishTask(DeliverPostTask(create, userEntity.url, followerEntity.inbox))
owlProducer.publishTask(DeliverCreateTask(create, userEntity.url, followerEntity.inbox))
}
logger.debug("SUCCESS Create Local Note ${post.url}")

View File

@ -1,39 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.activitypub.service.activity.delete
import dev.usbharu.hideout.activitypub.service.common.APRequestService
import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.external.job.DeliverDeleteJob
import dev.usbharu.hideout.core.external.job.DeliverDeleteJobParam
import dev.usbharu.hideout.core.service.job.JobProcessor
import org.springframework.stereotype.Service
@Service
class APDeliverDeleteJobProcessor(
private val apRequestService: APRequestService,
private val transaction: Transaction,
private val deliverDeleteJob: DeliverDeleteJob,
private val actorRepository: ActorRepository
) : JobProcessor<DeliverDeleteJobParam, DeliverDeleteJob> {
override suspend fun process(param: DeliverDeleteJobParam): Unit = transaction.transaction {
apRequestService.apPost(param.inbox, param.delete, actorRepository.findById(param.signer))
}
override fun job(): DeliverDeleteJob = deliverDeleteJob
}

View File

@ -24,7 +24,7 @@ import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
import dev.usbharu.hideout.core.domain.model.actor.Actor
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.domain.model.post.Post
import dev.usbharu.hideout.core.external.job.DeliverDeleteJobParam
import dev.usbharu.hideout.core.external.job.DeliverDeleteTask
import dev.usbharu.hideout.core.query.FollowerQueryService
import dev.usbharu.owl.producer.api.OwlProducer
import org.springframework.stereotype.Service
@ -55,7 +55,7 @@ class APSendDeleteServiceImpl(
)
followersById.forEach {
val jobProps = DeliverDeleteJobParam(
val jobProps = DeliverDeleteTask(
delete,
it.inbox,
actor.id
@ -76,7 +76,7 @@ class APSendDeleteServiceImpl(
)
followers.forEach {
DeliverDeleteJobParam(
DeliverDeleteTask(
delete = delete,
it.inbox,
deletedActor.id

View File

@ -22,7 +22,7 @@ import dev.usbharu.hideout.activitypub.service.common.AbstractActivityPubProcess
import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessContext
import dev.usbharu.hideout.activitypub.service.common.ActivityType
import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.core.external.job.ReceiveFollowJobParam
import dev.usbharu.hideout.core.external.job.ReceiveFollowTask
import dev.usbharu.owl.producer.api.OwlProducer
import org.springframework.stereotype.Service
@ -37,9 +37,9 @@ class APFollowProcessor(
logger.info("FOLLOW from: {} to {}", activity.activity.actor, activity.activity.apObject)
// inboxをジョブキューに乗せているので既に不要だが、フォロー承認制アカウントを実装する際に必要なので残す
val jobProps = ReceiveFollowJobParam(
val jobProps = ReceiveFollowTask(
activity.activity.actor,
objectMapper.writeValueAsString(activity.activity),
activity.activity,
activity.activity.apObject
)
owlProducer.publishTask(jobProps)

View File

@ -1,63 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.activitypub.service.activity.follow
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import dev.usbharu.hideout.activitypub.domain.model.Follow
import dev.usbharu.hideout.activitypub.service.objects.user.APUserService
import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.external.job.ReceiveFollowJob
import dev.usbharu.hideout.core.external.job.ReceiveFollowJobParam
import dev.usbharu.hideout.core.service.job.JobProcessor
import dev.usbharu.hideout.core.service.relationship.RelationshipService
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
@Service
class APReceiveFollowJobProcessor(
private val transaction: Transaction,
private val apUserService: APUserService,
private val objectMapper: ObjectMapper,
private val relationshipService: RelationshipService,
private val actorRepository: ActorRepository
) :
JobProcessor<ReceiveFollowJobParam, ReceiveFollowJob> {
override suspend fun process(param: ReceiveFollowJobParam) = transaction.transaction {
apUserService.fetchPerson(param.actor, param.targetActor)
val follow = objectMapper.readValue<Follow>(param.follow)
logger.info("START Follow from: {} to {}", param.targetActor, param.actor)
val targetEntity =
actorRepository.findByUrl(param.targetActor) ?: throw UserNotFoundException.withUrl(param.targetActor)
val followActorEntity =
actorRepository.findByUrl(follow.actor) ?: throw UserNotFoundException.withUrl(follow.actor)
relationshipService.followRequest(followActorEntity.id, targetEntity.id)
logger.info("SUCCESS Follow from: {} to: {}", param.targetActor, param.actor)
}
override fun job(): ReceiveFollowJob = ReceiveFollowJob
companion object {
private val logger = LoggerFactory.getLogger(APReceiveFollowJobProcessor::class.java)
}
}

View File

@ -16,16 +16,20 @@
package dev.usbharu.hideout.activitypub.service.activity.like
import dev.usbharu.hideout.activitypub.domain.model.Like
import dev.usbharu.hideout.activitypub.domain.model.Undo
import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.core.domain.exception.resource.PostNotFoundException
import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.domain.model.post.PostRepository
import dev.usbharu.hideout.core.domain.model.reaction.Reaction
import dev.usbharu.hideout.core.external.job.DeliverReactionTask
import dev.usbharu.hideout.core.external.job.DeliverRemoveReactionTask
import dev.usbharu.hideout.core.external.job.DeliverUndoTask
import dev.usbharu.hideout.core.query.FollowerQueryService
import dev.usbharu.owl.producer.api.OwlProducer
import org.springframework.stereotype.Service
import java.time.Instant
interface APReactionService {
suspend fun reaction(like: Reaction)
@ -37,6 +41,7 @@ class APReactionServiceImpl(
private val followerQueryService: FollowerQueryService,
private val actorRepository: ActorRepository,
private val postRepository: PostRepository,
private val applicationConfig: ApplicationConfig,
private val owlProducer: OwlProducer,
) : APReactionService {
override suspend fun reaction(like: Reaction) {
@ -48,10 +53,13 @@ class APReactionServiceImpl(
owlProducer.publishTask(
DeliverReactionTask(
actor = user.url,
reaction = "",
inbox = follower.inbox,
postUrl = post.url,
id = post.id
like = Like(
actor = user.url,
id = "${applicationConfig.url}/like/note/${post.id}",
content = "",
apObject = post.url
),
inbox = follower.inbox
)
)
}
@ -64,11 +72,20 @@ class APReactionServiceImpl(
postRepository.findById(like.postId) ?: throw PostNotFoundException.withId(like.postId)
followers.forEach { follower ->
owlProducer.publishTask(
DeliverRemoveReactionTask(
actor = user.url,
DeliverUndoTask(
signer = user.id,
inbox = follower.inbox,
id = post.id,
reaction = like
undo = Undo(
actor = user.url,
id = "${applicationConfig.url}/undo/like/${post.id}",
apObject = Like(
actor = user.url,
id = "${applicationConfig.url}/like/note/${post.id}",
content = "",
apObject = post.url
),
published = Instant.now().toString(),
)
)
)
}

View File

@ -1,52 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.activitypub.service.activity.like
import dev.usbharu.hideout.activitypub.domain.model.Like
import dev.usbharu.hideout.activitypub.service.common.APRequestService
import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.external.job.DeliverReactionJob
import dev.usbharu.hideout.core.external.job.DeliverReactionJobParam
import dev.usbharu.hideout.core.service.job.JobProcessor
import org.springframework.stereotype.Service
@Service
class ApReactionJobProcessor(
private val apRequestService: APRequestService,
private val applicationConfig: ApplicationConfig,
private val transaction: Transaction,
private val actorRepository: ActorRepository
) : JobProcessor<DeliverReactionJobParam, DeliverReactionJob> {
override suspend fun process(param: DeliverReactionJobParam): Unit = transaction.transaction {
val signer = actorRepository.findByUrl(param.actor)
apRequestService.apPost(
param.inbox,
Like(
actor = param.actor,
apObject = param.postUrl,
id = "${applicationConfig.url}/liek/note/${param.id}",
content = param.reaction
),
signer
)
}
override fun job(): DeliverReactionJob = DeliverReactionJob
}

View File

@ -1,59 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.activitypub.service.activity.like
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import dev.usbharu.hideout.activitypub.domain.model.Like
import dev.usbharu.hideout.activitypub.domain.model.Undo
import dev.usbharu.hideout.activitypub.service.common.APRequestService
import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.external.job.DeliverRemoveReactionJob
import dev.usbharu.hideout.core.external.job.DeliverRemoveReactionJobParam
import dev.usbharu.hideout.core.service.job.JobProcessor
import org.springframework.stereotype.Service
import java.time.Instant
@Service
class ApRemoveReactionJobProcessor(
private val transaction: Transaction,
private val objectMapper: ObjectMapper,
private val apRequestService: APRequestService,
private val applicationConfig: ApplicationConfig,
private val actorRepository: ActorRepository
) : JobProcessor<DeliverRemoveReactionJobParam, DeliverRemoveReactionJob> {
override suspend fun process(param: DeliverRemoveReactionJobParam): Unit = transaction.transaction {
val like = objectMapper.readValue<Like>(param.like)
val signer = actorRepository.findByUrl(param.actor)
apRequestService.apPost(
param.inbox,
Undo(
actor = param.actor,
apObject = like,
id = "${applicationConfig.url}/undo/like/${param.id}",
published = Instant.now().toString()
),
signer
)
}
override fun job(): DeliverRemoveReactionJob = DeliverRemoveReactionJob
}

View File

@ -20,7 +20,7 @@ import dev.usbharu.hideout.activitypub.domain.model.Follow
import dev.usbharu.hideout.activitypub.domain.model.Reject
import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.core.domain.model.actor.Actor
import dev.usbharu.hideout.core.external.job.DeliverRejectJobParam
import dev.usbharu.hideout.core.external.job.DeliverRejectTask
import dev.usbharu.owl.producer.api.OwlProducer
import org.springframework.stereotype.Service
@ -30,7 +30,7 @@ class ApSendRejectServiceImpl(
private val owlProducer: OwlProducer,
) : ApSendRejectService {
override suspend fun sendRejectFollow(actor: Actor, target: Actor) {
val deliverRejectJobParam = DeliverRejectJobParam(
val deliverRejectTask = DeliverRejectTask(
Reject(
actor.url,
"${applicationConfig.url}/reject/${actor.id}/${target.id}",
@ -40,6 +40,6 @@ class ApSendRejectServiceImpl(
actor.id
)
owlProducer.publishTask(deliverRejectJobParam)
owlProducer.publishTask(deliverRejectTask)
}
}

View File

@ -21,7 +21,7 @@ import dev.usbharu.hideout.activitypub.domain.model.Follow
import dev.usbharu.hideout.activitypub.domain.model.Undo
import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.core.domain.model.actor.Actor
import dev.usbharu.hideout.core.external.job.DeliverUndoJobParam
import dev.usbharu.hideout.core.external.job.DeliverUndoTask
import dev.usbharu.owl.producer.api.OwlProducer
import org.springframework.stereotype.Service
import java.time.Instant
@ -32,7 +32,7 @@ class APSendUndoServiceImpl(
private val owlProducer: OwlProducer,
) : APSendUndoService {
override suspend fun sendUndoFollow(actor: Actor, target: Actor) {
val deliverUndoJobParam = DeliverUndoJobParam(
val deliverUndoTask = DeliverUndoTask(
Undo(
actor = actor.url,
id = "${applicationConfig.url}/undo/follow/${actor.id}/${target.url}",
@ -46,11 +46,11 @@ class APSendUndoServiceImpl(
actor.id
)
owlProducer.publishTask(deliverUndoJobParam)
owlProducer.publishTask(deliverUndoTask)
}
override suspend fun sendUndoBlock(actor: Actor, target: Actor) {
val deliverUndoJobParam = DeliverUndoJobParam(
val deliverUndoTask = DeliverUndoTask(
Undo(
actor = actor.url,
id = "${applicationConfig.url}/undo/block/${actor.id}/${target.url}",
@ -65,6 +65,6 @@ class APSendUndoServiceImpl(
actor.id
)
owlProducer.publishTask(deliverUndoJobParam)
owlProducer.publishTask(deliverUndoTask)
}
}

View File

@ -1,58 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.activitypub.service.objects.note
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import dev.usbharu.hideout.activitypub.domain.model.Create
import dev.usbharu.hideout.activitypub.service.common.APRequestService
import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.external.job.DeliverPostJob
import dev.usbharu.hideout.core.external.job.DeliverPostJobParam
import dev.usbharu.hideout.core.service.job.JobProcessor
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
@Service
class ApNoteJobProcessor(
private val transaction: Transaction,
private val objectMapper: ObjectMapper,
private val apRequestService: APRequestService,
private val actorRepository: ActorRepository
) : JobProcessor<DeliverPostJobParam, DeliverPostJob> {
override suspend fun process(param: DeliverPostJobParam) {
val create = objectMapper.readValue<Create>(param.create)
transaction.transaction {
val signer = actorRepository.findByUrl(param.actor)
logger.debug("CreateNoteJob: actor: {} create: {} inbox: {}", param.actor, create, param.inbox)
apRequestService.apPost(
param.inbox,
create,
signer
)
}
}
override fun job(): DeliverPostJob = DeliverPostJob
companion object {
private val logger = LoggerFactory.getLogger(ApNoteJobProcessor::class.java)
}
}

View File

@ -1,56 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.application.config
import dev.usbharu.hideout.core.external.job.HideoutJob
import dev.usbharu.hideout.core.service.job.JobQueueParentService
import dev.usbharu.hideout.core.service.job.JobQueueWorkerService
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.boot.ApplicationArguments
import org.springframework.boot.ApplicationRunner
import org.springframework.stereotype.Component
@Component
class JobQueueRunner(
private val jobQueueParentService: JobQueueParentService,
private val jobs: List<HideoutJob<*, *>>
) :
ApplicationRunner {
override fun run(args: ApplicationArguments?) {
LOGGER.info("Init job queue. ${jobs.size}")
jobQueueParentService.init(jobs)
}
companion object {
val LOGGER: Logger = LoggerFactory.getLogger(JobQueueRunner::class.java)
}
}
@Component
class JobQueueWorkerRunner(
private val jobQueueWorkerService: JobQueueWorkerService,
) : ApplicationRunner {
override fun run(args: ApplicationArguments?) {
LOGGER.info("Init job queue worker.")
jobQueueWorkerService.init<Any?, HideoutJob<*, *>>(emptyList())
}
companion object {
val LOGGER: Logger = LoggerFactory.getLogger(JobQueueWorkerRunner::class.java)
}
}

View File

@ -39,19 +39,16 @@ class OwlConfig(private val producerConfig: ProducerConfig) {
if (producerConfig.port != null) {
this.port = producerConfig.port.toString()
}
}
}
ProducerMode.GRPC -> {
OWL(EMBEDDED_GRPC) {
}
}
ProducerMode.EMBEDDED_GRPC -> {
OWL(DEFAULT) {
}
}
}

View File

@ -1,54 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.external.job
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import dev.usbharu.hideout.activitypub.domain.model.Accept
import dev.usbharu.owl.common.task.Task
import kjob.core.dsl.ScheduleContext
import kjob.core.job.JobProps
import org.springframework.stereotype.Component
data class DeliverAcceptJobParam(
val accept: Accept,
val inbox: String,
val signer: Long,
) : Task()
@Component
class DeliverAcceptJob(private val objectMapper: ObjectMapper) :
HideoutJob<DeliverAcceptJobParam, DeliverAcceptJob>("DeliverAcceptJob") {
val accept = string("accept")
val inbox = string("inbox")
val signer = long("signer")
override fun convert(value: DeliverAcceptJobParam): ScheduleContext<DeliverAcceptJob>.(DeliverAcceptJob) -> Unit = {
props[accept] = objectMapper.writeValueAsString(value.accept)
props[inbox] = value.inbox
props[signer] = value.signer
}
override fun convert(props: JobProps<DeliverAcceptJob>): DeliverAcceptJobParam {
return DeliverAcceptJobParam(
objectMapper.readValue(props[accept]),
props[inbox],
props[signer]
)
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.external.job
import dev.usbharu.hideout.activitypub.domain.model.Accept
import dev.usbharu.owl.common.property.PropertyValue
import dev.usbharu.owl.common.task.PropertyDefinition
import dev.usbharu.owl.common.task.Task
import dev.usbharu.owl.common.task.TaskDefinition
data class DeliverAcceptTask(
val accept: Accept,
val inbox: String,
val signer: Long,
) : Task()
data object DeliverAcceptTaskDef : TaskDefinition<DeliverAcceptTask> {
override val name: String
get() = TODO("Not yet implemented")
override val priority: Int
get() = TODO("Not yet implemented")
override val maxRetry: Int
get() = TODO("Not yet implemented")
override val retryPolicy: String
get() = TODO("Not yet implemented")
override val timeoutMilli: Long
get() = TODO("Not yet implemented")
override val propertyDefinition: PropertyDefinition
get() = TODO("Not yet implemented")
override val type: Class<DeliverAcceptTask>
get() = TODO("Not yet implemented")
override fun serialize(task: DeliverAcceptTask): Map<String, PropertyValue<*>> {
TODO("Not yet implemented")
}
override fun deserialize(value: Map<String, PropertyValue<*>>): DeliverAcceptTask {
TODO("Not yet implemented")
}
}

View File

@ -1,69 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.external.job
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import dev.usbharu.hideout.activitypub.domain.model.Block
import dev.usbharu.hideout.activitypub.domain.model.Reject
import dev.usbharu.owl.common.task.Task
import kjob.core.dsl.ScheduleContext
import kjob.core.job.JobProps
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.stereotype.Component
/**
* ブロックアクティビティ配送のジョブパラメーター
*
* @property signer ブロック操作を行ったユーザーid
* @property block 配送するブロックアクティビティ
* @property reject 配送するフォロー解除アクティビティ
* @property inbox 配送先url
*/
data class DeliverBlockJobParam(
val signer: Long,
val block: Block,
val reject: Reject,
val inbox: String,
) : Task()
/**
* ブロックアクティビティ配送のジョブ
*/
@Component
class DeliverBlockJob(@Qualifier("activitypub") private val objectMapper: ObjectMapper) :
HideoutJob<DeliverBlockJobParam, DeliverBlockJob>("DeliverBlockJob") {
val block = string("block")
val reject = string("reject")
val inbox = string("inbox")
val signer = long("signer")
override fun convert(value: DeliverBlockJobParam): ScheduleContext<DeliverBlockJob>.(DeliverBlockJob) -> Unit = {
props[block] = objectMapper.writeValueAsString(value.block)
props[reject] = objectMapper.writeValueAsString(value.reject)
props[inbox] = value.inbox
props[signer] = value.signer
}
override fun convert(props: JobProps<DeliverBlockJob>): DeliverBlockJobParam = DeliverBlockJobParam(
signer = props[signer],
block = objectMapper.readValue(props[block]),
reject = objectMapper.readValue(props[reject]),
inbox = props[inbox]
)
}

View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.external.job
import dev.usbharu.hideout.activitypub.domain.model.Create
import dev.usbharu.owl.common.property.PropertyValue
import dev.usbharu.owl.common.task.PropertyDefinition
import dev.usbharu.owl.common.task.Task
import dev.usbharu.owl.common.task.TaskDefinition
data class DeliverCreateTask(
val create: Create,
val inbox: String,
val actor: String,
) : Task()
data object DeliverCreateTaskDef : TaskDefinition<DeliverCreateTask> {
override val name: String
get() = TODO("Not yet implemented")
override val priority: Int
get() = TODO("Not yet implemented")
override val maxRetry: Int
get() = TODO("Not yet implemented")
override val retryPolicy: String
get() = TODO("Not yet implemented")
override val timeoutMilli: Long
get() = TODO("Not yet implemented")
override val propertyDefinition: PropertyDefinition
get() = TODO("Not yet implemented")
override val type: Class<DeliverCreateTask>
get() = TODO("Not yet implemented")
override fun serialize(task: DeliverCreateTask): Map<String, PropertyValue<*>> {
TODO("Not yet implemented")
}
override fun deserialize(value: Map<String, PropertyValue<*>>): DeliverCreateTask {
TODO("Not yet implemented")
}
}

View File

@ -1,53 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.external.job
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import dev.usbharu.hideout.activitypub.domain.model.Delete
import dev.usbharu.owl.common.task.Task
import kjob.core.dsl.ScheduleContext
import kjob.core.job.JobProps
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.stereotype.Component
data class DeliverDeleteJobParam(
val delete: Delete,
val inbox: String,
val signer: Long,
) : Task()
@Component
class DeliverDeleteJob(@Qualifier("activitypub") private val objectMapper: ObjectMapper) :
HideoutJob<DeliverDeleteJobParam, DeliverDeleteJob>("DeliverDeleteJob") {
val delete = string("delete")
val inbox = string("inbox")
val signer = long("signer")
override fun convert(value: DeliverDeleteJobParam): ScheduleContext<DeliverDeleteJob>.(DeliverDeleteJob) -> Unit = {
props[delete] = objectMapper.writeValueAsString(value.delete)
props[inbox] = value.inbox
props[signer] = value.signer
}
override fun convert(props: JobProps<DeliverDeleteJob>): DeliverDeleteJobParam = DeliverDeleteJobParam(
objectMapper.readValue(props[delete]),
props[inbox],
props[signer]
)
}

View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.external.job
import dev.usbharu.hideout.activitypub.domain.model.Delete
import dev.usbharu.owl.common.property.PropertyValue
import dev.usbharu.owl.common.task.PropertyDefinition
import dev.usbharu.owl.common.task.Task
import dev.usbharu.owl.common.task.TaskDefinition
data class DeliverDeleteTask(
val delete: Delete,
val inbox: String,
val signer: Long,
) : Task()
data object DeliverDeleteTaskDef : TaskDefinition<DeliverDeleteTask> {
override val name: String
get() = TODO("Not yet implemented")
override val priority: Int
get() = TODO("Not yet implemented")
override val maxRetry: Int
get() = TODO("Not yet implemented")
override val retryPolicy: String
get() = TODO("Not yet implemented")
override val timeoutMilli: Long
get() = TODO("Not yet implemented")
override val propertyDefinition: PropertyDefinition
get() = TODO("Not yet implemented")
override val type: Class<DeliverDeleteTask>
get() = TODO("Not yet implemented")
override fun serialize(task: DeliverDeleteTask): Map<String, PropertyValue<*>> {
TODO("Not yet implemented")
}
override fun deserialize(value: Map<String, PropertyValue<*>>): DeliverDeleteTask {
TODO("Not yet implemented")
}
}

View File

@ -16,12 +16,39 @@
package dev.usbharu.hideout.core.external.job
import dev.usbharu.hideout.activitypub.domain.model.Like
import dev.usbharu.owl.common.property.PropertyValue
import dev.usbharu.owl.common.task.PropertyDefinition
import dev.usbharu.owl.common.task.Task
import dev.usbharu.owl.common.task.TaskDefinition
data class DeliverReactionTask(
val actor: String,
val reaction: String,
val like: Like,
val inbox: String,
val postUrl: String,
val id: Long,
) : Task()
data object DeliverReactionTaskDef : TaskDefinition<DeliverReactionTask> {
override val name: String
get() = TODO("Not yet implemented")
override val priority: Int
get() = TODO("Not yet implemented")
override val maxRetry: Int
get() = TODO("Not yet implemented")
override val retryPolicy: String
get() = TODO("Not yet implemented")
override val timeoutMilli: Long
get() = TODO("Not yet implemented")
override val propertyDefinition: PropertyDefinition
get() = TODO("Not yet implemented")
override val type: Class<DeliverReactionTask>
get() = TODO("Not yet implemented")
override fun deserialize(value: Map<String, PropertyValue<*>>): DeliverReactionTask {
TODO("Not yet implemented")
}
override fun serialize(task: DeliverReactionTask): Map<String, PropertyValue<*>> {
TODO("Not yet implemented")
}
}

View File

@ -16,38 +16,39 @@
package dev.usbharu.hideout.core.external.job
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import dev.usbharu.hideout.activitypub.domain.model.Reject
import dev.usbharu.owl.common.property.PropertyValue
import dev.usbharu.owl.common.task.PropertyDefinition
import dev.usbharu.owl.common.task.Task
import kjob.core.dsl.ScheduleContext
import kjob.core.job.JobProps
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.stereotype.Component
import dev.usbharu.owl.common.task.TaskDefinition
data class DeliverRejectJobParam(
data class DeliverRejectTask(
val reject: Reject,
val inbox: String,
val signer: Long,
) : Task()
@Component
class DeliverRejectJob(@Qualifier("activitypub") private val objectMapper: ObjectMapper) :
HideoutJob<DeliverRejectJobParam, DeliverRejectJob>("DeliverRejectJob") {
val reject = string("reject")
val inbox = string("inbox")
val signer = long("signer")
data object DeliverRejectTaskDef : TaskDefinition<DeliverRejectTask> {
override val name: String
get() = TODO("Not yet implemented")
override val priority: Int
get() = TODO("Not yet implemented")
override val maxRetry: Int
get() = TODO("Not yet implemented")
override val retryPolicy: String
get() = TODO("Not yet implemented")
override val timeoutMilli: Long
get() = TODO("Not yet implemented")
override val propertyDefinition: PropertyDefinition
get() = TODO("Not yet implemented")
override val type: Class<DeliverRejectTask>
get() = TODO("Not yet implemented")
override fun convert(value: DeliverRejectJobParam): ScheduleContext<DeliverRejectJob>.(DeliverRejectJob) -> Unit =
{
props[reject] = objectMapper.writeValueAsString(value.reject)
props[inbox] = value.inbox
props[signer] = value.signer
}
override fun serialize(task: DeliverRejectTask): Map<String, PropertyValue<*>> {
TODO("Not yet implemented")
}
override fun convert(props: JobProps<DeliverRejectJob>): DeliverRejectJobParam = DeliverRejectJobParam(
objectMapper.readValue<Reject>(props[reject]),
props[inbox],
props[signer]
)
override fun deserialize(value: Map<String, PropertyValue<*>>): DeliverRejectTask {
TODO("Not yet implemented")
}
}

View File

@ -1,55 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.external.job
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import dev.usbharu.hideout.activitypub.domain.model.Undo
import dev.usbharu.owl.common.task.Task
import kjob.core.dsl.ScheduleContext
import kjob.core.job.JobProps
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.stereotype.Component
data class DeliverUndoJobParam(
val undo: Undo,
val inbox: String,
val signer: Long,
) : Task()
@Component
class DeliverUndoJob(@Qualifier("activitypub") private val objectMapper: ObjectMapper) :
HideoutJob<DeliverUndoJobParam, DeliverUndoJob>("DeliverUndoJob") {
val undo = string("undo")
val inbox = string("inbox")
val signer = long("signer")
override fun convert(value: DeliverUndoJobParam): ScheduleContext<DeliverUndoJob>.(DeliverUndoJob) -> Unit = {
props[undo] = objectMapper.writeValueAsString(value.undo)
props[inbox] = value.inbox
props[signer] = value.signer
}
override fun convert(props: JobProps<DeliverUndoJob>): DeliverUndoJobParam {
return DeliverUndoJobParam(
objectMapper.readValue(props[undo]),
props[inbox],
props[signer]
)
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.external.job
import dev.usbharu.hideout.activitypub.domain.model.Undo
import dev.usbharu.owl.common.property.PropertyValue
import dev.usbharu.owl.common.task.PropertyDefinition
import dev.usbharu.owl.common.task.Task
import dev.usbharu.owl.common.task.TaskDefinition
data class DeliverUndoTask(
val undo: Undo,
val inbox: String,
val signer: Long,
) : Task()
data object DeliverUndoTaskDef : TaskDefinition<DeliverUndoTask> {
override val name: String
get() = TODO("Not yet implemented")
override val priority: Int
get() = TODO("Not yet implemented")
override val maxRetry: Int
get() = TODO("Not yet implemented")
override val retryPolicy: String
get() = TODO("Not yet implemented")
override val timeoutMilli: Long
get() = TODO("Not yet implemented")
override val propertyDefinition: PropertyDefinition
get() = TODO("Not yet implemented")
override val type: Class<DeliverUndoTask>
get() = TODO("Not yet implemented")
override fun deserialize(value: Map<String, PropertyValue<*>>): DeliverUndoTask {
TODO("Not yet implemented")
}
override fun serialize(task: DeliverUndoTask): Map<String, PropertyValue<*>> {
TODO("Not yet implemented")
}
}

View File

@ -1,178 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.external.job
import dev.usbharu.hideout.activitypub.service.common.ActivityType
import dev.usbharu.owl.common.task.Task
import kjob.core.Job
import kjob.core.Prop
import kjob.core.dsl.ScheduleContext
import kjob.core.job.JobProps
import org.springframework.stereotype.Component
abstract class HideoutJob<out T, out R : HideoutJob<T, R>>(name: String) : Job(name) {
abstract fun convert(value: @UnsafeVariance T): ScheduleContext<@UnsafeVariance R>.(@UnsafeVariance R) -> Unit
fun convertUnsafe(props: JobProps<*>): T = convert(props as JobProps<R>)
abstract fun convert(props: JobProps<@UnsafeVariance R>): T
}
data class ReceiveFollowJobParam(
val actor: String,
val follow: String,
val targetActor: String,
) : Task()
@Component
object ReceiveFollowJob : HideoutJob<ReceiveFollowJobParam, ReceiveFollowJob>("ReceiveFollowJob") {
val actor: Prop<ReceiveFollowJob, String> = string("actor")
val follow: Prop<ReceiveFollowJob, String> = string("follow")
val targetActor: Prop<ReceiveFollowJob, String> = string("targetActor")
override fun convert(value: ReceiveFollowJobParam): ScheduleContext<ReceiveFollowJob>.(ReceiveFollowJob) -> Unit = {
props[follow] = value.follow
props[actor] = value.actor
props[targetActor] = value.targetActor
}
override fun convert(props: JobProps<ReceiveFollowJob>): ReceiveFollowJobParam = ReceiveFollowJobParam(
actor = props[actor],
follow = props[follow],
targetActor = props[targetActor]
)
}
data class DeliverPostJobParam(
val create: String,
val inbox: String,
val actor: String
)
@Component
object DeliverPostJob : HideoutJob<DeliverPostJobParam, DeliverPostJob>("DeliverPostJob") {
val create = string("create")
val inbox = string("inbox")
val actor = string("actor")
override fun convert(value: DeliverPostJobParam): ScheduleContext<DeliverPostJob>.(DeliverPostJob) -> Unit = {
props[create] = value.create
props[inbox] = value.inbox
props[actor] = value.actor
}
override fun convert(props: JobProps<DeliverPostJob>): DeliverPostJobParam = DeliverPostJobParam(
create = props[create],
inbox = props[inbox],
actor = props[actor]
)
}
data class DeliverReactionJobParam(
val reaction: String,
val postUrl: String,
val actor: String,
val inbox: String,
val id: String
)
@Component
object DeliverReactionJob : HideoutJob<DeliverReactionJobParam, DeliverReactionJob>("DeliverReactionJob") {
val reaction: Prop<DeliverReactionJob, String> = string("reaction")
val postUrl: Prop<DeliverReactionJob, String> = string("postUrl")
val actor: Prop<DeliverReactionJob, String> = string("actor")
val inbox: Prop<DeliverReactionJob, String> = string("inbox")
val id: Prop<DeliverReactionJob, String> = string("id")
override fun convert(
value: DeliverReactionJobParam
): ScheduleContext<DeliverReactionJob>.(DeliverReactionJob) -> Unit =
{
props[reaction] = value.reaction
props[postUrl] = value.postUrl
props[actor] = value.actor
props[inbox] = value.inbox
props[id] = value.id
}
override fun convert(props: JobProps<DeliverReactionJob>): DeliverReactionJobParam = DeliverReactionJobParam(
props[reaction],
props[postUrl],
props[actor],
props[inbox],
props[id]
)
}
data class DeliverRemoveReactionJobParam(
val id: String,
val inbox: String,
val actor: String,
val like: String
)
@Component
object DeliverRemoveReactionJob :
HideoutJob<DeliverRemoveReactionJobParam, DeliverRemoveReactionJob>("DeliverRemoveReactionJob") {
val id: Prop<DeliverRemoveReactionJob, String> = string("id")
val inbox: Prop<DeliverRemoveReactionJob, String> = string("inbox")
val actor: Prop<DeliverRemoveReactionJob, String> = string("actor")
val like: Prop<DeliverRemoveReactionJob, String> = string("like")
override fun convert(
value: DeliverRemoveReactionJobParam
): ScheduleContext<DeliverRemoveReactionJob>.(DeliverRemoveReactionJob) -> Unit =
{
props[id] = value.id
props[inbox] = value.inbox
props[actor] = value.actor
props[like] = value.like
}
override fun convert(props: JobProps<DeliverRemoveReactionJob>): DeliverRemoveReactionJobParam =
DeliverRemoveReactionJobParam(
id = props[id],
inbox = props[inbox],
actor = props[actor],
like = props[like]
)
}
data class InboxJobParam(
val json: String,
val type: ActivityType,
val httpRequest: String,
val headers: String
)
@Component
object InboxJob : HideoutJob<InboxJobParam, InboxJob>("InboxJob") {
val json = string("json")
val type = string("type")
val httpRequest = string("http_request")
val headers = string("headers")
override fun convert(value: InboxJobParam): ScheduleContext<InboxJob>.(InboxJob) -> Unit = {
props[json] = value.json
props[type] = value.type.name
props[httpRequest] = value.httpRequest
props[headers] = value.headers
}
override fun convert(props: JobProps<InboxJob>): InboxJobParam = InboxJobParam(
props[json],
ActivityType.valueOf(props[type]),
props[httpRequest],
props[headers]
)
}

View File

@ -18,7 +18,10 @@ package dev.usbharu.hideout.core.external.job
import dev.usbharu.hideout.activitypub.service.common.ActivityType
import dev.usbharu.httpsignature.common.HttpRequest
import dev.usbharu.owl.common.property.PropertyValue
import dev.usbharu.owl.common.task.PropertyDefinition
import dev.usbharu.owl.common.task.Task
import dev.usbharu.owl.common.task.TaskDefinition
data class InboxTask(
val json: String,
@ -26,3 +29,28 @@ data class InboxTask(
val httpRequest: HttpRequest,
val headers: Map<String, List<String>>,
) : Task()
data object InboxTaskDef : TaskDefinition<InboxTask> {
override val name: String
get() = TODO("Not yet implemented")
override val priority: Int
get() = TODO("Not yet implemented")
override val maxRetry: Int
get() = TODO("Not yet implemented")
override val retryPolicy: String
get() = TODO("Not yet implemented")
override val timeoutMilli: Long
get() = TODO("Not yet implemented")
override val propertyDefinition: PropertyDefinition
get() = TODO("Not yet implemented")
override val type: Class<InboxTask>
get() = TODO("Not yet implemented")
override fun serialize(task: InboxTask): Map<String, PropertyValue<*>> {
TODO("Not yet implemented")
}
override fun deserialize(value: Map<String, PropertyValue<*>>): InboxTask {
TODO("Not yet implemented")
}
}

View File

@ -17,10 +17,38 @@
package dev.usbharu.hideout.core.external.job
import dev.usbharu.hideout.activitypub.domain.model.Follow
import dev.usbharu.owl.common.property.PropertyValue
import dev.usbharu.owl.common.task.PropertyDefinition
import dev.usbharu.owl.common.task.Task
import dev.usbharu.owl.common.task.TaskDefinition
data class ReceiveFollowTask(
val actor: String,
val follow: Follow,
val targetActor: String,
) : Task()
data object ReceiveFollowTaskDef : TaskDefinition<ReceiveFollowTask> {
override val name: String
get() = TODO("Not yet implemented")
override val priority: Int
get() = TODO("Not yet implemented")
override val maxRetry: Int
get() = TODO("Not yet implemented")
override val retryPolicy: String
get() = TODO("Not yet implemented")
override val timeoutMilli: Long
get() = TODO("Not yet implemented")
override val propertyDefinition: PropertyDefinition
get() = TODO("Not yet implemented")
override val type: Class<ReceiveFollowTask>
get() = TODO("Not yet implemented")
override fun deserialize(value: Map<String, PropertyValue<*>>): ReceiveFollowTask {
TODO("Not yet implemented")
}
override fun serialize(task: ReceiveFollowTask): Map<String, PropertyValue<*>> {
TODO("Not yet implemented")
}
}

View File

@ -1,58 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.infrastructure.kjobexposed
import dev.usbharu.hideout.core.external.job.HideoutJob
import dev.usbharu.hideout.core.service.job.JobQueueParentService
import kjob.core.Job
import kjob.core.KJob
import kjob.core.dsl.ScheduleContext
import kjob.core.kjob
import org.jetbrains.exposed.sql.transactions.TransactionManager
import org.slf4j.LoggerFactory
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.stereotype.Service
@Service
@ConditionalOnProperty(name = ["hideout.use-mongodb"], havingValue = "false", matchIfMissing = true)
class KJobJobQueueParentService : JobQueueParentService {
private val logger = LoggerFactory.getLogger(this::class.java)
val kjob: KJob by lazy {
kjob(ExposedKJob) {
connectionDatabase = TransactionManager.defaultDatabase
isWorker = false
}.start()
}
override fun init(jobDefines: List<Job>) = Unit
@Deprecated("use type safe → scheduleTypeSafe")
override suspend fun <J : Job> schedule(job: J, block: ScheduleContext<J>.(J) -> Unit) {
logger.debug("schedule job={}", job.name)
kjob.schedule(job, block)
}
override suspend fun <T, J : HideoutJob<T, J>> scheduleTypeSafe(job: J, jobProps: T) {
logger.debug("SCHEDULE Job: {}", job.name)
logger.trace("Job props: {}", jobProps)
val convert: ScheduleContext<J>.(J) -> Unit = job.convert(jobProps)
kjob.schedule(job, convert)
logger.debug("SUCCESS Schedule Job: {}", job.name)
}
}

View File

@ -1,70 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.infrastructure.kjobexposed
import dev.usbharu.hideout.core.external.job.HideoutJob
import dev.usbharu.hideout.core.service.job.JobProcessor
import dev.usbharu.hideout.core.service.job.JobQueueWorkerService
import kjob.core.dsl.JobContextWithProps
import kjob.core.dsl.JobRegisterContext
import kjob.core.dsl.KJobFunctions
import kjob.core.kjob
import org.jetbrains.exposed.sql.transactions.TransactionManager
import org.slf4j.MDC
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.stereotype.Service
@Service
@ConditionalOnProperty(name = ["hideout.use-mongodb"], havingValue = "false", matchIfMissing = true)
class KJobJobQueueWorkerService(private val jobQueueProcessorList: List<JobProcessor<*, *>>) : JobQueueWorkerService {
val kjob by lazy {
kjob(ExposedKJob) {
connectionDatabase = TransactionManager.defaultDatabase
nonBlockingMaxJobs = 10
blockingMaxJobs = 10
jobExecutionPeriodInSeconds = 1
}.start()
}
override fun <T, R : HideoutJob<T, R>> init(
defines:
List<Pair<R, JobRegisterContext<R, JobContextWithProps<R>>.(R) -> KJobFunctions<R, JobContextWithProps<R>>>>
) {
defines.forEach { job ->
kjob.register(job.first, job.second)
}
for (jobProcessor in jobQueueProcessorList) {
kjob.register(jobProcessor.job()) {
execute {
@Suppress("TooGenericExceptionCaught")
try {
MDC.put("x-job-id", this.jobId)
val param = it.convertUnsafe(props)
jobProcessor.process(param)
} catch (e: Exception) {
logger.warn("FAILED Execute Job. job name: {} job id: {}", it.name, this.jobId, e)
throw e
} finally {
MDC.remove("x-job-id")
}
}
}
}
}
}

View File

@ -1,84 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.infrastructure.kjobmongodb
import com.mongodb.reactivestreams.client.MongoClient
import dev.usbharu.hideout.core.external.job.HideoutJob
import dev.usbharu.hideout.core.service.job.JobProcessor
import dev.usbharu.hideout.core.service.job.JobQueueWorkerService
import kjob.core.dsl.JobContextWithProps
import kjob.core.dsl.JobRegisterContext
import kjob.core.dsl.KJobFunctions
import kjob.core.job.JobExecutionType
import kjob.core.kjob
import kjob.mongo.Mongo
import kotlinx.coroutines.CancellationException
import org.slf4j.MDC
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.stereotype.Service
@Service
@ConditionalOnProperty(name = ["hideout.use-mongodb"], havingValue = "true", matchIfMissing = false)
class KJobMongoJobQueueWorkerService(
private val mongoClient: MongoClient,
private val jobQueueProcessorList: List<JobProcessor<*, *>>
) : JobQueueWorkerService, AutoCloseable {
val kjob by lazy {
kjob(Mongo) {
client = mongoClient
nonBlockingMaxJobs = 10
blockingMaxJobs = 10
jobExecutionPeriodInSeconds = 1
maxRetries = 3
defaultJobExecutor = JobExecutionType.NON_BLOCKING
}.start()
}
override fun <T, R : HideoutJob<T, R>> init(
defines:
List<Pair<R, JobRegisterContext<R, JobContextWithProps<R>>.(R) -> KJobFunctions<R, JobContextWithProps<R>>>>
) {
defines.forEach { job ->
kjob.register(job.first, job.second)
}
for (jobProcessor in jobQueueProcessorList) {
kjob.register(jobProcessor.job()) {
execute {
@Suppress("TooGenericExceptionCaught")
try {
MDC.put("x-job-id", this.jobId)
val param = it.convertUnsafe(props)
jobProcessor.process(param)
} catch (e: CancellationException) {
throw e
} catch (e: Exception) {
logger.warn("FAILED Excute Job. job name: {} job id: {}", it.name, this.jobId, e)
throw e
} finally {
MDC.remove("x-job-id")
}
}.onError {
logger.warn("FAILED Excute Job. job name: {} job id: {}", this.jobName, this.jobId, error)
}
}
}
}
override fun close() {
kjob.shutdown()
}
}

View File

@ -1,65 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.infrastructure.kjobmongodb
import com.mongodb.reactivestreams.client.MongoClient
import dev.usbharu.hideout.core.external.job.HideoutJob
import dev.usbharu.hideout.core.service.job.JobQueueParentService
import kjob.core.Job
import kjob.core.dsl.ScheduleContext
import kjob.core.kjob
import kjob.mongo.Mongo
import org.slf4j.LoggerFactory
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.stereotype.Service
@Service
@ConditionalOnProperty(name = ["hideout.use-mongodb"], havingValue = "true", matchIfMissing = false)
class KjobMongoJobQueueParentService(private val mongoClient: MongoClient) : JobQueueParentService, AutoCloseable {
private val kjob = kjob(Mongo) {
client = mongoClient
databaseName = "kjob"
jobCollection = "kjob-jobs"
lockCollection = "kjob-locks"
expireLockInMinutes = 5L
isWorker = false
}.start()
override fun init(jobDefines: List<Job>) = Unit
@Deprecated("use type safe → scheduleTypeSafe")
override suspend fun <J : Job> schedule(job: J, block: ScheduleContext<J>.(J) -> Unit) {
logger.debug("SCHEDULE Job: {}", job.name)
kjob.schedule(job, block)
}
override suspend fun <T, J : HideoutJob<T, J>> scheduleTypeSafe(job: J, jobProps: T) {
logger.debug("SCHEDULE Job: {}", job.name)
logger.trace("Job props: {}", jobProps)
val convert = job.convert(jobProps)
kjob.schedule(job, convert)
logger.debug("SUCCESS Job: {}", job.name)
}
override fun close() {
kjob.shutdown()
}
companion object {
private val logger = LoggerFactory.getLogger(KjobMongoJobQueueParentService::class.java)
}
}

View File

@ -1,25 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.service.job
import dev.usbharu.hideout.core.external.job.HideoutJob
@Deprecated("use owl")
interface JobProcessor<in T, out R : HideoutJob<@UnsafeVariance T, R>> {
suspend fun process(param: @UnsafeVariance T)
fun job(): R
}

View File

@ -1,31 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.core.service.job
import kjob.core.dsl.KJobFunctions
import org.springframework.stereotype.Service
import dev.usbharu.hideout.core.external.job.HideoutJob as HJ
import kjob.core.dsl.JobContextWithProps as JCWP
import kjob.core.dsl.JobRegisterContext as JRC
@Deprecated("use owl")
@Service
interface JobQueueWorkerService {
fun <T, R : HJ<T, R>> init(
defines: List<Pair<R, JRC<R, JCWP<R>>.(R) -> KJobFunctions<R, JCWP<R>>>>
)
}

View File

@ -1,86 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.activitypub.service.activity.accept
import dev.usbharu.hideout.activitypub.domain.model.Accept
import dev.usbharu.hideout.activitypub.domain.model.Follow
import dev.usbharu.hideout.activitypub.service.common.APRequestService
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.external.job.DeliverAcceptJob
import dev.usbharu.hideout.core.external.job.DeliverAcceptJobParam
import kotlinx.coroutines.test.runTest
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.InjectMocks
import org.mockito.Mock
import org.mockito.Spy
import org.mockito.junit.jupiter.MockitoExtension
import org.mockito.kotlin.*
import utils.TestTransaction
import utils.UserBuilder
@ExtendWith(MockitoExtension::class)
class APDeliverAcceptJobProcessorTest {
@Mock
private lateinit var apRequestService: APRequestService
@Mock
private lateinit var actorRepository: ActorRepository
@Mock
private lateinit var deliverAcceptJob: DeliverAcceptJob
@Spy
private val transaction = TestTransaction
@InjectMocks
private lateinit var apDeliverAcceptJobProcessor: APDeliverAcceptJobProcessor
@Test
fun `process apPostが発行される`() = runTest {
val user = UserBuilder.localUserOf()
whenever(actorRepository.findById(eq(1))).doReturn(user)
val accept = Accept(
apObject = Follow(
apObject = "https://example.com",
actor = "https://remote.example.com"
),
actor = "https://example.com"
)
val param = DeliverAcceptJobParam(
accept = accept,
"https://remote.example.com",
1
)
apDeliverAcceptJobProcessor.process(param)
verify(apRequestService, times(1)).apPost(eq("https://remote.example.com"), eq(accept), eq(user))
}
@Test
fun `job DeliverAcceptJobが返ってくる`() {
val actual = apDeliverAcceptJobProcessor.job()
assertThat(actual).isEqualTo(deliverAcceptJob)
}
}

View File

@ -1,61 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.activitypub.service.activity.accept
import dev.usbharu.hideout.activitypub.domain.model.Accept
import dev.usbharu.hideout.activitypub.domain.model.Follow
import dev.usbharu.hideout.core.external.job.DeliverAcceptJob
import dev.usbharu.hideout.core.external.job.DeliverAcceptJobParam
import dev.usbharu.hideout.core.service.job.JobQueueParentService
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.InjectMocks
import org.mockito.Mock
import org.mockito.junit.jupiter.MockitoExtension
import org.mockito.kotlin.eq
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import utils.UserBuilder
@ExtendWith(MockitoExtension::class)
class ApSendAcceptServiceImplTest {
@Mock
private lateinit var jobQueueParentService: JobQueueParentService
@Mock
private lateinit var deliverAcceptJob: DeliverAcceptJob
@InjectMocks
private lateinit var apSendAcceptServiceImpl: ApSendAcceptServiceImpl
@Test
fun `sendAccept DeliverAcceptJobが発行される`() = runTest {
val user = UserBuilder.localUserOf()
val remoteUser = UserBuilder.remoteUserOf()
apSendAcceptServiceImpl.sendAcceptFollow(user, remoteUser)
val deliverAcceptJobParam = DeliverAcceptJobParam(
Accept(apObject = Follow(apObject = user.url, actor = remoteUser.url), actor = user.url),
remoteUser.inbox,
user.id
)
verify(jobQueueParentService, times(1)).scheduleTypeSafe(eq(deliverAcceptJob), eq(deliverAcceptJobParam))
}
}

View File

@ -1,94 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.activitypub.service.activity.block
import dev.usbharu.hideout.activitypub.domain.model.Block
import dev.usbharu.hideout.activitypub.domain.model.Follow
import dev.usbharu.hideout.activitypub.domain.model.Reject
import dev.usbharu.hideout.activitypub.service.common.APRequestService
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.external.job.DeliverBlockJob
import dev.usbharu.hideout.core.external.job.DeliverBlockJobParam
import kotlinx.coroutines.test.runTest
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.InjectMocks
import org.mockito.Mock
import org.mockito.Spy
import org.mockito.junit.jupiter.MockitoExtension
import org.mockito.kotlin.*
import utils.TestTransaction
import utils.UserBuilder
@ExtendWith(MockitoExtension::class)
class APDeliverBlockJobProcessorTest {
@Mock
private lateinit var apRequestService: APRequestService
@Mock
private lateinit var actorRepository: ActorRepository
@Spy
private val transaction = TestTransaction
@Mock
private lateinit var deliverBlockJob: DeliverBlockJob
@InjectMocks
private lateinit var apDeliverBlockJobProcessor: APDeliverBlockJobProcessor
@Test
fun `process rejectとblockがapPostされる`() = runTest {
val user = UserBuilder.localUserOf()
whenever(actorRepository.findById(eq(user.id))).doReturn(user)
val block = Block(
actor = user.url,
"https://example.com/block",
apObject = "https://remote.example.com"
)
val reject = Reject(
actor = user.url,
"https://example.com/reject/follow",
apObject = Follow(
apObject = user.url,
actor = "https://remote.example.com"
)
)
val param = DeliverBlockJobParam(
user.id,
block,
reject,
"https://remote.example.com"
)
apDeliverBlockJobProcessor.process(param)
verify(apRequestService, times(1)).apPost(eq("https://remote.example.com"), eq(block), eq(user))
verify(apRequestService, times(1)).apPost(eq("https://remote.example.com"), eq(reject), eq(user))
}
@Test
fun `job deliverBlockJobが返ってくる`() {
val actual = apDeliverBlockJobProcessor.job()
assertThat(actual).isEqualTo(deliverBlockJob)
}
}

View File

@ -1,94 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.activitypub.service.activity.create
import com.fasterxml.jackson.databind.ObjectMapper
import dev.usbharu.hideout.activitypub.domain.model.Note
import dev.usbharu.hideout.activitypub.query.NoteQueryService
import dev.usbharu.hideout.activitypub.service.objects.note.APNoteServiceImpl
import dev.usbharu.hideout.application.config.ActivityPubConfig
import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.external.job.DeliverPostJob
import dev.usbharu.hideout.core.query.FollowerQueryService
import dev.usbharu.hideout.core.service.job.JobQueueParentService
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.InjectMocks
import org.mockito.Mock
import org.mockito.Spy
import org.mockito.junit.jupiter.MockitoExtension
import org.mockito.kotlin.*
import utils.PostBuilder
import utils.UserBuilder
import java.net.URL
import java.time.Instant
@ExtendWith(MockitoExtension::class)
class ApSendCreateServiceImplTest {
@Mock
private lateinit var followerQueryService: FollowerQueryService
@Spy
private val objectMapper: ObjectMapper = ActivityPubConfig().objectMapper()
@Mock
private lateinit var jobQueueParentService: JobQueueParentService
@Mock
private lateinit var actorRepository: ActorRepository
@Mock
private lateinit var noteQueryService: NoteQueryService
@Spy
private val applicationConfig: ApplicationConfig = ApplicationConfig(URL("https://example.com"))
@InjectMocks
private lateinit var apSendCreateServiceImpl: ApSendCreateServiceImpl
@Test
fun `createNote 正常なPostでCreateのジョブを発行できる`() = runTest {
val post = PostBuilder.of()
val user = UserBuilder.localUserOf(id = post.actorId)
val note = Note(
id = post.apId,
attributedTo = user.url,
content = post.text,
published = Instant.ofEpochMilli(post.createdAt).toString(),
to = listOfNotNull(APNoteServiceImpl.public, user.followers),
sensitive = post.sensitive,
cc = listOfNotNull(APNoteServiceImpl.public, user.followers),
inReplyTo = null
)
val followers = listOf(
UserBuilder.remoteUserOf(),
UserBuilder.remoteUserOf(),
UserBuilder.remoteUserOf()
)
whenever(followerQueryService.findFollowersById(eq(post.actorId))).doReturn(followers)
whenever(actorRepository.findById(eq(post.actorId))).doReturn(user)
whenever(noteQueryService.findById(eq(post.id))).doReturn(note to post)
apSendCreateServiceImpl.createNote(post)
verify(jobQueueParentService, times(followers.size)).schedule(eq(DeliverPostJob), any())
}
}

View File

@ -1,114 +0,0 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.activitypub.service.activity.like
import dev.usbharu.hideout.application.service.id.TwitterSnowflakeIdGenerateService
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.domain.model.emoji.UnicodeEmoji
import dev.usbharu.hideout.core.domain.model.post.PostRepository
import dev.usbharu.hideout.core.domain.model.reaction.Reaction
import dev.usbharu.hideout.core.external.job.DeliverReactionJob
import dev.usbharu.hideout.core.external.job.DeliverRemoveReactionJob
import dev.usbharu.hideout.core.query.FollowerQueryService
import dev.usbharu.hideout.core.service.job.JobQueueParentService
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Test
import org.mockito.kotlin.*
import utils.JsonObjectMapper.objectMapper
import utils.PostBuilder
import utils.UserBuilder
class APReactionServiceImplTest {
@Test
fun `reaction リアクションするとフォロワーの数だけ配送ジョブが作成される`() = runTest {
val user = UserBuilder.localUserOf()
val post = PostBuilder.of()
val postQueryService = mock<PostRepository> {
onBlocking { findById(eq(post.id)) } doReturn post
}
val followerQueryService = mock<FollowerQueryService> {
onBlocking { findFollowersById(eq(user.id)) } doReturn listOf(
UserBuilder.localUserOf(),
UserBuilder.localUserOf(),
UserBuilder.localUserOf()
)
}
val jobQueueParentService = mock<JobQueueParentService>()
val actorRepository = mock<ActorRepository> {
onBlocking { findById(eq(user.id)) }.doReturn(user)
}
val apReactionServiceImpl = APReactionServiceImpl(
actorRepository = actorRepository,
followerQueryService = followerQueryService,
postRepository = postQueryService,
)
apReactionServiceImpl.reaction(
Reaction(
id = TwitterSnowflakeIdGenerateService.generateId(),
emoji = UnicodeEmoji(""),
postId = post.id,
actorId = user.id
)
)
verify(jobQueueParentService, times(3)).schedule(eq(DeliverReactionJob), any())
}
@Test
fun `removeReaction リアクションを削除するとフォロワーの数だけ配送ジョブが作成される`() = runTest {
val user = UserBuilder.localUserOf()
val post = PostBuilder.of()
val postQueryService = mock<PostRepository> {
onBlocking { findById(eq(post.id)) } doReturn post
}
val followerQueryService = mock<FollowerQueryService> {
onBlocking { findFollowersById(eq(user.id)) } doReturn listOf(
UserBuilder.localUserOf(),
UserBuilder.localUserOf(),
UserBuilder.localUserOf()
)
}
val jobQueueParentService = mock<JobQueueParentService>()
val actorRepository = mock<ActorRepository> {
onBlocking { findById(eq(user.id)) }.doReturn(user)
}
val apReactionServiceImpl = APReactionServiceImpl(
jobQueueParentService = jobQueueParentService,
actorRepository = actorRepository,
followerQueryService = followerQueryService,
postRepository = postQueryService,
objectMapper = objectMapper
)
apReactionServiceImpl.removeReaction(
Reaction(
id = TwitterSnowflakeIdGenerateService.generateId(),
emoji = UnicodeEmoji(""),
postId = post.id,
actorId = user.id
)
)
verify(jobQueueParentService, times(3)).schedule(eq(DeliverRemoveReactionJob), any())
}
}

View File

@ -27,7 +27,7 @@ class APServiceImplTest {
@Test
fun `parseActivity 正常なActivityをパースできる`() {
val apServiceImpl = APServiceImpl(
objectMapper = objectMapper, jobQueueParentService = mock()
objectMapper = objectMapper, owlProducer = mock()
)
//language=JSON
@ -39,7 +39,7 @@ class APServiceImplTest {
@Test
fun `parseActivity Typeが配列のActivityをパースできる`() {
val apServiceImpl = APServiceImpl(
objectMapper = objectMapper, jobQueueParentService = mock()
objectMapper = objectMapper, owlProducer = mock()
)
//language=JSON
@ -51,7 +51,7 @@ class APServiceImplTest {
@Test
fun `parseActivity Typeが配列で関係ない物が入っていてもパースできる`() {
val apServiceImpl = APServiceImpl(
objectMapper = objectMapper, jobQueueParentService = mock()
objectMapper = objectMapper, owlProducer = mock()
)
//language=JSON
@ -64,7 +64,7 @@ class APServiceImplTest {
fun `parseActivity jsonとして解釈できない場合JsonParseExceptionがthrowされる`() {
val apServiceImpl = APServiceImpl(
objectMapper = objectMapper, jobQueueParentService = mock()
objectMapper = objectMapper, owlProducer = mock()
)
//language=JSON
@ -77,7 +77,7 @@ class APServiceImplTest {
fun `parseActivity 空の場合JsonParseExceptionがthrowされる`() {
val apServiceImpl = APServiceImpl(
objectMapper = objectMapper, jobQueueParentService = mock()
objectMapper = objectMapper, owlProducer = mock()
)
//language=JSON
@ -90,7 +90,7 @@ class APServiceImplTest {
fun `parseActivity jsonにtypeプロパティがない場合JsonParseExceptionがthrowされる`() {
val apServiceImpl = APServiceImpl(
objectMapper = objectMapper, jobQueueParentService = mock()
objectMapper = objectMapper, owlProducer = mock()
)
//language=JSON
@ -103,7 +103,7 @@ class APServiceImplTest {
fun `parseActivity typeが配列でないときtypeが未定義の場合IllegalArgumentExceptionがthrowされる`() {
val apServiceImpl = APServiceImpl(
objectMapper = objectMapper, jobQueueParentService = mock()
objectMapper = objectMapper, owlProducer = mock()
)
//language=JSON
@ -116,7 +116,7 @@ class APServiceImplTest {
fun `parseActivity typeが配列のとき定義済みのtypeを見つけられなかった場合IllegalArgumentExceptionがthrowされる`() {
val apServiceImpl = APServiceImpl(
objectMapper = objectMapper, jobQueueParentService = mock()
objectMapper = objectMapper, owlProducer = mock()
)
//language=JSON
@ -129,7 +129,7 @@ class APServiceImplTest {
fun `parseActivity typeが空の場合IllegalArgumentExceptionがthrowされる`() {
val apServiceImpl = APServiceImpl(
objectMapper = objectMapper, jobQueueParentService = mock()
objectMapper = objectMapper, owlProducer = mock()
)
//language=JSON
@ -142,7 +142,7 @@ class APServiceImplTest {
fun `parseActivity typeに指定されている文字の判定がcase-insensitiveで行われる`() {
val apServiceImpl = APServiceImpl(
objectMapper = objectMapper, jobQueueParentService = mock()
objectMapper = objectMapper, owlProducer = mock()
)
//language=JSON
@ -155,7 +155,7 @@ class APServiceImplTest {
fun `parseActivity typeが配列のとき指定されている文字の判定がcase-insensitiveで行われる`() {
val apServiceImpl = APServiceImpl(
objectMapper = objectMapper, jobQueueParentService = mock()
objectMapper = objectMapper, owlProducer = mock()
)
//language=JSON
@ -168,7 +168,7 @@ class APServiceImplTest {
fun `parseActivity activityがarrayのときJsonParseExceptionがthrowされる`() {
val apServiceImpl = APServiceImpl(
objectMapper = objectMapper, jobQueueParentService = mock()
objectMapper = objectMapper, owlProducer = mock()
)
//language=JSON
@ -181,7 +181,7 @@ class APServiceImplTest {
fun `parseActivity activityがvalueのときJsonParseExceptionがthrowされる`() {
val apServiceImpl = APServiceImpl(
objectMapper = objectMapper, jobQueueParentService = mock()
objectMapper = objectMapper, owlProducer = mock()
)
//language=JSON

View File

@ -16,7 +16,6 @@
package dev.usbharu.hideout.mastodon.interfaces.api.status
import Status
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import dev.usbharu.hideout.core.infrastructure.springframework.security.OAuth2JwtLoginUserContextHolder
import dev.usbharu.hideout.domain.mastodon.model.generated.Account

View File

@ -16,7 +16,6 @@
package dev.usbharu.hideout.mastodon.interfaces.api.timeline
import Status
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList

View File

@ -16,7 +16,6 @@
package dev.usbharu.hideout.mastodon.service.account
import Status
import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.application.infrastructure.exposed.Page
import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList

View File

@ -1,5 +1,11 @@
plugins {
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.kotlin.spring)
alias(libs.plugins.spring.boot)
}
apply {
plugin("io.spring.dependency-management")
}
group = "dev.usbharu"
@ -7,11 +13,41 @@ version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
maven {
url = uri("https://git.usbharu.dev/api/packages/usbharu/maven")
}
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/usbharu/http-signature")
credentials {
username = project.findProperty("gpr.user") as String? ?: System.getenv("USERNAME")
password = project.findProperty("gpr.key") as String? ?: System.getenv("TOKEN")
}
}
maven {
name = "GitHubPackages2"
url = uri("https://maven.pkg.github.com/multim-dev/emoji-kt")
credentials {
username = project.findProperty("gpr.user") as String? ?: System.getenv("USERNAME")
password = project.findProperty("gpr.key") as String? ?: System.getenv("TOKEN")
}
}
}
dependencies {
testImplementation(kotlin("test"))
implementation("dev.usbharu:owl-consumer:0.0.1")
implementation("dev.usbharu:owl-common:0.0.1")
implementation("dev.usbharu:hideout-core:0.0.1")
implementation("dev.usbharu:http-signature:1.0.0")
implementation("org.springframework.boot:spring-boot-starter")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation(libs.jackson.databind)
implementation(libs.jackson.module.kotlin)
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
tasks.test {

View File

@ -16,15 +16,31 @@
package dev.usbharu.hideout.worker
import dev.usbharu.hideout.activitypub.service.common.APRequestService
import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.external.job.DeliverAcceptTask
import dev.usbharu.hideout.core.external.job.DeliverAcceptTaskDef
import dev.usbharu.owl.consumer.AbstractTaskRunner
import dev.usbharu.owl.consumer.TaskRequest
import dev.usbharu.owl.consumer.TaskResult
import dev.usbharu.owl.consumer.TaskRunner
import org.springframework.stereotype.Component
class DeliverAcceptTaskRunner : TaskRunner {
override val name: String
get() = ""
@Component
class DeliverAcceptTaskRunner(
private val apRequestService: APRequestService,
private val actorRepository: ActorRepository,
private val transaction: Transaction,
) : AbstractTaskRunner<DeliverAcceptTask, DeliverAcceptTaskDef>(DeliverAcceptTaskDef) {
override suspend fun typedRun(typedParam: DeliverAcceptTask, taskRequest: TaskRequest): TaskResult {
override suspend fun run(taskRequest: TaskRequest): TaskResult {
TODO("Not yet implemented")
transaction.transaction {
apRequestService.apPost(
typedParam.inbox,
typedParam.accept,
actorRepository.findById(typedParam.signer)
)
}
return TaskResult.ok()
}
}

View File

@ -14,26 +14,31 @@
* limitations under the License.
*/
package dev.usbharu.hideout.activitypub.service.activity.undo
package dev.usbharu.hideout.worker
import dev.usbharu.hideout.activitypub.service.common.APRequestService
import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.external.job.DeliverUndoJob
import dev.usbharu.hideout.core.external.job.DeliverUndoJobParam
import dev.usbharu.hideout.core.service.job.JobProcessor
import org.springframework.stereotype.Service
import dev.usbharu.hideout.core.external.job.DeliverCreateTask
import dev.usbharu.hideout.core.external.job.DeliverCreateTaskDef
import dev.usbharu.owl.consumer.AbstractTaskRunner
import dev.usbharu.owl.consumer.TaskRequest
import dev.usbharu.owl.consumer.TaskResult
import org.springframework.stereotype.Component
@Service
class APDeliverUndoJobProcessor(
private val deliverUndoJob: DeliverUndoJob,
private val apRequestService: APRequestService,
@Component
class DeliverCreateTaskRunner(
private val transaction: Transaction,
private val actorRepository: ActorRepository
) : JobProcessor<DeliverUndoJobParam, DeliverUndoJob> {
override suspend fun process(param: DeliverUndoJobParam): Unit = transaction.transaction {
apRequestService.apPost(param.inbox, param.undo, actorRepository.findById(param.signer))
}
private val apRequestService: APRequestService,
private val actorRepository: ActorRepository,
) : AbstractTaskRunner<DeliverCreateTask, DeliverCreateTaskDef>(DeliverCreateTaskDef) {
override suspend fun typedRun(typedParam: DeliverCreateTask, taskRequest: TaskRequest): TaskResult {
transaction.transaction {
val signer = actorRepository.findByUrl(typedParam.actor)
override fun job(): DeliverUndoJob = deliverUndoJob
}
apRequestService.apPost(typedParam.inbox, typedParam.create, signer)
}
return TaskResult.ok()
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.worker
import dev.usbharu.hideout.activitypub.service.common.APRequestService
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.external.job.DeliverDeleteTask
import dev.usbharu.hideout.core.external.job.DeliverDeleteTaskDef
import dev.usbharu.owl.consumer.AbstractTaskRunner
import dev.usbharu.owl.consumer.TaskRequest
import dev.usbharu.owl.consumer.TaskResult
import org.springframework.stereotype.Component
@Component
class DeliverDeleteTaskRunner(
private val apRequestService: APRequestService,
private val actorRepository: ActorRepository,
) :
AbstractTaskRunner<DeliverDeleteTask, DeliverDeleteTaskDef>(DeliverDeleteTaskDef) {
override suspend fun typedRun(typedParam: DeliverDeleteTask, taskRequest: TaskRequest): TaskResult {
apRequestService.apPost(typedParam.inbox, typedParam.delete, actorRepository.findById(typedParam.signer))
return TaskResult.ok()
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.worker
import dev.usbharu.hideout.activitypub.service.common.APRequestService
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.external.job.DeliverReactionTask
import dev.usbharu.hideout.core.external.job.DeliverReactionTaskDef
import dev.usbharu.owl.consumer.AbstractTaskRunner
import dev.usbharu.owl.consumer.TaskRequest
import dev.usbharu.owl.consumer.TaskResult
import org.springframework.stereotype.Component
@Component
class DeliverReactionTaskRunner(
private val apRequestService: APRequestService,
private val actorRepository: ActorRepository,
) : AbstractTaskRunner<DeliverReactionTask, DeliverReactionTaskDef>(DeliverReactionTaskDef) {
override suspend fun typedRun(typedParam: DeliverReactionTask, taskRequest: TaskRequest): TaskResult {
val signer = actorRepository.findByUrl(typedParam.actor)
apRequestService.apPost(
typedParam.inbox,
typedParam.like,
signer
)
return TaskResult.ok()
}
}

View File

@ -14,27 +14,30 @@
* limitations under the License.
*/
package dev.usbharu.hideout.activitypub.service.activity.accept
package dev.usbharu.hideout.worker
import dev.usbharu.hideout.activitypub.service.common.APRequestService
import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.external.job.DeliverAcceptJob
import dev.usbharu.hideout.core.external.job.DeliverAcceptJobParam
import dev.usbharu.hideout.core.service.job.JobProcessor
import org.springframework.stereotype.Service
import dev.usbharu.hideout.core.external.job.DeliverRejectTask
import dev.usbharu.hideout.core.external.job.DeliverRejectTaskDef
import dev.usbharu.owl.consumer.AbstractTaskRunner
import dev.usbharu.owl.consumer.TaskRequest
import dev.usbharu.owl.consumer.TaskResult
import org.springframework.stereotype.Component
@Service
class APDeliverAcceptJobProcessor(
private val apRequestService: APRequestService,
private val deliverAcceptJob: DeliverAcceptJob,
@Component
class DeliverRejectTaskRunner(
private val transaction: Transaction,
private val actorRepository: ActorRepository
) :
JobProcessor<DeliverAcceptJobParam, DeliverAcceptJob> {
override suspend fun process(param: DeliverAcceptJobParam): Unit = transaction.transaction {
apRequestService.apPost(param.inbox, param.accept, actorRepository.findById(param.signer))
}
private val apRequestService: APRequestService,
private val actorRepository: ActorRepository,
) : AbstractTaskRunner<DeliverRejectTask, DeliverRejectTaskDef>(DeliverRejectTaskDef) {
override suspend fun typedRun(typedParam: DeliverRejectTask, taskRequest: TaskRequest): TaskResult {
val signer = transaction.transaction {
actorRepository.findById(typedParam.signer)
}
apRequestService.apPost(typedParam.inbox, typedParam.reject, signer)
override fun job(): DeliverAcceptJob = deliverAcceptJob
}
return TaskResult.ok()
}
}

View File

@ -14,27 +14,30 @@
* limitations under the License.
*/
package dev.usbharu.hideout.activitypub.service.activity.reject
package dev.usbharu.hideout.worker
import dev.usbharu.hideout.activitypub.service.common.APRequestService
import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.external.job.DeliverRejectJob
import dev.usbharu.hideout.core.external.job.DeliverRejectJobParam
import dev.usbharu.hideout.core.service.job.JobProcessor
import dev.usbharu.hideout.core.external.job.DeliverUndoTask
import dev.usbharu.hideout.core.external.job.DeliverUndoTaskDef
import dev.usbharu.owl.consumer.AbstractTaskRunner
import dev.usbharu.owl.consumer.TaskRequest
import dev.usbharu.owl.consumer.TaskResult
import org.springframework.stereotype.Component
@Component
class APDeliverRejectJobProcessor(
private val apRequestService: APRequestService,
private val deliverRejectJob: DeliverRejectJob,
class DeliverUndoTaskRunner(
private val transaction: Transaction,
private val actorRepository: ActorRepository
) :
JobProcessor<DeliverRejectJobParam, DeliverRejectJob> {
override suspend fun process(param: DeliverRejectJobParam): Unit = transaction.transaction {
apRequestService.apPost(param.inbox, param.reject, actorRepository.findById(param.signer))
}
private val apRequestService: APRequestService,
private val actorRepository: ActorRepository,
) : AbstractTaskRunner<DeliverUndoTask, DeliverUndoTaskDef>(DeliverUndoTaskDef) {
override suspend fun typedRun(typedParam: DeliverUndoTask, taskRequest: TaskRequest): TaskResult {
val signer = transaction.transaction {
actorRepository.findById(typedParam.signer)
}
apRequestService.apPost(typedParam.inbox, typedParam.undo, signer)
override fun job(): DeliverRejectJob = deliverRejectJob
}
return TaskResult.ok()
}
}

View File

@ -14,19 +14,17 @@
* limitations under the License.
*/
package dev.usbharu.hideout.activitypub.service.inbox
package dev.usbharu.hideout.worker
import com.fasterxml.jackson.core.JsonParseException
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import dev.usbharu.hideout.activitypub.domain.model.objects.Object
import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessContext
import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessor
import dev.usbharu.hideout.activitypub.service.objects.user.APUserService
import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.core.external.job.InboxJob
import dev.usbharu.hideout.core.external.job.InboxJobParam
import dev.usbharu.hideout.core.service.job.JobProcessor
import dev.usbharu.hideout.core.external.job.InboxTask
import dev.usbharu.hideout.core.external.job.InboxTaskDef
import dev.usbharu.hideout.util.RsaUtil
import dev.usbharu.httpsignature.common.HttpHeaders
import dev.usbharu.httpsignature.common.HttpMethod
@ -35,28 +33,85 @@ import dev.usbharu.httpsignature.common.PublicKey
import dev.usbharu.httpsignature.verify.HttpSignatureVerifier
import dev.usbharu.httpsignature.verify.Signature
import dev.usbharu.httpsignature.verify.SignatureHeaderParser
import dev.usbharu.owl.consumer.AbstractTaskRunner
import dev.usbharu.owl.consumer.TaskRequest
import dev.usbharu.owl.consumer.TaskResult
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
import org.springframework.stereotype.Component
@Service
class InboxJobProcessor(
@Component
class InboxTaskRunner(
private val activityPubProcessorList: List<ActivityPubProcessor<*>>,
private val objectMapper: ObjectMapper,
private val signatureHeaderParser: SignatureHeaderParser,
private val signatureVerifier: HttpSignatureVerifier,
private val apUserService: APUserService,
private val transaction: Transaction
) : JobProcessor<InboxJobParam, InboxJob> {
private val objectMapper: ObjectMapper,
private val transaction: Transaction,
) : AbstractTaskRunner<InboxTask, InboxTaskDef>(InboxTaskDef) {
@Value("\${hideout.debug.trace-inbox:false}")
private var traceJson: Boolean = false
override suspend fun typedRun(typedParam: InboxTask, taskRequest: TaskRequest): TaskResult {
val jsonNode = objectMapper.readTree(typedParam.json)
logger.info("START Process inbox. type: {}", typedParam.type)
if (traceJson) {
logger.trace("type: {}\njson: \n{}", typedParam.type, jsonNode.toPrettyString())
}
val map = typedParam.headers
val httpRequest = typedParam.httpRequest.copy(headers = HttpHeaders(map))
logger.trace("Request: {}\nheaders: {}", httpRequest, map)
val signature = parseSignatureHeader(httpRequest.headers)
logger.debug("Has signature? {}", signature != null)
// todo 不正なactorを取得してしまわないようにする
val verify =
signature?.let {
verifyHttpSignature(
httpRequest,
it,
transaction,
jsonNode.get("actor")?.asText() ?: signature.keyId
)
}
?: false
logger.debug("Is verifying success? {}", verify)
val activityPubProcessor =
activityPubProcessorList.firstOrNull { it.isSupported(typedParam.type) } as? ActivityPubProcessor<Object>
if (activityPubProcessor == null) {
logger.warn("ActivityType {} is not support.", typedParam.type)
throw IllegalStateException("ActivityPubProcessor not found. type: ${typedParam.type}")
}
val value = try {
objectMapper.treeToValue(jsonNode, activityPubProcessor.type())
} catch (e: JsonParseException) {
logger.warn("Invalid JSON\n\n{}\n\n", jsonNode.toPrettyString())
throw e
}
activityPubProcessor.process(ActivityPubProcessContext(value, jsonNode, httpRequest, signature, verify))
logger.info("SUCCESS Process inbox. type: {}", typedParam.type)
return TaskResult.ok()
}
private suspend fun verifyHttpSignature(
httpRequest: HttpRequest,
signature: Signature,
transaction: Transaction,
actor: String
actor: String,
): Boolean {
val requiredHeaders = when (httpRequest.method) {
HttpMethod.GET -> getRequiredHeaders
@ -96,62 +151,9 @@ class InboxJobProcessor(
}
}
override suspend fun process(param: InboxJobParam) {
val jsonNode = objectMapper.readTree(param.json)
logger.info("START Process inbox. type: {}", param.type)
if (traceJson) {
logger.trace("type: {}\njson: \n{}", param.type, jsonNode.toPrettyString())
}
val map = objectMapper.readValue<Map<String, List<String>>>(param.headers)
val httpRequest = objectMapper.readValue<HttpRequest>(param.httpRequest).copy(headers = HttpHeaders(map))
logger.trace("Request: {}\nheaders: {}", httpRequest, map)
val signature = parseSignatureHeader(httpRequest.headers)
logger.debug("Has signature? {}", signature != null)
// todo 不正なactorを取得してしまわないようにする
val verify =
signature?.let {
verifyHttpSignature(
httpRequest,
it,
transaction,
jsonNode.get("actor")?.asText() ?: signature.keyId
)
}
?: false
logger.debug("Is verifying success? {}", verify)
val activityPubProcessor =
activityPubProcessorList.firstOrNull { it.isSupported(param.type) } as? ActivityPubProcessor<Object>
if (activityPubProcessor == null) {
logger.warn("ActivityType {} is not support.", param.type)
throw IllegalStateException("ActivityPubProcessor not found. type: ${param.type}")
}
val value = try {
objectMapper.treeToValue(jsonNode, activityPubProcessor.type())
} catch (e: JsonParseException) {
logger.warn("Invalid JSON\n\n{}\n\n", jsonNode.toPrettyString())
throw e
}
activityPubProcessor.process(ActivityPubProcessContext(value, jsonNode, httpRequest, signature, verify))
logger.info("SUCCESS Process inbox. type: {}", param.type)
}
override fun job(): InboxJob = InboxJob
companion object {
private val logger = LoggerFactory.getLogger(InboxJobProcessor::class.java)
private val logger = LoggerFactory.getLogger(InboxTaskRunner::class.java)
private val postRequiredHeaders = listOf("(request-target)", "date", "host", "digest")
private val getRequiredHeaders = listOf("(request-target)", "date", "host")
}
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2024 usbharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.usbharu.hideout.worker
import dev.usbharu.hideout.activitypub.service.objects.user.APUserService
import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.external.job.ReceiveFollowTask
import dev.usbharu.hideout.core.external.job.ReceiveFollowTaskDef
import dev.usbharu.hideout.core.service.relationship.RelationshipService
import dev.usbharu.owl.consumer.AbstractTaskRunner
import dev.usbharu.owl.consumer.TaskRequest
import dev.usbharu.owl.consumer.TaskResult
import org.springframework.stereotype.Component
@Component
class ReceiveFollowTaskRunner(
private val transaction: Transaction,
private val apUserService: APUserService,
private val actorRepository: ActorRepository,
private val relationshipService: RelationshipService,
) : AbstractTaskRunner<ReceiveFollowTask, ReceiveFollowTaskDef>(ReceiveFollowTaskDef) {
override suspend fun typedRun(typedParam: ReceiveFollowTask, taskRequest: TaskRequest): TaskResult {
transaction.transaction {
apUserService.fetchPerson(typedParam.actor, typedParam.targetActor)
val targetEntity = actorRepository.findByUrl(typedParam.targetActor) ?: throw UserNotFoundException.withUrl(
typedParam.targetActor
)
val followActorEntity = actorRepository.findByUrl(typedParam.follow.actor)
?: throw UserNotFoundException.withUrl(typedParam.follow.actor)
relationshipService.followRequest(followActorEntity.id, targetEntity.id)
}
return TaskResult.ok()
}
}

View File

@ -11,6 +11,7 @@ serialization = "1.6.3"
kjob = "0.6.0"
tika = "2.9.1"
owl = "0.0.1"
jackson = "2.17.1"
[libraries]
@ -60,6 +61,9 @@ owl-producer-api = { module = "dev.usbharu:owl-producer-api", version.ref = "owl
owl-producer-default = { module = "dev.usbharu:owl-producer-default", version.ref = "owl" }
owl-producer-embedded = { module = "dev.usbharu:owl-producer-embedded", version.ref = "owl" }
jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson" }
jackson-module-kotlin = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jackson" }
[bundles]
exposed = ["exposed-core", "exposed-java-time", "exposed-jdbc", "exposed-spring"]

View File

@ -14,20 +14,20 @@
* limitations under the License.
*/
package dev.usbharu.hideout.core.service.job
package dev.usbharu.owl.consumer
import dev.usbharu.hideout.core.external.job.HideoutJob
import kjob.core.Job
import kjob.core.dsl.ScheduleContext
import org.springframework.stereotype.Service
import dev.usbharu.owl.common.task.Task
import dev.usbharu.owl.common.task.TaskDefinition
@Service
@Deprecated("use owl producer")
interface JobQueueParentService {
abstract class AbstractTaskRunner<T : Task, D : TaskDefinition<T>>(private val taskDefinition: D) : TaskRunner {
override val name: String
get() = taskDefinition.name
fun init(jobDefines: List<Job>)
override suspend fun run(taskRequest: TaskRequest): TaskResult {
val deserialize = taskDefinition.deserialize(taskRequest.properties)
return typedRun(deserialize, taskRequest)
}
@Deprecated("use type safe → scheduleTypeSafe")
suspend fun <J : Job> schedule(job: J, block: ScheduleContext<J>.(J) -> Unit = {})
suspend fun <T, J : HideoutJob<T, J>> scheduleTypeSafe(job: J, jobProps: T)
}
abstract suspend fun typedRun(typedParam: T, taskRequest: TaskRequest): TaskResult
}

View File

@ -43,9 +43,9 @@ class Consumer(
private val subscribeTaskStub: SubscribeTaskServiceGrpcKt.SubscribeTaskServiceCoroutineStub,
private val assignmentTaskStub: AssignmentTaskServiceGrpcKt.AssignmentTaskServiceCoroutineStub,
private val taskResultStub: TaskResultServiceGrpcKt.TaskResultServiceCoroutineStub,
private val runnerMap: Map<String, TaskRunner>,
taskRunnerLoader: TaskRunnerLoader,
private val propertySerializerFactory: PropertySerializerFactory,
consumerConfig: ConsumerConfig
consumerConfig: ConsumerConfig,
) {
private lateinit var consumerId: UUID
@ -55,6 +55,8 @@ class Consumer(
private val concurrent = MutableStateFlow(consumerConfig.concurrent)
private val processing = MutableStateFlow(0)
private val runnerMap = taskRunnerLoader.load()
/**
* Consumerを初期化します
*

View File

@ -14,14 +14,16 @@
* limitations under the License.
*/
package dev.usbharu.hideout.core.external.job
package dev.usbharu.owl.consumer
import dev.usbharu.hideout.core.domain.model.reaction.Reaction
import dev.usbharu.owl.common.task.Task
import java.util.*
data class DeliverRemoveReactionTask(
val actor: String,
val inbox: String,
val id: Long,
val reaction: Reaction,
) : Task()
class ServiceLoaderTaskRunnerLoader : TaskRunnerLoader {
private val taskRunnerMap = ServiceLoader
.load(TaskRunner::class.java)
.associateBy { it.name }
override fun load(): Map<String, TaskRunner> {
return taskRunnerMap
}
}

View File

@ -23,7 +23,6 @@ import dev.usbharu.owl.common.property.CustomPropertySerializerFactory
import dev.usbharu.owl.common.property.PropertySerializerFactory
import io.grpc.ManagedChannelBuilder
import java.nio.file.Path
import java.util.*
/**
* 単独で起動できるConsumer
@ -33,18 +32,27 @@ import java.util.*
*/
class StandaloneConsumer(
private val config: StandaloneConsumerConfig,
private val propertySerializerFactory: PropertySerializerFactory
private val propertySerializerFactory: PropertySerializerFactory,
taskRunnerLoader: TaskRunnerLoader,
) {
constructor(
path: Path,
propertySerializerFactory: PropertySerializerFactory = CustomPropertySerializerFactory(
emptySet()
)
) : this(StandaloneConsumerConfigLoader.load(path), propertySerializerFactory)
),
taskRunnerLoader: TaskRunnerLoader = ServiceLoaderTaskRunnerLoader(),
) : this(StandaloneConsumerConfigLoader.load(path), propertySerializerFactory, taskRunnerLoader)
constructor(string: String) : this(Path.of(string))
constructor(
string: String,
propertySerializerFactory: PropertySerializerFactory = CustomPropertySerializerFactory(emptySet()),
taskRunnerLoader: TaskRunnerLoader = ServiceLoaderTaskRunnerLoader(),
) : this(Path.of(string), propertySerializerFactory, taskRunnerLoader)
constructor() : this(Path.of("consumer.properties"))
constructor(
propertySerializerFactory: PropertySerializerFactory = CustomPropertySerializerFactory(emptySet()),
taskRunnerLoader: TaskRunnerLoader = ServiceLoaderTaskRunnerLoader(),
) : this(Path.of("consumer.properties"), propertySerializerFactory, taskRunnerLoader)
private val channel = ManagedChannelBuilder.forAddress(config.address, config.port)
.usePlaintext()
@ -54,15 +62,11 @@ class StandaloneConsumer(
private val assignmentTaskStub = AssignmentTaskServiceGrpcKt.AssignmentTaskServiceCoroutineStub(channel)
private val taskResultStub = TaskResultServiceGrpcKt.TaskResultServiceCoroutineStub(channel)
private val taskRunnerMap = ServiceLoader
.load(TaskRunner::class.java)
.associateBy { it.name }
private val consumer = Consumer(
subscribeTaskStub = subscribeStub,
assignmentTaskStub = assignmentTaskStub,
taskResultStub = taskResultStub,
runnerMap = taskRunnerMap,
taskRunnerLoader = taskRunnerLoader,
propertySerializerFactory = propertySerializerFactory,
consumerConfig = ConsumerConfig(config.concurrency)
)

View File

@ -28,5 +28,11 @@ import dev.usbharu.owl.common.property.PropertyValue
data class TaskResult(
val success: Boolean,
val result: Map<String, PropertyValue<*>>,
val message: String
)
val message: String,
) {
companion object {
fun ok(result: Map<String, PropertyValue<*>> = emptyMap()): TaskResult {
return TaskResult(true, result, "")
}
}
}

View File

@ -14,13 +14,8 @@
* limitations under the License.
*/
package dev.usbharu.hideout.core.external.job
package dev.usbharu.owl.consumer
import dev.usbharu.hideout.activitypub.domain.model.Create
import dev.usbharu.owl.common.task.Task
data class DeliverPostTask(
val create: Create,
val inbox: String,
val actor: String,
) : Task()
interface TaskRunnerLoader {
fun load(): Map<String, TaskRunner>
}