Replace Sone change detector with simple comparison helper
[Sone.git] / src / main / kotlin / net / pterodactylus / sone / core / UpdatedSoneProcessor.kt
1 package net.pterodactylus.sone.core
2
3 import com.google.common.eventbus.*
4 import com.google.inject.*
5 import net.pterodactylus.sone.core.event.*
6 import net.pterodactylus.sone.data.*
7 import net.pterodactylus.sone.data.Sone.*
8 import net.pterodactylus.sone.database.*
9 import net.pterodactylus.sone.utils.*
10 import net.pterodactylus.util.logging.*
11 import javax.inject.Inject
12
13 /**
14  * An `UpdatedSoneProcessor` is called to process a [Sone] after it has been
15  * downloaded from Freenet.
16  */
17 @ImplementedBy(DefaultUpdateSoneProcessor::class)
18 interface UpdatedSoneProcessor {
19
20         fun updateSone(sone: Sone)
21
22 }
23
24 abstract class BasicUpdateSoneProcessor(private val database: Database, private val eventBus: EventBus) :
25                 UpdatedSoneProcessor {
26
27         private val logger = Logging.getLogger(UpdatedSoneProcessor::javaClass.name)!!
28
29         override fun updateSone(sone: Sone) {
30                 val storedSone = database.getSone(sone.id) ?: return
31                 if (!soneCanBeUpdated(storedSone, sone)) {
32                         logger.fine("Downloaded Sone $sone can not update stored Sone $storedSone.")
33                         return
34                 }
35
36                 SoneComparison(storedSone, sone).apply {
37                         newPosts
38                                         .onEach { post -> if (post.time <= sone.followingTime) post.isKnown = true }
39                                         .mapNotNull { post -> post.isKnown.ifFalse { NewPostFoundEvent(post) } }
40                                         .forEach(eventBus::post)
41                         removedPosts
42                                         .map { PostRemovedEvent(it) }
43                                         .forEach(eventBus::post)
44                         newPostReplies
45                                         .onEach { postReply -> if (postReply.time <= sone.followingTime) postReply.isKnown = true }
46                                         .mapNotNull { postReply -> postReply.isKnown.ifFalse { NewPostReplyFoundEvent(postReply) } }
47                                         .forEach(eventBus::post)
48                         removedPostReplies
49                                         .map { PostReplyRemovedEvent(it) }
50                                         .forEach(eventBus::post)
51                 }
52                 sone.options = storedSone.options
53                 sone.isKnown = storedSone.isKnown
54                 sone.status = if (sone.time != 0L) SoneStatus.idle else SoneStatus.unknown
55         }
56
57         protected abstract fun soneCanBeUpdated(storedSone: Sone, newSone: Sone): Boolean
58
59         private val Sone.followingTime get() = database.getFollowingTime(id) ?: 0
60
61 }
62
63 class DefaultUpdateSoneProcessor @Inject constructor(database: Database, eventBus: EventBus) :
64                 BasicUpdateSoneProcessor(database, eventBus) {
65
66         override fun soneCanBeUpdated(storedSone: Sone, newSone: Sone) =
67                         newSone.time > storedSone.time
68
69 }