Migrates channel notes to LargeCache
This commit is contained in:
@@ -22,9 +22,11 @@ package com.vitorpamplona.amethyst.model
|
|||||||
|
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
|
import com.vitorpamplona.amethyst.commons.data.LargeCache
|
||||||
import com.vitorpamplona.amethyst.service.NostrSingleChannelDataSource
|
import com.vitorpamplona.amethyst.service.NostrSingleChannelDataSource
|
||||||
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
||||||
import com.vitorpamplona.amethyst.ui.components.BundledUpdate
|
import com.vitorpamplona.amethyst.ui.components.BundledUpdate
|
||||||
|
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
|
||||||
import com.vitorpamplona.amethyst.ui.note.toShortenHex
|
import com.vitorpamplona.amethyst.ui.note.toShortenHex
|
||||||
import com.vitorpamplona.quartz.encoders.ATag
|
import com.vitorpamplona.quartz.encoders.ATag
|
||||||
import com.vitorpamplona.quartz.encoders.Hex
|
import com.vitorpamplona.quartz.encoders.Hex
|
||||||
@@ -33,7 +35,6 @@ import com.vitorpamplona.quartz.encoders.toNote
|
|||||||
import com.vitorpamplona.quartz.events.ChannelCreateEvent
|
import com.vitorpamplona.quartz.events.ChannelCreateEvent
|
||||||
import com.vitorpamplona.quartz.events.LiveActivitiesEvent
|
import com.vitorpamplona.quartz.events.LiveActivitiesEvent
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
class PublicChatChannel(idHex: String) : Channel(idHex) {
|
class PublicChatChannel(idHex: String) : Channel(idHex) {
|
||||||
@@ -110,7 +111,7 @@ abstract class Channel(val idHex: String) {
|
|||||||
|
|
||||||
var updatedMetadataAt: Long = 0
|
var updatedMetadataAt: Long = 0
|
||||||
|
|
||||||
val notes = ConcurrentHashMap<HexKey, Note>()
|
val notes = LargeCache<HexKey, Note>()
|
||||||
|
|
||||||
open fun id() = Hex.decode(idHex)
|
open fun id() = Hex.decode(idHex)
|
||||||
|
|
||||||
@@ -145,7 +146,7 @@ abstract class Channel(val idHex: String) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun addNote(note: Note) {
|
fun addNote(note: Note) {
|
||||||
notes[note.idHex] = note
|
notes.put(note.idHex, note)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeNote(note: Note) {
|
fun removeNote(note: Note) {
|
||||||
@@ -163,18 +164,18 @@ abstract class Channel(val idHex: String) {
|
|||||||
|
|
||||||
fun pruneOldAndHiddenMessages(account: Account): Set<Note> {
|
fun pruneOldAndHiddenMessages(account: Account): Set<Note> {
|
||||||
val important =
|
val important =
|
||||||
notes.values
|
notes.filter { key, it ->
|
||||||
.filter { it.author?.let { it1 -> account.isHidden(it1) } == false }
|
it.author?.let { author -> account.isHidden(author) } == false
|
||||||
.sortedWith(compareBy({ it.createdAt() }, { it.idHex }))
|
}
|
||||||
.reversed()
|
.sortedWith(DefaultFeedOrder)
|
||||||
.take(1000)
|
.take(500)
|
||||||
.toSet()
|
.toSet()
|
||||||
|
|
||||||
val toBeRemoved = notes.values.filter { it !in important }.toSet()
|
val toBeRemoved = notes.filter { key, it -> it !in important }
|
||||||
|
|
||||||
toBeRemoved.forEach { notes.remove(it.idHex) }
|
toBeRemoved.forEach { notes.remove(it.idHex) }
|
||||||
|
|
||||||
return toBeRemoved
|
return toBeRemoved.toSet()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1780,9 +1780,9 @@ object LocalCache {
|
|||||||
|
|
||||||
removeFromCache(childrenToBeRemoved)
|
removeFromCache(childrenToBeRemoved)
|
||||||
|
|
||||||
if (toBeRemoved.size > 100 || it.value.notes.size > 100) {
|
if (toBeRemoved.size > 100 || it.value.notes.size() > 100) {
|
||||||
println(
|
println(
|
||||||
"PRUNE: ${toBeRemoved.size} messages removed from ${it.value.toBestDisplayName()}. ${it.value.notes.size} kept",
|
"PRUNE: ${toBeRemoved.size} messages removed from ${it.value.toBestDisplayName()}. ${it.value.notes.size()} kept",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -171,7 +171,8 @@ open class Note(val idHex: String) {
|
|||||||
event is LiveActivitiesEvent
|
event is LiveActivitiesEvent
|
||||||
) {
|
) {
|
||||||
(event as? ChannelMessageEvent)?.channel()
|
(event as? ChannelMessageEvent)?.channel()
|
||||||
?: (event as? ChannelMetadataEvent)?.channel() ?: (event as? ChannelCreateEvent)?.id
|
?: (event as? ChannelMetadataEvent)?.channel()
|
||||||
|
?: (event as? ChannelCreateEvent)?.id
|
||||||
?: (event as? LiveActivitiesChatMessageEvent)?.activity()?.toTag()
|
?: (event as? LiveActivitiesChatMessageEvent)?.activity()?.toTag()
|
||||||
?: (event as? LiveActivitiesEvent)?.address()?.toTag()
|
?: (event as? LiveActivitiesEvent)?.address()?.toTag()
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ class ParticipantListBuilder {
|
|||||||
it.replyTo?.forEach { addFollowsThatDirectlyParticipateOnToSet(it, followingSet, mySet) }
|
it.replyTo?.forEach { addFollowsThatDirectlyParticipateOnToSet(it, followingSet, mySet) }
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalCache.getChannelIfExists(baseNote.idHex)?.notes?.values?.forEach {
|
LocalCache.getChannelIfExists(baseNote.idHex)?.notes?.forEach { key, it ->
|
||||||
addFollowsThatDirectlyParticipateOnToSet(it, followingSet, mySet)
|
addFollowsThatDirectlyParticipateOnToSet(it, followingSet, mySet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,10 +31,11 @@ class ChannelFeedFilter(val channel: Channel, val account: Account) : AdditiveFe
|
|||||||
|
|
||||||
// returns the last Note of each user.
|
// returns the last Note of each user.
|
||||||
override fun feed(): List<Note> {
|
override fun feed(): List<Note> {
|
||||||
return channel.notes.values
|
return sort(
|
||||||
.filter { account.isAcceptable(it) }
|
channel.notes.filterIntoSet { key, it ->
|
||||||
.sortedWith(compareBy({ it.createdAt() }, { it.idHex }))
|
account.isAcceptable(it)
|
||||||
.reversed()
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun applyFilter(collection: Set<Note>): Set<Note> {
|
override fun applyFilter(collection: Set<Note>): Set<Note> {
|
||||||
|
|||||||
@@ -56,15 +56,12 @@ class ChatroomListKnownFeedFilter(val account: Account) : AdditiveFeedFilter<Not
|
|||||||
.selectedChatsFollowList()
|
.selectedChatsFollowList()
|
||||||
.mapNotNull { LocalCache.getChannelIfExists(it) }
|
.mapNotNull { LocalCache.getChannelIfExists(it) }
|
||||||
.mapNotNull { it ->
|
.mapNotNull { it ->
|
||||||
it.notes.values
|
it.notes.filter { key, it -> account.isAcceptable(it) && it.event != null }
|
||||||
.filter { account.isAcceptable(it) && it.event != null }
|
.sortedWith(DefaultFeedOrder)
|
||||||
.sortedWith(compareBy({ it.createdAt() }, { it.idHex }))
|
.firstOrNull()
|
||||||
.lastOrNull()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (privateMessages + publicChannels)
|
return (privateMessages + publicChannels).sortedWith(DefaultFeedOrder)
|
||||||
.sortedWith(compareBy({ it.createdAt() }, { it.idHex }))
|
|
||||||
.reversed()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateListWith(
|
override fun updateListWith(
|
||||||
|
|||||||
@@ -48,9 +48,8 @@ open class DiscoverLiveFeedFilter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun feed(): List<Note> {
|
override fun feed(): List<Note> {
|
||||||
val allChannelNotes =
|
val allChannelNotes = LocalCache.channels.values.mapNotNull { LocalCache.getNoteIfExists(it.idHex) }
|
||||||
LocalCache.channels.values.mapNotNull { LocalCache.getNoteIfExists(it.idHex) }
|
val allMessageNotes = LocalCache.channels.values.map { it.notes.filter { key, it -> it.event is LiveActivitiesEvent } }.flatten()
|
||||||
val allMessageNotes = LocalCache.channels.values.map { it.notes.values }.flatten()
|
|
||||||
|
|
||||||
val notes = innerApplyFilter(allChannelNotes + allMessageNotes)
|
val notes = innerApplyFilter(allChannelNotes + allMessageNotes)
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,17 @@ class LargeCache<K, V> {
|
|||||||
|
|
||||||
fun size() = cache.size
|
fun size() = cache.size
|
||||||
|
|
||||||
|
fun isEmpty() = cache.isEmpty()
|
||||||
|
|
||||||
|
fun containsKey(key: K) = cache.containsKey(key)
|
||||||
|
|
||||||
|
fun put(
|
||||||
|
key: K,
|
||||||
|
value: V,
|
||||||
|
) {
|
||||||
|
cache.put(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
fun getOrCreate(
|
fun getOrCreate(
|
||||||
key: K,
|
key: K,
|
||||||
builder: (key: K) -> V,
|
builder: (key: K) -> V,
|
||||||
|
|||||||
Reference in New Issue
Block a user