Speeding up the loop through local cache.
This commit is contained in:
@@ -1202,7 +1202,7 @@ class Account(
|
|||||||
Client.send(signedEvent, relayList = relayList)
|
Client.send(signedEvent, relayList = relayList)
|
||||||
LocalCache.consume(signedEvent, null)
|
LocalCache.consume(signedEvent, null)
|
||||||
|
|
||||||
return LocalCache.notes[signedEvent.id]
|
return LocalCache.getNoteIfExists(signedEvent.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun consumeNip95(
|
fun consumeNip95(
|
||||||
@@ -1212,7 +1212,7 @@ class Account(
|
|||||||
LocalCache.consume(data, null)
|
LocalCache.consume(data, null)
|
||||||
LocalCache.consume(signedEvent, null)
|
LocalCache.consume(signedEvent, null)
|
||||||
|
|
||||||
return LocalCache.notes[signedEvent.id]
|
return LocalCache.getNoteIfExists(signedEvent.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendNip95(
|
fun sendNip95(
|
||||||
@@ -1232,7 +1232,7 @@ class Account(
|
|||||||
Client.send(signedEvent, relayList = relayList)
|
Client.send(signedEvent, relayList = relayList)
|
||||||
LocalCache.consume(signedEvent, null)
|
LocalCache.consume(signedEvent, null)
|
||||||
|
|
||||||
LocalCache.notes[signedEvent.id]?.let { onReady(it) }
|
LocalCache.getNoteIfExists(signedEvent.id)?.let { onReady(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createHeader(
|
fun createHeader(
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ import com.vitorpamplona.quartz.events.TextNoteEvent
|
|||||||
import com.vitorpamplona.quartz.events.VideoHorizontalEvent
|
import com.vitorpamplona.quartz.events.VideoHorizontalEvent
|
||||||
import com.vitorpamplona.quartz.events.VideoVerticalEvent
|
import com.vitorpamplona.quartz.events.VideoVerticalEvent
|
||||||
import com.vitorpamplona.quartz.events.WikiNoteEvent
|
import com.vitorpamplona.quartz.events.WikiNoteEvent
|
||||||
|
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.persistentSetOf
|
import kotlinx.collections.immutable.persistentSetOf
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
@@ -118,18 +119,31 @@ import java.time.Instant
|
|||||||
import java.time.ZoneId
|
import java.time.ZoneId
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
import kotlin.time.measureTimedValue
|
||||||
|
|
||||||
object LocalCache {
|
object LocalCache {
|
||||||
val antiSpam = AntiSpamFilter()
|
val antiSpam = AntiSpamFilter()
|
||||||
|
|
||||||
val users = ConcurrentHashMap<HexKey, User>(5000)
|
private val users = ConcurrentHashMap<HexKey, User>(5000)
|
||||||
val notes = ConcurrentHashMap<HexKey, Note>(5000)
|
private val notes = ConcurrentHashMap<HexKey, Note>(5000)
|
||||||
val channels = ConcurrentHashMap<HexKey, Channel>()
|
val channels = ConcurrentHashMap<HexKey, Channel>()
|
||||||
val addressables = ConcurrentHashMap<String, AddressableNote>(100)
|
val addressables = ConcurrentHashMap<String, AddressableNote>(100)
|
||||||
|
|
||||||
val awaitingPaymentRequests =
|
val awaitingPaymentRequests =
|
||||||
ConcurrentHashMap<HexKey, Pair<Note?, (LnZapPaymentResponseEvent) -> Unit>>(10)
|
ConcurrentHashMap<HexKey, Pair<Note?, (LnZapPaymentResponseEvent) -> Unit>>(10)
|
||||||
|
|
||||||
|
var noteListCache: List<Note> = emptyList()
|
||||||
|
var userListCache: List<User> = emptyList()
|
||||||
|
|
||||||
|
fun updateListCache() {
|
||||||
|
val (value, elapsed) =
|
||||||
|
measureTimedValue {
|
||||||
|
noteListCache = ArrayList(notes.values)
|
||||||
|
userListCache = ArrayList(users.values)
|
||||||
|
}
|
||||||
|
Log.d("LocalCache", "UpdateListCache $elapsed")
|
||||||
|
}
|
||||||
|
|
||||||
fun checkGetOrCreateUser(key: String): User? {
|
fun checkGetOrCreateUser(key: String): User? {
|
||||||
// checkNotInMainThread()
|
// checkNotInMainThread()
|
||||||
|
|
||||||
@@ -910,7 +924,7 @@ object LocalCache {
|
|||||||
|
|
||||||
event
|
event
|
||||||
.deleteEvents()
|
.deleteEvents()
|
||||||
.mapNotNull { notes[it] }
|
.mapNotNull { getNoteIfExists(it) }
|
||||||
.forEach { deleteNote ->
|
.forEach { deleteNote ->
|
||||||
// must be the same author
|
// must be the same author
|
||||||
if (deleteNote.author?.pubkeyHex == event.pubKey) {
|
if (deleteNote.author?.pubkeyHex == event.pubKey) {
|
||||||
@@ -1547,11 +1561,14 @@ object LocalCache {
|
|||||||
|
|
||||||
val key = decodePublicKeyAsHexOrNull(username)
|
val key = decodePublicKeyAsHexOrNull(username)
|
||||||
|
|
||||||
if (key != null && users[key] != null) {
|
if (key != null) {
|
||||||
return listOfNotNull(users[key])
|
val user = getUserIfExists(key)
|
||||||
|
if (user != null) {
|
||||||
|
return listOfNotNull(user)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return users.values.filter {
|
return userListCache.filter {
|
||||||
(it.anyNameStartsWith(username)) ||
|
(it.anyNameStartsWith(username)) ||
|
||||||
it.pubkeyHex.startsWith(username, true) ||
|
it.pubkeyHex.startsWith(username, true) ||
|
||||||
it.pubkeyNpub().startsWith(username, true)
|
it.pubkeyNpub().startsWith(username, true)
|
||||||
@@ -1569,11 +1586,14 @@ object LocalCache {
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key != null && (notes[key] ?: addressables[key]) != null) {
|
if (key != null) {
|
||||||
return listOfNotNull(notes[key] ?: addressables[key])
|
val note = getNoteIfExists(key)
|
||||||
|
if (note != null) {
|
||||||
|
return listOfNotNull(note)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return notes.values.filter {
|
return noteListCache.filter {
|
||||||
(
|
(
|
||||||
it.event !is GenericRepostEvent &&
|
it.event !is GenericRepostEvent &&
|
||||||
it.event !is RepostEvent &&
|
it.event !is RepostEvent &&
|
||||||
@@ -1652,28 +1672,29 @@ object LocalCache {
|
|||||||
suspend fun findEarliestOtsForNote(note: Note): Long? {
|
suspend fun findEarliestOtsForNote(note: Note): Long? {
|
||||||
checkNotInMainThread()
|
checkNotInMainThread()
|
||||||
|
|
||||||
val validOts =
|
var minTime: Long? = null
|
||||||
notes
|
val time = TimeUtils.now()
|
||||||
.mapNotNull {
|
|
||||||
val noteEvent = it.value.event
|
noteListCache.forEach { item ->
|
||||||
if ((noteEvent is OtsEvent && noteEvent.isTaggedEvent(note.idHex) && !noteEvent.isExpired())) {
|
val noteEvent = item.event
|
||||||
noteEvent.verifiedTime
|
if ((noteEvent is OtsEvent && noteEvent.isTaggedEvent(note.idHex) && !noteEvent.isExpirationBefore(time))) {
|
||||||
} else {
|
noteEvent.verifiedTime?.let { stampedTime ->
|
||||||
null
|
if (minTime == null || stampedTime < (minTime ?: Long.MAX_VALUE)) {
|
||||||
|
minTime = stampedTime
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (validOts.isEmpty()) return null
|
return minTime
|
||||||
|
|
||||||
return validOts.minBy { it }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun cleanObservers() {
|
fun cleanObservers() {
|
||||||
notes.forEach { it.value.clearLive() }
|
noteListCache.forEach { it.clearLive() }
|
||||||
|
|
||||||
addressables.forEach { it.value.clearLive() }
|
addressables.forEach { it.value.clearLive() }
|
||||||
|
|
||||||
users.forEach { it.value.clearLive() }
|
userListCache.forEach { it.clearLive() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun pruneOldAndHiddenMessages(account: Account) {
|
fun pruneOldAndHiddenMessages(account: Account) {
|
||||||
@@ -1699,8 +1720,8 @@ object LocalCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
users.forEach { userPair ->
|
userListCache.forEach { userPair ->
|
||||||
userPair.value.privateChatrooms.values.map {
|
userPair.privateChatrooms.values.map {
|
||||||
val toBeRemoved = it.pruneMessagesToTheLatestOnly()
|
val toBeRemoved = it.pruneMessagesToTheLatestOnly()
|
||||||
|
|
||||||
val childrenToBeRemoved = mutableListOf<Note>()
|
val childrenToBeRemoved = mutableListOf<Note>()
|
||||||
@@ -1715,7 +1736,7 @@ object LocalCache {
|
|||||||
|
|
||||||
if (toBeRemoved.size > 1) {
|
if (toBeRemoved.size > 1) {
|
||||||
println(
|
println(
|
||||||
"PRUNE: ${toBeRemoved.size} private messages with ${userPair.value.toBestDisplayName()} removed. ${it.roomMessages.size} kept",
|
"PRUNE: ${toBeRemoved.size} private messages with ${userPair.toBestDisplayName()} removed. ${it.roomMessages.size} kept",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1724,9 +1745,9 @@ object LocalCache {
|
|||||||
|
|
||||||
fun prunePastVersionsOfReplaceables() {
|
fun prunePastVersionsOfReplaceables() {
|
||||||
val toBeRemoved =
|
val toBeRemoved =
|
||||||
notes
|
noteListCache
|
||||||
.filter {
|
.filter {
|
||||||
val noteEvent = it.value.event
|
val noteEvent = it.event
|
||||||
if (noteEvent is AddressableEvent) {
|
if (noteEvent is AddressableEvent) {
|
||||||
noteEvent.createdAt() <
|
noteEvent.createdAt() <
|
||||||
(addressables[noteEvent.address().toTag()]?.event?.createdAt() ?: 0)
|
(addressables[noteEvent.address().toTag()]?.event?.createdAt() ?: 0)
|
||||||
@@ -1734,7 +1755,6 @@ object LocalCache {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.values
|
|
||||||
|
|
||||||
val childrenToBeRemoved = mutableListOf<Note>()
|
val childrenToBeRemoved = mutableListOf<Note>()
|
||||||
|
|
||||||
@@ -1759,24 +1779,23 @@ object LocalCache {
|
|||||||
checkNotInMainThread()
|
checkNotInMainThread()
|
||||||
|
|
||||||
val toBeRemoved =
|
val toBeRemoved =
|
||||||
notes
|
noteListCache
|
||||||
.filter {
|
.filter {
|
||||||
(
|
(
|
||||||
(it.value.event is TextNoteEvent && !it.value.isNewThread()) ||
|
(it.event is TextNoteEvent && !it.isNewThread()) ||
|
||||||
it.value.event is ReactionEvent ||
|
it.event is ReactionEvent ||
|
||||||
it.value.event is LnZapEvent ||
|
it.event is LnZapEvent ||
|
||||||
it.value.event is LnZapRequestEvent ||
|
it.event is LnZapRequestEvent ||
|
||||||
it.value.event is ReportEvent ||
|
it.event is ReportEvent ||
|
||||||
it.value.event is GenericRepostEvent
|
it.event is GenericRepostEvent
|
||||||
) &&
|
) &&
|
||||||
it.value.replyTo?.any { it.liveSet?.isInUse() == true } != true &&
|
it.replyTo?.any { it.liveSet?.isInUse() == true } != true &&
|
||||||
it.value.liveSet?.isInUse() != true && // don't delete if observing.
|
it.liveSet?.isInUse() != true && // don't delete if observing.
|
||||||
it.value.author?.pubkeyHex !in
|
it.author?.pubkeyHex !in
|
||||||
accounts && // don't delete if it is the logged in account
|
accounts && // don't delete if it is the logged in account
|
||||||
it.value.event?.isTaggedUsers(accounts) !=
|
it.event?.isTaggedUsers(accounts) !=
|
||||||
true // don't delete if it's a notification to the logged in user
|
true // don't delete if it's a notification to the logged in user
|
||||||
}
|
}
|
||||||
.values
|
|
||||||
|
|
||||||
val childrenToBeRemoved = mutableListOf<Note>()
|
val childrenToBeRemoved = mutableListOf<Note>()
|
||||||
|
|
||||||
@@ -1842,7 +1861,8 @@ object LocalCache {
|
|||||||
fun pruneExpiredEvents() {
|
fun pruneExpiredEvents() {
|
||||||
checkNotInMainThread()
|
checkNotInMainThread()
|
||||||
|
|
||||||
val toBeRemoved = notes.filter { it.value.event?.isExpired() == true }.values
|
val now = TimeUtils.now()
|
||||||
|
val toBeRemoved = noteListCache.filter { it.event?.isExpirationBefore(now) == true }
|
||||||
|
|
||||||
val childrenToBeRemoved = mutableListOf<Note>()
|
val childrenToBeRemoved = mutableListOf<Note>()
|
||||||
|
|
||||||
@@ -1868,7 +1888,7 @@ object LocalCache {
|
|||||||
?.hiddenUsers
|
?.hiddenUsers
|
||||||
?.map { userHex ->
|
?.map { userHex ->
|
||||||
(
|
(
|
||||||
notes.values.filter { it.event?.pubKey() == userHex } +
|
noteListCache.filter { it.event?.pubKey() == userHex } +
|
||||||
addressables.values.filter { it.event?.pubKey() == userHex }
|
addressables.values.filter { it.event?.pubKey() == userHex }
|
||||||
)
|
)
|
||||||
.toSet()
|
.toSet()
|
||||||
@@ -1890,7 +1910,7 @@ object LocalCache {
|
|||||||
checkNotInMainThread()
|
checkNotInMainThread()
|
||||||
|
|
||||||
var removingContactList = 0
|
var removingContactList = 0
|
||||||
users.values.forEach {
|
userListCache.forEach {
|
||||||
if (
|
if (
|
||||||
it.pubkeyHex !in loggedIn &&
|
it.pubkeyHex !in loggedIn &&
|
||||||
(it.liveSet == null || it.liveSet?.isInUse() == false) &&
|
(it.liveSet == null || it.liveSet?.isInUse() == false) &&
|
||||||
@@ -2044,6 +2064,10 @@ class LocalCacheLiveData {
|
|||||||
private val bundler = BundledInsert<Note>(1000, Dispatchers.IO)
|
private val bundler = BundledInsert<Note>(1000, Dispatchers.IO)
|
||||||
|
|
||||||
fun invalidateData(newNote: Note) {
|
fun invalidateData(newNote: Note) {
|
||||||
bundler.invalidateList(newNote) { bundledNewNotes -> _newEventBundles.emit(bundledNewNotes) }
|
bundler.invalidateList(newNote) {
|
||||||
|
bundledNewNotes ->
|
||||||
|
_newEventBundles.emit(bundledNewNotes)
|
||||||
|
LocalCache.updateListCache()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,10 +139,10 @@ class User(val pubkeyHex: String) {
|
|||||||
// Update Followers of the past user list
|
// Update Followers of the past user list
|
||||||
// Update Followers of the new contact list
|
// Update Followers of the new contact list
|
||||||
(oldContactListEvent)?.unverifiedFollowKeySet()?.forEach {
|
(oldContactListEvent)?.unverifiedFollowKeySet()?.forEach {
|
||||||
LocalCache.users[it]?.liveSet?.innerFollowers?.invalidateData()
|
LocalCache.getUserIfExists(it)?.liveSet?.innerFollowers?.invalidateData()
|
||||||
}
|
}
|
||||||
(latestContactList)?.unverifiedFollowKeySet()?.forEach {
|
(latestContactList)?.unverifiedFollowKeySet()?.forEach {
|
||||||
LocalCache.users[it]?.liveSet?.innerFollowers?.invalidateData()
|
LocalCache.getUserIfExists(it)?.liveSet?.innerFollowers?.invalidateData()
|
||||||
}
|
}
|
||||||
|
|
||||||
liveSet?.innerRelays?.invalidateData()
|
liveSet?.innerRelays?.invalidateData()
|
||||||
@@ -363,7 +363,7 @@ class User(val pubkeyHex: String) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
suspend fun transientFollowerCount(): Int {
|
suspend fun transientFollowerCount(): Int {
|
||||||
return LocalCache.users.count { it.value.latestContactList?.isTaggedUser(pubkeyHex) ?: false }
|
return LocalCache.userListCache.count { it.latestContactList?.isTaggedUser(pubkeyHex) ?: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun cachedFollowingKeySet(): Set<HexKey> {
|
fun cachedFollowingKeySet(): Set<HexKey> {
|
||||||
@@ -387,7 +387,7 @@ class User(val pubkeyHex: String) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
suspend fun cachedFollowerCount(): Int {
|
suspend fun cachedFollowerCount(): Int {
|
||||||
return LocalCache.users.count { it.value.latestContactList?.isTaggedUser(pubkeyHex) ?: false }
|
return LocalCache.userListCache.count { it.latestContactList?.isTaggedUser(pubkeyHex) ?: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hasSentMessagesTo(key: ChatroomKey?): Boolean {
|
fun hasSentMessagesTo(key: ChatroomKey?): Boolean {
|
||||||
|
|||||||
+3
-3
@@ -112,7 +112,7 @@ class EventNotificationConsumer(private val applicationContext: Context) {
|
|||||||
event.pubKey != acc.userProfile().pubkeyHex
|
event.pubKey != acc.userProfile().pubkeyHex
|
||||||
) { // from the user
|
) { // from the user
|
||||||
|
|
||||||
val chatNote = LocalCache.notes[event.id] ?: return
|
val chatNote = LocalCache.getNoteIfExists(event.id) ?: return
|
||||||
val chatRoom = event.chatroomKey(acc.keyPair.pubKey.toHexKey())
|
val chatRoom = event.chatroomKey(acc.keyPair.pubKey.toHexKey())
|
||||||
|
|
||||||
val followingKeySet = acc.followingKeySet()
|
val followingKeySet = acc.followingKeySet()
|
||||||
@@ -145,7 +145,7 @@ class EventNotificationConsumer(private val applicationContext: Context) {
|
|||||||
event: PrivateDmEvent,
|
event: PrivateDmEvent,
|
||||||
acc: Account,
|
acc: Account,
|
||||||
) {
|
) {
|
||||||
val note = LocalCache.notes[event.id] ?: return
|
val note = LocalCache.getNoteIfExists(event.id) ?: return
|
||||||
|
|
||||||
// old event being re-broadcast
|
// old event being re-broadcast
|
||||||
if (event.createdAt < TimeUtils.fiveMinutesAgo()) return
|
if (event.createdAt < TimeUtils.fiveMinutesAgo()) return
|
||||||
@@ -184,7 +184,7 @@ class EventNotificationConsumer(private val applicationContext: Context) {
|
|||||||
event: LnZapEvent,
|
event: LnZapEvent,
|
||||||
acc: Account,
|
acc: Account,
|
||||||
) {
|
) {
|
||||||
val noteZapEvent = LocalCache.notes[event.id] ?: return
|
val noteZapEvent = LocalCache.getNoteIfExists(event.id) ?: return
|
||||||
|
|
||||||
// old event being re-broadcast
|
// old event being re-broadcast
|
||||||
if (event.createdAt < TimeUtils.fiveMinutesAgo()) return
|
if (event.createdAt < TimeUtils.fiveMinutesAgo()) return
|
||||||
|
|||||||
@@ -66,19 +66,19 @@ class MarkdownParser {
|
|||||||
|
|
||||||
private fun getDisplayNameFromNip19(nip19: Nip19Bech32.Return): Pair<String, String>? {
|
private fun getDisplayNameFromNip19(nip19: Nip19Bech32.Return): Pair<String, String>? {
|
||||||
if (nip19.type == Nip19Bech32.Type.USER) {
|
if (nip19.type == Nip19Bech32.Type.USER) {
|
||||||
LocalCache.users[nip19.hex]?.let {
|
LocalCache.getUserIfExists(nip19.hex)?.let {
|
||||||
return Pair(it.toBestDisplayName(), it.pubkeyNpub())
|
return Pair(it.toBestDisplayName(), it.pubkeyNpub())
|
||||||
}
|
}
|
||||||
} else if (nip19.type == Nip19Bech32.Type.NOTE) {
|
} else if (nip19.type == Nip19Bech32.Type.NOTE) {
|
||||||
LocalCache.notes[nip19.hex]?.let {
|
LocalCache.getNoteIfExists(nip19.hex)?.let {
|
||||||
return Pair(it.idDisplayNote(), it.toNEvent())
|
return Pair(it.idDisplayNote(), it.toNEvent())
|
||||||
}
|
}
|
||||||
} else if (nip19.type == Nip19Bech32.Type.ADDRESS) {
|
} else if (nip19.type == Nip19Bech32.Type.ADDRESS) {
|
||||||
LocalCache.addressables[nip19.hex]?.let {
|
LocalCache.getAddressableNoteIfExists(nip19.hex)?.let {
|
||||||
return Pair(it.idDisplayNote(), it.toNEvent())
|
return Pair(it.idDisplayNote(), it.toNEvent())
|
||||||
}
|
}
|
||||||
} else if (nip19.type == Nip19Bech32.Type.EVENT) {
|
} else if (nip19.type == Nip19Bech32.Type.EVENT) {
|
||||||
LocalCache.notes[nip19.hex]?.let {
|
LocalCache.getNoteIfExists(nip19.hex)?.let {
|
||||||
return Pair(it.idDisplayNote(), it.toNEvent())
|
return Pair(it.idDisplayNote(), it.toNEvent())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class CommunityFeedFilter(val note: AddressableNote, val account: Account) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun feed(): List<Note> {
|
override fun feed(): List<Note> {
|
||||||
return sort(innerApplyFilter(LocalCache.notes.values))
|
return sort(innerApplyFilter(LocalCache.noteListCache))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun applyFilter(collection: Set<Note>): Set<Note> {
|
override fun applyFilter(collection: Set<Note>): Set<Note> {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class GeoHashFeedFilter(val tag: String, val account: Account) : AdditiveFeedFil
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun feed(): List<Note> {
|
override fun feed(): List<Note> {
|
||||||
return sort(innerApplyFilter(LocalCache.notes.values))
|
return sort(innerApplyFilter(LocalCache.noteListCache))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun applyFilter(collection: Set<Note>): Set<Note> {
|
override fun applyFilter(collection: Set<Note>): Set<Note> {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class HashtagFeedFilter(val tag: String, val account: Account) : AdditiveFeedFil
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun feed(): List<Note> {
|
override fun feed(): List<Note> {
|
||||||
return sort(innerApplyFilter(LocalCache.notes.values))
|
return sort(innerApplyFilter(LocalCache.noteListCache))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun applyFilter(collection: Set<Note>): Set<Note> {
|
override fun applyFilter(collection: Set<Note>): Set<Note> {
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class HomeConversationsFeedFilter(val account: Account) : AdditiveFeedFilter<Not
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun feed(): List<Note> {
|
override fun feed(): List<Note> {
|
||||||
return sort(innerApplyFilter(LocalCache.notes.values))
|
return sort(innerApplyFilter(LocalCache.noteListCache))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun applyFilter(collection: Set<Note>): Set<Note> {
|
override fun applyFilter(collection: Set<Note>): Set<Note> {
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class HomeNewThreadFeedFilter(val account: Account) : AdditiveFeedFilter<Note>()
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun feed(): List<Note> {
|
override fun feed(): List<Note> {
|
||||||
val notes = innerApplyFilter(LocalCache.notes.values, true)
|
val notes = innerApplyFilter(LocalCache.noteListCache, true)
|
||||||
val longFormNotes = innerApplyFilter(LocalCache.addressables.values, false)
|
val longFormNotes = innerApplyFilter(LocalCache.addressables.values, false)
|
||||||
|
|
||||||
return sort(notes + longFormNotes)
|
return sort(notes + longFormNotes)
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class NotificationFeedFilter(val account: Account) : AdditiveFeedFilter<Note>()
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun feed(): List<Note> {
|
override fun feed(): List<Note> {
|
||||||
return sort(innerApplyFilter(LocalCache.notes.values))
|
return sort(innerApplyFilter(LocalCache.noteListCache))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun applyFilter(collection: Set<Note>): Set<Note> {
|
override fun applyFilter(collection: Set<Note>): Set<Note> {
|
||||||
|
|||||||
+1
-1
@@ -36,7 +36,7 @@ class UserProfileConversationsFeedFilter(val user: User, val account: Account) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun feed(): List<Note> {
|
override fun feed(): List<Note> {
|
||||||
return sort(innerApplyFilter(LocalCache.notes.values))
|
return sort(innerApplyFilter(LocalCache.noteListCache))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun applyFilter(collection: Set<Note>): Set<Note> {
|
override fun applyFilter(collection: Set<Note>): Set<Note> {
|
||||||
|
|||||||
+1
-1
@@ -30,7 +30,7 @@ class UserProfileFollowersFeedFilter(val user: User, val account: Account) : Fee
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun feed(): List<User> {
|
override fun feed(): List<User> {
|
||||||
return LocalCache.users.values.filter { it.isFollowing(user) && !account.isHidden(it) }
|
return LocalCache.userListCache.filter { it.isFollowing(user) && !account.isHidden(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun limit() = 400
|
override fun limit() = 400
|
||||||
|
|||||||
+1
-1
@@ -41,7 +41,7 @@ class UserProfileNewThreadFeedFilter(val user: User, val account: Account) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun feed(): List<Note> {
|
override fun feed(): List<Note> {
|
||||||
val notes = innerApplyFilter(LocalCache.notes.values)
|
val notes = innerApplyFilter(LocalCache.noteListCache)
|
||||||
val longFormNotes = innerApplyFilter(LocalCache.addressables.values)
|
val longFormNotes = innerApplyFilter(LocalCache.addressables.values)
|
||||||
|
|
||||||
return sort(notes + longFormNotes)
|
return sort(notes + longFormNotes)
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class VideoFeedFilter(val account: Account) : AdditiveFeedFilter<Note>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun feed(): List<Note> {
|
override fun feed(): List<Note> {
|
||||||
val notes = innerApplyFilter(LocalCache.notes.values)
|
val notes = innerApplyFilter(LocalCache.noteListCache)
|
||||||
|
|
||||||
return sort(notes)
|
return sort(notes)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -979,11 +979,11 @@ fun debugState(context: Context) {
|
|||||||
Log.d(
|
Log.d(
|
||||||
"STATE DUMP",
|
"STATE DUMP",
|
||||||
"Notes: " +
|
"Notes: " +
|
||||||
LocalCache.notes.filter { it.value.liveSet != null }.size +
|
LocalCache.noteListCache.filter { it.liveSet != null }.size +
|
||||||
" / " +
|
" / " +
|
||||||
LocalCache.notes.filter { it.value.event != null }.size +
|
LocalCache.noteListCache.filter { it.event != null }.size +
|
||||||
" / " +
|
" / " +
|
||||||
LocalCache.notes.size,
|
LocalCache.noteListCache.size,
|
||||||
)
|
)
|
||||||
Log.d(
|
Log.d(
|
||||||
"STATE DUMP",
|
"STATE DUMP",
|
||||||
@@ -997,21 +997,21 @@ fun debugState(context: Context) {
|
|||||||
Log.d(
|
Log.d(
|
||||||
"STATE DUMP",
|
"STATE DUMP",
|
||||||
"Users: " +
|
"Users: " +
|
||||||
LocalCache.users.filter { it.value.liveSet != null }.size +
|
LocalCache.userListCache.filter { it.liveSet != null }.size +
|
||||||
" / " +
|
" / " +
|
||||||
LocalCache.users.filter { it.value.info?.latestMetadata != null }.size +
|
LocalCache.userListCache.filter { it.info?.latestMetadata != null }.size +
|
||||||
" / " +
|
" / " +
|
||||||
LocalCache.users.size,
|
LocalCache.userListCache.size,
|
||||||
)
|
)
|
||||||
|
|
||||||
Log.d(
|
Log.d(
|
||||||
"STATE DUMP",
|
"STATE DUMP",
|
||||||
"Memory used by Events: " +
|
"Memory used by Events: " +
|
||||||
LocalCache.notes.values.sumOf { it.event?.countMemory() ?: 0 } / (1024 * 1024) +
|
LocalCache.noteListCache.sumOf { it.event?.countMemory() ?: 0 } / (1024 * 1024) +
|
||||||
" MB",
|
" MB",
|
||||||
)
|
)
|
||||||
|
|
||||||
LocalCache.notes.values
|
LocalCache.noteListCache
|
||||||
.groupBy { it.event?.kind() }
|
.groupBy { it.event?.kind() }
|
||||||
.forEach { Log.d("STATE DUMP", "Kind ${it.key}: \t${it.value.size} elements ") }
|
.forEach { Log.d("STATE DUMP", "Kind ${it.key}: \t${it.value.size} elements ") }
|
||||||
LocalCache.addressables.values
|
LocalCache.addressables.values
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ class UserReactionsViewModel(val account: Account) : ViewModel() {
|
|||||||
val replies = mutableMapOf<String, Int>()
|
val replies = mutableMapOf<String, Int>()
|
||||||
val takenIntoAccount = mutableSetOf<HexKey>()
|
val takenIntoAccount = mutableSetOf<HexKey>()
|
||||||
|
|
||||||
LocalCache.notes.values.forEach {
|
LocalCache.noteListCache.forEach {
|
||||||
val noteEvent = it.event
|
val noteEvent = it.event
|
||||||
if (noteEvent != null && !takenIntoAccount.contains(noteEvent.id())) {
|
if (noteEvent != null && !takenIntoAccount.contains(noteEvent.id())) {
|
||||||
if (noteEvent is ReactionEvent) {
|
if (noteEvent is ReactionEvent) {
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ open class CardFeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
|
|||||||
val event = (zapEvent.event as LnZapEvent)
|
val event = (zapEvent.event as LnZapEvent)
|
||||||
val author =
|
val author =
|
||||||
event.zappedAuthor().firstNotNullOfOrNull {
|
event.zappedAuthor().firstNotNullOfOrNull {
|
||||||
LocalCache.users[it] // don't create user if it doesn't exist
|
LocalCache.getUserIfExists(it) // don't create user if it doesn't exist
|
||||||
}
|
}
|
||||||
if (author != null) {
|
if (author != null) {
|
||||||
val zapRequest = author.zaps.filter { it.value == zapEvent }.keys.firstOrNull()
|
val zapRequest = author.zaps.filter { it.value == zapEvent }.keys.firstOrNull()
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow
|
|||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.coroutines.withTimeoutOrNull
|
import kotlinx.coroutines.withTimeoutOrNull
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
@@ -897,18 +898,22 @@ class AccountViewModel(val account: Account, val settings: SettingsState) : View
|
|||||||
return LocalCache.addressables[key]
|
return LocalCache.addressables[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findStatusesForUser(
|
suspend fun findStatusesForUser(
|
||||||
myUser: User,
|
myUser: User,
|
||||||
onResult: (ImmutableList<AddressableNote>) -> Unit,
|
onResult: (ImmutableList<AddressableNote>) -> Unit,
|
||||||
) {
|
) {
|
||||||
viewModelScope.launch(Dispatchers.IO) { onResult(LocalCache.findStatusesForUser(myUser)) }
|
withContext(Dispatchers.IO) {
|
||||||
|
onResult(LocalCache.findStatusesForUser(myUser))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findOtsEventsForNote(
|
suspend fun findOtsEventsForNote(
|
||||||
note: Note,
|
note: Note,
|
||||||
onResult: (Long?) -> Unit,
|
onResult: (Long?) -> Unit,
|
||||||
) {
|
) {
|
||||||
viewModelScope.launch(Dispatchers.IO) { onResult(LocalCache.findEarliestOtsForNote(note)) }
|
withContext(Dispatchers.IO) {
|
||||||
|
onResult(LocalCache.findEarliestOtsForNote(note))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun checkGetOrCreateChannel(key: HexKey): Channel? {
|
private suspend fun checkGetOrCreateChannel(key: HexKey): Channel? {
|
||||||
|
|||||||
@@ -33,11 +33,14 @@ class Lud06 {
|
|||||||
val url = toLnUrlp(str)
|
val url = toLnUrlp(str)
|
||||||
|
|
||||||
val matcher = LNURLP_PATTERN.matcher(url)
|
val matcher = LNURLP_PATTERN.matcher(url)
|
||||||
matcher.find()
|
if (matcher.find()) {
|
||||||
val domain = matcher.group(2)
|
val domain = matcher.group(2)
|
||||||
val username = matcher.group(3)
|
val username = matcher.group(3)
|
||||||
|
|
||||||
"$username@$domain"
|
"$username@$domain"
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
} catch (t: Throwable) {
|
} catch (t: Throwable) {
|
||||||
t.printStackTrace()
|
t.printStackTrace()
|
||||||
Log.w("Lud06ToLud16", "Fail to convert LUD06 to LUD16", t)
|
Log.w("Lud06ToLud16", "Fail to convert LUD06 to LUD16", t)
|
||||||
|
|||||||
@@ -207,6 +207,8 @@ open class Event(
|
|||||||
|
|
||||||
override fun isExpired() = (expiration() ?: Long.MAX_VALUE) < TimeUtils.now()
|
override fun isExpired() = (expiration() ?: Long.MAX_VALUE) < TimeUtils.now()
|
||||||
|
|
||||||
|
override fun isExpirationBefore(time: Long) = (expiration() ?: Long.MAX_VALUE) < time
|
||||||
|
|
||||||
override fun getTagOfAddressableKind(kind: Int): ATag? {
|
override fun getTagOfAddressableKind(kind: Int): ATag? {
|
||||||
val kindStr = kind.toString()
|
val kindStr = kind.toString()
|
||||||
val aTag =
|
val aTag =
|
||||||
|
|||||||
@@ -137,5 +137,7 @@ interface EventInterface {
|
|||||||
|
|
||||||
fun isExpired(): Boolean
|
fun isExpired(): Boolean
|
||||||
|
|
||||||
|
fun isExpirationBefore(time: Long): Boolean
|
||||||
|
|
||||||
fun hasZapSplitSetup(): Boolean
|
fun hasZapSplitSetup(): Boolean
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user