mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-09-19 04:59:59 +00:00
fix(notes): drop expired notes and match geohash tags case-insensitively
Two ways the Android note handler disagrees with the iOS one, on the same event: - NIP-40. Relays are not required to drop expired events, so iOS checks the `expiration` tag client-side "so 24h dead drops actually vanish". Android had no such check, so an expired note kept showing until the list was cleared - the opposite of what a dead drop promises. - Case. Tag names and geohashes are case-insensitive, and iOS lowercases both before matching. Android compared them exactly, so a note tagged ["G", "U4PRUYD"] was visible on iOS and invisible on Android. Both now follow the iOS handler.
This commit is contained in:
parent
b028270cc4
commit
293a751596
@ -417,23 +417,30 @@ class LocationNotesManager private constructor() {
|
||||
return
|
||||
}
|
||||
|
||||
// Check for geohash tag
|
||||
val geohashTag = event.tags.firstOrNull { it.size >= 2 && it[0] == "g" }
|
||||
// Check for geohash tag. Tag names and geohashes are case-insensitive,
|
||||
// and iOS matches them lowercased, so a note tagged ["G", "U4PRUYD"]
|
||||
// has to be the same note on both platforms.
|
||||
val validGeohashes = subscribedGeohashes.map { it.lowercase() }.toSet()
|
||||
val geohashTag = event.tags.firstOrNull {
|
||||
it.size >= 2 && it[0].lowercase() == "g" && validGeohashes.contains(it[1].lowercase())
|
||||
}
|
||||
if (geohashTag == null) {
|
||||
Log.v(TAG, "Ignoring event without geohash tag: ${event.id.take(16)}...")
|
||||
Log.v(TAG, "Ignoring event without a matching geohash tag: ${event.id.take(16)}...")
|
||||
return
|
||||
}
|
||||
|
||||
// Check if matches current geohash
|
||||
val eventGeohash = geohashTag[1]
|
||||
if (!subscribedGeohashes.contains(eventGeohash)) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// Deduplicate
|
||||
if (noteIDs.contains(event.id)) {
|
||||
return
|
||||
}
|
||||
|
||||
// NIP-40: relays are not required to drop expired events, so enforce it
|
||||
// here - otherwise a 24h dead drop stays visible past its expiry.
|
||||
val expiresAt = expirationSeconds(event)
|
||||
if (expiresAt != null && expiresAt * 1000L <= System.currentTimeMillis()) {
|
||||
Log.v(TAG, "Ignoring expired note: ${event.id.take(16)}...")
|
||||
return
|
||||
}
|
||||
|
||||
// Extract nickname from tags
|
||||
val nicknameTag = event.tags.firstOrNull { it.size >= 2 && it[0] == "n" }
|
||||
@ -465,6 +472,15 @@ class LocationNotesManager private constructor() {
|
||||
_state.value = State.READY
|
||||
}
|
||||
|
||||
/**
|
||||
* The NIP-40 `expiration` tag as unix seconds, when the event carries one.
|
||||
*/
|
||||
private fun expirationSeconds(event: NostrEvent): Long? {
|
||||
val tag = event.tags.firstOrNull { it.size >= 2 && it[0].lowercase() == "expiration" }
|
||||
?: return null
|
||||
return tag[1].toLongOrNull()
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim oldest notes to stay within memory limit
|
||||
*/
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user