Improvements on NIP-11
- Support for self, privacy_policy, terms_of_service, grasps - New UI for the Relay Information Screen - Improvements to the Debug Message - Compose-stable objects - Clickable elements for NIPs, external links, grasps, etc
This commit is contained in:
+29
-21
@@ -21,8 +21,10 @@
|
||||
package com.vitorpamplona.quartz.nip01Core.relay.client.stats
|
||||
|
||||
import androidx.collection.LruCache
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
|
||||
@Stable
|
||||
class RelayStat(
|
||||
var receivedBytes: Int = 0,
|
||||
var sentBytes: Int = 0,
|
||||
@@ -31,12 +33,11 @@ class RelayStat(
|
||||
var pingInMs: Int = 0,
|
||||
var compression: Boolean = false,
|
||||
) {
|
||||
val messages = LruCache<RelayDebugMessage, RelayDebugMessage>(100)
|
||||
val messages = LruCache<IRelayDebugMessage, IRelayDebugMessage>(100)
|
||||
|
||||
fun newNotice(notice: String?) {
|
||||
val debugMessage =
|
||||
RelayDebugMessage(
|
||||
type = RelayDebugMessageType.NOTICE,
|
||||
NoticeDebugMessage(
|
||||
message = notice ?: "No error message provided",
|
||||
)
|
||||
|
||||
@@ -47,8 +48,7 @@ class RelayStat(
|
||||
errorCounter++
|
||||
|
||||
val debugMessage =
|
||||
RelayDebugMessage(
|
||||
type = RelayDebugMessageType.ERROR,
|
||||
ErrorDebugMessage(
|
||||
message = error ?: "No error message provided",
|
||||
)
|
||||
|
||||
@@ -63,27 +63,35 @@ class RelayStat(
|
||||
sentBytes += bytesUsedInMemory
|
||||
}
|
||||
|
||||
fun newSpam(spamDescriptor: String) {
|
||||
fun newSpam(
|
||||
link1: String,
|
||||
link2: String,
|
||||
) {
|
||||
spamCounter++
|
||||
|
||||
val debugMessage =
|
||||
RelayDebugMessage(
|
||||
type = RelayDebugMessageType.SPAM,
|
||||
message = spamDescriptor,
|
||||
)
|
||||
val debugMessage = SpamDebugMessage(link1, link2)
|
||||
|
||||
messages.put(debugMessage, debugMessage)
|
||||
}
|
||||
}
|
||||
|
||||
class RelayDebugMessage(
|
||||
val type: RelayDebugMessageType,
|
||||
val message: String,
|
||||
val time: Long = TimeUtils.now(),
|
||||
)
|
||||
|
||||
enum class RelayDebugMessageType {
|
||||
SPAM,
|
||||
NOTICE,
|
||||
ERROR,
|
||||
@Stable
|
||||
sealed interface IRelayDebugMessage {
|
||||
val time: Long
|
||||
}
|
||||
|
||||
class SpamDebugMessage(
|
||||
val link1: String,
|
||||
val link2: String,
|
||||
override val time: Long = TimeUtils.now(),
|
||||
) : IRelayDebugMessage
|
||||
|
||||
class NoticeDebugMessage(
|
||||
val message: String,
|
||||
override val time: Long = TimeUtils.now(),
|
||||
) : IRelayDebugMessage
|
||||
|
||||
class ErrorDebugMessage(
|
||||
val message: String,
|
||||
override val time: Long = TimeUtils.now(),
|
||||
) : IRelayDebugMessage
|
||||
|
||||
+3
@@ -20,6 +20,9 @@
|
||||
*/
|
||||
package com.vitorpamplona.quartz.nip01Core.relay.normalizer
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
|
||||
@Stable
|
||||
data class NormalizedRelayUrl(
|
||||
val url: String,
|
||||
) : Comparable<NormalizedRelayUrl> {
|
||||
|
||||
+7
-7
@@ -21,6 +21,7 @@
|
||||
package com.vitorpamplona.quartz.nip11RelayInfo
|
||||
|
||||
import com.vitorpamplona.quartz.utils.Log
|
||||
import com.vitorpamplona.quartz.utils.text
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.builtins.ListSerializer
|
||||
@@ -32,15 +33,14 @@ import kotlinx.serialization.json.JsonArray
|
||||
import kotlinx.serialization.json.JsonDecoder
|
||||
import kotlinx.serialization.json.JsonNull
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
import kotlinx.serialization.json.int
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
|
||||
object FlexibleIntListSerializer : KSerializer<List<Int>?> {
|
||||
private val listSerializer = ListSerializer(Int.serializer())
|
||||
object FlexibleIntListSerializer : KSerializer<List<String>?> {
|
||||
private val listSerializer = ListSerializer(String.serializer())
|
||||
|
||||
override val descriptor: SerialDescriptor = listSerializer.descriptor
|
||||
|
||||
override fun deserialize(decoder: Decoder): List<Int>? {
|
||||
override fun deserialize(decoder: Decoder): List<String>? {
|
||||
require(decoder is JsonDecoder) { "This serializer can only be used with Json format" }
|
||||
|
||||
return when (val element = decoder.decodeJsonElement()) {
|
||||
@@ -51,7 +51,7 @@ object FlexibleIntListSerializer : KSerializer<List<Int>?> {
|
||||
is JsonArray -> {
|
||||
element.mapNotNull { arrayElement ->
|
||||
try {
|
||||
arrayElement.jsonPrimitive.int
|
||||
arrayElement.jsonPrimitive.text
|
||||
} catch (e: Exception) {
|
||||
// Skip elements that aren't valid integers (strings, booleans, floats, etc.)
|
||||
Log.w("FlexibleIntListSerializer", "Invalid element in array: $arrayElement", e)
|
||||
@@ -63,7 +63,7 @@ object FlexibleIntListSerializer : KSerializer<List<Int>?> {
|
||||
// Handle single integer format (malformed but found in the wild): 1
|
||||
is JsonPrimitive if !element.isString -> {
|
||||
try {
|
||||
listOf(element.int)
|
||||
listOf(element.text)
|
||||
} catch (e: Exception) {
|
||||
// Can't parse as integer (e.g., float, boolean), treat as missing data
|
||||
Log.w("FlexibleIntListSerializer", "Invalid primitive: $element", e)
|
||||
@@ -79,7 +79,7 @@ object FlexibleIntListSerializer : KSerializer<List<Int>?> {
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
override fun serialize(
|
||||
encoder: Encoder,
|
||||
value: List<Int>?,
|
||||
value: List<String>?,
|
||||
) {
|
||||
if (value == null) {
|
||||
encoder.encodeNull()
|
||||
|
||||
+53
-43
@@ -21,19 +21,22 @@
|
||||
package com.vitorpamplona.quartz.nip11RelayInfo
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.JsonMapper
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Stable
|
||||
@Serializable
|
||||
class Nip11RelayInformation(
|
||||
val id: String? = null,
|
||||
val name: String? = null,
|
||||
val description: String? = null,
|
||||
val icon: String? = null,
|
||||
val pubkey: String? = null,
|
||||
val pubkey: HexKey? = null,
|
||||
val self: HexKey? = null,
|
||||
val contact: String? = null,
|
||||
@Serializable(with = FlexibleIntListSerializer::class)
|
||||
val supported_nips: List<Int>? = null,
|
||||
val supported_nips: List<String>? = null,
|
||||
val supported_nip_extensions: List<String>? = null,
|
||||
val software: String? = null,
|
||||
val version: String? = null,
|
||||
@@ -42,53 +45,60 @@ class Nip11RelayInformation(
|
||||
val language_tags: List<String>? = null,
|
||||
val tags: List<String>? = null,
|
||||
val posting_policy: String? = null,
|
||||
val privacy_policy: String? = null,
|
||||
val terms_of_service: String? = null,
|
||||
val payments_url: String? = null,
|
||||
val retention: List<RelayInformationRetentionData>? = null,
|
||||
val fees: RelayInformationFees? = null,
|
||||
val nip50: List<String>? = null,
|
||||
val supported_grasps: List<String>? = null,
|
||||
) {
|
||||
companion object {
|
||||
fun fromJson(json: String): Nip11RelayInformation = JsonMapper.fromJson<Nip11RelayInformation>(json)
|
||||
}
|
||||
|
||||
@Stable
|
||||
@Serializable
|
||||
class RelayInformationFee(
|
||||
val amount: Int? = null,
|
||||
val unit: String? = null,
|
||||
val period: Int? = null,
|
||||
val kinds: List<Int>? = null,
|
||||
)
|
||||
|
||||
@Stable
|
||||
@Serializable
|
||||
class RelayInformationFees(
|
||||
val admission: List<RelayInformationFee>? = null,
|
||||
val subscription: List<RelayInformationFee>? = null,
|
||||
val publication: List<RelayInformationFee>? = null,
|
||||
)
|
||||
|
||||
@Stable
|
||||
@Serializable
|
||||
class RelayInformationLimitation(
|
||||
val max_message_length: Int? = null,
|
||||
val max_subscriptions: Int? = null,
|
||||
val max_filters: Int? = null,
|
||||
val max_limit: Int? = null,
|
||||
val default_limit: Int? = null,
|
||||
val max_subid_length: Int? = null,
|
||||
val min_prefix: Int? = null,
|
||||
val max_event_tags: Int? = null,
|
||||
val max_content_length: Int? = null,
|
||||
val min_pow_difficulty: Int? = null,
|
||||
val auth_required: Boolean? = null,
|
||||
val payment_required: Boolean? = null,
|
||||
val restricted_writes: Boolean? = null,
|
||||
val created_at_lower_limit: Int? = null,
|
||||
val created_at_upper_limit: Int? = null,
|
||||
)
|
||||
|
||||
@Stable
|
||||
@Serializable
|
||||
class RelayInformationRetentionData(
|
||||
val kinds: ArrayList<Int>? = null,
|
||||
val time: Int? = null,
|
||||
val count: Int? = null,
|
||||
)
|
||||
}
|
||||
|
||||
@Stable
|
||||
@Serializable
|
||||
class RelayInformationFee(
|
||||
val amount: Int? = null,
|
||||
val unit: String? = null,
|
||||
val period: Int? = null,
|
||||
val kinds: List<Int>? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class RelayInformationFees(
|
||||
val admission: List<RelayInformationFee>? = null,
|
||||
val subscription: List<RelayInformationFee>? = null,
|
||||
val publication: List<RelayInformationFee>? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class RelayInformationLimitation(
|
||||
val max_message_length: Int? = null,
|
||||
val max_subscriptions: Int? = null,
|
||||
val max_filters: Int? = null,
|
||||
val max_limit: Int? = null,
|
||||
val max_subid_length: Int? = null,
|
||||
val min_prefix: Int? = null,
|
||||
val max_event_tags: Int? = null,
|
||||
val max_content_length: Int? = null,
|
||||
val min_pow_difficulty: Int? = null,
|
||||
val auth_required: Boolean? = null,
|
||||
val payment_required: Boolean? = null,
|
||||
val restricted_writes: Boolean? = null,
|
||||
val created_at_lower_limit: Int? = null,
|
||||
val created_at_upper_limit: Int? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class RelayInformationRetentionData(
|
||||
val kinds: ArrayList<Int>? = null,
|
||||
val time: Int? = null,
|
||||
val count: Int? = null,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user