1 package net.pterodactylus.sone.core
3 import com.google.common.eventbus.EventBus
4 import com.google.inject.ImplementedBy
5 import net.pterodactylus.sone.core.event.NewPostFoundEvent
6 import net.pterodactylus.sone.core.event.NewPostReplyFoundEvent
7 import net.pterodactylus.sone.core.event.PostRemovedEvent
8 import net.pterodactylus.sone.core.event.PostReplyRemovedEvent
9 import net.pterodactylus.sone.data.Sone
10 import net.pterodactylus.sone.data.Sone.SoneStatus
11 import net.pterodactylus.sone.database.Database
12 import net.pterodactylus.sone.utils.ifFalse
13 import net.pterodactylus.util.logging.Logging
14 import javax.inject.Inject
17 * An `UpdatedSoneProcessor` is called to process a [Sone] after it has been
18 * downloaded from Freenet.
20 @ImplementedBy(DefaultUpdateSoneProcessor::class)
21 interface UpdatedSoneProcessor {
23 fun updateSone(sone: Sone)
27 abstract class BasicUpdateSoneProcessor(private val database: Database, private val eventBus: EventBus) :
28 UpdatedSoneProcessor {
30 private val logger = Logging.getLogger(UpdatedSoneProcessor::javaClass.name)!!
32 override fun updateSone(sone: Sone) {
33 val storedSone = database.getSone(sone.id) ?: return
34 if (!soneCanBeUpdated(storedSone, sone)) {
35 logger.fine("Downloaded Sone $sone can not update stored Sone $storedSone.")
38 collectEventsForChanges(storedSone, sone)
39 .also { database.storeSone(sone) }
40 .forEach(eventBus::post)
41 sone.options = storedSone.options
42 sone.isKnown = storedSone.isKnown
43 sone.status = if (sone.time != 0L) SoneStatus.idle else SoneStatus.unknown
46 protected abstract fun soneCanBeUpdated(storedSone: Sone, newSone: Sone): Boolean
48 private val Sone.followingTime get() = database.getFollowingTime(id) ?: 0
50 private fun collectEventsForChanges(oldSone: Sone, newSone: Sone): List<Any> =
51 SoneChangeCollector(oldSone)
52 .onNewPost { post -> if (post.time <= newSone.followingTime) post.isKnown = true }
53 .newPostEvent { post -> post.isKnown.ifFalse { NewPostFoundEvent(post) } }
54 .removedPostEvent { PostRemovedEvent(it) }
55 .onNewPostReply { postReply -> if (postReply.time <= newSone.followingTime) postReply.isKnown = true }
56 .newPostReplyEvent { postReply -> postReply.isKnown.ifFalse { NewPostReplyFoundEvent(postReply) } }
57 .onRemovedPostReply { PostReplyRemovedEvent(it) }
58 .detectChanges(newSone)
62 class DefaultUpdateSoneProcessor @Inject constructor(database: Database, eventBus: EventBus) :
63 BasicUpdateSoneProcessor(database, eventBus) {
65 override fun soneCanBeUpdated(storedSone: Sone, newSone: Sone) =
66 newSone.time > storedSone.time