refactor(cache): P3 simplifications — remove dead code, reduce abstractions
- Replace SubscriptionHealth map + data class with single lastEventAt Long? timestamp (only consumer was RelayHealthIndicator taking max()) - Replace consumer HashMap registry with when block (safe casts, compiler-checked, 9 kinds doesn't benefit from O(1) lookup) - Remove dead loadReactionsForNotes() (superseded by requestInteractions) - Remove unused BoundedLargeCache methods: containsKey, isEmpty, mapNotNull, forEach (zero external callers) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -736,7 +736,7 @@ fun MainContent(
|
||||
Row(Modifier.fillMaxSize().weight(1f)) {
|
||||
when (layoutMode) {
|
||||
LayoutMode.SINGLE_PANE -> {
|
||||
val healthMap by subscriptionsCoordinator.subscriptionHealth.collectAsState()
|
||||
val lastRelayEvent by subscriptionsCoordinator.lastEventAt.collectAsState()
|
||||
SinglePaneLayout(
|
||||
relayManager = relayManager,
|
||||
localCache = localCache,
|
||||
@@ -753,7 +753,7 @@ fun MainContent(
|
||||
onZapFeedback = onZapFeedback,
|
||||
signerConnectionState = signerConnectionState,
|
||||
lastPingTimeSec = lastPingTimeSec,
|
||||
subscriptionHealth = healthMap,
|
||||
lastRelayEventAt = lastRelayEvent,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
}
|
||||
|
||||
Vendored
-8
@@ -72,12 +72,8 @@ class BoundedLargeCache<K : Comparable<K>, V>(
|
||||
return removed
|
||||
}
|
||||
|
||||
fun containsKey(key: K): Boolean = inner.containsKey(key)
|
||||
|
||||
fun size(): Int = sizeCounter.get()
|
||||
|
||||
fun isEmpty(): Boolean = sizeCounter.get() == 0
|
||||
|
||||
fun clear() {
|
||||
inner.clear()
|
||||
sizeCounter.set(0)
|
||||
@@ -89,10 +85,6 @@ class BoundedLargeCache<K : Comparable<K>, V>(
|
||||
|
||||
fun filterIntoSet(consumer: CacheCollectors.BiFilter<K, V>): Set<V> = inner.filterIntoSet(consumer)
|
||||
|
||||
fun <R> mapNotNull(consumer: CacheCollectors.BiMapper<K, V, R?>): List<R> = inner.mapNotNull(consumer)
|
||||
|
||||
fun forEach(consumer: java.util.function.BiConsumer<K, V>) = inner.forEach(consumer)
|
||||
|
||||
fun count(consumer: CacheCollectors.BiFilter<K, V>): Int = inner.count(consumer)
|
||||
|
||||
private fun enforceSize() {
|
||||
|
||||
Vendored
+46
-23
@@ -82,25 +82,6 @@ class DesktopLocalCache : ICacheProvider {
|
||||
|
||||
val paymentTracker = NwcPaymentTracker()
|
||||
|
||||
// ----- Kind-based event consumer registry -----
|
||||
|
||||
private val consumers = HashMap<Int, (Event, NormalizedRelayUrl?) -> Boolean>()
|
||||
|
||||
init {
|
||||
consumers[MetadataEvent.KIND] = { e, _ ->
|
||||
consumeMetadata(e as MetadataEvent)
|
||||
true
|
||||
}
|
||||
consumers[TextNoteEvent.KIND] = { e, r -> consumeTextNote(e as TextNoteEvent, r) }
|
||||
consumers[ReactionEvent.KIND] = { e, r -> consumeReaction(e as ReactionEvent, r) }
|
||||
consumers[LnZapRequestEvent.KIND] = { e, r -> consumeZapRequest(e as LnZapRequestEvent, r) }
|
||||
consumers[LnZapEvent.KIND] = { e, r -> consumeZap(e as LnZapEvent, r) }
|
||||
consumers[RepostEvent.KIND] = { e, r -> consumeRepost(e as RepostEvent, r) }
|
||||
consumers[ContactListEvent.KIND] = { e, _ -> consumeContactList(e as ContactListEvent) }
|
||||
consumers[LongTextNoteEvent.KIND] = { e, r -> consumeLongTextNote(e as LongTextNoteEvent, r) }
|
||||
consumers[BookmarkListEvent.KIND] = { e, _ -> consumeBookmarkList(e as BookmarkListEvent) }
|
||||
}
|
||||
|
||||
// ----- User operations -----
|
||||
|
||||
override fun getUserIfExists(pubkey: HexKey): User? = users.get(pubkey)
|
||||
@@ -170,16 +151,58 @@ class DesktopLocalCache : ICacheProvider {
|
||||
}
|
||||
}
|
||||
|
||||
// ----- Event consumption (kind-based registry) -----
|
||||
// ----- Event consumption -----
|
||||
|
||||
/**
|
||||
* Routes an event to the appropriate consume method via kind-based registry.
|
||||
* O(1) dispatch. Returns true if the event was consumed (new), false if already seen.
|
||||
* Routes an event to the appropriate consume method.
|
||||
* Returns true if the event was consumed (new), false if already seen.
|
||||
*/
|
||||
fun consume(
|
||||
event: Event,
|
||||
relay: NormalizedRelayUrl?,
|
||||
): Boolean = consumers[event.kind]?.invoke(event, relay) ?: false
|
||||
): Boolean =
|
||||
when (event) {
|
||||
is MetadataEvent -> {
|
||||
consumeMetadata(event)
|
||||
true
|
||||
}
|
||||
|
||||
is TextNoteEvent -> {
|
||||
consumeTextNote(event, relay)
|
||||
}
|
||||
|
||||
is ReactionEvent -> {
|
||||
consumeReaction(event, relay)
|
||||
}
|
||||
|
||||
is LnZapRequestEvent -> {
|
||||
consumeZapRequest(event, relay)
|
||||
}
|
||||
|
||||
is LnZapEvent -> {
|
||||
consumeZap(event, relay)
|
||||
}
|
||||
|
||||
is RepostEvent -> {
|
||||
consumeRepost(event, relay)
|
||||
}
|
||||
|
||||
is ContactListEvent -> {
|
||||
consumeContactList(event)
|
||||
}
|
||||
|
||||
is LongTextNoteEvent -> {
|
||||
consumeLongTextNote(event, relay)
|
||||
}
|
||||
|
||||
is BookmarkListEvent -> {
|
||||
consumeBookmarkList(event)
|
||||
}
|
||||
|
||||
else -> {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumes a kind 1 text note event.
|
||||
|
||||
+5
-43
@@ -40,7 +40,6 @@ import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
@@ -68,11 +67,6 @@ import java.util.concurrent.ConcurrentHashMap
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
data class SubscriptionHealth(
|
||||
val lastEventReceivedAt: Long? = null,
|
||||
val eoseReceived: Boolean = false,
|
||||
)
|
||||
|
||||
class DesktopRelaySubscriptionsCoordinator(
|
||||
private val client: INostrClient,
|
||||
private val scope: CoroutineScope,
|
||||
@@ -112,26 +106,9 @@ class DesktopRelaySubscriptionsCoordinator(
|
||||
// Screen-triggered subscription Jobs — keyed by subId for proper cancellation
|
||||
private val screenSubscriptions = ConcurrentHashMap<String, Job>()
|
||||
|
||||
// Subscription health tracking
|
||||
private val _subscriptionHealth = MutableStateFlow<Map<String, SubscriptionHealth>>(emptyMap())
|
||||
val subscriptionHealth: StateFlow<Map<String, SubscriptionHealth>> = _subscriptionHealth.asStateFlow()
|
||||
|
||||
private fun updateHealth(
|
||||
subId: String,
|
||||
lastEventReceivedAt: Long? = null,
|
||||
eoseReceived: Boolean? = null,
|
||||
) {
|
||||
_subscriptionHealth.update { current ->
|
||||
current.toMutableMap().apply {
|
||||
val existing = this[subId] ?: SubscriptionHealth()
|
||||
this[subId] =
|
||||
existing.copy(
|
||||
lastEventReceivedAt = lastEventReceivedAt ?: existing.lastEventReceivedAt,
|
||||
eoseReceived = eoseReceived ?: existing.eoseReceived,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Last event received from any subscription — drives RelayHealthIndicator
|
||||
private val _lastEventAt = MutableStateFlow<Long?>(null)
|
||||
val lastEventAt: StateFlow<Long?> = _lastEventAt.asStateFlow()
|
||||
|
||||
/**
|
||||
* Central event router — consumes an event into the cache and emits to event stream.
|
||||
@@ -146,6 +123,7 @@ class DesktopRelaySubscriptionsCoordinator(
|
||||
try {
|
||||
val consumed = localCache.consume(event, relay)
|
||||
if (consumed) {
|
||||
_lastEventAt.value = System.currentTimeMillis()
|
||||
val note = localCache.getNoteIfExists(event.id) ?: return@launch
|
||||
eventBundler.invalidateList(note) { batch ->
|
||||
localCache.eventStream.emitNewNotes(batch)
|
||||
@@ -202,14 +180,6 @@ class DesktopRelaySubscriptionsCoordinator(
|
||||
forFilters: List<Filter>?,
|
||||
) {
|
||||
consumeEvent(event, relay)
|
||||
updateHealth(subId, lastEventReceivedAt = System.currentTimeMillis())
|
||||
}
|
||||
|
||||
override fun onEose(
|
||||
relay: NormalizedRelayUrl,
|
||||
forFilters: List<Filter>?,
|
||||
) {
|
||||
updateHealth(subId, eoseReceived = true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +202,6 @@ class DesktopRelaySubscriptionsCoordinator(
|
||||
fun releaseInteractions(subId: String) {
|
||||
screenSubscriptions.remove(subId)?.cancel()
|
||||
client.close(subId)
|
||||
_subscriptionHealth.update { it - subId }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -276,13 +245,6 @@ class DesktopRelaySubscriptionsCoordinator(
|
||||
feedMetadata.loadMetadataForPubkeys(pubkeys)
|
||||
}
|
||||
|
||||
/**
|
||||
* Load reactions for specific notes.
|
||||
*/
|
||||
fun loadReactionsForNotes(noteIds: List<HexKey>) {
|
||||
feedMetadata.loadReactionsForNotes(noteIds)
|
||||
}
|
||||
|
||||
// -- DM Subscription Support --
|
||||
|
||||
/** Active DM subscription IDs for cleanup */
|
||||
@@ -389,7 +351,7 @@ class DesktopRelaySubscriptionsCoordinator(
|
||||
client.close(subId)
|
||||
}
|
||||
screenSubscriptions.clear()
|
||||
_subscriptionHealth.value = emptyMap()
|
||||
_lastEventAt.value = null
|
||||
|
||||
unsubscribeFromDms()
|
||||
feedMetadata.clear()
|
||||
|
||||
+2
-7
@@ -65,7 +65,6 @@ import com.vitorpamplona.amethyst.desktop.cache.DesktopLocalCache
|
||||
import com.vitorpamplona.amethyst.desktop.network.DesktopRelayConnectionManager
|
||||
import com.vitorpamplona.amethyst.desktop.service.highlights.DesktopHighlightStore
|
||||
import com.vitorpamplona.amethyst.desktop.subscriptions.DesktopRelaySubscriptionsCoordinator
|
||||
import com.vitorpamplona.amethyst.desktop.subscriptions.SubscriptionHealth
|
||||
import com.vitorpamplona.amethyst.desktop.ui.ZapFeedback
|
||||
import com.vitorpamplona.amethyst.desktop.ui.components.RelayHealthIndicator
|
||||
import com.vitorpamplona.amethyst.desktop.ui.media.LocalIsImmersiveFullscreen
|
||||
@@ -110,7 +109,7 @@ fun SinglePaneLayout(
|
||||
onZapFeedback: (ZapFeedback) -> Unit,
|
||||
signerConnectionState: SignerConnectionState,
|
||||
lastPingTimeSec: Long?,
|
||||
subscriptionHealth: Map<String, SubscriptionHealth> = emptyMap(),
|
||||
lastRelayEventAt: Long? = null,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var currentColumnType by remember { mutableStateOf<DeckColumnType>(DeckColumnType.HomeFeed) }
|
||||
@@ -154,12 +153,8 @@ fun SinglePaneLayout(
|
||||
Spacer(Modifier.weight(1f))
|
||||
|
||||
// Relay health — shows elapsed time since last event (hidden when <30s)
|
||||
val latestEvent =
|
||||
subscriptionHealth.values
|
||||
.mapNotNull { it.lastEventReceivedAt }
|
||||
.maxOrNull()
|
||||
RelayHealthIndicator(
|
||||
lastEventReceivedAt = latestEvent,
|
||||
lastEventReceivedAt = lastRelayEventAt,
|
||||
modifier = Modifier.padding(bottom = 4.dp),
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user