Refactors GiftWrap caching to delete encrypted text and reload the wrap if necessary.
- Changes host to a host stub to reduce memory use - Only download GiftWraps form 2 days past the last EOSE
This commit is contained in:
@@ -39,7 +39,9 @@ import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
|||||||
import com.vitorpamplona.amethyst.service.relays.Client
|
import com.vitorpamplona.amethyst.service.relays.Client
|
||||||
import com.vitorpamplona.amethyst.service.relays.Constants
|
import com.vitorpamplona.amethyst.service.relays.Constants
|
||||||
import com.vitorpamplona.amethyst.service.relays.FeedType
|
import com.vitorpamplona.amethyst.service.relays.FeedType
|
||||||
|
import com.vitorpamplona.amethyst.service.relays.JsonFilter
|
||||||
import com.vitorpamplona.amethyst.service.relays.Relay
|
import com.vitorpamplona.amethyst.service.relays.Relay
|
||||||
|
import com.vitorpamplona.amethyst.service.relays.TypedFilter
|
||||||
import com.vitorpamplona.amethyst.ui.components.BundledUpdate
|
import com.vitorpamplona.amethyst.ui.components.BundledUpdate
|
||||||
import com.vitorpamplona.quartz.crypto.KeyPair
|
import com.vitorpamplona.quartz.crypto.KeyPair
|
||||||
import com.vitorpamplona.quartz.encoders.ATag
|
import com.vitorpamplona.quartz.encoders.ATag
|
||||||
@@ -856,7 +858,22 @@ class Account(
|
|||||||
fun broadcast(note: Note) {
|
fun broadcast(note: Note) {
|
||||||
note.event?.let {
|
note.event?.let {
|
||||||
if (it is WrappedEvent && it.host != null) {
|
if (it is WrappedEvent && it.host != null) {
|
||||||
it.host?.let { hostEvent -> Client.send(hostEvent) }
|
it.host?.let {
|
||||||
|
Client.sendFilterAndStopOnFirstResponse(
|
||||||
|
filters =
|
||||||
|
listOf(
|
||||||
|
TypedFilter(
|
||||||
|
setOf(FeedType.FOLLOWS, FeedType.PRIVATE_DMS, FeedType.GLOBAL),
|
||||||
|
JsonFilter(
|
||||||
|
ids = listOf(it.id),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onResponse = {
|
||||||
|
Client.send(it)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Client.send(it)
|
Client.send(it)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1808,7 +1808,7 @@ object LocalCache {
|
|||||||
// Already processed this event.
|
// Already processed this event.
|
||||||
if (note.event != null) return
|
if (note.event != null) return
|
||||||
|
|
||||||
note.loadEvent(event, author, emptyList())
|
note.loadEvent(event.copyNoContent(), author, emptyList())
|
||||||
|
|
||||||
refreshObservers(note)
|
refreshObservers(note)
|
||||||
}
|
}
|
||||||
@@ -1828,7 +1828,7 @@ object LocalCache {
|
|||||||
// Already processed this event.
|
// Already processed this event.
|
||||||
if (note.event != null) return
|
if (note.event != null) return
|
||||||
|
|
||||||
note.loadEvent(event, author, emptyList())
|
note.loadEvent(event.copyNoContent(), author, emptyList())
|
||||||
|
|
||||||
refreshObservers(note)
|
refreshObservers(note)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ open class Note(val idHex: String) {
|
|||||||
Nip19Bech32.createNEvent(
|
Nip19Bech32.createNEvent(
|
||||||
host.id,
|
host.id,
|
||||||
host.pubKey,
|
host.pubKey,
|
||||||
host.kind(),
|
host.kind,
|
||||||
relays.firstOrNull()?.url,
|
relays.firstOrNull()?.url,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -239,6 +239,14 @@ object NostrAccountDataSource : NostrDataSource("AccountData") {
|
|||||||
JsonFilter(
|
JsonFilter(
|
||||||
kinds = listOf(GiftWrapEvent.KIND),
|
kinds = listOf(GiftWrapEvent.KIND),
|
||||||
tags = mapOf("p" to listOf(account.userProfile().pubkeyHex)),
|
tags = mapOf("p" to listOf(account.userProfile().pubkeyHex)),
|
||||||
|
since =
|
||||||
|
latestEOSEs.users[account.userProfile()]
|
||||||
|
?.followList
|
||||||
|
?.get("&&((GIFTWRAPS_EOSE))&&")
|
||||||
|
?.relayList
|
||||||
|
?.mapValues {
|
||||||
|
EOSETime(it.value.time - TimeUtils.twoDays())
|
||||||
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -251,6 +259,13 @@ object NostrAccountDataSource : NostrDataSource("AccountData") {
|
|||||||
relayUrl,
|
relayUrl,
|
||||||
time,
|
time,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
latestEOSEs.addOrUpdate(
|
||||||
|
account.userProfile(),
|
||||||
|
"&&((GIFTWRAPS_EOSE))&&",
|
||||||
|
relayUrl,
|
||||||
|
time,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
hasLoadedTheBasics[account.userProfile()] = true
|
hasLoadedTheBasics[account.userProfile()] = true
|
||||||
|
|
||||||
|
|||||||
@@ -100,6 +100,34 @@ object Client : RelayPool.Listener {
|
|||||||
RelayPool.sendFilter(subscriptionId, filters)
|
RelayPool.sendFilter(subscriptionId, filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun sendFilterAndStopOnFirstResponse(
|
||||||
|
subscriptionId: String = UUID.randomUUID().toString().substring(0..10),
|
||||||
|
filters: List<TypedFilter> = listOf(),
|
||||||
|
onResponse: (Event) -> Unit,
|
||||||
|
) {
|
||||||
|
checkNotInMainThread()
|
||||||
|
|
||||||
|
subscribe(
|
||||||
|
object : Listener() {
|
||||||
|
override fun onEvent(
|
||||||
|
event: Event,
|
||||||
|
subId: String,
|
||||||
|
relay: Relay,
|
||||||
|
afterEOSE: Boolean,
|
||||||
|
) {
|
||||||
|
if (subId == subscriptionId) {
|
||||||
|
onResponse(event)
|
||||||
|
unsubscribe(this)
|
||||||
|
close(subscriptionId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
subscriptions = subscriptions + Pair(subscriptionId, filters)
|
||||||
|
RelayPool.sendFilter(subscriptionId, filters)
|
||||||
|
}
|
||||||
|
|
||||||
fun sendFilterOnlyIfDisconnected(
|
fun sendFilterOnlyIfDisconnected(
|
||||||
subscriptionId: String = UUID.randomUUID().toString().substring(0..10),
|
subscriptionId: String = UUID.randomUUID().toString().substring(0..10),
|
||||||
filters: List<TypedFilter> = listOf(),
|
filters: List<TypedFilter> = listOf(),
|
||||||
|
|||||||
@@ -526,9 +526,15 @@ open class WrappedEvent(
|
|||||||
content: String,
|
content: String,
|
||||||
sig: HexKey,
|
sig: HexKey,
|
||||||
) : Event(id, pubKey, createdAt, kind, tags, content, sig) {
|
) : Event(id, pubKey, createdAt, kind, tags, content, sig) {
|
||||||
@Transient var host: Event? = null // host event to broadcast when needed
|
@Transient var host: HostStub? = null // host event to broadcast when needed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class HostStub(
|
||||||
|
val id: HexKey,
|
||||||
|
val pubKey: HexKey,
|
||||||
|
val kind: Int,
|
||||||
|
)
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
interface AddressableEvent {
|
interface AddressableEvent {
|
||||||
fun dTag(): String
|
fun dTag(): String
|
||||||
|
|||||||
@@ -38,6 +38,22 @@ class GiftWrapEvent(
|
|||||||
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
|
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||||
@Transient private var cachedInnerEvent: Map<HexKey, Event?> = mapOf()
|
@Transient private var cachedInnerEvent: Map<HexKey, Event?> = mapOf()
|
||||||
|
|
||||||
|
fun copyNoContent(): GiftWrapEvent {
|
||||||
|
val copy =
|
||||||
|
GiftWrapEvent(
|
||||||
|
id,
|
||||||
|
pubKey,
|
||||||
|
createdAt,
|
||||||
|
tags,
|
||||||
|
"",
|
||||||
|
sig,
|
||||||
|
)
|
||||||
|
|
||||||
|
copy.cachedInnerEvent = cachedInnerEvent
|
||||||
|
|
||||||
|
return copy
|
||||||
|
}
|
||||||
|
|
||||||
override fun isContentEncoded() = true
|
override fun isContentEncoded() = true
|
||||||
|
|
||||||
fun preCachedGift(signer: NostrSigner): Event? {
|
fun preCachedGift(signer: NostrSigner): Event? {
|
||||||
@@ -61,7 +77,7 @@ class GiftWrapEvent(
|
|||||||
}
|
}
|
||||||
unwrap(signer) { gift ->
|
unwrap(signer) { gift ->
|
||||||
if (gift is WrappedEvent) {
|
if (gift is WrappedEvent) {
|
||||||
gift.host = this
|
gift.host = HostStub(this.id, this.pubKey, this.kind)
|
||||||
}
|
}
|
||||||
addToCache(signer.pubKey, gift)
|
addToCache(signer.pubKey, gift)
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,23 @@ class SealedGossipEvent(
|
|||||||
) : WrappedEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
|
) : WrappedEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||||
@Transient private var cachedInnerEvent: Map<HexKey, Event?> = mapOf()
|
@Transient private var cachedInnerEvent: Map<HexKey, Event?> = mapOf()
|
||||||
|
|
||||||
|
fun copyNoContent(): SealedGossipEvent {
|
||||||
|
val copy =
|
||||||
|
SealedGossipEvent(
|
||||||
|
id,
|
||||||
|
pubKey,
|
||||||
|
createdAt,
|
||||||
|
tags,
|
||||||
|
"",
|
||||||
|
sig,
|
||||||
|
)
|
||||||
|
|
||||||
|
copy.cachedInnerEvent = cachedInnerEvent
|
||||||
|
copy.host = host
|
||||||
|
|
||||||
|
return copy
|
||||||
|
}
|
||||||
|
|
||||||
override fun isContentEncoded() = true
|
override fun isContentEncoded() = true
|
||||||
|
|
||||||
fun preCachedGossip(signer: NostrSigner): Event? {
|
fun preCachedGossip(signer: NostrSigner): Event? {
|
||||||
@@ -64,7 +81,7 @@ class SealedGossipEvent(
|
|||||||
unseal(signer) { gossip ->
|
unseal(signer) { gossip ->
|
||||||
val event = gossip.mergeWith(this)
|
val event = gossip.mergeWith(this)
|
||||||
if (event is WrappedEvent) {
|
if (event is WrappedEvent) {
|
||||||
event.host = host ?: this
|
event.host = host ?: HostStub(this.id, this.pubKey, this.kind)
|
||||||
}
|
}
|
||||||
addToCache(signer.pubKey, event)
|
addToCache(signer.pubKey, event)
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ object TimeUtils {
|
|||||||
|
|
||||||
fun eightHoursAgo() = now() - EIGHT_HOURS
|
fun eightHoursAgo() = now() - EIGHT_HOURS
|
||||||
|
|
||||||
|
fun twoDays() = ONE_DAY * 2
|
||||||
|
|
||||||
fun oneWeekAgo() = now() - ONE_WEEK
|
fun oneWeekAgo() = now() - ONE_WEEK
|
||||||
|
|
||||||
fun randomWithinAWeek() = System.currentTimeMillis() / 1000 - CryptoUtils.randomInt(ONE_WEEK)
|
fun randomWithinAWeek() = System.currentTimeMillis() / 1000 - CryptoUtils.randomInt(ONE_WEEK)
|
||||||
|
|||||||
Reference in New Issue
Block a user