Saves a copy of the NIP65 and NIP17 relay lists locally

This commit is contained in:
Vitor Pamplona
2024-06-24 17:56:24 -04:00
parent 8cef7bcb75
commit 839cadea35
2 changed files with 167 additions and 20 deletions

View File

@@ -42,6 +42,8 @@ import com.vitorpamplona.quartz.encoders.Nip47WalletConnect
import com.vitorpamplona.quartz.encoders.hexToByteArray
import com.vitorpamplona.quartz.encoders.toHexKey
import com.vitorpamplona.quartz.encoders.toNpub
import com.vitorpamplona.quartz.events.AdvertisedRelayListEvent
import com.vitorpamplona.quartz.events.ChatMessageRelayListEvent
import com.vitorpamplona.quartz.events.ContactListEvent
import com.vitorpamplona.quartz.events.Event
import com.vitorpamplona.quartz.events.LnZapEvent
@@ -90,6 +92,8 @@ private object PrefKeys {
const val DEFAULT_DISCOVERY_FOLLOW_LIST = "defaultDiscoveryFollowList"
const val ZAP_PAYMENT_REQUEST_SERVER = "zapPaymentServer"
const val LATEST_CONTACT_LIST = "latestContactList"
const val LATEST_DM_RELAY_LIST = "latestDMRelayList"
const val LATEST_NIP65_RELAY_LIST = "latestNIP65RelayList"
const val HIDE_DELETE_REQUEST_DIALOG = "hide_delete_request_dialog"
const val HIDE_BLOCK_ALERT_DIALOG = "hide_block_alert_dialog"
const val HIDE_NIP_17_WARNING_DIALOG = "hide_nip24_warning_dialog" // delete later
@@ -311,10 +315,33 @@ object LocalPreferences {
PrefKeys.ZAP_PAYMENT_REQUEST_SERVER,
Event.mapper.writeValueAsString(account.zapPaymentRequest),
)
putString(
PrefKeys.LATEST_CONTACT_LIST,
Event.mapper.writeValueAsString(account.backupContactList),
)
if (account.backupContactList != null) {
putString(
PrefKeys.LATEST_CONTACT_LIST,
Event.mapper.writeValueAsString(account.backupContactList),
)
} else {
remove(PrefKeys.LATEST_CONTACT_LIST)
}
if (account.backupDMRelayList != null) {
putString(
PrefKeys.LATEST_DM_RELAY_LIST,
Event.mapper.writeValueAsString(account.backupDMRelayList),
)
} else {
remove(PrefKeys.LATEST_DM_RELAY_LIST)
}
if (account.backupNIP65RelayList != null) {
putString(
PrefKeys.LATEST_NIP65_RELAY_LIST,
Event.mapper.writeValueAsString(account.backupNIP65RelayList),
)
} else {
remove(PrefKeys.LATEST_NIP65_RELAY_LIST)
}
putBoolean(PrefKeys.HIDE_DELETE_REQUEST_DIALOG, account.hideDeleteRequestDialog)
putBoolean(PrefKeys.HIDE_NIP_17_WARNING_DIALOG, account.hideNIP17WarningDialog)
putBoolean(PrefKeys.HIDE_BLOCK_ALERT_DIALOG, account.hideBlockAlertDialog)
@@ -471,8 +498,8 @@ object LocalPreferences {
val latestContactList =
try {
getString(PrefKeys.LATEST_CONTACT_LIST, null)?.let {
println("Decoding Contact List: " + it)
if (it != null) {
if (it != "null") {
println("Decoding Contact List: $it")
Event.fromJson(it) as ContactListEvent?
} else {
null
@@ -488,6 +515,46 @@ object LocalPreferences {
null
}
val latestDmRelayList =
try {
getString(PrefKeys.LATEST_DM_RELAY_LIST, null)?.let {
if (it != "null") {
println("Decoding DM Relay List: $it")
Event.fromJson(it) as ChatMessageRelayListEvent?
} else {
null
}
}
} catch (e: Throwable) {
if (e is CancellationException) throw e
Log.w(
"LocalPreferences",
"Error Decoding DM Relay List ${getString(PrefKeys.LATEST_DM_RELAY_LIST, null)}",
e,
)
null
}
val latestNip65RelayList =
try {
getString(PrefKeys.LATEST_NIP65_RELAY_LIST, null)?.let {
if (it != "null") {
println("Decoding NIP65 Relay List: $it")
Event.fromJson(it) as AdvertisedRelayListEvent?
} else {
null
}
}
} catch (e: Throwable) {
if (e is CancellationException) throw e
Log.w(
"LocalPreferences",
"Error Decoding NIP65 Relay List ${getString(PrefKeys.LATEST_NIP65_RELAY_LIST, null)}",
e,
)
null
}
val pendingAttestations =
try {
getString(PrefKeys.PENDING_ATTESTATIONS, null)?.let {
@@ -502,7 +569,7 @@ object LocalPreferences {
if (e is CancellationException) throw e
Log.w(
"LocalPreferences",
"Error Decoding Contact List ${getString(PrefKeys.LATEST_CONTACT_LIST, null)}",
"Error Decoding Contact List ${getString(PrefKeys.PENDING_ATTESTATIONS, null)}",
e,
)
null
@@ -595,6 +662,8 @@ object LocalPreferences {
hideBlockAlertDialog = hideBlockAlertDialog,
hideNIP17WarningDialog = hideNIP17WarningDialog,
backupContactList = latestContactList,
backupNIP65RelayList = latestNip65RelayList,
backupDMRelayList = latestDmRelayList,
proxy = proxy,
proxyPort = proxyPort,
showSensitiveContent = MutableStateFlow(showSensitiveContent),

View File

@@ -116,6 +116,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combineTransform
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flattenMerge
@@ -192,6 +193,8 @@ class Account(
var hideBlockAlertDialog: Boolean = false,
var hideNIP17WarningDialog: Boolean = false,
var backupContactList: ContactListEvent? = null,
var backupDMRelayList: ChatMessageRelayListEvent? = null,
var backupNIP65RelayList: AdvertisedRelayListEvent? = null,
var proxy: Proxy? = null,
var proxyPort: Int = 9050,
var showSensitiveContent: MutableStateFlow<Boolean?> = MutableStateFlow(null),
@@ -269,7 +272,9 @@ class Account(
if (mappedRelaySet.none { it.url == newUrl }) {
mappedRelaySet = mappedRelaySet +
RelaySetupInfo(
newUrl, true, true,
newUrl,
true,
true,
setOf(
FeedType.PRIVATE_DMS,
),
@@ -294,7 +299,9 @@ class Account(
if (mappedRelaySet.none { it.url == newUrl }) {
mappedRelaySet = mappedRelaySet +
RelaySetupInfo(
newUrl, true, false,
newUrl,
true,
false,
setOf(
FeedType.SEARCH,
),
@@ -319,9 +326,14 @@ class Account(
if (mappedRelaySet.none { it.url == newUrl }) {
mappedRelaySet = mappedRelaySet +
RelaySetupInfo(
newUrl, true, true,
newUrl,
true,
true,
setOf(
FeedType.FOLLOWS, FeedType.PUBLIC_CHATS, FeedType.GLOBAL, FeedType.PRIVATE_DMS,
FeedType.FOLLOWS,
FeedType.PUBLIC_CHATS,
FeedType.GLOBAL,
FeedType.PRIVATE_DMS,
),
)
}
@@ -344,9 +356,14 @@ class Account(
if (mappedRelaySet.none { it.url == newUrl }) {
mappedRelaySet = mappedRelaySet +
RelaySetupInfo(
newUrl, true, true,
newUrl,
true,
true,
setOf(
FeedType.FOLLOWS, FeedType.PUBLIC_CHATS, FeedType.GLOBAL, FeedType.PRIVATE_DMS,
FeedType.FOLLOWS,
FeedType.PUBLIC_CHATS,
FeedType.GLOBAL,
FeedType.PRIVATE_DMS,
),
)
}
@@ -363,10 +380,14 @@ class Account(
val write = nip65setup.type == AdvertisedRelayListEvent.AdvertisedRelayType.BOTH || nip65setup.type == AdvertisedRelayListEvent.AdvertisedRelayType.READ
RelaySetupInfo(
relay.url, true, relay.write || write,
relay.url,
true,
relay.write || write,
relay.feedTypes +
setOf(
FeedType.FOLLOWS, FeedType.GLOBAL, FeedType.PUBLIC_CHATS,
FeedType.FOLLOWS,
FeedType.GLOBAL,
FeedType.PUBLIC_CHATS,
),
)
} else {
@@ -380,9 +401,12 @@ class Account(
mappedRelaySet = mappedRelaySet +
RelaySetupInfo(
newNip65Setup.relayUrl, true, write,
newNip65Setup.relayUrl,
true,
write,
setOf(
FeedType.FOLLOWS, FeedType.PUBLIC_CHATS,
FeedType.FOLLOWS,
FeedType.PUBLIC_CHATS,
),
)
}
@@ -2635,6 +2659,26 @@ class Account(
}
}
private fun updateDMRelayList(newDMRelayList: ChatMessageRelayListEvent?) {
if (newDMRelayList == null || newDMRelayList.tags.isEmpty()) return
// Events might be different objects, we have to compare their ids.
if (backupDMRelayList?.id != newDMRelayList.id) {
backupDMRelayList = newDMRelayList
saveable.invalidateData()
}
}
private fun updateNIP65RelayList(newNIP65RelayList: AdvertisedRelayListEvent?) {
if (newNIP65RelayList == null || newNIP65RelayList.tags.isEmpty()) return
// Events might be different objects, we have to compare their ids.
if (backupNIP65RelayList?.id != newNIP65RelayList.id) {
backupNIP65RelayList = newNIP65RelayList
saveable.invalidateData()
}
}
// Takes a User's relay list and adds the types of feeds they are active for.
fun activeRelays(): Array<RelaySetupInfo>? {
val usersRelayList =
@@ -2968,8 +3012,32 @@ class Account(
suspend fun registerObservers() =
withContext(Dispatchers.Main) {
// saves contact list for the next time.
userProfile().live().follows.observeForever {
GlobalScope.launch(Dispatchers.IO) { updateContactListTo(userProfile().latestContactList) }
scope.launch {
Log.d("AccountRegisterObservers", "Kind 3 Collector Start")
userProfile().flow().follows.stateFlow.collect {
Log.d("AccountRegisterObservers", "Updating Kind 3 ${userProfile().toBestDisplayName()}")
updateContactListTo(userProfile().latestContactList)
}
}
scope.launch {
Log.d("AccountRegisterObservers", "NIP-17 Relay List Collector Start")
getDMRelayListFlow().collect {
Log.d("AccountRegisterObservers", "Updating DM Relay List for ${userProfile().toBestDisplayName()}")
(it.note.event as? ChatMessageRelayListEvent)?.let {
updateDMRelayList(it)
}
}
}
scope.launch {
Log.d("AccountRegisterObservers", "NIP-65 Relay List Collector Start")
getNIP65RelayListFlow().collect {
Log.d("AccountRegisterObservers", "Updating NIP-65 List for ${userProfile().toBestDisplayName()}")
(it.note.event as? AdvertisedRelayListEvent)?.let {
updateNIP65RelayList(it)
}
}
}
// imports transient blocks due to spam.
@@ -2990,7 +3058,7 @@ class Account(
}
init {
Log.d("Init", "Account")
Log.d("Account", "Init")
backupContactList?.let {
println("Loading saved contacts ${it.toJson()}")
@@ -2998,6 +3066,16 @@ class Account(
GlobalScope.launch(Dispatchers.IO) { LocalCache.consume(it) }
}
}
backupDMRelayList?.let {
println("Loading DM Relay List ${it.toJson()}")
GlobalScope.launch(Dispatchers.IO) { LocalCache.verifyAndConsume(it, null) }
}
backupNIP65RelayList?.let {
println("Loading saved contacts ${it.toJson()}")
GlobalScope.launch(Dispatchers.IO) { LocalCache.verifyAndConsume(it, null) }
}
}
}