Improves relay list NIP-11 caching, updates NIP-11 properties in the document and adds icon rendering from the NIP11 document.

pull/779/head
Vitor Pamplona 2024-02-22 18:43:46 -05:00
rodzic 2ee4b24c9b
commit dd160ecb71
7 zmienionych plików z 119 dodań i 30 usunięć

Wyświetl plik

@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.service
import android.util.Log
import android.util.LruCache
import com.vitorpamplona.quartz.encoders.Nip11RelayInformation
import com.vitorpamplona.quartz.utils.TimeUtils
import kotlinx.coroutines.CancellationException
import okhttp3.Call
import okhttp3.Callback
@ -31,9 +32,21 @@ import okhttp3.Response
import java.io.IOException
object Nip11CachedRetriever {
val relayInformationDocumentCache = LruCache<String, Nip11RelayInformation>(100)
open class RetrieveResult(val time: Long)
class RetrieveResultError(val error: Nip11Retriever.ErrorCode, val msg: String? = null) : RetrieveResult(TimeUtils.now())
class RetrieveResultSuccess(val data: Nip11RelayInformation) : RetrieveResult(TimeUtils.now())
val relayInformationDocumentCache = LruCache<String, RetrieveResult?>(100)
val retriever = Nip11Retriever()
fun getFromCache(dirtyUrl: String): Nip11RelayInformation? {
val result = relayInformationDocumentCache.get(retriever.cleanUrl(dirtyUrl)) ?: return null
if (result is RetrieveResultSuccess) return result.data
return null
}
suspend fun loadRelayInfo(
dirtyUrl: String,
onInfo: (Nip11RelayInformation) -> Unit,
@ -43,17 +56,40 @@ object Nip11CachedRetriever {
val doc = relayInformationDocumentCache.get(url)
if (doc != null) {
onInfo(doc)
if (doc is RetrieveResultSuccess) {
onInfo(doc.data)
} else if (doc is RetrieveResultError) {
if (TimeUtils.now() - doc.time < TimeUtils.ONE_HOUR) {
onError(dirtyUrl, doc.error, null)
} else {
Nip11Retriever()
.loadRelayInfo(
url = url,
dirtyUrl = dirtyUrl,
onInfo = {
relayInformationDocumentCache.put(url, RetrieveResultSuccess(it))
onInfo(it)
},
onError = { dirtyUrl, code, errorMsg ->
relayInformationDocumentCache.put(url, RetrieveResultError(code, errorMsg))
onError(url, code, errorMsg)
},
)
}
}
} else {
Nip11Retriever()
.loadRelayInfo(
url,
dirtyUrl,
url = url,
dirtyUrl = dirtyUrl,
onInfo = {
relayInformationDocumentCache.put(url, it)
relayInformationDocumentCache.put(url, RetrieveResultSuccess(it))
onInfo(it)
},
onError,
onError = { dirtyUrl, code, errorMsg ->
relayInformationDocumentCache.put(url, RetrieveResultError(code, errorMsg))
onError(url, code, errorMsg)
},
)
}
}
@ -81,6 +117,7 @@ class Nip11Retriever {
onInfo: (Nip11RelayInformation) -> Unit,
onError: (String, ErrorCode, String?) -> Unit,
) {
checkNotInMainThread()
try {
val request: Request =
Request.Builder().header("Accept", "application/nostr+json").url(url).build()

Wyświetl plik

@ -79,6 +79,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.RelayBriefInfoCache
import com.vitorpamplona.amethyst.model.RelaySetupInfo
import com.vitorpamplona.amethyst.service.Nip11CachedRetriever
import com.vitorpamplona.amethyst.service.Nip11Retriever
import com.vitorpamplona.amethyst.service.relays.Constants
import com.vitorpamplona.amethyst.service.relays.Constants.defaultRelays
@ -193,8 +194,10 @@ fun NewRelayListView(
onToggleSearch = { postViewModel.toggleSearch(it) },
onDelete = { postViewModel.deleteRelay(it) },
accountViewModel = accountViewModel,
nav = nav,
)
) {
onClose()
nav(it)
}
}
}
}
@ -410,9 +413,14 @@ fun ServerConfigClickableLine(
modifier = Modifier.padding(vertical = 5.dp),
) {
Column(Modifier.clickable(onClick = onClick)) {
val iconUrlFromRelayInfoDoc =
remember(item) {
Nip11CachedRetriever.getFromCache(item.url)?.icon
}
RenderRelayIcon(
item.briefInfo.displayUrl,
item.briefInfo.favIcon,
iconUrlFromRelayInfoDoc ?: item.briefInfo.favIcon,
loadProfilePicture,
MaterialTheme.colorScheme.largeRelayIconModifier,
)

Wyświetl plik

@ -62,7 +62,9 @@ class NewRelayListViewModel : ViewModel() {
_relays.value.forEach { item ->
Nip11CachedRetriever.loadRelayInfo(
dirtyUrl = item.url,
onInfo = { togglePaidRelay(item, it.limitation?.payment_required ?: false) },
onInfo = {
togglePaidRelay(item, it.limitation?.payment_required ?: false)
},
onError = { url, errorCode, exceptionMessage -> },
)
}

Wyświetl plik

@ -104,7 +104,7 @@ fun RelayInformationDialog(
Column {
RenderRelayIcon(
relayBriefInfo.displayUrl,
relayBriefInfo.favIcon,
relayInfo.icon ?: relayBriefInfo.favIcon,
automaticallyShowProfilePicture,
MaterialTheme.colorScheme.largeRelayIconModifier,
)
@ -121,7 +121,12 @@ fun RelayInformationDialog(
Section(stringResource(R.string.owner))
relayInfo.pubkey?.let { DisplayOwnerInformation(it, accountViewModel, nav) }
relayInfo.pubkey?.let {
DisplayOwnerInformation(it, accountViewModel) {
onClose()
nav(it)
}
}
Section(stringResource(R.string.software))
@ -170,12 +175,14 @@ fun RelayInformationDialog(
relayInfo.limitation?.let {
Section(stringResource(R.string.limitations))
val authRequired = it.auth_required ?: false
val authRequiredText =
if (authRequired) stringResource(R.string.yes) else stringResource(R.string.no)
val paymentRequired = it.payment_required ?: false
if (it.auth_required ?: false) stringResource(R.string.yes) else stringResource(R.string.no)
val paymentRequiredText =
if (paymentRequired) stringResource(R.string.yes) else stringResource(R.string.no)
if (it.payment_required ?: false) stringResource(R.string.yes) else stringResource(R.string.no)
val restrictedWritesText =
if (it.restricted_writes ?: false) stringResource(R.string.yes) else stringResource(R.string.no)
Column {
SectionContent(
@ -184,7 +191,7 @@ fun RelayInformationDialog(
SectionContent(
"${stringResource(R.string.subscriptions)}: ${it.max_subscriptions ?: 0}",
)
SectionContent("${stringResource(R.string.filters)}: ${it.max_subscriptions ?: 0}")
SectionContent("${stringResource(R.string.filters)}: ${it.max_filters ?: 0}")
SectionContent(
"${stringResource(R.string.subscription_id_length)}: ${it.max_subid_length ?: 0}",
)
@ -195,9 +202,13 @@ fun RelayInformationDialog(
SectionContent(
"${stringResource(R.string.content_length)}: ${it.max_content_length ?: 0}",
)
SectionContent(
"${stringResource(R.string.max_limit)}: ${it.max_limit ?: 0}",
)
SectionContent("${stringResource(R.string.minimum_pow)}: ${it.min_pow_difficulty ?: 0}")
SectionContent("${stringResource(R.string.auth)}: $authRequiredText")
SectionContent("${stringResource(R.string.payment)}: $paymentRequiredText")
SectionContent("${stringResource(R.string.restricted_writes)}: $restrictedWritesText")
}
}

Wyświetl plik

@ -39,6 +39,7 @@ import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
@ -51,6 +52,7 @@ import androidx.lifecycle.map
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.RelayBriefInfoCache
import com.vitorpamplona.amethyst.service.Nip11CachedRetriever
import com.vitorpamplona.amethyst.service.Nip11Retriever
import com.vitorpamplona.amethyst.ui.actions.RelayInformationDialog
import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage
@ -61,7 +63,6 @@ import com.vitorpamplona.amethyst.ui.theme.Size15dp
import com.vitorpamplona.amethyst.ui.theme.StdStartPadding
import com.vitorpamplona.amethyst.ui.theme.placeholderText
import com.vitorpamplona.amethyst.ui.theme.relayIconModifier
import com.vitorpamplona.quartz.encoders.Nip11RelayInformation
@Composable
public fun RelayBadgesHorizontal(
@ -132,11 +133,27 @@ fun RenderRelay(
accountViewModel: AccountViewModel,
nav: (String) -> Unit,
) {
var relayInfo: Nip11RelayInformation? by remember { mutableStateOf(null) }
val relayInfo by
produceState(
initialValue = Nip11CachedRetriever.getFromCache(relay.url),
) {
if (value == null) {
accountViewModel.retrieveRelayDocument(
relay.url,
onInfo = {
value = it
},
onError = { url, errorCode, exceptionMessage ->
},
)
}
}
if (relayInfo != null) {
var openRelayDialog by remember { mutableStateOf(false) }
if (openRelayDialog && relayInfo != null) {
RelayInformationDialog(
onClose = { relayInfo = null },
onClose = { openRelayDialog = false },
relayInfo = relayInfo!!,
relayBriefInfo = relay,
accountViewModel = accountViewModel,
@ -149,11 +166,6 @@ fun RenderRelay(
val interactionSource = remember { MutableInteractionSource() }
val ripple = rememberRipple(bounded = false, radius = Size15dp)
val automaticallyShowProfilePicture =
remember {
accountViewModel.settings.showProfilePictures.value
}
val clickableModifier =
remember(relay) {
Modifier
@ -166,7 +178,9 @@ fun RenderRelay(
onClick = {
accountViewModel.retrieveRelayDocument(
relay.url,
onInfo = { relayInfo = it },
onInfo = {
openRelayDialog = true
},
onError = { url, errorCode, exceptionMessage ->
val msg =
when (errorCode) {
@ -213,14 +227,18 @@ fun RenderRelay(
modifier = clickableModifier,
contentAlignment = Alignment.Center,
) {
RenderRelayIcon(relay.displayUrl, relay.favIcon, automaticallyShowProfilePicture)
RenderRelayIcon(
displayUrl = relay.displayUrl,
iconUrl = relayInfo?.icon ?: relay.favIcon,
loadProfilePicture = accountViewModel.settings.showProfilePictures.value,
)
}
}
@Composable
fun RenderRelayIcon(
displayUrl: String,
iconUrl: String,
iconUrl: String?,
loadProfilePicture: Boolean,
iconModifier: Modifier = MaterialTheme.colorScheme.relayIconModifier,
) {

Wyświetl plik

@ -774,4 +774,6 @@
<string name="this_version_brought_to_you_by">This version was brought to you by:</string>
<string name="version_name">Version %1$s</string>
<string name="thank_you">Thank you!</string>
<string name="max_limit">Max Limit</string>
<string name="restricted_writes">Restricted Writes</string>
</resources>

Wyświetl plik

@ -29,6 +29,7 @@ class Nip11RelayInformation(
val id: String?,
val name: String?,
val description: String?,
val icon: String?,
val pubkey: String?,
val contact: String?,
val supported_nips: List<Int>?,
@ -41,7 +42,9 @@ class Nip11RelayInformation(
val tags: List<String>?,
val posting_policy: String?,
val payments_url: String?,
val retention: List<RelayInformationRetentionData>?,
val fees: RelayInformationFees?,
val nip50: List<String>?,
) {
companion object {
val mapper =
@ -63,7 +66,6 @@ class RelayInformationFees(
val admission: List<RelayInformationFee>?,
val subscription: List<RelayInformationFee>?,
val publication: List<RelayInformationFee>?,
val retention: List<RelayInformationFee>?,
)
class RelayInformationLimitation(
@ -78,4 +80,13 @@ class RelayInformationLimitation(
val min_pow_difficulty: Int?,
val auth_required: Boolean?,
val payment_required: Boolean?,
val restricted_writes: Boolean?,
val created_at_lower_limit: Int?,
val created_at_upper_limit: Int?,
)
class RelayInformationRetentionData(
val kinds: ArrayList<Int>,
val tiem: Int?,
val count: Int?,
)