Adds a Deletion event cache.
This commit is contained in:
@@ -24,6 +24,7 @@ import android.util.Log
|
||||
import android.util.LruCache
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.vitorpamplona.amethyst.Amethyst
|
||||
import com.vitorpamplona.amethyst.commons.data.DeletionIndex
|
||||
import com.vitorpamplona.amethyst.commons.data.LargeCache
|
||||
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
||||
import com.vitorpamplona.amethyst.service.relays.Relay
|
||||
@@ -133,6 +134,8 @@ object LocalCache {
|
||||
val channels = LargeCache<HexKey, Channel>()
|
||||
val awaitingPaymentRequests = ConcurrentHashMap<HexKey, Pair<Note?, (LnZapPaymentResponseEvent) -> Unit>>(10)
|
||||
|
||||
val deletionIndex = DeletionIndex()
|
||||
|
||||
fun checkGetOrCreateUser(key: String): User? {
|
||||
// checkNotInMainThread()
|
||||
|
||||
@@ -956,10 +959,11 @@ object LocalCache {
|
||||
}
|
||||
|
||||
fun consume(event: DeletionEvent) {
|
||||
deletionIndex.add(event)
|
||||
|
||||
var deletedAtLeastOne = false
|
||||
|
||||
event
|
||||
.deleteEvents()
|
||||
event.deleteEvents()
|
||||
.mapNotNull { getNoteIfExists(it) }
|
||||
.forEach { deleteNote ->
|
||||
// must be the same author
|
||||
@@ -2210,6 +2214,8 @@ object LocalCache {
|
||||
event: Event,
|
||||
relay: Relay?,
|
||||
) {
|
||||
if (deletionIndex.hasBeenDeleted(event)) return
|
||||
|
||||
checkNotInMainThread()
|
||||
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright (c) 2024 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.commons.data
|
||||
|
||||
import com.vitorpamplona.quartz.encoders.HexKey
|
||||
import com.vitorpamplona.quartz.events.AddressableEvent
|
||||
import com.vitorpamplona.quartz.events.DeletionEvent
|
||||
import com.vitorpamplona.quartz.events.Event
|
||||
|
||||
class DeletionIndex {
|
||||
data class DeletionRequest(val reference: String, val publicKey: HexKey)
|
||||
|
||||
// stores a set of id OR atags (kind:pubkey:dtag) by pubkey with the created at of the deletion event.
|
||||
// Anything newer than the date should not be deleted.
|
||||
private val deletedReferencesBefore = LargeCache<DeletionRequest, Long>()
|
||||
|
||||
fun add(event: DeletionEvent) {
|
||||
event.tags.forEach {
|
||||
if (it.size > 1 && (it[0] == "a" || it[0] == "e")) {
|
||||
add(it[1], event.createdAt, event.pubKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun add(
|
||||
ref: String,
|
||||
createdAt: Long,
|
||||
byPubKey: HexKey,
|
||||
) {
|
||||
val key = DeletionRequest(ref, byPubKey)
|
||||
val deletionTime = deletedReferencesBefore.get(key)
|
||||
if (deletionTime == null) {
|
||||
deletedReferencesBefore.put(key, createdAt)
|
||||
} else {
|
||||
// updates with newer deletion.
|
||||
if (createdAt > deletionTime) {
|
||||
deletedReferencesBefore.put(key, createdAt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun hasBeenDeleted(event: Event): Boolean {
|
||||
val key = DeletionRequest(event.id, event.pubKey)
|
||||
if (hasBeenDeleted(key)) return true
|
||||
|
||||
if (event is AddressableEvent) {
|
||||
if (hasBeenDeleted(key, event.createdAt)) return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun hasBeenDeleted(key: DeletionRequest) = deletedReferencesBefore.containsKey(key)
|
||||
|
||||
private fun hasBeenDeleted(
|
||||
key: DeletionRequest,
|
||||
createdAt: Long,
|
||||
): Boolean {
|
||||
val deletionTime = deletedReferencesBefore.get(key)
|
||||
return deletionTime != null && createdAt < deletionTime
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ import androidx.compose.runtime.Immutable
|
||||
|
||||
@Immutable
|
||||
data class ATag(val kind: Int, val pubKeyHex: String, val dTag: String, val relay: String?) {
|
||||
fun toTag() = "$kind:$pubKeyHex:$dTag"
|
||||
fun toTag() = assembleATag(kind, pubKeyHex, dTag)
|
||||
|
||||
fun toNAddr(): String {
|
||||
return TlvBuilder()
|
||||
@@ -40,6 +40,12 @@ data class ATag(val kind: Int, val pubKeyHex: String, val dTag: String, val rela
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun assembleATag(
|
||||
kind: Int,
|
||||
pubKeyHex: String,
|
||||
dTag: String,
|
||||
) = "$kind:$pubKeyHex:$dTag"
|
||||
|
||||
fun isATag(key: String): Boolean {
|
||||
return key.startsWith("naddr1") || key.contains(":")
|
||||
}
|
||||
|
||||
@@ -514,6 +514,8 @@ interface AddressableEvent {
|
||||
fun dTag(): String
|
||||
|
||||
fun address(): ATag
|
||||
|
||||
fun addressTag(): String
|
||||
}
|
||||
|
||||
@Immutable
|
||||
@@ -529,6 +531,11 @@ open class BaseAddressableEvent(
|
||||
override fun dTag() = tags.firstOrNull { it.size > 1 && it[0] == "d" }?.get(1) ?: ""
|
||||
|
||||
override fun address() = ATag(kind, pubKey, dTag(), null)
|
||||
|
||||
/**
|
||||
* Creates the tag in a memory effecient way (without creating the ATag class
|
||||
*/
|
||||
override fun addressTag() = ATag.assembleATag(kind, pubKey, dTag())
|
||||
}
|
||||
|
||||
fun String.bytesUsedInMemory(): Int {
|
||||
|
||||
@@ -39,6 +39,8 @@ class LongTextNoteEvent(
|
||||
|
||||
override fun address() = ATag(kind, pubKey, dTag(), null)
|
||||
|
||||
override fun addressTag() = ATag.assembleATag(kind, pubKey, dTag())
|
||||
|
||||
fun topics() = hashtags()
|
||||
|
||||
fun title() = tags.firstOrNull { it.size > 1 && it[0] == "title" }?.get(1)
|
||||
|
||||
@@ -39,6 +39,8 @@ class WikiNoteEvent(
|
||||
|
||||
override fun address() = ATag(kind, pubKey, dTag(), null)
|
||||
|
||||
override fun addressTag() = ATag.assembleATag(kind, pubKey, dTag())
|
||||
|
||||
fun topics() = hashtags()
|
||||
|
||||
fun title() = tags.firstOrNull { it.size > 1 && it[0] == "title" }?.get(1)
|
||||
|
||||
Reference in New Issue
Block a user