Fixes the fact that SortedSets can have duplicated objects in parallel adds.
Moves to concurrent sets with a Comparator that checks the object's reference to remove duplications in the set when events from addressables differ
This commit is contained in:
@@ -32,11 +32,11 @@ import com.vitorpamplona.amethyst.commons.model.privateChats.ChatroomList
|
|||||||
import com.vitorpamplona.amethyst.commons.services.nwc.NwcPaymentTracker
|
import com.vitorpamplona.amethyst.commons.services.nwc.NwcPaymentTracker
|
||||||
import com.vitorpamplona.amethyst.isDebug
|
import com.vitorpamplona.amethyst.isDebug
|
||||||
import com.vitorpamplona.amethyst.model.nip51Lists.HiddenUsersState
|
import com.vitorpamplona.amethyst.model.nip51Lists.HiddenUsersState
|
||||||
|
import com.vitorpamplona.amethyst.model.observables.CreatedAtIdHexComparator
|
||||||
import com.vitorpamplona.amethyst.model.observables.EventListMatchingFilter
|
import com.vitorpamplona.amethyst.model.observables.EventListMatchingFilter
|
||||||
import com.vitorpamplona.amethyst.model.observables.NoteListMatchingFilter
|
import com.vitorpamplona.amethyst.model.observables.NoteListMatchingFilter
|
||||||
import com.vitorpamplona.amethyst.service.BundledInsert
|
import com.vitorpamplona.amethyst.service.BundledInsert
|
||||||
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
||||||
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
|
|
||||||
import com.vitorpamplona.amethyst.ui.note.dateFormatter
|
import com.vitorpamplona.amethyst.ui.note.dateFormatter
|
||||||
import com.vitorpamplona.quartz.experimental.audio.header.AudioHeaderEvent
|
import com.vitorpamplona.quartz.experimental.audio.header.AudioHeaderEvent
|
||||||
import com.vitorpamplona.quartz.experimental.audio.track.AudioTrackEvent
|
import com.vitorpamplona.quartz.experimental.audio.track.AudioTrackEvent
|
||||||
@@ -307,7 +307,7 @@ object LocalCache : ILocalCache, ICacheProvider {
|
|||||||
(addressableMatches + noteMatches)
|
(addressableMatches + noteMatches)
|
||||||
}
|
}
|
||||||
|
|
||||||
return limitedSet.toSortedSet(DefaultFeedOrder)
|
return limitedSet.toSortedSet(CreatedAtIdHexComparator)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun observeNotes(filter: Filter): Flow<List<Note>> =
|
fun observeNotes(filter: Filter): Flow<List<Note>> =
|
||||||
|
|||||||
+26
@@ -23,6 +23,32 @@ package com.vitorpamplona.amethyst.model.observables
|
|||||||
import com.vitorpamplona.amethyst.model.AddressableNote
|
import com.vitorpamplona.amethyst.model.AddressableNote
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
|
|
||||||
|
val CreatedAtIdHexComparator: Comparator<Note> =
|
||||||
|
Comparator { note1, note2 ->
|
||||||
|
// Sort by created_at and idhex, but define uniqueness by reference
|
||||||
|
if (note1 === note2) return@Comparator 0
|
||||||
|
|
||||||
|
if (note1 == null) return@Comparator 1 // null is greater, moves to last
|
||||||
|
if (note2 == null) return@Comparator -1 // null is greater, moves to last
|
||||||
|
|
||||||
|
val createdAt1 = note1.createdAt()
|
||||||
|
val createdAt2 = note2.createdAt()
|
||||||
|
|
||||||
|
if (createdAt1 == createdAt2) {
|
||||||
|
val event1 = note1.event
|
||||||
|
val event2 = note2.event
|
||||||
|
|
||||||
|
if (event1 == null && event2 == null) return@Comparator 0
|
||||||
|
if (event1 == null) return@Comparator 1 // null is greater, moves to last
|
||||||
|
if (event2 == null) return@Comparator -1 // null is greater, moves to last
|
||||||
|
|
||||||
|
event1.id.compareTo(event2.id)
|
||||||
|
} else {
|
||||||
|
// Descending, inverts
|
||||||
|
compareValues(createdAt2, createdAt1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object CreatedAtComparator : Comparator<Note> {
|
object CreatedAtComparator : Comparator<Note> {
|
||||||
override fun compare(
|
override fun compare(
|
||||||
first: Note?,
|
first: Note?,
|
||||||
|
|||||||
+4
-4
@@ -23,10 +23,9 @@ package com.vitorpamplona.amethyst.model.observables
|
|||||||
import com.vitorpamplona.amethyst.model.LocalCache
|
import com.vitorpamplona.amethyst.model.LocalCache
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
import com.vitorpamplona.amethyst.model.Observable
|
import com.vitorpamplona.amethyst.model.Observable
|
||||||
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
|
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||||
import java.util.SortedSet
|
import java.util.concurrent.ConcurrentSkipListSet
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a list of events (regular and addressable)
|
* Creates a list of events (regular and addressable)
|
||||||
@@ -39,7 +38,7 @@ class EventListMatchingFilter(
|
|||||||
private val update: (List<Event>) -> Unit,
|
private val update: (List<Event>) -> Unit,
|
||||||
) : Observable {
|
) : Observable {
|
||||||
// Keeping this here blocks it from being cleared from memory
|
// Keeping this here blocks it from being cleared from memory
|
||||||
var currentResults: SortedSet<Note> = sortedSetOf<Note>(DefaultFeedOrder)
|
var currentResults: ConcurrentSkipListSet<Note> = ConcurrentSkipListSet(CreatedAtIdHexComparator)
|
||||||
|
|
||||||
override fun new(
|
override fun new(
|
||||||
event: Event,
|
event: Event,
|
||||||
@@ -51,6 +50,7 @@ class EventListMatchingFilter(
|
|||||||
if (limit != null && currentResults.size > limit) {
|
if (limit != null && currentResults.size > limit) {
|
||||||
currentResults.remove(currentResults.last())
|
currentResults.remove(currentResults.last())
|
||||||
}
|
}
|
||||||
|
|
||||||
update(currentResults.mapNotNull { it.event })
|
update(currentResults.mapNotNull { it.event })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ class EventListMatchingFilter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun init() {
|
fun init() {
|
||||||
currentResults = cache.filter(filter)
|
currentResults = ConcurrentSkipListSet(cache.filter(filter))
|
||||||
update(currentResults.mapNotNull { it.event })
|
update(currentResults.mapNotNull { it.event })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-4
@@ -23,10 +23,9 @@ package com.vitorpamplona.amethyst.model.observables
|
|||||||
import com.vitorpamplona.amethyst.model.LocalCache
|
import com.vitorpamplona.amethyst.model.LocalCache
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
import com.vitorpamplona.amethyst.model.Observable
|
import com.vitorpamplona.amethyst.model.Observable
|
||||||
import com.vitorpamplona.amethyst.ui.dal.DefaultFeedOrder
|
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||||
import java.util.SortedSet
|
import java.util.concurrent.ConcurrentSkipListSet
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a list of notes (regular and addressable)
|
* Creates a list of notes (regular and addressable)
|
||||||
@@ -39,7 +38,7 @@ class NoteListMatchingFilter(
|
|||||||
private val cache: LocalCache,
|
private val cache: LocalCache,
|
||||||
private val update: (List<Note>) -> Unit,
|
private val update: (List<Note>) -> Unit,
|
||||||
) : Observable {
|
) : Observable {
|
||||||
var currentResults: SortedSet<Note> = sortedSetOf<Note>(DefaultFeedOrder)
|
var currentResults: ConcurrentSkipListSet<Note> = ConcurrentSkipListSet(CreatedAtIdHexComparator)
|
||||||
|
|
||||||
override fun new(
|
override fun new(
|
||||||
event: Event,
|
event: Event,
|
||||||
@@ -64,7 +63,7 @@ class NoteListMatchingFilter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun init() {
|
fun init() {
|
||||||
currentResults = cache.filter(filter)
|
currentResults = ConcurrentSkipListSet(cache.filter(filter))
|
||||||
update(currentResults.toList())
|
update(currentResults.toList())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user