Memory Pruning: Only keeping 1000 messages per channel

pull/141/head
Vitor Pamplona 2023-02-19 12:40:19 -05:00
rodzic d57fca3549
commit 23a5e9e66b
6 zmienionych plików z 65 dodań i 2 usunięć

Wyświetl plik

@ -1,6 +1,7 @@
package com.vitorpamplona.amethyst
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.service.relays.Constants
import com.vitorpamplona.amethyst.service.NostrAccountDataSource
import com.vitorpamplona.amethyst.service.NostrChannelDataSource
@ -66,4 +67,12 @@ object ServiceManager {
Client.disconnect()
}
fun cleanUp() {
LocalCache.cleanObservers()
account?.let {
LocalCache.pruneOldAndHiddenMessages(it)
}
}
}

Wyświetl plik

@ -4,6 +4,7 @@ import androidx.lifecycle.LiveData
import com.vitorpamplona.amethyst.service.NostrSingleChannelDataSource
import com.vitorpamplona.amethyst.service.NostrSingleEventDataSource
import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent
import com.vitorpamplona.amethyst.ui.dal.ChannelFeedFilter
import com.vitorpamplona.amethyst.ui.note.toShortenHex
import fr.acinq.secp256k1.Hex
import java.util.concurrent.ConcurrentHashMap
@ -53,6 +54,23 @@ class Channel(val idHex: String) {
private fun refreshObservers() {
live.refresh()
}
fun pruneOldAndHiddenMessages(account: Account): Set<Note> {
val important = notes.values
.filter { it.author?.let { it1 -> account.isHidden(it1) } == false }
.sortedBy { it.event?.createdAt }
.reversed()
.take(1000)
.toSet()
val toBeRemoved = notes.values.filter { it in important }.toSet()
toBeRemoved.forEach {
notes.remove(it.idHex)
}
return toBeRemoved
}
}

Wyświetl plik

@ -544,6 +544,29 @@ object LocalCache {
}
}
fun cleanObservers() {
notes.forEach {
it.value.clearLive()
}
users.forEach {
it.value.clearLive()
}
}
fun pruneOldAndHiddenMessages(account: Account) {
channels.forEach {
val toBeRemoved = it.value.pruneOldAndHiddenMessages(account)
toBeRemoved.forEach {
notes.remove(it.idHex)
// Doesn't need to clean up the replies and mentions.. Too small to matter.
}
println("PRUNE: ${toBeRemoved.size} messages removed from ${it.value.info.name}")
}
}
// Observers line up here.
val live: LocalCacheLiveData = LocalCacheLiveData(this)

Wyświetl plik

@ -363,3 +363,4 @@ class UserLiveData(val user: User): LiveData<UserState>(UserState(user)) {
}
class UserState(val user: User)

Wyświetl plik

@ -38,7 +38,7 @@ object NostrChatroomListDataSource: NostrDataSource("MailBoxFeed") {
)
fun createMyChannelsFilter() = TypedFilter(
types = setOf(FeedType.PUBLIC_CHATS),
types = FeedType.values().toSet(), // Metadata comes from any relay
filter = JsonFilter(
kinds = listOf(ChannelCreateEvent.kind),
ids = account.followingChannels.toList()
@ -48,7 +48,7 @@ object NostrChatroomListDataSource: NostrDataSource("MailBoxFeed") {
fun createLastChannelInfoFilter(): List<TypedFilter> {
return account.followingChannels.map {
TypedFilter(
types = setOf(FeedType.PUBLIC_CHATS),
types = FeedType.values().toSet(), // Metadata comes from any relay
filter = JsonFilter(
kinds = listOf(ChannelMetadataEvent.kind),
tags = mapOf("e" to listOf(it)),

Wyświetl plik

@ -1,5 +1,6 @@
package com.vitorpamplona.amethyst.ui
import android.content.ComponentCallbacks2
import android.net.Uri
import android.os.Build.VERSION.SDK_INT
import android.os.Bundle
@ -22,6 +23,7 @@ import coil.util.DebugLogger
import com.vitorpamplona.amethyst.EncryptedStorage
import com.vitorpamplona.amethyst.LocalPreferences
import com.vitorpamplona.amethyst.ServiceManager
import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.decodePublicKey
import com.vitorpamplona.amethyst.model.toHexKey
import com.vitorpamplona.amethyst.service.Nip19
@ -85,4 +87,14 @@ class MainActivity : ComponentActivity() {
super.onPause()
}
/**
* Release memory when the UI becomes hidden or when system resources become low.
* @param level the memory-related event that was raised.
*/
override fun onTrimMemory(level: Int) {
super.onTrimMemory(level)
println("Trim Memory $level")
ServiceManager.cleanUp()
}
}