Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 88 additions & 3 deletions rhodium-core/src/commonMain/kotlin/rhodium/nostr/relay/Relay.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,19 @@ import rhodium.nostr.relay.info.Payments
import rhodium.nostr.relay.info.RelayLimits
import rhodium.nostr.relay.info.RetentionPolicy

/**
* Represents a Nostr relay, including it's read/write policies.
* When creating you can use the `Relay(...)` constructor, or use
* [fromUrl], and just pass in the relay address.
*
* The read/write policies are set to true by default.
*
* @constructor Relay(String, Boolean, Boolean)
*
* @property relayURI - The relay's address, as a String
* @property readPolicy - The relay's read status(whether a relay accepts reads from it), as a Boolean.
* @property writePolicy - The relay's write status(whether a relay accepts writes to it), as a Boolean.
*/
class Relay(
val relayURI: String,
val readPolicy: Boolean = true,
Expand All @@ -48,7 +61,21 @@ class Relay(
return Relay(address)
}

suspend fun fetchInfoFor(relayUrl: String, httpClient: HttpClient = httpClient()): Info {
/**
* Fetches information about a relay, per [NIP-11](https://github.com/nostr-protocol/nips/blob/master/11.md),
* and returns the information as an [Info] object.
*
* @param relayUrl - The relay URL/URI, as a String
* @param httpClient - (Optional) A custom HTTP client that can be used for fetching the info,
* particularly for a project using a particular client.
* By default, the library's own [client][rhodium.net.httpClient] is used.
*
* @return Relay information, as an [Info] object.
*/
suspend fun fetchInfoFor(
relayUrl: String,
httpClient: HttpClient = httpClient()
): Info {
val raw = relayUrl.removePrefix("wss://").removePrefix("ws://")
val actualUrl = "https://$raw"
val relayInfoResponse = httpClient.get(actualUrl) {
Expand All @@ -61,17 +88,75 @@ class Relay(
else throw RelayInfoFetchError("Could not fetch relay info with reason: ${relayInfoResponse.bodyAsText()}")
}

fun infoFromJson(relayInfoJson: String): Info {
/**
* Transforms already obtained relay info in JSON form,
* and returns it as an `Info` object.
*
* @param relayInfoJson - The relay info, in JSON format.
*
* @return Relay information, stored as an [Info] object.
*/
fun infoFromJson(
relayInfoJson: String
): Info {
val relayInfo = eventMapper.decodeFromString<Info>(relayInfoJson)
return relayInfo
}

/**
* Does the exact opposite of [infoFromJson],
* taking relay information stored in an `Info` object, and returns it in JSON format.
*
* @param relayInfo - The relay's information, as an `Info` object
*
* @return A JSON formatted `String` representation of the relay info.
*/
fun infoToJson(
relayInfo: Info
): String {
val relayInfoJson = eventMapper.encodeToString(relayInfo)
return relayInfoJson
}
}

override fun toString(): String {
return "Relay(url=$relayURI, read=$readPolicy, write=$writePolicy)"
}

//Docs: Write something useful about Relay Info
/**
* Represents a relay's information,
* provided as per [NIP-11](https://github.com/nostr-protocol/nips/blob/master/11.md).
* The elements required for a relay's details are its name, description, banner, icon,
* pubkey, and contact. The other properties are optional.
*
* By default, an `Info` object is "empty".
*
* @property name - The relay's name
* @property description - A description of the relay
* @property banner - A banner for the relay, similar to a user profile's banner.
* @property icon - An icon for the relay, similar to a user's profile picture.
* @property pubkey - The Nostr pubkey of the relay's administrator.
* @property contact - An alternative contact for the relay administrator.
* @property supportedNips - (Optional) A list of Nostr specs(NIPs) supported by the relay.
* @property relaySoftware - (Optional) The name of the underlying relay implementation used by this relay.
* @property softwareVersion - (Optional) The version of the relay implementation currently in use by the relay.
* @property privacyPolicy - (Optional) The privacy policy for this relay.
* @property termsOfService - (Optional) The relay's terms of service.
* @property limits - (Optional) A set of limits imposed by the relay, as a [RelayLimits] object.
* @property retentionPolicies - (Optional) A set of data retention policies provided by the relay.
* A retention policy is stored as a [RetentionPolicy] object.
* @see RetentionPolicy
*
* @property relayRegionHosts - (Optional) Countries, regions, whose policies might affect the relay's hosted content.
* @property allowedLanguages - (Optional) A relay's preference concerning the language of content to be published to it.
* @property allowedTopics - (Optional) A set of allowed topics for discussion on this relay.
* @property postingPolicy - (Optional) The relay's posting policy; a set of guidelines on content
* to be published to the relay.
* @property paymentUrl - (Optional) Indicates where you should pay the relay operator.
* Usually for paid relays, or paid tiers on mixed relays.
* @property paymentInfo - (Optional) Contains info on payments to make: what to pay for, how to pay, how much to pay, etc.
* The information is stored as a [Payments] object.
*/
@Serializable
data class Info(
val name: String = "",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,41 @@
/*
* MIT License
*
* Copyright (c) 2025 KotlinGeekDev
*
* 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 rhodium.nostr.relay

import rhodium.nostr.RelayError
import kotlin.jvm.JvmStatic

/**
* Handles the relays used by the `NostrService`.
* For now, it is very simple. It just handles addition,
* removal, and resetting of the relay pool.
*
* You can specify a custom list of relays by using the `Relay(...)` primary constructor,
* or using [RelayPool.fromUrls].
*/
class RelayPool {

private val relayList: MutableList<Relay> = mutableListOf()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,18 @@ package rhodium.nostr.relay.info
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

/**
* Represents the different payment options given by the relay, provided the relay has paid features.
* For more, see [Pay-to-Relay](https://github.com/nostr-protocol/nips/blob/master/11.md#pay-to-relay).
* The payment options are divided into 3 nominal categories: admission, subscription, and publication.
* Each category has a set of payment choices, each choice represented by a [PaymentInfo] object.
*
*@see PaymentInfo
*
* @property admissionFees The payment choices for *admission*(admission tiers), as an array.
* @property subscriptionFees The payment choices for *subscription*(subscription tiers), as an array.
* @property publicationFees The payment choices for *event publication*(publishing tiers), as an array.
*/
@Serializable
data class Payments(
@SerialName("admission") val admissionFees: Array<PaymentInfo>? = null,
Expand Down Expand Up @@ -55,6 +67,17 @@ data class Payments(
}
}

/**
* Represents a payment choice, or tier, provided by the relay.
*
* @see Payments
*
* @property amount The amount to be paid for this tier.
* @property unit The currency(or units of currency) for the amount.
* @property durationInSeconds Specifies how long the usage of this tier will last.
* @property eventKinds - The event kinds that will be retained,
* or allowed for publication if paying for this tier.
*/
@Serializable
data class PaymentInfo(
val amount: Long,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* MIT License
*
* Copyright (c) 2025 KotlinGeekDev
*
* 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 rhodium.nostr.relay.info

import kotlinx.serialization.Serializable

@Serializable()
class Preferences
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,27 @@ package rhodium.nostr.relay.info
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

/**
* Represents a relay's advertised limits.
* For more, see [NIP-11](https://github.com/nostr-protocol/nips/blob/master/11.md).
* All properties here are *optional*.
*
* @property maxMessageLength - The maximum length of the event to be published, in bytes.
* @property maxSubscriptions - The maximum number of active subscriptions on a single connection to the relay.
* @property maxLimit - The maximum limit for subscription filters sent to this relay.
* @property maxSubscriptionIdLength - The maximum length of the subscription id string.
* @property maxEventTagNumber - The maximum number of tags allowed in an event published to this relay.
* @property maxContentLength - The maximum number of characters in the content field of an event to be published
* to this relay.
* @property minPowDifficulty - The minimum amount of PoW difficulty needed for an event to be published to this
* relay.
* @property isAuthRequired - Determines if the relay has placed limits on publishing events/sending requests.
* @property creationDateLowerLimit - Determines the 'lowest date', or date furthest back in time,
* that an event being published(or request being made) can reach.
* @property creationDateUpperLimit - Determines the 'highest date', or date furthest into the future, that
* an event being published(or request limit being made) to the relay can reach.
* @property defaultLimit - The limit being applied by default, when a request is sent without any limits.
*/
@Serializable
data class RelayLimits(
@SerialName("max_message_length") val maxMessageLength: Int? = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@ package rhodium.nostr.relay.info
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

/**
* Represents a relay's data retention policies, per NIP-11,
* on [event retention](https://github.com/nostr-protocol/nips/blob/master/11.md#event-retention).
*
* @property retainedKinds - A set of event kinds specified by the relay.
* Events of these kinds are the ones kept by the relay.
* @property retentionTime - The amount of time for which a set of events(specified by `retainedKinds` above)
* will be kept by the relay, measured in seconds.
* A value of zero(`0`) indicates that the relay won't store that event kind, and a `null` value indicates that
* the event set will be stored forever.
* @property retainedEventCount - The number of events for a particular
* kind(or all kinds mentioned in `retainedKinds` above) that will be stored by the relay.
*/
@Serializable
data class RetentionPolicy(
@SerialName("kinds") val retainedKinds: IntArray = emptyArray<Int>().toIntArray(),
Expand Down
Loading